The track endpoint
Send events to Pixel Relay from your own code or server, with the request format, limits and every response.
The tracker posts to the website's track endpoint. You can call it yourself, from a browser or a server, when the tracker does not fit.
POST https://pixelrelay.co/api/track/{API_KEY}
There is no other authentication. The API key, the allowed domains and the rate limit protect it.
Request
The body is JSON, sent as application/json or as text/plain (which saves browsers a preflight request). It holds up to 100 events:
{
"events": [
{
"event_name": "schedule_appointment",
"event_time": 1791480000,
"event_id": "evt_1791480000_k2j4h5g6",
"event_source_url": "https://clinic.example/book",
"referrer": "https://www.google.com/",
"user_data": { "email": "person@example.com", "phone": "+44 20 7946 0000" },
"custom_data": { "value": 150, "currency": "GBP" }
}
]
}
| Field | Rules |
|---|---|
event_name |
Required, up to 255 characters. Matched against the website's mappings. |
event_time |
Optional Unix time in seconds. Defaults to now. |
event_id |
Optional, up to 64 characters. Meta drops events with an ID it has already seen, so reuse it when sending the same conversion from two places. |
event_source_url |
Optional, a full URL. Cleaned before it reaches Meta. |
referrer |
Optional. Only its host is kept, and it is never sent to Meta. |
user_data |
Optional: email, phone, first_name, last_name, external_id (hashed by the relay, send them readable), plus fbp, fbc and client_user_agent. Anything else is dropped. |
custom_data |
Optional: value, currency, content_ids, num_items, content_name, content_type, content_category. Anything else is dropped. |
Origin
From a browser, the request's Origin must be on the website's allowed domains or one of their subdomains. The relay only returns CORS headers for allowed origins. Server-to-server requests send no Origin and skip this check, so keep the API key out of places you do not control.
Responses
| Status | Body | Meaning |
|---|---|---|
| 200 | {"success": true, "events_received": 1, "message": "Events tracked"} |
Delivered to Meta. |
| 200 | {"success": false, "events_received": 1, "message": "..."} |
Received, but Meta refused them. The message is Meta's. They show as failed in analytics. |
| 403 | {"error": "Invalid client key"} |
Unknown API key, or the website is paused. |
| 403 | {"error": "Origin not allowed"} |
The page's domain is not an allowed domain. |
| 422 | Validation errors | The body does not match the rules above. Send Accept: application/json to get them as JSON. |
| 429 | {"error": "Rate limit exceeded"} |
Too many requests from one visitor this minute. See the website's rate limit. |
| 429 | {"error": "Monthly event limit reached"} |
The account's monthly event allowance is used up. |
A request counts once against the rate limit however many events it carries, so batch where you can.
Related articles
Still stuck?
Tell us what you are trying to do and we will help you set it up.