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

# Flutter API reference

Every public export of the `appstack_plugin` pub.dev package. For installation and
integration guidance, see the [Flutter SDK guide](/SDKs/flutter).

Current stable release: **2.10.0**, published 16 September 2026. See the [changelog](/changelog/flutter) for everything that changed.

## AppstackPlugin

All members are static. Every method returns a `Future`, except
[`getAttributionParamsWithCallback()`](#getattributionparamswithcallback), which
returns a `Stream`.

```dart theme={null}
import 'package:appstack_plugin/appstack_plugin.dart';
```

### configure()

```dart theme={null}
static Future<void> configure(
  String apiKey,
```

Starts the SDK. Call once, as early in app startup as possible. A repeat call is a
no-op, including its `customerUserId`, so use
[`setCustomerUserId()`](#setcustomeruserid) to set the ID later.

Throws `ArgumentError` when `apiKey` is empty or `logLevel` falls outside 0 to 3.

<ParamField path="apiKey" type="String" required>
  Your app's Appstack API key, from the dashboard under app settings.
</ParamField>

<ParamField path="logLevel" type="int" default="1">
  Console verbosity, descending: `0` DEBUG, `1` INFO, `2` WARN, `3` ERROR. iOS has
  no dedicated WARN tier, so `2` behaves like `3` there.
</ParamField>

<ParamField path="customerUserId" type="String?" default="null">
  Your identifier for the signed-in user, when known at startup.
</ParamField>

```dart theme={null}
await AppstackPlugin.configure('your_api_key');

await AppstackPlugin.configure(
  'your_api_key',
  logLevel: 0,
  customerUserId: 'user_123',
);
```

<Accordion title="Deprecated parameters">
  Both are still accepted and have no effect. Each logs a warning when used, and
  will be removed in a future release.

  <ResponseField name="isDebug" type="bool">
    The native debug overlay was removed from the Appstack SDKs. Use `logLevel: 0`
    for verbose logging instead.
  </ResponseField>

  <ResponseField name="endpointBaseUrl" type="String?">
    The custom endpoint override was removed from the public API. The dev proxy is
    now applied natively from a repo-only host-app key.
  </ResponseField>
</Accordion>

### setCustomerUserId()

```dart theme={null}
static Future<void> setCustomerUserId(String? customerUserId)
```

Sets your identifier for the signed-in user, after `configure()`. Callable at any
time; last write wins.

<ParamField path="customerUserId" type="String?" required>
  Your identifier for the signed-in user. Set it as soon as it is known, and at
  least one event has to follow for it to take effect.
</ParamField>

```dart theme={null}
await AppstackPlugin.setCustomerUserId('user_123');  // once login reveals it
```

### sendEvent()

```dart theme={null}
static Future<bool> sendEvent(
  EventType eventType,
```

Sends a standard or custom event.

<ParamField path="eventType" type="EventType" required>
  The event to send. See [EventType](#eventtype).
</ParamField>

<ParamField path="eventName" type="String?" default="null">
  The event name, for `EventType.custom`.
</ParamField>

<ParamField path="parameters" type="Map<String, dynamic>?" default="null">
  Event properties. For revenue events send `revenue` and `currency`.
</ParamField>

<ResponseField name="returns" type="Future<bool>">
  Resolves `true` when the event was sent successfully.
</ResponseField>

```dart theme={null}
await AppstackPlugin.sendEvent(EventType.login);

await AppstackPlugin.sendEvent(
  EventType.purchase,
  parameters: {'revenue': 29.99, 'currency': 'USD'},
);

await AppstackPlugin.sendEvent(
  EventType.custom,
  eventName: 'onboarding_finished',
  parameters: {'variant': 'b'},
);
```

<Warning>
  Parameter values must be strings, finite numbers, booleans, lists, or nested
  string-keyed maps. A `DateTime`, `Uri`, `Set` or arbitrary object cannot cross the
  platform channel and throws `ArgumentError` before reaching the native SDK.
  Convert those yourself, for example with `date.toIso8601String()`.

  A `null` value is omitted from the payload and the event still sends; nulls nested
  inside a list are preserved. A value the native SDK cannot serialize, such as
  `double.nan`, `double.infinity`, or a typed-data list like `Uint8List`, has its key
  dropped individually and the event still sends with the remaining parameters.
</Warning>

<Note>
  Custom parameter values may be encrypted on the device before they are sent, so
  avoid relying on them being readable in raw payload inspection. This is driven
  entirely by remote config, with nothing to set here, and keys the backend needs in
  the clear (`currency`, `revenue`, campaign fields) are excluded. Revenue reporting
  is unaffected.
</Note>

### getAppstackId()

```dart theme={null}
static Future<String?> getAppstackId()
```

Returns the stable local Appstack identity for this install.

<ResponseField name="returns" type="Future<String?>">
  The install's Appstack ID, or `null` when not available.
</ResponseField>

### isSdkDisabled()

```dart theme={null}
static Future<bool> isSdkDisabled()
```

Whether the SDK is disabled. Call it after `configure()` to verify that
configuration succeeded.

<ResponseField name="returns" type="Future<bool>">
  `true` when the SDK is disabled, for example because the API key is invalid.
</ResponseField>

```dart theme={null}
await AppstackPlugin.configure('your_api_key');
if (await AppstackPlugin.isSdkDisabled()) {
  debugPrint('SDK is disabled, check your API key');
}
```

### getAttributionParams()

```dart theme={null}
static Future<Map<String, dynamic>?> getAttributionParams()
```

A request-response call over the method channel. On Android it runs synchronously on
the platform thread, so prefer
[`getAttributionParamsWithCallback()`](#getattributionparamswithcallback) when
attribution retrieval time may vary.

<ResponseField name="returns" type="Future<Map<String, dynamic>?>">
  Attribution parameters, or `null` when none are available.
</ResponseField>

<Note>
  On iOS the map always contains `appstack_match_status`, describing the attribution
  outcome: `matched`, `matched_no_params`, `organic`, `skipped`, `failed` or
  `not_configured`. Only `failed` is worth retrying. Android does not send that key
  yet, so keep treating an empty map as "nothing yet".
</Note>

### getAttributionParamsWithCallback()

```dart theme={null}
static Stream<Map<String, dynamic>?> getAttributionParamsWithCallback()
```

A push-style stream backed by a native background thread, freeing the platform
thread rather than blocking it until the SDK responds. The stream emits exactly one
value and then closes.

<ResponseField name="returns" type="Stream<Map<String, dynamic>?>">
  A single-value stream of attribution parameters.
</ResponseField>

```dart theme={null}
AppstackPlugin.getAttributionParamsWithCallback().listen(
  (params) => debugPrint('Attribution params: $params'),
  onError: (e) => debugPrint('Error: $e'),
);
```

### handleUniversalLink()

```dart theme={null}
static Future<AppstackLinkResult?> handleUniversalLink(
  Uri url,
```

Parses an Appstack standard Universal Link or App Link delivered by your app's link
handler. Safe to call before `configure()`.

Throws `ArgumentError` when `allowedHosts` contains a blank hostname.

<ParamField path="url" type="Uri" required>
  The tapped link.
</ParamField>

<ParamField path="allowedHosts" type="Set<String>?" default="null">
  Hosts to accept. A link on any other host returns `null`. Omit to accept any host.
</ParamField>

<ResponseField name="returns" type="Future<AppstackLinkResult?>">
  The parsed link, or `null` for unsupported links.
</ResponseField>

### enableAppleAdsAttribution()

```dart theme={null}
static Future<bool> enableAppleAdsAttribution()
```

Starts Apple Search Ads attribution. iOS 14.3+ only, and a no-op on Android.

<ResponseField name="returns" type="Future<bool>">
  Resolves `true` when attribution was enabled successfully.
</ResponseField>

### deleteUserData()

```dart theme={null}
static Future<void> deleteUserData()
```

Permanently deletes this install's Appstack data, for GDPR and privacy requests.
Available on both iOS and Android.

## Types

### AppstackLinkResult

```dart theme={null}
class AppstackLinkResult {
  final String? deeplinkId;
  final Map<String, String> queryParams;
  final Uri url;
}
```

<ResponseField name="deeplinkId" type="String?">
  The link's single path segment. Optional in both native SDKs, so it is nullable
  here rather than collapsed to an empty string.
</ResponseField>

<ResponseField name="queryParams" type="Map<String, String>">
  Query parameters parsed off the tapped URL.
</ResponseField>

<ResponseField name="url" type="Uri">
  The URL that was handled.
</ResponseField>

### EventType

```dart theme={null}
enum EventType
```

Standard attribution events. Cases are lowerCamelCase in Dart, and the value sent
over the wire is the SNAKE\_CASE form: `EventType.addToCart` becomes
`"ADD_TO_CART"`. Where two names are synonymous, both are provided for compatibility
with existing integrations.

| Group        | Cases                                                                                   |
| ------------ | --------------------------------------------------------------------------------------- |
| Lifecycle    | `install`                                                                               |
| Auth         | `login`, `signUp`, `register`                                                           |
| Monetization | `purchase`, `addToCart`, `addToWishlist`, `initiateCheckout`, `startTrial`, `subscribe` |
| Games        | `levelStart`, `levelComplete`                                                           |
| Engagement   | `tutorialComplete`, `search`, `viewItem`, `viewContent`, `share`                        |
| Catch-all    | `custom`                                                                                |

<Note>
  `install` is tracked by the SDK itself. Passing it to `sendEvent()` has no effect:
  both native SDKs discard a manual install event so it cannot inflate install
  counts.
</Note>

### EventTypeExtension

```dart theme={null}
extension EventTypeExtension on EventType {
  String get name;
}
```

<ResponseField name="name" type="String">
  The SNAKE\_CASE event name as sent over the wire.
</ResponseField>
