CohorlyDocs
GitHub

Data model

Cohorly's data model has three core concepts - events, users, and projects - all scoped by project. Event properties are stored as schemaless JSON, so you never define a schema up front.

Projects

A project represents one app you are tracking. All data is scoped to a project; create projects in the dashboard under Settings.

ts
interface Project {
  id: number;
  name: string;
  token: string;      // UUID, authenticates ingestion
  created_at: number; // unix ms
}

The token is what SDKs send with each request; Cohorly resolves it to a project_id and stores data under it. Ingestion is authed by this token, while the admin and query API is authed by your account API key.

Events

An event is an immutable record of something a user did. Events belong to a project and a distinct_id, carry a time, and store their properties as jsonb.

ColumnTypeNotes
project_idintegerOwning project.
eventtextEvent name.
distinct_idtextUser/device this event belongs to.
timebigintUnix milliseconds.
$insert_idtextIdempotency key for deduplication.
propertiesjsonbArbitrary event properties (GIN indexed).

Properties are stored as jsonb with a GIN index, so filters and breakdowns on property keys are queryable without a fixed schema.

Users

A user (profile) aggregates identity and profile properties for a distinct_id within a project. Profiles are mutated via the /engage endpoint (the People API), while the derived stats come from the underlying events.

ts
interface UserProfile {
  distinct_id: string;
  properties: Record<string, unknown>; // from $set / $set_once / $add / $unset
  first_seen: number | null;           // unix ms
  last_seen: number | null;            // unix ms
  event_count: number;
}

Aliases

Aliasing links an anonymous distinct_id to a known one so that pre-login and post-login activity resolve to a single user. The web SDK issues an /alias call automatically on the first identify() after being anonymous.

Multi-project isolation

Every table is keyed by project_id, and every query resolves a target project (from the token on ingestion, or the projectId parameter on the admin/query API). This keeps data for separate apps fully isolated within one Cohorly deployment.