Server-side ingest API
Send pageviews and custom events from your backend with the server-side ingest API: the endpoint, ingest key authentication, event fields, limits and responses.
Send events from your server when the browser can't or shouldn't: payment webhooks, signups confirmed by email, API products, backend jobs, or pages served to clients without JavaScript.
Endpoint#
POST https://privatusanalytics.com/api/events
Authorization: Bearer pik_…
Content-Type: application/json
{
"events": [
{
"type": "event",
"name": "Purchase",
"url": "https://example.com/checkout",
"revenue": 49.99,
"currency": "USD",
"props": { "plan": "pro" },
"user_agent": "Mozilla/5.0 (Macintosh; …) Safari/605.1.15",
"ip": "203.0.113.7"
}
]
}
Authenticate with the site's secret ingest key (pik_…), either as a
Bearer token or in an X-Ingest-Key header. Each key belongs to one site.
See Ingest keys.
Event fields#
| Field | Required | Description |
|---|---|---|
type |
Yes | pageview or event (custom is an alias). engagement and vital are also accepted but need an existing visit |
name |
For events | Event name, up to 120 characters |
url |
Yes | Full http(s) URL of the page. Its hostname must be one of the site's domains (or a subdomain of one) |
referrer |
No | Where the visitor came from, which drives sources and channels |
props |
No | Up to 30 properties |
revenue |
No | Amount in major units, e.g. 49.99 (Revenue) |
currency |
No | ISO 4217 code. Defaults to the site currency |
timestamp |
No | ISO 8601. Must be within the last 72 hours. Otherwise (or if missing or in the future) the time of receipt is used |
user_agent |
In practice, yes | The visitor's browser User-Agent. Missing or library User-Agents are dropped as bots (see below) |
ip |
No | The visitor's IP. Used in memory for the country and the daily visit key, then dropped. Without it there's no location |
session_hint |
No | An opaque string that groups your server events into one visit. See Sessions |
language |
No | e.g. en-US |
screen_width |
No | Pixels, stored as a size bucket |
The short keys the browser tracker uses (t, n, u, r, p…) are
accepted too. See What the tracker sends.
Limits#
- Up to 100 events per request. More returns
422. - The request body must be at most 32 KB. Larger bodies are read as empty. Split big batches.
- Everything else (property limits, name length, PII scrubbing, path masking, traffic rules, bot filtering) works exactly as for browser hits.
Response#
202 Accepted with one result per event, in order:
{
"data": [
{ "index": 0, "status": "accepted", "reason": null },
{ "index": 1, "status": "dropped", "reason": "bot_automation" }
]
}
accepted means the event was queued and will appear in the dashboard
within seconds. dropped events aren't stored and don't count toward
usage. Reasons:
| Reason | Meaning |
|---|---|
bad_type |
type isn't one of the accepted values |
bad_url |
url is missing or not an http(s) URL |
foreign_host |
The URL's hostname isn't one of the site's domains |
privacy_signal |
The event carried DNT/GPC (dnt/gpc fields) and the site honours it |
bot_empty_user_agent |
No user_agent |
bot_known_bot |
A known crawler User-Agent |
bot_automation |
An automation or HTTP-library User-Agent (see Bot rules) |
bot_datacenter |
The ip belongs to a cloud or hosting network |
bot_referrer_spam |
The referrer is on the referrer-spam list |
rule_<list> |
Blocked by a traffic rule, e.g. rule_paths |
vital_sampled |
A Web Vital outside the sample rate |
no_visit |
An engagement or vital hit with no visit to attach to |
paused |
Collection is paused for the workspace by Privatus Analytics support |
limit_reached |
The workspace reached its monthly event limit, so pageviews and custom events are not recorded until the reset or an upgrade (see Monthly limit) |
Errors:
| Status | Body error.code |
When |
|---|---|---|
401 |
unauthorized |
Missing or unknown ingest key |
422 |
validation_failed |
More than 100 events, or events isn't an array |
Next#
- Examples in curl, Node, Python, PHP, Go and Ruby.
- SDKs that batch, retry and handle timestamps for you.
- The browser's no-JavaScript pixel for pages without JavaScript.
Create, rotate and revoke the secret ingest key that authenticates server-side events, keep it out of browser code, and see how it differs from an API token.
How server-side events are grouped into visits with the daily salted visit key and how session_hint splits or joins visits.
Bot filtering rules for User-Agents, crawlers and data centers, and how to send server-side events with the visitor's User-Agent and IP so they count.
Server-side ingest examples that send an event with curl, Node.js, Python, PHP, Go, Rails and Next.js, forwarding the visitor's User-Agent and IP.
Server-side analytics SDKs for Node.js, Python, PHP, Go and Ruby that wrap the ingest API and batch events. They are not published yet, so read the warning.