CohorlyDocs
GitHub

Event properties

Every event carries a properties object. A few keys are special - they drive identity, timing, deduplication, and attribution - while everything else is free-form data you define. The SDKs set the special keys for you; when calling the HTTP API directly, set them yourself.

Required and reserved keys

KeyTypeMeaning
distinct_idstringRequired. Identifies the user or device the event belongs to.
timenumberUnix milliseconds. Optional over HTTP (defaults to server receipt time); the SDKs always set it at capture time.
$insert_idstringIdempotency key used for deduplication (see below).
$libstringWhich SDK produced the event: core, web, ios, etc.
tokenstringPer-event project token. Overrides the header and is stripped before storage.

Deduplication with $insert_id

Every SDK-generated event gets a unique $insert_id (a UUID). Because retries can resend a batch that already landed, the server treats $insert_id as an idempotency key: an event with an id that already exists for the project is not inserted twice. This makes the at-least-once delivery of the SDK queues safe - a flush that fails, is retried, and then succeeds twice still produces exactly one stored event.

json
{
  "event": "Purchased",
  "properties": {
    "distinct_id": "user_123",
    "time": 1751600000000,
    "$insert_id": "b1f2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
    "amount": 49
  }
}

When calling /track directly, supply your own stable $insert_id if you want the same dedup guarantee across retries. Omit it and each request is treated as a distinct event.

Time is unix milliseconds

time is stored as a bigint of unix milliseconds. If you send seconds (a common mistake) your events will land in 1970. When omitted over HTTP, the server stamps receipt time; the SDKs stamp the moment track() is called so offline/queued events keep their true timestamp.

Auto-captured properties

The SDKs enrich every event with context so you do not have to. What gets added depends on the platform:

SDKAuto-added
@cohorly/web$browser, $os, $current_url, screen size, $lib = web
CohorlySwift (iOS)$lib = ios, $os, $os_version, $model, $screen_width/$screen_height
Core / React Nativedistinct_id, time, $insert_id, $lib, plus your super properties

Custom properties

Any keys beyond the reserved ones are stored verbatim in the jsonb properties column and become available for filtering and breakdowns in queries. Use consistent naming and value types per key so segmentation stays clean.

ts
cohorly.track("Item Added", {
  sku: "A-100",     // string
  price: 29.0,      // number
  currency: "USD",  // string
  gift: false,      // boolean
});