Skip to content

feat(attribution): expose install-match certainty on the deferred deep link - #18

Merged
onamfc merged 1 commit into
mainfrom
feat/match-certainty
Oct 21, 2026
Merged

onamfc merged 1 commit into
mainfrom
feat/match-certainty

Conversation

@onamfc

@onamfc onamfc commented Oct 21, 2026

Copy link
Copy Markdown
Member

What changed

  • DeepLinkData gains nullable confidenceScore (double?), matchedFactors (List<String>?), attributionMethod (String?) and competingLinks (int?). The install endpoint sends them inside deepLinkData on a match, so they reach the app through onDeferredDeepLink. The resolve endpoint never sends them, so they are null on a direct open. fromJson/toJson, ==, hashCode, toString and mergingUrlParameters include them.
  • InstallResponse gains nullable attributionMethod ("fingerprint" or "none") and competingLinks, as optional named constructor parameters. The response the SDK builds on later launches (from the stored install data) leaves both null rather than inventing values.
  • The new fields are read by small lenient readers (lib/models/match_certainty_json.dart): a missing or wrongly typed value becomes null, and a whole-number double (2.0) becomes an int. A bad value in one of these informational fields never drops the deep link or fails the install response.
  • The install's deep link is stored as DeepLinkData JSON, so the fields round-trip through getInstallData(); data stored by earlier versions decodes with them null.
  • Dartdoc on competingLinks explains what it means; README has a "How certain is the match?" section with an example; CHANGELOG entry; version 0.5.0 in pubspec.yaml, SdkInfo.version and example/pubspec.lock. Generated *.g.dart files rebuilt with build_runner.

Why

competingLinks tells an app whether other links on the same network were also in contention for the install. 0 means no other link was; above 0, another device's tap may be what led to this install, so an app acting on a sensitive link (a sign-in, a gift) can treat the match as unverified, for example by asking the user to confirm. The match score and factors were already sent on the deferred deep link but not exposed by the SDK.

Tests

  • New model tests: parsing with and without the new fields, "none" for organic, a double competingLinks, wrongly typed values read as null, JSON round-trip, equality/hashCode, mergingUrlParameters keeping the fields.
  • Storage tests: save then load round-trip of the new fields, and decoding install data in the shape earlier versions stored.
  • Attribution manager: later launches return null for both new InstallResponse fields.
  • flutter test (164 passed), flutter analyze (no issues), dart format --output=none --set-exit-if-changed . (clean), dart run build_runner build --delete-conflicting-outputs (no diff in lib), flutter pub publish --dry-run (0 warnings).

…p link

The deferred deep link passed to onDeferredDeepLink now carries confidenceScore, matchedFactors, attributionMethod and competingLinks, and InstallResponse carries attributionMethod and competingLinks. competingLinks counts the other links that had a click from the install's network that also reached the confidence threshold, so an app acting on a sensitive link can treat a contested match as unverified and ask the user to confirm.

The fields are read leniently (missing or unexpected values become null, a whole-number double becomes an int), are null on direct opens and on launches after the one that reports the install, and are stored with the install's deep link; install data saved by earlier versions still decodes. Version 0.5.0.
@onamfc
onamfc merged commit 0df3813 into main Oct 21, 2026
4 checks passed
@onamfc
onamfc deleted the feat/match-certainty branch October 21, 2026 23:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants