Dokumentaatio
Selaa dokumentaatiota

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.

Näytä Markdown-muodossa

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#

http
POST https://privatusanalytics.com/api/events
Authorization: Bearer pik_…
Content-Type: application/json
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, vital and click are also accepted but need an existing visit
name For events Event name. Longer names are cut to 120 characters. For vital, one of LCP, INP, CLS, FCP or TTFB
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. More are ignored
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 daily visit key, the data-center check and IP-range traffic rules, then dropped. It is not used for location
session_hint No An opaque string that groups your server events into one visit. See Sessions
language No e.g. en-US. Cut to 16 characters
screen_width No Pixels, stored as a size bucket (xs, sm, md, lg or xl)
dnt, gpc No true when the visitor sent Do Not Track or Global Privacy Control. The event is dropped if the site honors that signal (DNT and GPC)
hash_mode No true to keep the URL's # fragment as part of the page path
engaged_ms No For engagement: engaged time in milliseconds, capped at 4 hours
scroll_depth No For engagement: scroll depth from 0 to 100, rounded down to a multiple of 10
value No For vital: the measured value
selector No For click: the clicked element's selector, cut to 512 characters

Country. The country is read from the request that delivers the batch, not from the ip field. Server-side events therefore carry the country of the server that sent them, not the visitor's.

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. A larger body, or one that isn't a JSON object, is read as empty: you get 202 with an empty data list and nothing is recorded. Split big batches.
  • Up to 600 requests per minute per ingest key. More returns 429 with a Retry-After header.
  • 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:

json
{
  "data": [
    { "index": 0, "status": "accepted", "reason": null },
    { "index": 1, "status": "dropped", "reason": "bot_automation" }
  ]
}

accepted means the event was queued. It is written in a batch and normally appears in the dashboard within seconds. dropped events aren't stored and don't count toward usage. Reasons:

Reason Meaning
invalid A field has the wrong type: a text field (url, name, referrer, ip, user_agent, session_hint and so on) is an object, a list or a boolean, or a number field (screen_width) isn't a finite number
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 honors 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. <list> is hostnames, paths, referrers, countries, ip_ranges, user_agents or events
vital_sampled A Web Vital outside the site's sample rate, or with an unknown name
no_visit An engagement, vital or click 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 a list of objects
429 rate_limited More than 600 requests in a minute with one key

Next#