adsparkle_flutter
Flutter client SDK for the AdSparkle affiliate attribution tracking platform. Deterministic Android install attribution via the Play Install Referrer; pure Dart on every other platform.
Mobile apps use this SDK to capture an attribution click_id from a deep link
and send affiliate attribution events (install, sign up, purchase, …) to the
tracking API.
Installation
flutter pub add adsparkle_flutter
Or add to your app's pubspec.yaml manually:
dependencies:
adsparkle_flutter: ^0.1.8
Then:
flutter pub get
Quick start
import 'package:adsparkle_flutter/adsparkle_flutter.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await AdSparkle.instance.configure(
companyKey: 'co_xxxxxxxxxxxxxxxx', // publishable key (see note below)
// baseUrl: the domain your tracking links are served from. Use the link
// domain on the panel's Integration page (<subdomain>.go.adsparkle.co), or
// your custom tracking domain if you set one up. On iOS, deferred
// attribution can fail when links and SDK requests use different hosts.
baseUrl: 'https://YOUR_TRACKING_DOMAIN',
debug: true, // verbose logs in debug builds
// Optional — only needed when your tracking links use a custom domain:
// linkDomainSuffix: '.go.adsparkle.co', // default
// extraLinkHosts: ['click.merchant.com'],
);
runApp(const MyApp());
}
A universal-link / App Links URL is recognised as a tracking link when its host
ends with linkDomainSuffix, equals the baseUrl host, or equals / is a
subdomain of an entry in extraLinkHosts. For such links opened while the app
is already installed, the SDK registers the click with the backend using the
last non-empty path segment as the link key (works for both /<key> and
multi-app /<appSlug>/<key> links).
Identifying the user
Set the end-user identifier once you know it (e.g. after login). It is persisted across launches.
await AdSparkle.instance.setUserId('user-123');
Capturing the click_id from a deep link
The attribution click_id arrives as a deep link query parameter:
https://app.example.com/open?click_id=2f1c9b7e-...
Pass any incoming Uri to handleDeepLink; the SDK extracts, persists, and
chains the click_id (most-recent-last, de-duplicated, capped at 50).
With uni_links / app_links
import 'package:app_links/app_links.dart';
final appLinks = AppLinks();
// Cold start
final initial = await appLinks.getInitialLink();
if (initial != null) {
await AdSparkle.instance.handleDeepLink(initial);
}
// While running
appLinks.uriLinkStream.listen((uri) {
AdSparkle.instance.handleDeepLink(uri);
});
With go_router
GoRouter(
redirect: (context, state) {
AdSparkle.instance.handleDeepLink(state.uri);
return null; // don't redirect; just harvest the click_id
},
routes: [...],
);
You can also set it manually if you obtain it another way:
await AdSparkle.instance.setClickId('2f1c9b7e-...');
Tracking events
Use the typed helpers, or the generic track(eventType, …):
await AdSparkle.instance.trackInstall();
await AdSparkle.instance.trackSignUp();
await AdSparkle.instance.trackLogin();
await AdSparkle.instance.trackDownload();
await AdSparkle.instance.trackPurchase(
transactionId: 'txn_001',
amount: 9.99,
currency: 'USD',
productIds: ['premium_monthly'],
customParams: {'campaign': 'summer'},
);
await AdSparkle.instance.trackSubscription(
transactionId: 'sub_001',
amount: 49.99,
currency: 'USD',
);
await AdSparkle.instance.trackRefund(transactionId: 'txn_001');
// Generic form:
await AdSparkle.instance.track(
'purchase',
transactionId: 'txn_002',
amount: 4.50,
currency: 'EUR',
);
If there is no click_id yet, the event is saved to a persisted deferred queue
and sent automatically once a click_id arrives (deep link, Install Referrer,
/match, or register-click). If no user_id was set, a persistent anonymous
identifier is generated. track never throws.
Event types
| Event | Wire value | Helper | Required extra fields |
|---|---|---|---|
| Install | install |
trackInstall |
— |
| Sign up | sign_up |
trackSignUp |
— |
| Login | login |
trackLogin |
— |
| Download | download |
trackDownload |
— |
| Purchase | purchase |
trackPurchase |
transactionId, amount |
| Subscription | subscription |
trackSubscription |
transactionId, amount |
| Refund | refund |
trackRefund |
transactionId |
Besides the built-ins above, a company custom-event shortId (e.g.
YE2YFSQ) can be passed directly as the event_type:
await AdSparkle.instance.track(
'YE2YFSQ',
productIds: ['premium_monthly'],
customParams: {'campaign': 'summer'},
);
The value is validated against ^[A-Za-z0-9_]{1,64}$ (mixed case — shortIds
are uppercase, built-in keys lowercase) and sent as-is on the wire; values that
fail this format check are ignored. product_ids and custom_params are
already supported by track (and the typed helpers) for every event type.
Reliability
- Postbacks go to
POST {baseUrl}/api/tracking/postback. - On
5xx/408/429responses or network errors the SDK retries up to 3 times with exponential backoff. - If all attempts fail, the event is saved to a persisted pending queue
(
shared_preferences) and re-sent on the nexttrack()/configure(). - Other
4xxresponses are treated as permanent and the event is dropped.
Debug diagnostics — see the chain on the device
debugPrint is useless when you are testing a release-ish build on a real
phone and are not attached to flutter run / Xcode / logcat. Turn on
debug: true and wrap your app with AdSparkleDebugOverlay to get the SDK's
diagnostics on screen:
await AdSparkle.instance.configure(companyKey: 'co_xxx', debug: true);
MaterialApp(
builder: (context, child) =>
AdSparkleDebugOverlay(child: child ?? const SizedBox.shrink()),
home: const HomePage(),
);
You will see one short line per step, newest on top:
AdSparkle 0.1.9 hazir | baseUrl=acme.go.adsparkle.co | suffix=.go.adsparkle.co
Link geldi: https://acme.go.adsparkle.co/abc123
Tiklama kaydediliyor: key=abc123
click_id alindi: 7f3a9c21
purchase gonderildi ✓
- Tap the bar to expand/collapse the list, long-press it (or use the copy button) to copy the whole buffer to the clipboard and send it to support. Buttons on the bar clear the list or dismiss the panel.
- The message list is
IgnorePointer, so it never blocks the UI underneath. - The exact same messages are produced by the iOS, Android and React Native SDKs, so support can read any platform's log the same way.
Using your own toast instead
If your app already has a toast/snackbar, take the messages directly — the overlay is then unnecessary (a handler takes priority; a message is shown exactly once):
setDebugHandler((String message) => showMySnackBar(message));
setDebugHandler(null) removes the hook. subscribeDebug(listener) is the
low-level alternative and returns an unsubscribe function; on subscribe it
replays the buffered history so a late listener does not miss the first steps.
What is not shown
companyKey, any postback secret, device_id and the full click_id are
never printed. click_id appears as its first 8 characters only, and URLs /
keys are truncated to 60. With debug: false (the default) not a single
diagnostic string is built and the overlay renders only its child — zero
production impact.
Security note — the company key is publishable
companyKey is a publishable co_ key. It is safe to ship inside your app
binary. It is not a secret. This SDK never uses an HMAC secret and never
signs requests — secret-based signing happens server-side only.
Reading the current click id
final id = AdSparkle.instance.clickId; // String?
Attribution callback
Register a callback to be notified the moment a click_id becomes active —
no polling needed. It fires for every source (deep-link ?click_id,
register-click, Play Install Referrer, iOS /match):
AdSparkle.instance.onClickId = (String clickId) {
debugPrint('attributed: $clickId');
};
- If a
click_idis already available when you set the handler, it is invoked immediately (once, asynchronously) with the current value — so a late-registered handler never misses the attribution moment. - The same value never fires twice in a row; a different new
click_idfires again. - Set to
nullto remove the handler. The callback is optional — pollingAdSparkle.instance.clickIdremains a valid alternative.
Libraries
- adsparkle_flutter
- AdSparkle — Flutter client SDK for the AdSparkle affiliate attribution tracking platform.