Documentation

Flutter

Install the Flutter SDK, register installs, track events, and read attribution. Setup takes about 5 minutes.

Requirements

  • Flutter 3.22+
  • Dart 3.3+
  • iOS 14.0+ and Android 7.0+ (API 24+)

Install

pub.dev

# pubspec.yaml
dependencies:
postback_flutter: ^2.0.1
# Then run:
flutter pub get

The Flutter plugin manages the iOS pod and the Android AAR for you. No extra repository setup needed.

Published on pub.dev. Always use the latest version.

Configure

import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:postback_flutter/postback_flutter.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final apiKey = Platform.isIOS
? 'pb_ios_live_xxxxx'
: 'pb_android_live_xxxxx';
await Postback.instance.configure(
PostbackConfig(apiKey: apiKey),
);
runApp(const MyApp());
}

Non-blocking. configure() resolves after local state is restored; install registration runs in the background on the native side. Platform-specific code (AdServices on iOS, Play Install Referrer on Android) runs through method channels.

Track events

// Standard event
await Postback.instance.sendEvent(PostbackEventType.login);
// Revenue event. Currency must be exactly three ASCII letters.
await Postback.instance.sendEvent(
PostbackEventType.purchase,
params: {'revenue': 9.99, 'currency': 'USD'},
);
// Custom event with parameters
await Postback.instance.sendEvent(
PostbackEventType.custom,
name: 'level_complete',
params: {'level': 5, 'score': 1200},
);
  • Custom events require a trimmed, non-empty name of 1-255 UTF-16 code units with no U+0000 character. Invalid custom events are not queued.
  • For standard event types, an invalid optional name is omitted and the event is still queued.
  • Currency must be exactly three ASCII letters. Lowercase values are normalized to uppercase; an invalid currency field is omitted and the event is still queued.

Read attribution

Once install registration completes, the SDK caches the attribution result from the install response. Native iOS and Android expose synchronous getters; React Native and Flutter bridge calls are asynchronous.

final attr = await Postback.instance.getAttribution();
print(attr?.source); // "apple_ads", "tracking_link", or "organic"
print(attr?.isAttributed); // bool
print(attr?.campaignName); // Campaign name when available
print(attr?.appleAds?.campaignId);
print(attr?.link?.name);

Verify the connection

Send a test event to confirm end-to-end delivery. You should see it in the Postback dashboard within seconds.

final result = await Postback.instance.sendTestEvent();
print('${result.success} — ${result.message}');

Reference

Configuration options
OptionTypeDefaultDescription
apiKeyStringYour live API key (starts with pb_).
apiUrlStringhttps://api.postback.shOverride for staging or self-hosted environments.
enableAppleAdsAttributionbooltrueiOS only. Fetches Apple AdServices at install time.
customerUserIdString?nullYour internal user ID. Persists across launches and replays automatically if the first send fails.
autoTrackSessionsbooltrueFires session_start on configure() and on foreground, debounced to one event per 30 minutes.
autoRefreshAttributionbooltrueRefetches /v1/sdk/attribution on configure() and foreground transitions.
isDebugboolfalseForces debug-level logging on the native side.
logLevelint2 (WARN)0 = DEBUG, 1 = INFO, 2 = WARN, 3 = ERROR.
Supported event types
session_startloginsign_upregisterpurchasesubscribestart_trialadd_payment_infoadd_to_cartadd_to_wishlistinitiate_checkoutview_contentview_itemsearchsharetutorial_completeachieve_levellevel_startlevel_completecustom

Use custom with a name parameter for any event not in this list.

Attribution fields
FieldDescription
source"apple_ads", "tracking_link", or "organic"
isAttributedfalse for organic installs, true otherwise
matchTypeBackend match method: apple_ads, click_id, gaid, ttclid, fbclid, gclid, gbraid, wbraid, ip_user_agent (Android only), or organic
campaignNameSignal Campaign name when available
linkSignal link object: id, name
appleAdsApple AdServices payload: campaignId, adGroupId, keywordId, countryOrRegion, conversionType
utmSourceUTM source from the signal link
utmMediumUTM medium from the signal link
utmCampaignUTM campaign value from the signal link
API reference

configure(config)

Future<bool>

Initializes the SDK. Resolves true after local state is restored; install registration runs in the background.

await Postback.instance.configure(const PostbackConfig(apiKey: '…'));

sendEvent(type, {name, params})

Future<bool>

Enqueues an event locally and schedules a flush. Custom events require a trimmed name of 1–255 UTF-16 code units.

await Postback.instance.sendEvent(PostbackEventType.purchase, params: {'revenue': 9.99, 'currency': 'USD'});

flush()

Future<void>

Drains the queue immediately.

await Postback.instance.flush()

refreshAttribution()

Future<AttributionResult?>

Fetches the latest attribution from the backend. Self-heals a 404 install_not_found by re-running install.

final attr = await Postback.instance.refreshAttribution();

setCustomerUserId(id)

Future<void>

Updates the customer user ID. Sent immediately if install is registered; otherwise queued and retried automatically.

await Postback.instance.setCustomerUserId('user-123');

getPostbackId()

Future<String?>

Returns the install ID, or null before install registration completes.

final id = await Postback.instance.getPostbackId();

getAttribution()

Future<AttributionResult?>

Returns the cached AttributionResult.

final attr = await Postback.instance.getAttribution();

getAttributionParams()

Future<Map<String, String>>

Flat attribution/debug payload for custom integrations. For RevenueCat, set only the postbackId subscriber attribute.

final params = await Postback.instance.getAttributionParams();

enableAppleAdsAttribution()

Future<bool>

Re-enables Apple Ads at runtime on iOS. Returns false on Android.

await Postback.instance.enableAppleAdsAttribution()

isInitialized()

Future<bool>

True once configure() resolved.

await Postback.instance.isInitialized()

isSdkDisabled()

Future<bool>

True if a 401 or 403 permanently disabled the SDK.

await Postback.instance.isSdkDisabled()

sendTestEvent()

Future<TestEventResult>

Posts a diagnostic event and resolves to (success, message).

final result = await Postback.instance.sendTestEvent();

clearData()

Future<void>

Wipes local state and the event queue.

await Postback.instance.clearData()
Offline behavior
  • Events that fail to send are queued in native storage (up to 100 events).
  • The queue persists across app restarts.
  • Queued events are retried when configure() completes, when another event is sent, when lifecycle flushes run, or when you call flush().
  • If a queued event receives a 401/403, the SDK disables itself and clears the queue.
Platform notes
  • The Flutter plugin wraps the native iOS and Android SDKs through method channels. Behavior matches the native SDKs exactly; the Dart layer is a thin pass-through.
  • configure() is non-blocking. The future resolves once local state is restored; install registration runs in the background on the native side.
  • On iOS, the plugin never requests ATT permission. IDFA is read only when the host app already has authorized ATT status; IDFV and app-scoped device context may be used for attribution.
  • Apple Ads attribution uses AdServices and works independently of IDFA.
  • Host apps remain responsible for their own privacy notices, App Store answers, and any permissions required by their complete data practices.
  • On Android, GAID is read off the main thread, honoring Limit Ad Tracking and dropping the all-zero advertising ID. The plugin declares INTERNET, ACCESS_NETWORK_STATE, and AD_ID for you.
  • Events persist to native storage (UserDefaults on iOS, SharedPreferences on Android) and survive app restarts. Maximum queue size is 100 events.
  • On iOS, URLSession requests fail fast when connectivity is unavailable. Events stay in the persistent SDK queue and retry on lifecycle flushes, the next sendEvent(), or flush().

Next steps

Troubleshooting

ProblemWhat to try
getPostbackId() returns nullconfigure() resolves before install registration finishes on the native side. Check isInitialized() and retry briefly, or read the value after the first event has been sent.
Events do not appear in dashboardConfirm the API key starts with pb_. Call sendTestEvent() and inspect the message. iOS logs flow into Console.app; Android logs flow into logcat under the Postback tag.
SDK disabled after 401/403Call clearData(), then configure() with a valid key.
pod install fails after adding the packageRun flutter clean, flutter pub get, then cd ios && pod install --repo-update.
Attribution returns organic on iOS when Apple Ads is expectedBackend resolution can take up to 75 seconds. The SDK refetches automatically by default; if disabled, call refreshAttribution() manually.