Ingest API reference
Prefer the hosted tracker.js or SDK for browser installs. Use these endpoints when you need a custom client, server-side beacon, or debugging.
All three routes accept JSON, share the same ingest guards (rate limits, bot filters, shields), and return 200 { ok: true } even when traffic is silently dropped (no database write).
POST {origin}/api/ingest/pageview
All fields except tracking_id and pathname are optional.
| Field | Type | Description |
|---|---|---|
tracking_id | UUID (required) | Your site's tracking ID from the dashboard |
pathname | string (required) | URL path only, e.g. /blog/my-post (no query string) |
referrer | string | Full referrer URL |
session_id | UUID | Anonymous visit id — use a sessionStorage UUID for consistency |
user_agent | string | User-Agent string (the server-side request header is preferred; use this only for non-browser SDK contexts) |
utm_source | string | Campaign source |
utm_medium | string | Campaign medium |
utm_campaign | string | Campaign name |
utm_term | string | Paid search keyword |
utm_content | string | Differentiates creatives or links |
Country and device type are always derived server-side from CDN-injected headers (X-Vercel-IP-Country) and the User-Agent request header. These values cannot be overridden from the request body.
The hosted tracker fills UTM fields from the current page URL automatically (sticky for the visit).
POST {origin}/api/ingest/event
Custom events from Antlytics.track(name, props). See Custom events.
| Field | Type | Description |
|---|---|---|
tracking_id | UUID (required) | Site tracking ID |
event_name | string (required) | Event name (letters, numbers, spaces, . : / _ -) |
pathname | string (required) | Path where the event fired |
referrer | string | Optional referrer |
session_id | UUID | Optional visit id |
props | object | Optional scalar props only (string / number / boolean / null); max 20 keys, ~1 KB JSON |
POST {origin}/api/ingest/engagement
Engagement beacon (scroll depth + active time) sent on page hide / unload by the hosted tracker.
The hosted tracker.js sends this via navigator.sendBeacon with a JSON body and Content-Type: text/plain (CORS-safelisted, avoids a preflight). A keepalive fetch with application/json is the fallback. The server parses JSON from the body either way.
Browser CORS responses echo the request Origin and allow credentials so sendBeacon succeeds cross-origin (for example WordPress → www.antlytics.com).
| Field | Type | Description |
|---|---|---|
tracking_id | UUID (required) | Site tracking ID |
pathname | string (required) | Path being measured |
session_id | UUID | Optional visit id |
scroll_depth | integer 0–100 | Max scroll percentage |
duration_ms | integer | Active time on page (capped server-side) |
At least one of scroll_depth or duration_ms must be present or the request is accepted with no write.
Rate limits
Ingest enforces sliding-window rate limits per IP address and per tracking ID. Requests that exceed the limit receive 429 Too Many Requests with a Retry-After header.
Bot and spam filtering
Ingest silently accepts (HTTP 200) but does not record traffic that matches known bot user-agents, spam referrers, datacenter / cloud hosting client IPs, shield rules, or suspicious header patterns. See Bot filtering.
A valid site server secret in the Authorization header bypasses hostname policy and the datacenter / suspicious-header layers (trusted server callers often run in cloud). UA and spam-referrer filters and IP shields still apply.