Schemas
HeartbeatEvent
client_tsClient send time, ISO 8601 (UTC). Batched events carry their own. Server receive time is recorded separately and is authoritative for sessionization.
event_idClient-generated UUID. Required: the pipeline dedupes retries and batch replays on it, which a server-generated id could not do.
event_typeschema_versionSemver of the event_type schema the client speaks.
No fields defined in v1; omit or send {}.
PlaylistResponse
stream_session_idServer-issued stream session id (ss). Carry it on firstplay and viewhour of the same session.
TelemetryEnvelope
app_versionApp or web build version.
didClient-generated persistent device id: in an app, stable across app restarts and app updates; on web, a first-party UUID in localStorage with a cookie fallback. Send on every event, and send the same value on player events and telemetry — it is the join key between the two surfaces, so two separately minted UUIDs break the join silently. (Audience counting lives on the telemetry surface, not on player events.)
1..N events, identity fields above sent once per request. Typed schemas exist for the v1 types only (visit, heartbeat, view). Allow-listed on this deployment: visit, heartbeat, view — any allow-listed type outside the three is accepted with the base fields (event_id, event_type, schema_version, client_ts, context) and routed to its own topic; unlisted types are routed to the unknown quarantine table.
platformPlatform, keep granular: web, android, androidtv, ios, tvos, roku, tizen, webos, firetv, vizio, hoteltv, box, chromecast. Web sends plain web.
serviceService: odk, amasian. Required. A value outside this allow-list, or an omitted field, returns 400 and no row is produced — an unknown service would land rows under the wrong service. Case-sensitive, so ODK and odkr are rejected; the wire value for ODK is odk.
IAB GPP consent string from the CMP (__gpp). Mobile and web.
OS limit-ad-tracking flag as reported by the OS: 0 or 1. Apps and CTV. Same key on PEv2 (query string) and telemetry (JSON); both are stored as the string "0"/"1". JSON here, so send the integer.
OS advertising identifier, raw, one kind per platform: idfa (ios/tvos), gaid (android/androidtv), rida (roku), afai (firetv), tifa (tizen), lgudid (webos), vida (vizio). Not applicable on web. Send the OS value as-is, never suppress; the pipeline honours islat. Same key as PEv2.
IAB US Privacy (USP) string, e.g. 1YNN. Backward compatibility for any client that cannot produce a GPP string yet — chiefly CTV, whose platforms have no GPP CMP. Web CMPs emit GPP, so web sends gpp only. Send both when both are available; the two fields are independent and neither is derived from the other.
Logged-in account id. Null or omitted for guests.
ViewContext
document.referrer or null.
UTM query parameters of the landing URL, or null.
ViewEvent
client_tsClient send time, ISO 8601 (UTC). Batched events carry their own. Server receive time is recorded separately and is authoritative for sessionization.
event_idClient-generated UUID. Required: the pipeline dedupes retries and batch replays on it, which a server-generated id could not do.
event_typeschema_versionSemver of the event_type schema the client speaks.
target_idPage path, e.g. /shorts. SPA route changes count as page views.
target_typev1 defines page only.
VisitContext
triggerlaunch on app start; resume on foreground-resume after ≥ 30 min in background (client persists its last telemetry time and compares on foreground). A pure OS-lifecycle fact, independent of why the user came back. The 30-minute suppression is overridden in two cases, which always emit: the first foreground of a new UTC day, and any deeplink entry.
The deeplink URI as received, minus any parameter carrying a credential — auth tokens, one-time codes, session ids, signed URLs, and any nested URL such as the url parameter of an external deeplink. Only the client knows which of its own links carry these, so the stripping is client-side. Route parameters and utm_* are sent as received and parsed in the warehouse.
How the user got in — orthogonal to trigger, which records only what the OS did. A deeplink can arrive on either a cold launch or a warm resume. A QR scan cannot identify itself: the camera app hands over a universal link, so QR attribution has to come from utm_source inside that link.
Who handed over the launch, where the OS exposes it: Android Activity.getReferrer() (android-app://<package>, or an http referrer), iOS sourceApplication or the universal-link referrer. The same question context.referrer answers on view, asked of the OS instead of the browser.
Milliseconds since this client's last telemetry send — the value it already computes to apply the 30-minute rule. Sent so the session threshold can be re-cut in the warehouse rather than by a client release on every platform.
In-app route the entry landed on. Same field, and same vocabulary, as target_id on view.
VisitEvent
client_tsClient send time, ISO 8601 (UTC). Batched events carry their own. Server receive time is recorded separately and is authoritative for sessionization.
event_idClient-generated UUID. Required: the pipeline dedupes retries and batch replays on it, which a server-generated id could not do.
event_typeschema_versionSemver of the event_type schema the client speaks.