Skip to content

Release: report the detected player to GA4 - #33

Merged
vpetersson merged 2 commits into
productionfrom
master
Jul 16, 2026
Merged

Release: report the detected player to GA4#33
vpetersson merged 2 commits into
productionfrom
master

Conversation

@vpetersson

Copy link
Copy Markdown
Contributor

Promotes #32 to production. Production is exactly two commits behind, so this release is that one change and nothing else.

Sends a player_detected GA4 event carrying the player profile the stale-notice already computes — vendor, platform, model, category, engine + version, below-floor, confidence, and the app's own player_stale verdict.

Tested on stage

Stage (stage-clock.srly.io) serves the new bundle and I drove it in a real browser across four spoofed player UAs. Each queued exactly one well-formed event to the real gtag shim, with player_stale agreeing with whether the notice actually mounted:

Player vendor engine_version stale notice shown
old Anthias (untagged QtWebEngine) unknown 83 true yes
current Anthias anthias 122 false no
Screenly viewer screenly 83 false no
BrightSign brightsign 65 false no

player_model correctly picked up XT1144 off the BrightSign UA. No page errors anywhere; the clock renders throughout.

What I could NOT verify, and who should

googletagmanager.com is connection-refused from the environment I tested in, so real gtag.js never loaded there and nothing flushed to Google's collect endpoint. Everything up to and including the handoff to gtag is confirmed; GA's actual ingestion is not. Worth a look in GA4 DebugView/Realtime from an unblocked network — on stage before this merges, or on production right after.

Before this reports anything

The params stay invisible in reports until registered as custom definitions in the GA4 UI (Admin → Custom definitions) on the production property G-QD11F7ZZ1Bplayer_engine_version as a metric, the rest as dimensions. Merging without that still collects the data; it just won't be queryable until they're registered.

🤖 Generated with Claude Code

vpetersson and others added 2 commits July 16, 2026 14:34
The stale-player notice already profiles every viewer to decide whether to
warn it, but that judgement was made and thrown away on each load — so the
population we are warning, and whether it ever shrinks, was unmeasurable.

Send the same profile as a `player_detected` event. One detectPlayer() call
now feeds both consumers, so the notice and the telemetry can never disagree
about what a screen is running.

Client-side for the same reason the notice is: the SSR page cache is keyed by
asset version + country + timezone with no user-agent component, so a server
-side profile would describe whichever player missed the cache and then be
attributed to every hit behind it.

Params are prefixed `player_` because the GA property is shared with the other
Screenly-Labs apps. Three calls worth naming:

* Nulls are sent as "unknown" rather than omitted — an absent param reads as
  "(not set)" in GA4, indistinguishable from a dimension nobody registered.
* engine_version stays numeric so GA4 will aggregate it.
* player_stale is sent despite being derivable from vendor + engine: "stale"
  is a judgement this app makes (see stale-player.js) rather than something a
  report author should re-derive, and it is what makes notice impressions
  countable against upgrades.

`sources` is not sent — page JS can only read the UA and referrer, so it is
near-constant here and would spend a custom dimension on nothing.

Verified against the built bundle in a browser across four spoofed player UAs:
one event per load, player_stale agreeing with whether the notice mounted, and
a silent no-op when gtag is absent (dev, or a blocked tag in the field).

Note: the params stay invisible in reports until they are registered as custom
definitions in the GA4 UI — engine_version as a metric, the rest dimensions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vpetersson
vpetersson merged commit 24c2707 into production Jul 16, 2026
1 check passed
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