
Amplitude Flutter SDK 4.0 features default event tracking, simplified interfaces, and wraps the latest [Amplitude iOS](/docs/sdks/analytics/ios/ios-swift-sdk), [Android Kotlin](/docs/sdks/analytics/android/android-kotlin-sdk), and [Browser Typescript](/docs/sdks/analytics/browser/browser-sdk-2) SDKs.

## Terminology

- `amplitude_flutter:v3`: Flutter SDK 3.0.
- `amplitude_flutter:v4`: Flutter SDK 4.0.

## Dependencies

Open `pubspec.yaml` and update the dependency:

```diff
dependencies:
-  amplitude_flutter: ^3
+  amplitude_flutter: ^4.0.0-beta.1
```

Run `flutter pub get` in the terminal to update the dependencies.

Open `Podfile` and update:

```diff
- platform :ios, '10.0'
+ platform :ios, '13.0'
```

Run `pod install` under the ios directory of your Flutter project to update the CocoaPods dependencies.

For Flutter Web, replace the "Amplitude-JavaScript" snippet located at `web/index.html` with the following "Browser SDK 2" snippet:

```html
<script type="text/javascript">
  !(function () {
    "use strict";
    !(function (e, t) {
      var r = e.amplitude || { _q: [], _iq: {} };
      if (r.invoked)
        e.console &&
          console.error &&
          console.error("Amplitude snippet has been loaded.");
      else {
        var n = function (e, t) {
            e.prototype[t] = function () {
              return (
                this._q.push({
                  name: t,
                  args: Array.prototype.slice.call(arguments, 0),
                }),
                this
              );
            };
          },
          s = function (e, t, r) {
            return function (n) {
              e._q.push({
                name: t,
                args: Array.prototype.slice.call(r, 0),
                resolve: n,
              });
            };
          },
          o = function (e, t, r) {
            e._q.push({ name: t, args: Array.prototype.slice.call(r, 0) });
          },
          i = function (e, t, r) {
            e[t] = function () {
              if (r)
                return {
                  promise: new Promise(
                    s(e, t, Array.prototype.slice.call(arguments)),
                  ),
                };
              o(e, t, Array.prototype.slice.call(arguments));
            };
          },
          a = function (e) {
            for (var t = 0; t < g.length; t++) i(e, g[t], !1);
            for (var r = 0; r < m.length; r++) i(e, m[r], !0);
          };
        r.invoked = !0;
        var c = t.createElement("script");
        ((c.type = "text/javascript"),
          (c.integrity =
            "sha384-R0H1kXlk6r2aEQMtwVcPolpk0NAuIqM/8NlxAv24Gr3/PBJPl+9elu0bc3o/FDjR"),
          (c.crossOrigin = "anonymous"),
          (c.async = !0),
          (c.src =
            "https://cdn.amplitude.com/libs/analytics-browser-2.11.10-min.js.gz"),
          (c.onload = function () {
            e.amplitude.runQueuedFunctions ||
              console.log("[Amplitude] Error: could not load SDK");
          }));
        var l = t.getElementsByTagName("script")[0];
        l.parentNode.insertBefore(c, l);
        for (
          var u = function () {
              return ((this._q = []), this);
            },
            p = [
              "add",
              "append",
              "clearAll",
              "prepend",
              "set",
              "setOnce",
              "unset",
              "preInsert",
              "postInsert",
              "remove",
              "getUserProperties",
            ],
            d = 0;
          d < p.length;
          d++
        )
          n(u, p[d]);
        r.Identify = u;
        for (
          var f = function () {
              return ((this._q = []), this);
            },
            v = [
              "getEventProperties",
              "setProductId",
              "setQuantity",
              "setPrice",
              "setRevenue",
              "setRevenueType",
              "setEventProperties",
            ],
            y = 0;
          y < v.length;
          y++
        )
          n(f, v[y]);
        r.Revenue = f;
        var g = [
            "getDeviceId",
            "setDeviceId",
            "getSessionId",
            "setSessionId",
            "getUserId",
            "setUserId",
            "setOptOut",
            "setTransport",
            "reset",
            "extendSession",
          ],
          m = [
            "init",
            "add",
            "remove",
            "track",
            "logEvent",
            "identify",
            "groupIdentify",
            "setGroup",
            "revenue",
            "flush",
          ];
        (a(r),
          (r.createInstance = function (e) {
            return ((r._iq[e] = { _q: [] }), a(r._iq[e]), r._iq[e]);
          }),
          (e.amplitude = r));
      }
    })(window, document);
  })();
</script>
```

## Instrumentation

Flutter SDK 4.0 offers an API to instrument events. To migrate to Flutter SDK 4.0, you need to update a few calls. The following sections detail which calls have changed.

## Initialization

Flutter SDK 4.0 removes `instance()` along with the other legacy calls. Flutter SDK 4.0 uses the Configuration object to set the configuration. Refer to [Configuration](#configuration) for more information.

```dart
import 'package:amplitude_flutter/amplitude.dart';
import 'package:amplitude_flutter/identify.dart';
import 'package:amplitude_flutter/amplitude.dart';
import 'package:amplitude_flutter/configuration.dart';

// Create the instance and initialize SDK
final Amplitude amplitude = Amplitude.getInstance(instanceName: "project");
amplitude.setServerUrl("https://your.endpoint.com")
amplitude.setServerZone("US")
amplitude.trackingSessionEvents(true)
amplitude.init(widget.apiKey);
final Amplitude amplitude = Amplitude(Configuration(
    apiKey: "YOUR-API-KEY",
    serverUrl: "https://your.endpoint.com",
    serverZone: ServerZone.eu,
    autocapture: AutocaptureOptions(
       sessions: true
    )
  ));
await amplitude.isBuilt;
```

## Configuration

Flutter SDK 4.0 includes the following configuration changes:

- Configuration is more consistent across runtimes.
- Flutter SDK 4.0 no longer supports certain configurations.
- Flutter SDK 4.0 uses an instance variable for configuration, instead of setters in SDK version 3.0.
- Configuration becomes immutable after you pass it to Amplitude.
- `defaultTracking` and `DefaultTrackingOptions` are deprecated. Use `autocapture` with `AutocaptureOptions` instead. Refer to [Autocapture](/docs/sdks/analytics/flutter/flutter-sdk-4#autocapture) in the Flutter SDK 4 reference.

| Flutter SDK 3.0                                   | Flutter SDK 4.0                       |
| ------------------------------------------------- | ------------------------------------- |
| `enableCoppaControl()` or `disableCoppaControl()` | `config.enableCoppaControl`           |
| `setMinTimeBetweenSessionsMillis()`               | `config.minTimeBetweenSessionsMillis` |
| `setEventUploadThreshol(d)`                       | `config.flushQueueSize`               |
| `setEventUploadPeriodMillis()`                    | `config.flushIntervalMillis`          |
| `setServerZone()`                                 | `config.serverZone`                   |
| `setServerUrl()`                                  | `config.serverUrl`                    |
| `setUseDynamicConfig()`                           | NOT SUPPORTED                         |
| `setOptOut()`                                     | `config.optOut`                       |
| `setOffline()`                                    | NOT SUPPORTED                         |
| `trackingSessionEvents()`                         | `autocapture: AutocaptureOptions(sessions: true)` |
| `useAppSetIdForDeviceId()`                        | `config.useAppSetIdForDeviceId`       |

## Track events

Flutter SDK 4.0 uses a unified `track` API to replace the following `logEvent` API variations:

- `withEventProperties`.
- `withApiProperties`.
- `withUserProperties`.
- `withGroup`.
- `withGroupProperties`.

### logEvent()

The `logEvent()` API maps to `track()`.

```dart
amplitude.logEvent('BUTTON_CLICKED');
amplitude.track(event: BaseEvent(eventType:'BUTTON_CLICKED'));
```

### logEvent() with event properties

```dart
amplitude.logEvent('BUTTON_CLICKED', {"Hover Time": "100ms"});
amplitude.track(event: BaseEvent(eventType:'BUTTON_CLICKED', eventProperties: {"Hover Time": "100ms"}));
```

### logEvent() with outOfSession

`logEvent()` receives an optional boolean argument `outOfSession`. The new `track()` API doesn't support `outOfSession`. To track an event as out-of-session, set `event.sessionId = -1`.

```dart
amplitude.logEvent("BUTTON_CLICKED", outOfSession: true);
amplitude.track(event: BaseEvent(eventType:'BUTTON_CLICKED', sessionId: -1));
```

### uploadEvents()

The `uploadEvents()` API maps to `flush()`.

```dart
amplitude.uploadEvents();
amplitude.flush();
```

## Set user properties

The APIs for setting user properties are the same, except that Flutter SDK 4.0 removes `instance()`. The following code snippets show how to migrate user property APIs.

### setUserId()

`setUserId()` no longer receives `startNewSession` and now has a default minimum length of 5. To override this default, set the `minIdLength` config option during initialization.

{% callout type="warning" heading="Minimum identifier length" %}
The maintenance SDK uses an old SDK endpoint (`api2.amplitude.com`) that enforces no length limit for `deviceId` and `userId`. The latest SDK uses Amplitude's HTTP V2 API (`api2.amplitude.com/2/httpapi`) and requires identifiers of at least 5 characters by default. When you migrate to the latest SDK, set `config.minIdLength` to a smaller value if you allowed identifiers with fewer than 5 characters.
{% /callout %}

### setDeviceId()

`setDeviceId()` now has a default minimum length of 5. To override this default, set the `minIdLength` config option during initialization.

{% callout type="warning" heading="Minimum identifier length" %}
The maintenance SDK uses an old SDK endpoint (`api2.amplitude.com`) that enforces no length limit for `deviceId` and `userId`. The latest SDK uses Amplitude's HTTP V2 API (`api2.amplitude.com/2/httpapi`) and requires identifiers of at least 5 characters by default. When you migrate to the latest SDK, set `config.minIdLength` to a smaller value if you allowed identifiers with fewer than 5 characters.
{% /callout %}

### regenerateDeviceId()

Flutter SDK 4.0 doesn't support `regenerateDeviceId()`.

### clearUserProperties()

Flutter SDK 4.0 removes the `clearUserProperties` API. To remove user properties, use the unified `identify` API.

```dart
amplitude.clearUserProperties();
final Identify identify = Identify()
  ..clearAll();
amplitude.identify(identify);
```

### setUserProperties()

Flutter SDK 4.0 removes the `setUserProperties` API. To add user properties, use the unified `identify` API.

```dart
- Map<String, dynamic> userProps = {
-   'gender': 'female',
-   'age': '20'
- };
- amplitude.setUserProperties(userProperties);
+ final Identify identify = Identify()
+                          ..set('gender','female')
+                          ..set('age',20);
+ amplitude.identify(identify);
```

### identify()

You can now make an identify call on `amplitude` without calling `instance()`.

```dart
final Identify identify = Identify()
                          ..set('gender','female')
                          ..set('age',20);
Amplitude.getInstance().identify(identify);
amplitude.identify(identify);
```

## Set group properties

### `setGroup()`

You can now make an identify call on `amplitude` without calling `instance()`.

```dart
// set group with a single group name
Amplitude.getInstance().setGroup("orgId", "15");
amplitude.setGroup("orgId", "15");
// set group with multiple group names
Amplitude.getInstance().setGroup("sport", ["tennis", "soccer"]);
amplitude.setGroup("sport", ["tennis", "soccer"]);
```

#### groupIdentify()

You can now make an identify call on `amplitude` without calling `instance()`.

```dart
final Identify identify = Identify()
                          ..set("gender", "female")
                          ..set("age", 20);
Amplitude.getInstance().groupIdentify("groupType", "groupValue", identify);
amplitude.groupIdentify("groupType", "groupValue", identify);
```

## Tracking revenue

The `revenue()` API replaces `logRevenue()` and `logRevenueAmount()`.

```dart
String productId = "product001";
int quantity = 2;
double price = 20;
double amount = 35;
amplitude.logRevenue(productId, quantity, price);
amplitude.logRevenueAmount(amount);
final Revenue revenue = Revenue()
  ..price = 3.99
  ..quantity = 3
  ..productId = "com.company.productId";
amplitude.revenue(revenue);
```
