# Track goals

> Record browser and server goals with TraceKit analytics.

- Canonical: https://tracekit.dev/docs/analytics/goals

## Choose a collection method

Use browser collection for actions in the user interface.
Use server collection for trusted application events.
Use a server event when the application confirms the goal on the server.

## Track a browser goal

```ts
import * as tracekit from '@tracekit/browser';

tracekit.init({
  apiKey: 'ctxio_pub_...',
  serviceName: 'your-service-name',
});

tracekit.track('signup_completed', {
  plan: 'starter',
});
```

Browser names use `^[A-Za-z0-9][A-Za-z0-9_.:-]{0,63}$`.
Names beginning with `$` are reserved.

Browser properties allow 50 object keys, five levels, 64-byte keys, and 1,024-byte strings.
The browser request body limit is 65,536 bytes.

`track` returns a stable 32-character event ID after local validation succeeds.
It returns an empty string when the SDK rejects the event.

The returned ID does not report queue overflow or confirm server delivery.

## Track a server goal

Send a request to the active service endpoint.

```bash
curl -X POST \
  'https://app.tracekit.dev/v1/analytics/projects/your-service-name/events' \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: ctxio_...' \
  -H 'Idempotency-Key: signup-2026-0001' \
  --data '{
    "name": "signup_completed",
    "timestamp": "2026-01-01T12:00:00Z",
    "properties": {"plan": "starter"},
    "visitor_id": "0123456789abcdef0123456789abcdef",
    "session_id": "abcdef0123456789abcdef0123456789",
    "user_id": "user_opaque_...",
    "trace_id": "0123456789abcdef0123456789abcdef",
    "span_id": "0123456789abcdef",
    "replay_id": "replay_...",
    "release_id": "release_..."
  }'
```

The endpoint is `POST https://app.tracekit.dev/v1/analytics/projects/:project/events`.
The :project is the active service name.
Use a private organization or service key in `X-API-Key`.
A Public `ctxio_pub_...` key receives HTTP 403.

`name` and `timestamp` are required.
Server event names use lowercase `^[a-z0-9][a-z0-9_:-]{0,63}$`.
The timestamp uses RFC3339 and cannot exceed five minutes in the future.

Optional fields are `properties`, `visitor_id`, `session_id`, `user_id`, `trace_id`, `span_id`, `replay_id`, and `release_id`.
The server rejects unknown fields, duplicate keys, and invalid UTF-8.
The server body limit is 64 KiB.

`Idempotency-Key` is optional and supports 1-255 printable ASCII characters.
Use one stable `Idempotency-Key` for each logical goal.
The server returns HTTP 201 for creation and HTTP 200 for a duplicate.

Use a private key for server requests.
Public keys receive HTTP 403 on this endpoint.

## Continue

- [Open Analytics](/docs/analytics) to verify collected goals.
- [Read the analytics reference](/docs/analytics/reference) for formulas and delivery limits.
