Identity and event taxonomy
Choose stable customer identifiers and a maintainable product event contract.
Identity model
Kite models one customer as one account, workspace, or tenant. Send the stable identifier from
your system as customerId; do not use an email address, mutable slug, or a person's session ID.
The identifier is opaque to Kite and unique within a project and environment.
Kite does not merge aliases or model a user-to-account hierarchy. If people act on behalf of an
account, use the account ID as customerId and include a non-sensitive actor ID in event
properties when analysis requires it. Test and live identities are isolated.
Use identify for the current attributes used by rules and scoring. Traits are shallow-merged,
so sending { plan: 'pro' } preserves other existing traits. A track call creates an unknown
customer with empty traits automatically.
await kite.identify('account_42', {
plan: 'pro',
availableFeatures: ['exports', 'sso'],
});
await kite.track('account_42', 'integration.connected', {
provider: 'salesforce',
});There is no identity merge operation. Resolve duplicate or migrated IDs in the source system before ingestion, then backfill and recompute the canonical customer if necessary.
Event taxonomy
Events are immutable product facts. Prefer past-tense domain names such as
integration.connected and report.exported. Avoid UI implementation names such as
modal_button_clicked, lifecycle conclusions such as customer.healthy, and values embedded in
the name. Put dimensions such as provider, feature, or plan in properties.
Keep a small contract for each event:
| Field | Decision |
|---|---|
| Name | A stable, namespaced fact with one meaning. |
| Producer | The backend component authoritative for the fact. |
| Customer | The account or workspace that receives the outcome. |
| Timestamp | When the fact occurred, including an ISO 8601 timezone. |
| Properties | Bounded dimensions needed by definitions or diagnosis. |
| Idempotency | A stable source operation ID when one exists. |
Declare the contract in kite.config.ts:
export default defineConfig({
project: 'acme',
strictSchema: true,
events: {
'integration.connected': {
description: 'A workspace completed an integration connection',
properties: {
provider: { type: 'string', enum: ['salesforce', 'hubspot'] },
},
},
'report.exported': {
properties: { format: { type: 'string', enum: ['csv', 'pdf'] } },
},
},
customerTraits: {
plan: { type: 'string', optional: true },
availableFeatures: { type: 'array', items: { type: 'string' }, optional: true },
},
});With strictSchema: true, undeclared events, unknown or missing properties, invalid traits, and
wrong types return 422. With false, Kite accepts the data and records the violation. Start in
test, inspect violations, and enable strict mode only after all producers conform.
Delivery semantics
Use an idempotency key for every retryable track. Its scope is project and environment. Reusing a
key with the same canonical event returns the original event; changing its customer, name,
properties, or explicit timestamp returns 409 IDEMPOTENCY_CONFLICT.
POST /v1/events/batch accepts 1 to 1,000 mixed identify and track operations and preserves
their order for each customer. Payloads are limited to 64 KiB of serialized properties or traits;
names and identifiers are limited to 256 characters.
Governance checklist
- Assign an owner and description to every event.
- Emit business facts from the backend, not inferred browser clicks.
- Never silently change the meaning or type of an existing property.
- Add a new event for a genuinely different fact; add an optional property for a new dimension.
- Exclude secrets, credentials, and unnecessary personal data.
- Validate producers in test before deploying the schema to live.