App integration
Flutter
Add Reception's native iOS support chat to a Flutter app with the reception_flutter package. The chat runs entirely in the official Reception iOS SDK, which the package bundles; the Dart API mirrors the React Native and native iOS ones. It needs Flutter 3.44+, Dart 3.12+, iOS 17+ and Xcode 26. Android and web calls complete immediately, log once and return default state.
Most teams let a coding agent do the setup: copy the prompt from Settings → your app → SDK setup in the dashboard; it detects Flutter from pubspec.yaml. The rest of this page is what the agent follows and what you need when you change things by hand.
1. Install
flutter pub add reception_flutterSwift Package Manager and CocoaPods both work without Podfile edits. Set the iOS deployment target to 17.0 or higher at the project level (Xcode: Runner project → Info → iOS Deployment Target, or the three IPHONEOS_DEPLOYMENT_TARGET entries in ios/Runner.xcodeproj/project.pbxproj), and raise any Runner target-level entries below 17.0. If ios/Podfile exists and pins an older platform, set platform :ios, '17.0' there too; a post_install hook that forces an older target on all pods must use 17.0 or skip reception_flutter. The chat follows the languages declared under CFBundleLocalizations in ios/Runner/Info.plist.
Do not also add the native reception-ios package: the plugin already bundles the SDK, and two copies would share the same storage.
2. Configure
Configure once in main(), before showing Support, and after Firebase.initializeApp() and any other notification plugin's setup. Your public App ID is in the dashboard under Settings → your app → General.
import 'package:flutter/widgets.dart';
import 'package:reception_flutter/reception_flutter.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Reception.configure(appId: 'app_YOUR_APP_ID');
runApp(const MyApp());
}Reception.isConfigured tells whether the native side accepted the configuration. Pass handlesNotifications: false only if your app routes Reception's own notifications itself; see Push.
3. Open chat
Call this from your app's Support button, shown only on iOS (!kIsWeb && defaultTargetPlatform == TargetPlatform.iOS); keep your existing contact path on other platforms:
await Reception.openChat();Reception.closeChat() dismisses the presented sheet. Reception.isChatOpen is a ValueListenable<bool> of whether the chat is visible.
Report app events for automations with await Reception.track('paywall_declined', opensChat: true).
Appearance and language
Assign a complete ReceptionAppearance; it applies immediately. Colors take a hex string or an adaptive light/dark pair, read from your app's theme so both modes follow the app.
Reception.appearance = const ReceptionAppearance(
accentColor: ReceptionColor.adaptive(light: '#635BFF', dark: '#A59FFF'),
onAccentColor: '#FFFFFF',
chatBackground: ReceptionColor.adaptive(light: '#FFFFFF', dark: '#151225'),
incomingBackground: ReceptionColor.adaptive(light: '#F2F2F7', dark: '#2C2C2E'),
incomingForeground: ReceptionColor.adaptive(light: '#000000', dark: '#FFFFFF'),
title: 'Support',
showsCloseButton: true,
);Other options: welcomeTitle, welcomeText, welcomeIcon (a symbol, an iOS asset image, or none) with welcomeIconColor, welcomeIconSize, welcomeIconCornerRadius and welcomeIconOffset; preferredColorScheme for an app that is always light or dark; closeIcon or closeImage; fontDesign or fontFamily (a font registered with iOS, not a pubspec.yaml font); fadesOlderMessages; and hidesTitle, hidesWelcomeTitle, hidesWelcomeText and hidesPushStatus (the "You'll get a notification when we reply." line). The dashboard's remote appearance overrides these without an app update unless you set Reception.usesRemoteAppearance = false.
The chat follows the app's language by itself. Only if your app has its own in-app language setting, set Reception.languageOverride = 'de' from it and update it when it changes; null follows the device. Texts are built in for 48 languages; see Text & localization.
Entry and unread badges
Reception.unreadCount is a ValueListenable<int>. Show it on the Support entry and on every menu row on the way, and hide the badge at zero:
ValueListenableBuilder<int>(
valueListenable: Reception.unreadCount,
builder: (context, unread, _) => Badge.count(
count: unread,
isLabelVisible: unread > 0,
child: const Icon(Icons.chat_bubble_outline),
),
)The count updates while the app runs and after launch; see Unread messages & badges. Reception.updatesAppBadge = false keeps the app icon badge under your control.
Accounts and user details
Identify the person so the team knows who writes:
await Reception.identify(ReceptionIdentity.user(userId: user.id, name: user.name, email: user.email));
await Reception.setMetadata({'plan': 'pro', 'orders': '12'});ReceptionIdentity.userlabels the device with a real signed-in account ID and optional name and email; use it with no user ID for a name the person entered without an account.ReceptionIdentity.tokencarries a signed token from your server for identity verification. The chat emitsReceptionIdentityRejectedwhen the server refuses it.setMetadatareplaces the whole dictionary (string values, up to 20 fields); names and emails belong inidentify.Call
Reception.logout()wherever a signed-in session ends, before the next person'sidentify, andawait Reception.deleteData()on account deletion. Both clear the user details and the push token; send them again with the next sign-in.deleteDatathrows aReceptionErrorwith code and HTTP status on failure.
Push
Add the Push Notifications capability to the Runner target and your Apple push credentials in the dashboard under Settings → your app → Push Notifications. With the default handlesNotifications: true, the plugin then:
registers the APNs device token with Reception,
shows Reception banners while the chat is closed and stays quiet while it is open,
opens the chat when a Reception notification is tapped, including cold starts,
keeps forwarding notifications from Firebase, OneSignal and other services to their own handlers.
It never requests permission: after your own permission request, call await Reception.registerForPushIfAuthorized(). If you prefer, turn on Ask for push notifications in the dashboard: the chat then asks with a small card right after the person's first message, with no code in your app; see Push notifications.
Apps that get the APNs token elsewhere, for example from Firebase's getAPNSToken(), pass it on with Reception.setPushToken(hexToken); FCM tokens are rejected. Apps that route notifications themselves (handlesNotifications: false) call await Reception.handlePushNotification(payload, openChat: tapped) for every notification; it returns true for Reception's. Payload shape, APNs setup and verification are on the push notifications page.
Paywalls
Register the paywalls your app can show, so the team, automations and the AI can send offer cards that open them:
Reception.paywalls = [ReceptionPaywall(id: 'plans', title: 'Plans')];
Reception.onPaywall = (id) => showPaywall(id); // the chat stays open behind it
Reception.paywallAvailability = (id) async => !await isSubscribed(); // optionalReception.availablePaywalls lists the registered paywalls that are available right now. Call Reception.refreshPaywalls(invalidate: true) after a purchase or subscription change. Pending offers become unavailable on failures, timeouts and hot restarts. The paywalls page has drop-in files for RevenueCat, Superwall and Adapty that fill paywalls and report the person's plan as user details.
Screens for link cards
Link cards open websites, other apps, the App Store, Mail and the phone without code. To let them open screens of your app too, list the screens once at startup; the dashboard then offers them by name and sends a screen link only to app versions that have it:
Reception.screens = [
ReceptionScreen('settings', onOpen: () => router.push('/settings')),
ReceptionScreen('paywall', onOpen: showPaywall),
ReceptionScreen.withValue('order', value: 'Order number', onOpenWithValue: (number) => router.push('/orders/$number')),
];onOpen runs after the chat closes. IDs use letters, digits, _, - or ., at most 64 characters, and stay stable: a renamed ID is a new screen. Set the list again at startup after a hot restart; until then the app reports no screens. The dashboard's Add a link → Screen in your app has a prompt for a coding agent that finds your screens and writes this list.
Embedded chat
ReceptionChatView() embeds the chat in your own screen instead of the sheet; give it a defined size, and your screen owns dismissal. The welcome texts, appearance and unread count apply the same way. Reception.closeChat() does not close an embedded view.
Events and diagnostics
Reception.onEvent receives ReceptionChatOpened, ReceptionMessageSent, ReceptionImageSent, ReceptionReviewOpened, ReceptionPaywallOpened, ReceptionLinkOpened, ReceptionDataDeleted and ReceptionIdentityRejected(error). Assignment replaces the previous handler; a hot restart clears it, so assign it in main(). See Events & callbacks.
Reception.logLevel = ReceptionLogLevel.debug prints the SDK's log lines (subsystem com.reception.sdk in Console) while you set things up. Reception.version is the bundled iOS SDK version.
Build and simulator checks
Build and run on an iOS simulator with flutter run, or build once with flutter build ios --simulator --debug and install build/ios/iphonesimulator/Runner.app with xcrun simctl install. Debug simulator builds support the SDK's launch arguments: -ReceptionSetupCheck <app id> sends the first message and logs the result, and -ReceptionPreview welcome or conversation opens the chat with example data; the setup page explains them. Let main() finish configuring Reception before reading the result.
For package:reception_flutter/testing.dart, configureReceptionForTesting(appId:, serviceUrl:) points a Debug simulator build at a local Reception backend; it is a no-op in release builds.
Updating
Run flutter pub upgrade reception_flutter, then pod install in ios/ if the project has a Podfile, and rebuild. The changelog lists what each release changes; the dashboard shows an update card when a newer version is available.