> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clix.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from Clix to Firebase Cloud Messaging

> Use Firebase Cloud Messaging directly and move Clix campaign logic to your backend.

<Warning>
  **Clix will shut down on November 30, 2026.**

  Complete your migration before this date to continue sending notifications.
  Preserve your campaign settings and reports before the service shuts down.

  If you would like to migrate to **Notifly**, email
  [support@clix.so](mailto:support@clix.so) for migration assistance.
</Warning>

<Warning>
  **Migration impact**

  * **Register with your backend.** Clix already uses FCM, but its device records do not automatically become your server's registrations. Keeping the same Firebase project may preserve existing tokens.
  * **Choose the registration API.** Current Firebase documentation recommends registered Firebase Installation IDs (FIDs). Keep FIDs and legacy FCM tokens distinct.
  * **Keep permissions and preferences.** The same installed app retains OS permission; your backend must also enforce existing marketing opt-outs.
  * **Replace campaign management.** Scheduling, event triggers, audiences, suppression, and reporting need explicit replacements.
</Warning>

This guide walks you through removing the Clix SDK while retaining Firebase Cloud Messaging as your delivery service. Your app will handle registration and notifications, and your backend will decide when and to whom messages are sent.

## Before Getting Started

* Keep the existing Firebase project, Android package name, and iOS bundle identifier when possible.
* Check that `google-services.json` and `GoogleService-Info.plist` belong to that project.
* Prepare an authenticated backend registration endpoint and a server-side send worker.
* Record Clix user mappings, notification handlers, campaign schedules, and messaging preferences.

<Info>
  Firebase's Notifications composer can support some campaign workflows. The FCM
  send API does not reproduce Clix's campaign engine, so plan a replacement for
  each workflow you use.
</Info>

## Migration Steps

<Steps>
  <Step title="Keep Firebase and remove Clix">
    Remove Clix initialization, notification configuration, user and event calls, and Clix listeners. Keep Firebase initialization and configuration files.

    <AccordionGroup>
      <Accordion title="Remove platform-specific Clix integration">
        * **Android:** Remove `so.clix:clix-android-sdk` or its version catalog alias. Keep the Google Services plugin and declare Firebase Messaging directly if Clix previously supplied it transitively.
        * **iOS:** Remove the Clix package or pod. Replace `ClixAppDelegate` with your normal app delegate and implement the Firebase and notification callbacks it previously supplied.
        * **React Native:** Remove `@clix-so/react-native-sdk`. Keep Firebase modules used by your app and reconnect foreground, background, and notification-open handlers.
        * **Flutter:** Remove `clix_flutter`. Keep `firebase_core` and `firebase_messaging` and reconnect message and token listeners.

        Replace the Clix notification service extension if you need rich media or receipt tracking. Remove Clix-specific receivers, imports, and extension code before building.
      </Accordion>
    </AccordionGroup>

    Follow the official [Android setup](https://firebase.google.com/docs/cloud-messaging/android/get-started) or [Apple setup](https://firebase.google.com/docs/cloud-messaging/ios/get-started). Use SDK versions that support the registration path you choose. Pin compatible versions rather than copying old version numbers from your Clix integration.
  </Step>

  <Step title="Register installations with your server">
    The examples below use the current FID registration flow. Upload the identifier returned by **Firebase Messaging after registration**, together with its type and Firebase project. Reading an unregistered Firebase Installations ID alone is not enough.

    <Tabs>
      <Tab title="Android">
        Enable FID registration inside your existing manifest's `application` element:

        ```xml AndroidManifest.xml theme={null} theme={null}
        <meta-data
            android:name="firebase_messaging_installation_id_enabled"
            android:value="true" />
        ```

        Register one messaging service in the same element:

        ```xml AndroidManifest.xml theme={null} theme={null}
        <service
            android:name=".AppMessagingService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        ```

        ```kotlin AppMessagingService.kt theme={null} theme={null}
        import com.google.firebase.messaging.FirebaseMessagingService
        import com.google.firebase.messaging.RemoteMessage

        class AppMessagingService : FirebaseMessagingService() {
            override fun onRegistered(installationId: String) {
                // Queue a retryable upload to your authenticated backend:
                // identifier = installationId, type = "fid", project = your project
            }

            override fun onMessageReceived(message: RemoteMessage) {
                // Handle foreground messages or data messages in your app.
            }
        }
        ```

        With auto-initialization enabled, registration callbacks keep your server updated. If it is disabled, call `FirebaseMessaging.getInstance().register()` at app startup and handle failure with retries. Reassociate the stored current registration after login or an account switch.
      </Tab>

      <Tab title="iOS">
        Keep Firebase Messaging, your existing Firebase configuration, and the APNs credentials in Firebase. Add the following to the app's `Info.plist`:

        ```xml Info.plist theme={null} theme={null}
        <key>FirebaseMessagingInstallationIdEnabled</key>
        <true/>
        ```

        Set `Messaging.messaging().delegate` after `FirebaseApp.configure()`. In your delegate conforming to `MessagingDelegate`, receive the registered FID:

        ```swift AppDelegate.swift theme={null} theme={null}
        import FirebaseMessaging

        func messaging(
            _ messaging: Messaging,
            didReceiveRegistration installationId: String?
        ) {
            guard let installationId else { return }
            // Queue a retryable upload to your authenticated backend:
            // identifier = installationId, type = "fid", project = your project
        }
        ```

        Register with APNs using `registerForRemoteNotifications()`. Restore `UNUserNotificationCenterDelegate` for presentation and taps. For SwiftUI or disabled Firebase swizzling, forward the APNs device token to `Messaging.messaging().apnsToken` as described in the Apple setup guide.
      </Tab>
    </Tabs>

    <Note>
      The upload and display comments above are application integration points, not a complete backend or notification renderer. Implement them before enabling sends. Store registration uploads durably and retry network failures.
    </Note>

    If your SDK or cross-platform wrapper still uses token registration, retrieve its current FCM token on startup and upload token changes through its documented callback. Use the send API's `token` field for those records. Do not label a token as an FID or enable FID mode before your entire send path supports it. See [registration management](https://firebase.google.com/docs/cloud-messaging/manage-tokens).
  </Step>

  <Step title="Move user data and campaign logic">
    | Clix integration | Direct FCM replacement |
    | - | - |
    | `Clix.setUserId()` | Authenticated account-to-installation mapping on your backend |
    | User properties | Your application database or audience service |
    | `Clix.trackEvent()` | Your event pipeline and trigger worker; Firebase Analytics is optional |
    | Scheduled campaigns | Scheduler and send queue |
    | Frequency caps and quiet hours | Server-side eligibility checks shared by all sends |
    | Delivery and open metrics | FCM reporting plus your own attribution pipeline |

    Store registrations per installation so an account can have multiple devices. Include account association, platform, identifier type, Firebase project, app version, permission state, preferences, and last registration time. Validate the account from the authenticated session rather than trusting a submitted user ID.

    On logout, remove the account association and account-specific topic subscriptions. On login, associate the current registration with the new account. Keep anonymous messaging eligibility explicit.

    Recreate each Clix campaign's trigger, schedule, audience, delay, cancellation rule, and personalization in your backend. Carry over frequency limits and quiet hours before launching any automated sends.
  </Step>

  <Step title="Replace Clix send requests and payloads">
    Send from a trusted backend using a current Firebase Admin SDK or the [FCM HTTP v1 API](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages). Use an OAuth access token backed by server-side credentials; never bundle service-account private keys in the app.

    This is an example HTTP v1 request body targeting a registered FID:

    ```json theme={null} theme={null}
    {
      "message": {
        "fid": "REGISTERED_FIREBASE_INSTALLATION_ID",
        "notification": {
          "title": "Your order is ready",
          "body": "Open the app to view your order."
        },
        "data": {
          "message_id": "order_123_ready",
          "deep_link": "myapp://orders/123"
        }
      }
    }
    ```

    Translate Clix payloads into your new schema. FCM `data` values must be strings. Implement `deep_link` handling in your app; FCM does not automatically interpret this custom key.

    Android background notification messages are displayed by the system, while foreground messages need app handling. Create notification channels and request Android 13+ permission at the appropriate point in your UI. On iOS, configure foreground presentation and replace Clix's service extension for image attachments. See [Android message handling](https://firebase.google.com/docs/cloud-messaging/android/receive) and [Apple message handling](https://firebase.google.com/docs/cloud-messaging/ios/receive).

    Set message expiry and collapse behavior deliberately. Remove invalid registrations from your server based on documented responses; distinguish invalid identifiers from malformed payload errors.
  </Step>

  <Step title="Test and switch the sender">
    Upgrade an existing Clix installation and verify registration upload, account association, one visible notification, and correct navigation. Also test a fresh installation, denied permission, logout, account switching, token or FID changes, and multiple devices.

    Compare delivery outcomes and crashes for a small release cohort. Record the selected sender per installation and use a stable business message ID to prevent the same event being sent twice.

    Exclude migrated installations from Clix before routing their messages through your backend. Keep old installations on Clix until they are upgraded or deliberately retired, and retire any remaining Clix integrations before November 30, 2026. Retain a rollback path only where the receiving app supports the chosen payload.
  </Step>
</Steps>

## Existing Push Tokens

An existing FCM token can remain usable when the Firebase project and app identity remain compatible. If you have an authorized export with account mappings, test a small set through the legacy token send path before importing it. Do not assume Clix exposes a token export, or that a token reveals the corresponding registered FID.

The safer default is to collect current registrations from the updated app. You do not need to delete Firebase installations or force a new notification permission prompt. Treat a later FID rollout as an explicit client-and-server change.

## Related Guides

<CardGroup cols={2}>
  <Card title="Clix Campaign Types" icon="calendar" href="/campaigns/types">
    Inventory the scheduled, event-triggered, and API-triggered workflows to
    replace.
  </Card>

  <Card title="Clix Notification Components" icon="paper-plane" href="/essentials/notification-components">
    Review the payload features your app currently uses.
  </Card>
</CardGroup>
