<!-- AI agents: this is the Markdown version of a Reception documentation page. Index: /llms.txt -->

# Get started

Add ReceptionKit to your iOS app, send your first message, and reply from the Reception dashboard. A coding agent does the setup with one prompt; by hand it takes a package and a few lines of Swift.

## Requirements

- An iOS 17 or later app, using SwiftUI or UIKit.
- Xcode 26 and Swift Package Manager.
- A Reception dashboard account with permission to create an app.

ReceptionKit has no package dependencies. Your iOS app does not need user accounts or push notifications for its first conversation.

## Create an app in the dashboard {#create-an-app}

1. Sign in and choose **Add your app**, or **Settings → Apps → Add app**.
2. Enter your app's name and create the app.
3. On **Connect**, choose **Copy setup prompt** for a coding agent or **Set up manually** for the Swift snippet. Both contain your app's configuration.

For an existing app, open **Settings → Apps → your app**. Before its first conversation, **Connect your app** offers the same setup options. Its permanent **App ID** is also available under **Setup**.

The App ID starts with `app_` and is safe to include in your app. It's the only configuration your app needs.

![Connect screen with Copy setup prompt and Set up manually controls](/docs/images/dashboard-connect-setup.webp "Copy the prepared setup prompt or open Set up manually.")

## Set up with a coding agent {#set-up-with-the-prompt}

Your coding agent adds ReceptionKit to your app, fits it into your app's design and flows, and checks that messages arrive. You answer two questions.

1. Choose **Copy setup prompt** in the dashboard. The prompt contains your App ID.
2. Paste it into your coding agent, such as Claude Code, Codex or Cursor, with your iOS project open.
3. Answer the agent's two questions.
4. Review the changes and the agent's report.

A coding agent with only this page follows the [setup prompt](#setup-prompt) below and asks you for the App ID.

### The two questions {#questions}

- **Where Support goes.** The agent recommends a Support entry on your home screen plus a row in Settings, in your app's style. If your app already has a contact option, it asks whether Support should replace it. The entry is your app's own code, so it can look and sit wherever you like.
- **What your team sees about each user.** The agent lists details it found in your app, such as the plan, sign-up date or number of projects. Pick any, name others, or choose none. They show next to each chat.

### What the agent does by itself {#automatic}

- Adds the package and configures it with your App ID.
- Adds a line with the docs link to your project's `AGENTS.md`, and to `CLAUDE.md` if you have one, so later agent sessions know where to look.
- Matches the chat to your app's colors, font, and light or dark mode, and connects your in-app language setting if there is one.
- Builds the Support entry and shows unread badges on it, on its tab, and on every row that leads to it.
- Connects sign-in, sign-out and account deletion if your app has accounts.
- Adds push handling without asking your users for notification permission. Once your app has permission and you've uploaded your APNs key, replies arrive as notifications.
- Connects your paywall to [paywall cards](/docs/paywalls) if your app has one.
- Builds the app and runs the setup check: the app sends "Hello from setup" from a simulator, and the message appears in your inbox. It's a real message and counts as your app's first conversation.

Identity verification is not part of setup. Signed-in customers show as **Unverified** in the inbox until you add it with its own prompt in the dashboard. See [Verified users](/docs/accounts#verified-users).

### Your steps afterwards {#afterwards}

1. **Push:** upload your APNs key under **Settings → Apps → your app → Apple Push Notifications**, then check on an iPhone that a reply arrives. See [Push notifications](/docs/push-notifications).
2. **App Store privacy:** update your app's privacy details in App Store Connect. Your agent can list what to select; see [App Store privacy](/docs/privacy-and-data#app-store-privacy).
3. **Reply:** answer a message in the inbox and check that it arrives in the app.

### Change it later {#change-later}

Tell your coding agent, for example "Move Support to the profile screen", "Use our secondary color in the chat" or "Also show the user's plan". The docs link next to `Reception.configure` and in your project's `AGENTS.md` leads agents in later sessions to the right page.

You can also change the chat's colors and welcome text without an app update under **Settings → Apps → your app → Chat appearance**. See [Remote appearance](/docs/remote-appearance).

### Setup prompt {#setup-prompt}

The dashboard copies this prompt with your App ID filled in.

````text Setup prompt {collapsed}
Integrate Reception, a native in-app support chat, into this iOS app.

App ID: not included. Ask the developer for it along with the questions in step 2 (dashboard: Settings → Apps → your app → Setup) and use it wherever app_YOUR_APP_ID appears. Never ship the placeholder.
Swift package: https://github.com/andilosing/reception-ios.git (branch main), product ReceptionKit
Docs for agents: https://reception.sh/llms.txt (every page is also Markdown at https://reception.sh/docs/<page>.md)

Work through the steps in order. Keep the app's code, style and flows; change only what the integration needs.

## 1. Understand the app

Inspect the app target, startup code, SwiftUI or UIKit, navigation (tabs, settings, menus), theme (color assets, theme types, custom fonts, fixed light or dark mode), sign-in and account deletion, notification handling, an in-app language setting, paywall code, and any existing contact or feedback path.

## 2. Ask two questions, then wait

Ask both in one message with your recommendations and wait for the answers. Everything else happens without asking.

a) Where should Support go? Recommend a Support entry on the home screen plus a Support row in Settings: the home screen brings the most feedback early, and it can move anytime. Describe the concrete plan in the app's own style (screen, button or row, icon, label) and invite changes. If the app already has a contact or feedback path, point it out and ask whether Support should replace it.
b) Which user details should the team see next to each chat? List concrete fields you found that help support, for example plan, sign-up date or counts of the app's main objects. Reception already shows app version, device, OS, language, region and push status, so skip those. With RevenueCat's paywall builder, the paywall file can send plan, status and renewal date; offer them as fields. The developer picks, names others, or says none. Never propose health data, passwords, precise location or payment details.

## 3. Add the package and configure

Add the ReceptionKit product to the app target (branch main); for XcodeGen or Tuist, edit the manifest and regenerate. ReceptionKit needs iOS 17+ and Xcode 26; report an older deployment target instead of changing it.

Configure once at launch on the main actor, in the existing App initializer (UIKit: application(_:didFinishLaunchingWithOptions:)), with this comment so later sessions find the docs:

```swift
// Reception support chat. Docs for changes: https://reception.sh/llms.txt
Reception.configure(appId: "app_YOUR_APP_ID")
```

Add this line to AGENTS.md at the project root (create the file if there is none) and, if the project has a CLAUDE.md, to that too, so later agent sessions find the docs:

```markdown
- Reception support chat (ReceptionKit): before changing or debugging it, read https://reception.sh/llms.txt and the page it links for the task. If the docs are unreachable, work from the ReceptionKit package source and say what you couldn't verify.
```

Right after configure, match the chat to the app:

- Set Reception.shared.appearance.accentColor, onAccentColor, chatBackground, incomingBackground and incomingForeground from the app's own colors, and fontFamily from its custom font. Read them from its color assets or theme type, so light and dark mode follow the app, and set them again when the app's own theme setting changes. Never hardcode or invent colors; leave an option unset when the app has no matching color.
- If the app is always dark or always light, or has its own light/dark setting, set preferredColorScheme from it.
- The chat follows the app's language by itself. Only if the app has its own in-app language setting, set Reception.shared.languageOverride from it and update it when it changes.
- Keep the chat's own texts; they are localized in 48 languages.

## 4. Add the support entry

Build the entry the developer chose with the app's own components, fonts and colors, calling Reception.shared.openChat(); localize its label through the app's strings. Show Reception.shared.unreadCount on the entry, on the tab that contains it (SwiftUI .badge(count), UIKit tabBarItem.badgeValue) and on every menu row on the way; hide badges at zero.

## 5. Connect what the app already has

Accounts, if users sign in to the app, with or without a server (skip apps without sign-in, and anonymous or guest IDs the app creates by itself):

- After restoring a signed-in session and after sign-in: Reception.shared.identify(userId:name:email:) with what the app knows and nil for the rest; no placeholders.
- Wherever the app ends a signed-in session (sign-out, account switch, a session found expired at launch): Reception.shared.logout(), before the next user's identify. Never when nobody was signed in, such as a guest at launch or before a first sign-in: it starts a new, empty chat.
- On account deletion: await Reception.shared.deleteData() before discarding the session; on failure keep the session, show the app's error UI and allow retry.
- logout() and deleteData() also clear the user details and the push token: send the user details again with the next identify, and call registerForPushIfAuthorized().

User details: send the fields chosen in 2b with Reception.shared.setMetadata(["plan": "Pro"]) (string values, up to 20), and again when they change. Each call replaces all fields, so set them in one place.

Push, always, but never request notification permission or add a permission prompt:

```swift
// In the app delegate (SwiftUI: reuse or add @UIApplicationDelegateAdaptor):
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken token: Data) {
    Reception.shared.setPushToken(token)
}

// At launch and whenever the app becomes active; registers only if permission already exists:
@MainActor func registerForPushIfAuthorized() async {
    let status = await UNUserNotificationCenter.current().notificationSettings().authorizationStatus
    if [.authorized, .provisional, .ephemeral].contains(status) { UIApplication.shared.registerForRemoteNotifications() }
}

// In the existing UNUserNotificationCenterDelegate (make the app delegate the delegate if there is none):
nonisolated func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
    let payload = notification.request.content.userInfo["reception"] as? [String: Any]
    if let conversationId = payload?["conversationId"] as? String {
        let options: UNNotificationPresentationOptions? = await MainActor.run {
            guard Reception.shared.handlePushNotification(userInfo: ["reception": ["conversationId": conversationId]], openChat: false) else { return nil }
            return Reception.shared.isChatOpen ? [] : [.banner, .sound]
        }
        if let options { return options }
    }
    return [.banner, .sound] // Keep the app's existing policy for its own notifications.
}

nonisolated func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
    let payload = response.notification.request.content.userInfo["reception"] as? [String: Any]
    if let conversationId = payload?["conversationId"] as? String {
        let handled = await MainActor.run { Reception.shared.handlePushNotification(userInfo: ["reception": ["conversationId": conversationId]]) }
        if handled { return }
    }
    // Keep the app's existing tap handling for its own notifications here.
}
```

Merge these into existing callbacks and keep other notification services working. With Firebase Messaging or OneSignal, pass the raw APNs token Data, never an FCM token or OneSignal ID. Add the Push Notifications capability when signing allows. If the app sets its icon badge itself, set Reception.shared.updatesAppBadge = false at launch.

Paywall cards, only if the app has a paywall. Choose by where the paywall is built, not by what processes purchases, and copy the matching file from https://reception.sh/docs/paywalls.md unchanged apart from its placeholders:

- RevenueCat paywall builder (RevenueCatUI): ReceptionRevenueCatPaywalls.swift, then ReceptionRevenueCatPaywalls.start(), which sends plan, status and renewal date as user details. If the developer chose other user details too, or declined these, use start(syncsSubscriptionMetadata: false) and send the chosen fields in one setMetadata call, as "Your own metadata" in paywalls.md shows.
- Superwall, also with RevenueCat for purchases: ReceptionSuperwallPaywalls.swift, then start(placements:) with every placement the app registers, each with a title the team recognizes.
- The app's own paywall screen, with RevenueCat or StoreKit: ReceptionStorePaywall.swift, pointed at that screen and its product IDs, then start().

Start it after Reception.configure and the vendor's configure. With the RevenueCat file, call Reception's logout or identify before Purchases.logIn or logOut. Without internet access, skip paywall cards and say so in the report.

Don't add identity verification; the dashboard offers it later with its own prompt.

## 6. Build and check

Build the app's scheme in Debug for an installed iOS simulator, signed as Xcode normally signs simulator builds (without signing, the chat can't use the Keychain and the check fails), and fix errors and warnings you introduced. Then run the setup check, which Debug simulator builds contain:

```sh
xcrun simctl install <device> <path to the built .app>
xcrun simctl launch --terminate-running-process <device> <bundle identifier> -ReceptionSetupCheck app_YOUR_APP_ID
xcrun simctl spawn <device> log show --last 2m --info --style compact --predicate 'subsystem == "com.reception.sdk"'
```

Repeat the log command every 10 seconds, for up to 70 seconds, until a setup check result appears after this launch. "Setup check passed" means Reception received the message "Hello from setup"; it shows in the dashboard inbox and counts as the app's first message. On "Setup check failed: <reason>", fix the cause and run it again: app_id_mismatch (a different App ID is configured), send_not_allowed (sending is blocked), not_delivered (the ReceptionKit lines before it name the reason), app_not_active (the app didn't reach the foreground), timeout. If you can't run a simulator or no result appears, say so; never report the check as passed.

## 7. Report

Keep it short:

- Changed files; where Support sits and how it looks; what you took from the theme; the accounts, push, paywall and user-detail connections.
- The build and setup check results.
- The developer's remaining steps: upload the APNs key (dashboard: Settings → Apps → your app → Apple Push Notifications); update the App Store privacy details in App Store Connect, offering to list exactly what to select from the app's integration (https://reception.sh/docs/privacy-and-data.md, section App Store privacy); check push on an iPhone.
- That they can change placement, look or user details anytime by telling you, and the chat's look without an app update in the dashboard under Settings → Apps → your app → Chat appearance.

Never put secrets, tokens or customer data in the report. Keep changes focused, add no other app dependencies, preserve existing work, and leave commits to the developer.
````

## Set up manually {#set-up-manually}

### Add the package

In Xcode, choose **File → Add Package Dependencies** and enter:

```text
https://github.com/andilosing/reception-ios.git
```

Select branch **main** and add the **ReceptionKit** product to your app target.

### Configure your existing app

Configure once in your existing SwiftUI `App` initializer, keeping your current root view and other startup work. Replace `app_YOUR_APP_ID` with your App ID; **Set up manually** in the dashboard shows this snippet with it filled in.

```swift
import SwiftUI
import ReceptionKit

@main
@MainActor
struct MyApp: App {
    init() {
        Reception.configure(appId: "app_YOUR_APP_ID")
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
```

`ContentView()` represents your existing root view. Configure once at launch, before using support, and keep SDK calls on the main actor. For an existing UIKit app, follow [UIKit integration](/docs/uikit).

### Add a visible entry point

Place this button in your existing settings screen or another chosen SwiftUI view, and import `ReceptionKit` in that file:

```swift
Button {
    Reception.shared.openChat()
} label: {
    HStack {
        Text("Support")
        Spacer()
        if Reception.shared.unreadCount > 0 {
            Text("\(Reception.shared.unreadCount) unread")
                .foregroundStyle(.secondary)
        }
    }
}
```

`openChat()` presents the chat sheet. The unread count updates the view automatically. Adapt the label and badge to your app's styling and localization. See [Open & close the chat](/docs/entry-point) for other placements and presentations.

If your app manages its own icon badge, set `Reception.shared.updatesAppBadge = false` at launch. Your in-app support badge still works.

### Development builds {#check-development-connectivity}

Simulator and iPhone builds connect to the hosted service with ordinary internet access. A separate app in the dashboard keeps test conversations apart from customer messages.

## Send your first message {#send-your-first-message}

1. Run your app and open **Support**.
2. Send `Hello from setup` and wait for **Sent**, or its localized equivalent, below the message.
3. Open that conversation in the dashboard. On **Connect**, it appears after **First message received**; otherwise find it in **Inbox** with the same app selected.
4. Reply with a recognizable message, such as `Hello back from the dashboard`, and confirm it appears in the iOS chat.
5. Dismiss and reopen chat to check the entry point.

**Sent** confirms Reception accepted the message. Seeing your dashboard reply in the app confirms the return path. Building the app or opening an empty chat alone does not verify the connection.

If you are in onboarding, choose **Continue** to reach **Integrations**, then continue to **Revenue** before **Go to inbox**. Push, Telegram, reviews, and [revenue connections](/docs/connect-revenue) are also available in app settings.

![Default ReceptionKit welcome screen in a sheet](/docs/images/ios-welcome.webp "Open support, send a message, and receive a dashboard reply.")

### If verification fails

| Symptom | What to check |
| --- | --- |
| Chat does not open | Configure before the button is used; check whether another sheet is already presenting. |
| The message is not sent | Check the copied configuration and internet connection. Follow any wait shown in chat, then use Retry when available. |
| The dashboard is still waiting | Check that you selected the app whose App ID is in your build. |
| A reply does not appear | Keep the app active with chat open and check its connection message. |

See [Troubleshooting](/docs/troubleshooting) for more help. Something not working? Write to us in the Reception chat. We're happy to help. Briefly describe what happens and any error message you see.

## Next steps {#next-steps}

- [Users & accounts](/docs/accounts#connect): show customer information and connect sign-in, sign-out, and account deletion.
- [Push notifications](/docs/push-notifications): let customers receive replies while away from the app; verify delivery on an iPhone.
- [Appearance](/docs/appearance) and [Language](/docs/language): match your existing theme and language settings.
- [Paywalls](/docs/paywalls): open your app's existing purchase screen from a support card.
- [Dashboard](/docs/dashboard): work with conversations, your team, and optional integrations.
- [Swift API reference](/docs/sdk-reference): look up SDK calls and options.
