EventRecord
The row every destination writes: one per event, with the same fields for every event. This page lists each field and who sets it, and shows example records.
Fields
| Field | Set by | What it holds |
|---|---|---|
specVersion | Hub | The version of the record shape, from the Hub that assembled the record. |
id | Producer | A UUID minted by the producer for this event. |
sessionId | Hub, from the request | The visitor's session identifier, or null when the storage policy stored none. |
name | Producer | The event name, as passed to track(). |
location | Producer | The page URL in the browser; the Referer header on the server. |
occurredAt | Producer's clock | When track() was called. |
sentAt | Producer's clock | When the event was handed to the Hub. |
receivedAt | Hub's clock | When the Hub received the event. |
producerType | Hub | "remote" for events that came in over HTTP through the collector, "local" for events from a server producer. |
producerName | Producer | Names the source stream, e.g. "browser". A claim from a remote producer; your own configuration on a local one. |
producerProperties | Producer | The track() properties merged over the producer's properties(). JSON you define. |
hubProperties | Hub | The request values the Hub collects (userAgent, forwardedFor, acceptLanguage) merged under your hubProperties(). forwardedFor is the raw X-Forwarded-For header. JSON you define. |
consent | Hub, from the request | The visitor's decision when the event arrived: "accepted", "denied" or "unset". |
In TypeScript, a record has the EventRecord type from @eventrail/nextjs/core.
Examples
Records as a destination receives them. The browser and server events come from the same visit, so
they share a sessionId. In each, userId comes from a hubProperties() function like the one in
Server-resolved user IDs.
Browser event
{
specVersion: 1,
id: "1f2a9c3e-6b8d-4f1a-9e2c-7d4b5a6f8e10",
sessionId: "9d2c7e4b-1f8a-4c3d-8e2b-7a6f5e4d3c2b",
name: "upgrade_plan_button_clicked",
location: "https://yourapp.com/pricing",
occurredAt: "2026-09-23T12:00:00.081Z",
sentAt: "2026-09-23T12:00:00.092Z",
receivedAt: "2026-09-23T12:00:00.140Z",
producerType: "remote",Came in over HTTP, through the collector.
producerName: "browser",
producerProperties: { plan: "pro" },
hubProperties: {
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
forwardedFor: "203.0.113.7",
acceptLanguage: "en-US,en;q=0.9",
userId: "usr_42"
},
consent: "accepted"
}Server event
{
specVersion: 1,
id: "7c1e4d2a-3b5f-4a8e-9d6c-2f1b0a9e8d7c",
sessionId: "9d2c7e4b-1f8a-4c3d-8e2b-7a6f5e4d3c2b",Same identifier as the click: read from the same visitor's cookies.
name: "plan_upgraded",
location: "https://yourapp.com/pricing",The Referer of the request the event was fired in.
occurredAt: "2026-09-23T12:00:01.204Z",
sentAt: "2026-09-23T12:00:01.204Z",
receivedAt: "2026-09-23T12:00:01.205Z",
producerType: "local",
producerName: "server",
producerProperties: { plan: "pro" },
hubProperties: {
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
forwardedFor: "203.0.113.7",
acceptLanguage: "en-US,en;q=0.9",
userId: "usr_42"
},
consent: "accepted"
}Webhook
{
specVersion: 1,
id: "b3d8f1a6-0c2e-4f7b-8a9d-5e6c4b3a2f10",
sessionId: null,A webhook request carries no visitor cookies, so there is no identifier.
name: "subscription_renewed",
location: null,
occurredAt: "2026-09-24T03:14:07.512Z",
sentAt: "2026-09-24T03:14:07.512Z",
receivedAt: "2026-09-24T03:14:07.513Z",
producerType: "local",
producerName: "server",
producerProperties: { plan: "pro" },
hubProperties: {
userAgent: "PaymentProvider-Webhooks/1.0",
forwardedFor: "198.51.100.23",
acceptLanguage: null,
userId: null
},
consent: "unset"No decision on the request: unset, not denied.
}Consent denied
{
specVersion: 1,
id: "e4a7c2f9-8b1d-4e3a-a6f5-0d9c8b7a6e54",
sessionId: null,Under the optIn and optOut policies, a visitor who denied has no stored identifier.
name: "page_view",
location: "https://yourapp.com/",
occurredAt: "2026-09-23T14:32:10.018Z",
sentAt: "2026-09-23T14:32:10.020Z",
receivedAt: "2026-09-23T14:32:10.071Z",
producerType: "remote",
producerName: "browser",
producerProperties: { referrer: "https://www.google.com/" },Added by the page view tracker: on the first page view after the page loads, the page the visitor came from.
hubProperties: {
userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Mobile/15E148 Safari/604.1",
forwardedFor: "192.0.2.44",
acceptLanguage: "nl-NL,nl;q=0.9",
userId: null
},
consent: "denied"
}Relating events
- Link events by
sessionId. Browser events and server events fired during the same visitor's request carry the same identifier. - Without a
sessionId, relate events by request values. Events with anullsessionIdcan still be grouped into approximate visits by IP address, user agent and language. See Relating events without a sessionId. - Deduplicate on
id. The same event written twice has the sameid. The Postgres table has no unique constraint on it, and BigQuery's deduplication on it is best-effort. - Order on
receivedAt. It comes from your server's clock.occurredAtandsentAtcome from the producer's clock, which on a visitor's device can be wrong.