Skip to content

fix: record installs without a deviceId and report the IANA timezone - #15

Merged
onamfc merged 4 commits into
mainfrom
fix/install-omit-null-device-id
Oct 20, 2026
Merged

onamfc merged 4 commits into
mainfrom
fix/install-omit-null-device-id

Conversation

@onamfc

@onamfc onamfc commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Installs without a deviceId are recorded. DeviceFingerprint.toJson() drops fields with no value, the same way EventRequest.toJson() does. The install endpoint accepts a missing deviceId but rejects null, so an app that didn't pass one had every install refused and treated as organic, and deferred deep links were never delivered.
  • The fingerprint's timezone is an IANA identifier. It's read through flutter_timezone, falling back to the abbreviation when the platform can't report one. The server records a browser click's timezone as an IANA identifier, so an abbreviation such as PDT never matched it and the factor never counted toward attribution. flutter_timezone replaces the timezone package, which is removed.
  • Version 0.3.1 in pubspec.yaml and SdkInfo.version.

Test plan

  • flutter test: 141 passing (3 new: deviceId omitted when null; IANA identifier from the platform; fallback when the platform can't answer)
  • flutter analyze: no issues
  • Android 14 emulator, example app built from this branch:
    • Cold start from a link: onDeepLink, registered after initialize(), receives the launch link with resolved data
    • Warm open: delivered once; the same URL again within 10 seconds is ignored
    • Deferred install: tap a link in Chrome, install, first launch. /install returns 200, attributed: true, confidence 80, matched on ip, platform, timezone, language. onDeferredDeepLink receives the link with its URL parameter in customParameters.

… none

The install endpoint accepts a missing deviceId but rejects null, so an
install reported without one was refused and treated as organic, and the
install was reported again on every launch. DeviceFingerprint.toJson()
drops fields with no value, as EventRequest.toJson() does.
The fingerprint read the zone from the timezone package's tz.local, which
is only set once the app initializes that package's database. The SDK
never does, so the fallback DateTime.now().timeZoneName always ran and
sent an abbreviation such as "PDT". The server records a browser click's
timezone as an IANA identifier derived from its IP, so the two never
matched and the factor never counted toward install attribution.

The identifier now comes from the flutter_timezone plugin, falling back to
the abbreviation on a platform that can't report one. The timezone
package is no longer used and is removed.

The declared minimums are raised to Flutter 3.38.1 and Dart 3.10, which
the existing dependencies already require.
Raising the Dart minimum changes the language version dart format and the
code generators target, which reformats existing files. That belongs in a
change of its own.
@onamfc
onamfc merged commit d4b4a33 into main Oct 20, 2026
4 checks passed
@onamfc
onamfc deleted the fix/install-omit-null-device-id branch October 20, 2026 20:25
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.

1 participant