Flutter SDK
Flutter quickstart for the amba Dart package — pubspec dep, Amba.configure(), first track, first collection insert, platform-channel notes for sign-in and push.
Amba for Flutter is published to pub.dev as amba. One package, every platform Flutter supports.
Supported platforms: iOS 13+, Android API 24+, macOS 12+, Windows 10+, Linux (x86_64).
1. Add the dependency
Or in pubspec.yaml:
Run flutter pub get. The package bundles prebuilt native binaries for iOS and Android — no separate build step is needed for those targets.
2. Configure at app start
Pass the key via --dart-define:
Amba.configure() is idempotent only for the first call — re-initializing in the same process throws AmbaException("amba already initialized"). To swap tenants, use the SDK's reset flow before re-calling configure. For typical apps this never matters: configure once at boot.
Which key goes here
For a Flutter app, always use the client key that npx @layers/amba init issued for you (printed as clientKey in the CLI output; visible in the amba console under your project's API keys tab). The client key is designed to ship to end-user devices.
Never put a server key in a Flutter build. Server keys are for trusted server contexts only — a server-side cron job, a backend endpoint, an edge function — and grant elevated privileges that would let any reverse-engineered APK/IPA impersonate your tenant. The SDK rejects server keys at configure time with AmbaException("server key not allowed in client SDK").
3. Verify the SDK reached amba
After flutter run, check your terminal (or Flutter DevTools → Logging) for the SDK's startup line via dart:developer:
If you see amba: connected, project=prj_... in your terminal, your client key resolved to a real project on the server and the wire round-tripped end-to-end. Compare serverProjectId against the project id you think you configured — a mismatch means a wrong --dart-define is loading. If you don't see the line:
- No
amba:log at all —Amba.configure(...)threw and was swallowed. Wrap with atry/catch(as above) so the actual error surfaces. AmbaException: amba already initializedafter hot-reload — expected; hot-reload re-runsmain(). See the Common pitfalls section for the standardtry/on AmbaExceptionguard.AmbaApiError: unauthorized— the--dart-define=AMBA_API_KEY=...value is empty, malformed, or revoked. Re-runnpx @layers/amba initto mint a fresh one.- Hangs for >5s with no output — the device can't reach
api.amba.dev. On Android emulator, check that you didn't restrict network with a custom DNS proxy; on iOS simulator, check the Mac's connection.
For machine-checkable verify in tests or CI, assert on ok plus the resolved project id:
A successful ping with the expected serverProjectId means the key resolved to a real project, the network round-trip completed, and your environment is the one you expected.
4. First sign-in (anonymous)
events.track is authenticated server-side — the request needs a session token. Mint one anonymously on first launch:
signInAnonymously() returns a Map<String, dynamic>; cast through your own model classes for type safety. The session token persists across app restarts (amba writes to platform-appropriate storage), so you only mint a new anonymous session on first launch.
5. First event
Once a session exists, track engagement events:
6. Sign in with Apple
Use sign_in_with_apple on iOS, then forward the identity token:
Enable the Sign in with Apple capability in Xcode (ios/Runner/Runner.entitlements) before building.
7. Sign in with Google
Use google_sign_in for the OAuth dance, then forward the idToken:
The serverClientId is the Web OAuth client ID from Google's API credentials console — not iOS or Android. Set up iOS in ios/Runner/Info.plist (CFBundleURLTypes) and Android in android/app/build.gradle per the google_sign_in setup guide.
8. Register for push
Use firebase_messaging on both platforms — it handles APNs registration on iOS and FCM on Android, returning a single token type per platform that you forward to amba:
Add the Push Notifications capability + Background Modes → Remote notifications in Xcode for iOS. For Android, add Firebase the standard way (google-services.json in android/app/).
9. First collection insert
For typed reads, cast through your own model classes or generate them with json_serializable.
10. AI proxy
Calling SDK methods from build()
Every Amba.* method returns a Future — don't await them from build() (it's synchronous). Use FutureBuilder for one-shot reads, or kick the call from initState and setState when it completes:
For mutations triggered by user interaction (button taps, form submits), wrap the call in async directly on the handler — that's the only context where await is allowed inside a widget tree:
Always check mounted before touching context after an await — the widget may have been disposed mid-call.
Hot reload + hot restart
- Hot reload (
r) preserves widget state, soAmba.configure(...)doesn't re-run. Safe. - Hot restart (
R) re-runsmain()from the top.Amba.configure(...)will throwAmbaException('amba already initialized')on the second invocation because the SDK's process-global state survives. Guard yourmain()with thetry/on AmbaExceptionpattern in Common pitfalls so a stale state doesn't cascade into a red screen.
Constructor DI for tests
AmbaClient accepts an AmbaBindings via the constructor — tests inject a fake, production code goes through the singleton Amba.configure(...) which wires real native bindings.
Platform notes
| Platform | Prebuilt | Notes |
|---|---|---|
| iOS | ✓ | Bundled with the package. Sign in / push via the platform packages above. |
| Android | ✓ | Bundled for all four standard ABIs (arm64-v8a, armeabi-v7a, x86_64, x86). Minimum API 24. |
| macOS | ✓ | Bundled with the package. Standard flutter build macos works out of the box. |
| Windows | ✓ | Bundled with the package. Standard flutter build windows works out of the box. |
| Linux | ✓ | Bundled with the package. Standard flutter build linux works out of the box. |
| Web | — | Flutter for Web is not supported by this package. Use @layers/amba-web from JS interop if you target the browser. |
Common pitfalls
- Events silently vanish —
Amba.events.trackqueues, batches, and retries by design; a wrong key, wrong env, or revoked credential does not throw at the call site. Always run the verify step in section 3 on every fresh build so a misconfiguration shows up as a loud failure, not silence. - Wrong env in a build flavour — a
clientKeyminted for staging will happily configure against the production stack and write to the wrong project. The verify snippet in section 3 prints the server-resolvedserverProjectId+environmenton every cold start; compare against the values your build expects on first launch instead of finding the drift in retention dashboards a week later. Amba.configurenot called before any otherAmba.*access throwsStateError("Amba.configure must be called before accessing Amba.*"). Always configure inmain()afterWidgetsFlutterBinding.ensureInitialized().- Hot-restart re-running
main()— callingAmba.configure()again throwsAmbaException("amba already initialized")on the second run. Wrap with atry/catchfor development: AmbaException: Failed to load ambaat runtime — the bundled artifact didn't ship with your build. Runflutter cleanthen rebuild; if it persists, verify yourpubspec.yamlreferencesamba: ^1.0.0(not apath:override pointing at an empty checkout) and thatflutter pub getran without errors.- Apple sign-in works in simulator, fails on device — the entitlement requires the app to be signed with a provisioning profile that includes the Sign in with Apple capability. Re-fetch the profile in Xcode after enabling.
See also
- Client API reference — HTTP endpoint reference for every namespace.
- Code samples — same operations side-by-side with the other 7 SDKs.
- Push notifications — campaign API, scheduling, fan-out.
- SDK on pub.dev.