Skip to content

Events & properties

An event freezes its properties at capture time. Nothing rewrites it afterwards — not identity merges, not trait updates, not enforcement decisions. If a person’s plan changes, their person changes; the events they sent while on the old plan keep saying the old plan. That’s the split: events are history, persons are state.

Every event carries:

Field What it is
uuid Client-generated UUID v7. The idempotency key: the pipeline deduplicates by it, which is why retries at every layer are safe
event The name. Your names are free-form; $-prefixed names are the system’s
distinct_id Who did it, as known at capture time
properties Arbitrary JSON. Kilden never validates or types it — the envelope is typed, the payload is yours by design
timestamp When it happened (client-supplied, corrected for clock skew using the batch’s sent_at)

Names starting with $ — events and properties — are reserved for the system. The SDK warns in debug mode if you track() one, but still delivers it: the namespace is a convention, never a reason to drop your data.

System events you’ll see in your stream:

Event Emitted by
$pageview, $pageleave SDK, automatically (including SPA route changes)
$autocapture Autocapture: clicks, submits, changes, described by $event_type and $elements
$identify identify() — carries $anon_distinct_id for identity linking
$set, $set_once Person trait updates
$feature_flag_called First flag read per session — $flag_key, $flag_value (exposures)
$session_recording_started Replay recording start
$email_sent, $email_delivered, $email_opened, $email_clicked, $email_bounced, $email_complained Campaigns and the email provider’s webhooks

Context properties stamped on every SDK event: $current_url, $referrer, $session_id, $device_type, $screen_width, $screen_height, $lib, $lib_version, $utm_source, $utm_medium, $utm_campaign, $utm_term, $utm_content.

Every event — browser, backend, email webhook, even Kilden’s own internal events — enters through the same capture endpoint and the same pipeline. There are no side doors, which is what makes the guarantees (dedup, identity resolution, trust levels) hold for everything uniformly.

The SDK maintains $session_id (UUID v7) on every event, rotating it after 30 minutes of inactivity. Sessions tie together events, feature-flag exposure dedupe and session replay — a recording is always joinable 1:1 with its session’s events.