Skip to content
Dashboard

Testing & Troubleshooting

Deferred flow testing has platform constraints: full attribution path depends on store redirect chain.

  • Deferred matching is first-launch oriented.
  • Runtime callbacks do not re-trigger deferred matching logic.
  • The Flutter bridge does not expose a session reset API.
  1. Uninstall the app from the device or simulator.
  2. Open a Detour link.
  3. Install and launch the app.
  4. Verify the initial intent and the resolved route in your UI logs.
  5. Relaunch the app and confirm the deferred behavior is not repeated.
Terminal window
adb shell am start -a android.intent.action.VIEW \
-d "https://<your-link-domain>/<link-token>" \
com.example.app
Terminal window
adb shell am start -a android.intent.action.VIEW \
-d "myapp://product/42" \
com.example.app
Terminal window
xcrun simctl openurl booted "myapp://product/42"
Terminal window
xcrun simctl openurl booted "https://<your-link-domain>/<link-token>"

Install referrer click_id is often unavailable in local/dev-store scenarios. In that case matching falls back to probabilistic flow.

For local install referrer testing workarounds, see How to test the Play Store Install Referrer API.

If an installed app does not open Detour links, the Dashboard SHA-256 probably does not match the key that signed the build on your device:

How you install the appSHA-256 to useWhere to find it
Google Play, any trackPlay App Signing keyPlay Console → Protected with Play → Manage Play app signing → App signing key certificate
flutter run / flutter build apk --debugAGP default debug keystorekeytool -list -v -keystore ~/.android/debug.keystore -storepass android, or ./gradlew signingReport
Release build with your own keystoreYour release keystorekeytool -list -v -keystore <path-to-your.keystore>

The Flutter template signs release with the debug config until you add your own release keystore, so a fresh flutter build apk --release is still debug-signed.

To check any build directly: apksigner verify --print-certs build/app/outputs/flutter-apk/app-debug.apk. The complete procedure is described in Finding your Android SHA-256 fingerprint.

No match found (404)
  • Check timestamps. The click may be older than the match window (15 minutes).
  • Confirm the click was recorded in your Detour Dashboard.
  • On the Android deterministic flow, confirm click_id is present in the install referrer.
App/Universal link never arrives despite a valid click

Your plan’s click limit may be exceeded. The plugin surfaces nothing in Dart, because the intent never arrives, so check the native log for [Detour:CLICK_LIMIT_ERROR]. See Click limits.

429 Too Many Requests

Detour limits deferred link matching per device and IP address, and per app. Wait between reinstall tests on one device. For tests on many devices at once, create a separate app for testing in the Dashboard, because each app has its own credentials and its own limit.

NOT_CONFIGURED platform error

resolveInitialLink() and processLink() raise it on both platforms. On Android, logEvent() and logRetention() raise it too.

Cause — the method ran before a successful configure(...) call.

Fix — await DetourService.start(...) or DetourFlutterPlugin.configure(...) before you call these methods. If configure(...) failed, fix that error first.

INVALID_ARGS platform error

Android only. configure(...) raises it when apiKey or appID is empty, processLink(...) when url is empty, and logRetention(...) when eventName is empty. A value that contains only whitespace counts as empty.

Cause — a required string argument is empty.

Fix — pass non-empty values. For where apiKey and appID come from, see Credentials.

NO_ACTIVITY platform error

Cause — on Android, configure(...) ran in a Flutter engine that has no attached activity, such as a separate engine started for background work.

Fix — call DetourService.start(...) or DetourFlutterPlugin.configure(...) from your app’s UI code, not from a background handler.

NATIVE_ERROR platform error

Android only. resolveInitialLink() and processLink() raise it, and linkStream emits it as an error event, when the native SDK fails to process a link. DetourService.start() throws the same error and leaves isInitialLinkProcessed at false, so catch it if your startup flow waits for that flag.

A failed deferred match request on first launch raises it. When the server responded, the message starts with the HTTP status code:

  • [401] — the apiKey or appID is wrong. See Credentials.
  • [402] — your organization is over its plan’s click limit. See Click limits.
  • [429] — too many match requests. See 429 Too Many Requests.
  • No status code — the request did not complete. Check the network connection.
iOS clipboard not read
  • Ensure shouldUseClipboard: true is set in DetourConfig.
  • Ensure the copy-link feature is enabled in the Detour Dashboard for your iOS app configuration.
  • The link must be copied to the clipboard before the app is opened, because the clipboard is only read during resolveInitialLink().
Android release build fails with Type com.swmansion.detour.BuildConfig is defined multiple times

Debug builds of the same project succeed.

Cause — detour_flutter_plugin 1.1.1 and 1.2.0 use the Android namespace com.swmansion.detour, which the native Detour SDK also uses. The release build then contains two classes named com.swmansion.detour.BuildConfig.

Fix — upgrade to detour_flutter_plugin: ^1.2.1 and run flutter pub get.

  • Android:
    • adb logcat | grep -i detour
  • iOS simulator:
    • xcrun simctl spawn booted log stream --predicate 'subsystem == "com.swmansion.detour"'

For full runnable setup and commands, use Examples.