# track

> Part of the Cowliss docs. Markdown for every page: append `index.md` to its URL. Site map: /llms.txt

```ts
await cow.track({
  identifiers: { userId: "user_1" },
  event: "checkout_started",
  properties: { cartId: "c_9", total: 4200 },
});
```

| Field | Required | Notes |
| --- | --- | --- |
| `identifiers` | yes | Who the event is about. Creates the profile if it is new. |
| `event` | yes | Up to 200 characters. It may not start with `system.`, which is reserved for the events Cowliss records itself. |
| `properties` | no | Any JSON object. Empty when omitted. |
| `timestamp` | no | ISO 8601 UTC, for a historical write. Never in the future. |
| `messageId` | on the wire | The dedupe key. The SDK generates one when you omit it. |

## Retries are safe

`messageId` is the dedupe key and travels as the `Idempotency-Key` header. Send the same one twice and the event is stored once. Derive it from the thing that happened (an order id, a request id), not a fresh random per attempt.

## What one call does

One `track`, synchronously, before the response: the profile is resolved or created, traits merge, segments recompute, and any automation whose trigger matches starts.

Importing history is different, and quieter: see [batch](/sdk/batch/).
