# Upgrade to Flutter 2.x

This page provides steps to help you upgrade from our Flutter 1.x SDK so you understand the development effort required to update your app and take advantage of the latest features.

## What changed?[](#what-changed)

This update provides native support for our new integrations framework. While this represents a significant change “under the hood,” we’ve tried to make it as seamless as possible for you; much of your implementation remains the same.

This move also adds two additional features:

*   **You’ll use SDK methods from an `instance`**:
*   **Support for anonymous tracking**: you can send events and other activity for anonymous users, and we’ll reconcile that activity with a person when you identify them.
*   **Built-in lifecycle events**: the SDK now automatically captures events like “Application Installed” and “Application Updated” for you.
*   **New device-level data**: the SDK captures the device `name` and other device-level context for you.

## Upgrade process[](#upgrade-process)

You’ll update initialization calls for the SDK itself and the push and/or in-app messaging modules.

**As a part of this process, your credentials change**. You’ll need to set up a new data inAn integration that feeds data *into* Customer.io. integration in Customer.io and get a new *CDP API Key*. But you’ll *also* need to keep your previous `siteId` as a `migrationSiteId` when you initialize the SDK. The `migrationSiteId` is a key helps the SDK send remaining traffic when people update your app.

When you’re done, you’ll also need to change a few base properties to fit the new APIs. In general, `identifier` becomes `userId`, `body` becomes `traits`, and `data` becomes `properties`.

### 1\. Get your new *CDP API Key*[](#1-get-your-new-cdp-api-key)

The new version of the SDK requires you to set up a new data inAn integration that feeds data *into* Customer.io. integration in Customer.io. As a part of this process, you’ll get your *CDP API Key*.

1.  Go to [*Data & Integrations* > *Integrations*](https://fly.customer.io/workspaces/last/journeys/integrations/all/overview) and click **Add Integration**.
2.  Select **Flutter**.
    
    [![set up your Flutter integration](https://docs.customer.io/images/cdp-flutter-source.png)](#b313d06604f0b0ea2cab391b1806b3cd-lightbox)
    
3.  Enter a *Name* for your integration, like “My Flutter App”.
4.  We’ll present you with a code sample containing a `cdpApiKey` that you’ll use to initialize the SDK. Copy this key and keep it handy.
5.  Test your connection and click **Complete Setup**. Or, if you don’t want to test your implementation yet, **Save & Complete Later** and then click **Install Source** to finish the setup process. In this case, *Complete Later* simply means that we haven’t seen any data from your Flutter app yet.
    
    [![Set your name, get your CDP API Key, and click Complete Setup](https://docs.customer.io/images/cdp-flutter-source-setup.png)](#1d7ba11eb6f6a64e4b1e289803050598-lightbox)
    

Remember, you can also [connect your Flutter app to services outside of Customer.io](/integrations/data-out/add-destination/)—like your analytics provider, data warehouse, or CRM.

### 2\. Update the SDK initialization[](#2-update-the-sdk-initialization)

You’ll need to update the way you initialize the SDK—with a new key and configuration options for in-app and push. We show an example configuration below.

You’ll find a complete list of configuration options on the [*Packages and Configuration Options* page](/integrations/sdk/flutter/getting-started/packages-options/), but you’ll want to pay close attention to the following changes:

*   You’ll initialize the SDK with a `cdpApiKey`. This is the key you’ll get when you create your Flutter integration in Customer.io.
*   `siteId` becomes `migrationSiteId`.
*   Your `inAppConfig` changes and requires your `siteId`.
*   The optional `pushConfig` is now a part of your initialization call. You won’t set push settings as a part of a separate configuration like you did with the 1.x SDK.

```dart
CustomerIO.initialize(
  config: CustomerIOConfig(
    cdpApiKey: 'cdpApiKey',
    migrationSiteId: 'migrationSiteId',
    region: Region.us,
    autoTrackDeviceAttributes: true,
    inAppConfig: InAppConfig(siteId: 'siteId'),
    // pushConfig is optional if you use default settings
    pushConfig: PushConfig(
      android: PushConfigAndroid(
        pushClickBehaviorAndroid:
        PushClickBehaviorAndroid.activityPreventRestart,
      ),
    ),
  ),
);
```

### 3\. Update your podfile (iOS)[](#3-update-your-podfile-ios)

For iOS, you’ll need to update your podfile with the correct iOS dependencies. Update your `Runner` and `NotificationServiceExtension` targets with the code below.

```ruby
target 'Runner' do
  pod 'customer_io/fcm', :path => '.symlinks/plugins/customer_io/ios'
end

target 'NotificationServiceExtension' do
  pod 'customer_io_richpush/fcm', :path => '.symlinks/plugins/customer_io/ios'
end
```

### 4\. Update your push notification handler[](#4-update-your-push-notification-handler)

In the previous version of the SDK, you had to initialize the SDK itself *and* the `MessagingPushFCM` package. You no longer need to initialize the SDK in your notification handler.

You’ll also notice that all the configuration settings for push are a part of the SDK initialization itself. You won’t set push settings in your notification handler anymore.

```swift
import UIKit
import Flutter
import CioMessagingPushFCM
import FirebaseMessaging
import FirebaseCore

@main
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        
        // Depending on how you install Firebase, 
        // you may need to add functions to this file, like:
        // FirebaseApp.configure()
        // 
        // Read the official Firebase docs to install Firebase correctly! 

        Messaging.messaging().delegate = self
        
        MessagingPushFCM.initialize(
            withConfig: MessagingPushConfigBuilder()
                .build()
        )
        
        // This Sets a 3rd party push event handler for the app—rather than the Customer.io SDK and FlutterFire.
        // Setting the AppDelegate as the handler will internally use `flutter_local_notifications` to handle push events.
        UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate

        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
    
    func application(application: UIApplication,
                    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        Messaging.messaging().setAPNSToken(deviceToken, type: .unknown);
    }
    
    override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        MessagingPush.shared.application(application, didFailToRegisterForRemoteNotificationsWithError: error)
    }
}

extension AppDelegate: MessagingDelegate {
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        MessagingPush.shared.messaging(messaging, didReceiveRegistrationToken: fcmToken)
    }
}
```

### 5\. Update your API calls[](#5-update-your-api-calls)

You’ll now make your calls from `.instance` methods. There are also a few crucial differences between the 1.x API and the 2.x API:

1.  `userId` replaces `identifier` in your `identify` call.
2.  `attributes` has changed to `traits` in `identify`, `setProfileAttributes`, and `setDeviceAttributes` methods.
3.  `properties` replaces `attributes` in `track`, `screen`, and any other [eventSomething that a person in your workspace did. Events can trigger campaigns, add people to segments, etc, and you can use properties from events to personalize messages.](/events/) calls.

 Identify

#### Identify[](#Identify)

```dart
//new call
CustomerIO.instance.identify(userId: email, traits: {
  "name": user.displayName,
  "email": user.email,
  "age": user.age,
});

//old call
CustomerIO.identify(identifier: email, attributes: {
  "name": user.displayName,
  "email": user.email,
  "age": user.age,
});
```

 Track

#### Track[](#Track)

```dart
//new call
CustomerIO.instance.track(name: "Movie Watched", properties: {
  "movie_name": "The Incredibles",
  "watch_time_in_minutes": 102,
});

//old call
CustomerIO.track(name: "Movie Watched", attributes: {
  "movie_name": "The Incredibles",
  "watch_time_in_minutes": 102,
});
```

 Screen

#### Screen[](#Screen)

```dart
//new call
CustomerIO.instance.screen(title: "Settings", properties: {
  "source": "Dashboard",
  "is_logged_in": true,
});

//old call
CustomerIO.screen(name: "Settings", attributes: {
  "source": "Dashboard",
  "is_logged_in": true,
});
```

## Configuration Changes[](#configuration-changes)

As a part of this release, we’ve changed a few `CustomerIOConfig` configuration options when you initialize the SDK. The following table shows the changes to the configuration options.

Field

Type

Default

Description

`cdpApiKey`

string

Replaces `apiKey`; required to initialize the SDK and send data to Customer.io.

`migrationSiteId`

string

Replaces `siteId`; required if you’re updating from 2.x. This is the key representing your previous version of the SDK.

`trackApplicationLifeCycleEvents`

boolean

`true`

When true, the SDK automatically tracks application lifecycle events (like *Application Installed*).

`inAppConfig`

object

Replaces the former `enableInApp` option, providing a place to set in-app configuration options. For now, it takes a single property called `siteId`.

`pushConfig`

object

Optional push configuration settings directly in the `CustomerIOConfig`. For now, it only takes the `android.PushClickBehavior` setting. If you don’t set a `pushConfig`, we’ll use default push settings.