> For the complete documentation index, see [llms.txt](https://docs.millimetric.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.millimetric.ai/quickstart.md).

# Quickstart

Three ways to send events: `curl` (or any HTTP client), the browser SDK, the Node SDK, or an AI agent via MCP. They all hit the same API.

## 1. Get an API key

In the dashboard, create a project. You'll get three keys:

| Key         | Use it from                        | What it can do |
| ----------- | ---------------------------------- | -------------- |
| `pk_live_…` | browsers (origin-restricted)       | ingest only    |
| `sk_live_…` | servers, scripts, anywhere private | ingest only    |
| `rk_live_…` | servers, MCP clients, dashboards   | read only      |

Add your site's origin to the project's allowlist before using `pk_*` keys from a browser.

## 2. Send your first event

### curl

```bash
curl -X POST https://api.millimetric.ai/v1/track \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "event": "signup",
    "anonymous_id": "u_abc",
    "user_id": "user_42",
    "url": "https://yoursite.com/?utm_source=facebook&utm_medium=cpc",
    "properties": { "plan": "free" }
  }'
```

### Browser — snippet (any HTML page)

```html
<script async src="https://cdn.millimetric.ai/v1/a.js"
        data-key="pk_live_…"></script>
<script>
  // optional: track a custom event
  window.mm?.track("clicked_pricing", { plan: "pro" });
</script>
```

What you get automatically:

* `$pageview` on load and every SPA route change
* `anonymous_id` in `localStorage` (no cookies)
* Captures `utm_*`, `fbclid`, `gclid`, `ttclid`, `msclkid`, `li_fat_id`, viewport, language, timezone
* Respects DNT / Global Privacy Control
* Batches events; flushes on `pagehide` via `sendBeacon`

### Browser — npm (React / Next / Vue / Svelte)

```bash
npm i @millimetric/track
```

```ts
import { init, track, identify, page } from "@millimetric/track";

init({ key: "pk_live_…" });
track("signup", { plan: "free" });
identify(user.id, { email: user.email });
```

### Node / Bun

```bash
npm i @millimetric/track-node
```

```ts
import { init, track, flush } from "@millimetric/track-node";

init({ key: "sk_live_…", host: "https://api.millimetric.ai" });
track({ event: "purchase", anonymous_id: req.cookies.aid, user_id: user.id,
        properties: { amount_cents: 4900 } });
// at the end of a serverless handler:
await flush();
```

### AI agent via MCP

Point any MCP-speaking agent at `https://api.millimetric.ai/mcp` with a Bearer token. **Only server-side keys** are accepted — `pk_*` is rejected because it's designed to ship in browser JS. Tools available:

* `track_event` (requires an `sk_*` or `admin` key)
* `query_events`, `get_stats`, `top_sources` (`rk_*`)

Example tool call:

```json
{ "name": "top_sources",
  "arguments": { "from": "2026-05-01T00:00:00Z", "to": "2026-05-16T00:00:00Z",
                 "breakdown": "source_medium" } }
```

## 3. Query your data

```bash
# Source/medium breakdown (this is what makes FB social vs paid show up)
curl "https://api.millimetric.ai/v1/sources?from=2026-05-01&to=2026-05-16&breakdown=source_medium" \
  -H "Authorization: Bearer rk_live_…"

# Aggregate stats
curl "https://api.millimetric.ai/v1/stats?metric=count&from=2026-05-01&to=2026-05-16&event=signup&group_by=source,medium&interval=day" \
  -H "Authorization: Bearer rk_live_…"

# Raw events
curl "https://api.millimetric.ai/v1/query?from=2026-05-01&to=2026-05-16&event=signup&limit=100" \
  -H "Authorization: Bearer rk_live_…"
```

## 4. Privacy operations

```bash
# Forget every event for a user (GDPR delete)
curl -X POST https://api.millimetric.ai/v1/forget \
  -H "Authorization: Bearer sk_live_…" \
  -d '{"user_id":"user_42"}'

# Bind an anonymous id to a user id
curl -X POST https://api.millimetric.ai/v1/identify \
  -H "Authorization: Bearer sk_live_…" \
  -d '{"anonymous_id":"u_abc","user_id":"user_42","traits":{"plan":"pro"}}'
```

## How attribution is classified

Every event runs through a server-side classifier that turns raw `utm_*`, click IDs, and referrer into a clean `(source, medium, confidence)` tuple. The rules cascade, first match wins:

1. `gclid`/`msclkid`/`ttclid`/`li_fat_id` ⇒ network / paid / **high**.
2. `fbclid` arriving via `l.facebook.com` or `lm.facebook.com` ⇒ facebook / paid / **high** (Meta's ad-redirect hosts).
3. `fbclid` + `utm_source=facebook|instagram|meta` ⇒ facebook|instagram / paid / **high**.
4. `utm_medium=cpc|paid|paid_social|cpm|display|retargeting` ⇒ paid / **high**.
5. `fbclid` alone, no other context ⇒ facebook / paid / **medium** (`fbclid` can leak onto organic shares but the dominant case is ad clicks).
6. Explicit `utm_source` with no paid signal ⇒ source / utm\_medium / **high**.
7. Referrer ∈ Facebook hosts without `fbclid` ⇒ facebook / **social** / medium.
8. Other known social referrers (twitter, linkedin, reddit, tiktok, youtube, pinterest, …) ⇒ source / social / medium.
9. Search engines (google.\*, bing, duckduckgo, …) ⇒ source / organic / medium.
10. Email clients / ESPs ⇒ email / email / medium.
11. Same-host referrer ⇒ internal / direct / high.
12. No referrer & no UTM & no click ID ⇒ direct / direct / high.
13. Otherwise ⇒ slug of referrer host / referral / **low**.

The matching rule's id is stored on every event so you can audit or re-classify later.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.millimetric.ai/quickstart.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
