Flutter SDK
The Flutter SDK is the primary Attriax runtime implementation and the best place to start when you want first-class mobile attribution, deep links, and lifecycle tracking.
Package surface
General guide for attriax_flutter. Use the project workspace when you need detailed setup steps, release context, and project-specific values.
What teams use it for
These are the runtime jobs the product already exposes through the SDK and the matching workspace tools.
Mobile-first runtime
Built for app-open attribution, install referrer handling, deferred deep links, and in-app routing.
Operational visibility
Pairs runtime tracking with analytics, crashes, diagnostics, and privacy helpers in the same workspace.
Good for shipping teams
Use one integration surface while the workspace handles platform-specific diagnostics and review steps.
Integration notes
Keep the public docs lightweight, then open the project workspace when you need the exact setup steps for your own release flow.
Capabilities
- Initialize one SDK instance for the whole app and keep navigation tracking close to the runtime.
- Wait for the initial deep link, handle deferred deep links, and subscribe to events that resolve after startup.
- Inspect install referrer information on Android when it is available.
- Enable GDPR-aware delivery with gdprEnabled and use attriax.consent.gdpr for GDPR state, checks, and consent writes.
- Load dashboard-managed SKAdNetwork rules during app open and evaluate local retention, purchase, revenue, and ad-show signals on Apple platforms.
- Track page views, custom events, crashes, ad callbacks, revenue, identity, and mobile token flows through focused facades such as attriax.tracking, attriax.deepLinks, and attriax.consent.
Notes
- Flutter is the reference runtime for shared product behavior, so it is the most direct path for new mobile integrations.
- Android and iOS are the strongest runtime targets. Desktop forwarding exists, but it is more manual and should be validated with diagnostics.
- Use the project workspace when you need project-specific configuration, exact host values, and platform-specific setup status.
- Do not hardcode SKAN mappings in app code. Use local SKAN config only when a build should disable local conversion updates.
Install
Use the publishable Flutter package, then open the project workspace for detailed diagnostics and platform configuration.
Install command
flutter pub add attriax_flutterExample
The snippet below mirrors the project workspace starting point while keeping the guide general instead of project-specific.
lib/main.dart
Initialize once, wait for the SDK, subscribe to deep links, and route resolved paths into your Flutter navigation stack.
1import 'dart:async';
2import 'package:flutter/material.dart';
3import 'package:attriax_flutter/attriax.dart';
4
5// Create one SDK instance for the whole application.
6final Attriax attriax = Attriax(
7 config: const AttriaxConfig(
8 projectToken: 'ax_your_project_token',
9 gdprEnabled: true,
10 ),
11);
12
13final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
14
15Future<void> main() async {
16 WidgetsFlutterBinding.ensureInitialized();
17
18 // Wait for the SDK before the UI starts.
19 await attriax.init();
20
21 // Use the GDPR helper from your privacy UI or settings screen when needed.
22 // final needsConsent = await attriax.consent.gdpr.needsConsent(localOnly: true);
23
24 runApp(const MyApp());
25}
26
27class MyApp extends StatelessWidget {
28 const MyApp({super.key});
29
30
31 Widget build(BuildContext context) {
32 return MaterialApp(
33 navigatorKey: navigatorKey,
34 navigatorObservers: <NavigatorObserver>[
35 // This tracks page changes for normal Flutter navigation.
36 AttriaxNavigationObserver(attriax: attriax),
37 ],
38 routes: <String, WidgetBuilder>{
39 '/': (_) => const HomeScreen(),
40 '/promo': (_) => const PromoScreen(),
41 '/deep-link': (_) => const DeepLinkScreen(),
42 },
43 );
44 }
45}
46
47class HomeScreen extends StatefulWidget {
48 const HomeScreen({super.key});
49
50
51 State<HomeScreen> createState() => _HomeScreenState();
52}
53
54class _HomeScreenState extends State<HomeScreen> {
55 StreamSubscription<AttriaxDeepLinkEvent>? _deepLinkSubscription;
56
57
58 void initState() {
59 super.initState();
60
61 // Listen for deep links that resolve after startup.
62 _deepLinkSubscription = attriax.deepLinks.stream.listen(_handleDeepLinkEvent);
63
64 // Load startup attribution without blocking the first frame.
65 unawaited(_loadStartupAttribution());
66 }
67
68
69 void dispose() {
70 unawaited(_deepLinkSubscription?.cancel() ?? Future<void>.value());
71 super.dispose();
72 }
73
74 Future<void> _loadStartupAttribution() async {
75 final initialDeepLinkEvent = await attriax.deepLinks.waitForInitialDeepLink();
76 final originalInstallReferrer = await attriax.referrer
77 .getOriginalInstallReferrer();
78 final reinstallReferrer = await attriax.referrer
79 .getReinstallReferrer();
80
81 if (!mounted) {
82 return;
83 }
84
85 if (originalInstallReferrer != null) {
86 debugPrint(
87 'Original install referrer: ${originalInstallReferrer.campaign}',
88 );
89 }
90
91 if (reinstallReferrer != null) {
92 debugPrint('Reinstall referrer: ${reinstallReferrer.campaign}');
93 }
94
95 if (initialDeepLinkEvent?.found == true) {
96 _openDeepLink(initialDeepLinkEvent!);
97 }
98 }
99
100 void _handleDeepLinkEvent(AttriaxDeepLinkEvent event) {
101 if (!mounted || !event.found) {
102 return;
103 }
104
105 _openDeepLink(event);
106 }
107
108 void _openDeepLink(AttriaxDeepLinkEvent event) {
109 final attriaxPath = event.uri.path.replaceFirst(RegExp(r'^/+'), '');
110 final routeName = attriaxPath.startsWith('promo/')
111 ? '/promo'
112 : '/deep-link';
113
114 navigatorKey.currentState?.pushNamed(routeName, arguments: event);
115 }
116
117
118 Widget build(BuildContext context) {
119 return const Scaffold(body: Center(child: Text('Attriax ready')));
120 }
121}
122
123class PromoScreen extends StatelessWidget {
124 const PromoScreen({super.key});
125
126
127 Widget build(BuildContext context) {
128 return const Scaffold(body: Center(child: Text('Promo screen')));
129 }
130}
131class DeepLinkScreen extends StatelessWidget {
132 const DeepLinkScreen({super.key});
133
134
135 Widget build(BuildContext context) {
136 return const Scaffold(body: Center(child: Text('Deep link screen')));
137 }
138}