Events & properties
The anatomy of an OakData event: system vs custom events, the properties attached to every event, and context.
Everything OakData records is an event: a named action with a bag of properties, stamped with who did it, when, and in which session. Events come from two places — the SDK's autocapture, and your own oak.capture() calls.
Anatomy of an event
Each event the SDK sends looks roughly like this. The fields outside properties identify the actor and session; everything specific to the event lives inside properties.
{
"id": "evt_5f2c…",
"event": "signup_completed",
"timestamp": "2026-06-11T14:03:21.881Z",
"distinct_id": "user_8f3a",
"anonymous_id": "a3c1…",
"session_id": "s_a1b2c3",
"session_number": 2,
"session_started_at": "2026-06-11T13:58:10.020Z",
"properties": { "plan": "pro", "$pathname": "/welcome" },
"context": {
"library": "oakdata-js",
"library_version": "0.4.0",
"page": { "url": "...", "path": "/welcome", "title": "Welcome", "referrer": "" }
},
"traits": { "email": "sam@acme.com" },
"groups": { "company": { "id": "acme-co", "traits": { "name": "Acme" } } }
}System vs custom events
Events whose names begin with $ are system events emitted by the SDK — $pageview, $click, $form_submit, $identify, $set, $group, and so on. Your own events should use plain names (signup_completed, invoice_paid). The same $ convention applies to system properties the SDK attaches automatically.
Naming convention
Use snake_case, past-tense, object-then-action names (checkout_completed, file_uploaded). Keep high-cardinality values (ids, emails) in properties, not in the event name.
Properties attached to every event
The SDK enriches each event with context the server stores as first-class columns — so you can filter and group without parsing JSON. Common keys:
| Property | Type | Description |
|---|---|---|
$current_url / $pathname / $host / $search | string | The page URL and its parts. |
$title | string | The document title. |
$referrer / referring_domain | string | Where the visitor arrived from. |
browser / browser_version / os / os_version | string | Parsed from the user agent. |
device_type | string | desktop, mobile, or tablet. |
viewport_width / viewport_height | number | Browser viewport size. |
utm_source / utm_medium / utm_campaign / utm_term / utm_content | string | Campaign attribution, captured from the landing URL and carried via first/last touch. |
Geo fields (country, region, city) are derived server-side from the request IP at ingest — the SDK never sends them.
Custom properties
Pass any JSON-serializable object as the second argument to capture. Keep property names stable and values low- cardinality where you intend to group by them.
oak.capture('plan_changed', {
from: 'free',
to: 'pro',
annual: true,
seats: 5,
})Scrubbing sensitive data
Strip fields before they leave the browser with the property_denylist init option, or rewrite/drop whole events with before_send. See the SDK reference.