Skip to content

Server-side collection

A server, a batch job or the backend of a mobile application can send its events directly, without a browser: it is the equivalent of Google Analytics’ Measurement Protocol. The most common case: the order confirmed by your server, once the payment is accepted.

POST https://stats.example.com/collect/server
Authorization: Bearer eoas_…
Content-Type: application/json
{
"events": [{
"type": "event",
"name": "purchase",
"at": "2026-10-04T14:12:00Z",
"visitor": "3f9c0d2e8b7a4c1d9e0f1a2b3c4d5e6f.20260912",
"props": { "transaction_id": "C-2026-10412", "value": 129.9, "currency": "EUR" },
"items": [{ "id": "KA2", "name": "Kerys Air 2", "price": 125, "quantity": 1 }]
}]
}

In the site’s Settings, Server keys section, create a key: eoas_….

  • It is shown only once, then stored hashed.
  • It is valid only for its site, and only for sending: it reads nothing.
  • It can be revoked in one click; its last use is displayed, and its creation and revocation are recorded in the audit log.

Keep it on the server side, in your application’s configuration.

A request carries up to 100 events. Each event:

FieldRequiredRole
typeyespageview or event
namefor eventthe event name, same rules as track
atnothe time, in ISO 8601 format; at most 72 hours in the past; now by default
url, referrer, titlenothe page concerned
props, itemsnothe properties and the items, as in the browser
visitornothe value of the visitor’s _eoa cookie
user_idnothe visitor’s identity on your side (if the site accepts signed-in visitors)
ip, user_agentnothe visitor’s address and browser, for the daily hash
languagenothe visitor’s language

Omit a missing field: do not send null. There is no origin check and no bot filter: the key is enough. The rate limit is specific to the key.

For the order to land in the right visit, and be attributed to the right channel, the server relays what it knows about the visitor:

  • in measurement cookie mode: the value of the _eoa cookie, which the browser sends with every request to your site;
  • otherwise: the visitor’s IP address and user agent, which give the same daily hash as the script. They are discarded immediately, as everywhere else.

With neither, the event is stored without a visitor (visitor_kind = none).

await fetch('https://stats.example.com/collect/server', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.EODIA_SERVER_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
events: [{
type: 'event',
name: 'purchase',
visitor: req.cookies._eoa, // cookie mode
ip: req.ip, user_agent: req.get('user-agent'),
props: { transaction_id: order.id, value: order.total, currency: 'EUR' },
}],
}),
})
<?php
$event = [
'type' => 'event',
'name' => 'purchase',
'ip' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
'props' => ['transaction_id' => $order->id, 'value' => $order->total, 'currency' => 'EUR'],
];
if (isset($_COOKIE['_eoa'])) $event['visitor'] = $_COOKIE['_eoa']; // cookie mode
$body = json_encode(['events' => [$event]]);
$ch = curl_init('https://stats.example.com/collect/server');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('EODIA_SERVER_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($ch);
import os, requests
event = {
"type": "event",
"name": "purchase",
"ip": request.remote_addr,
"user_agent": request.headers.get("User-Agent", ""),
"props": {"transaction_id": order.id, "value": order.total, "currency": "EUR"},
}
if "_eoa" in request.cookies: # cookie mode
event["visitor"] = request.cookies["_eoa"]
requests.post(
"https://stats.example.com/collect/server",
headers={"Authorization": f"Bearer {os.environ['EODIA_SERVER_KEY']}"},
json={"events": [event]},
timeout=5,
)
Fenêtre de terminal
curl -X POST https://stats.example.com/collect/server \
-H "Authorization: Bearer $EODIA_SERVER_KEY" \
-H "Content-Type: application/json" \
-d '{"events":[{"type":"event","name":"invoice_paid","props":{"value":49,"currency":"EUR"}}]}'

The same key can request the erasure of a person’s data, so you can connect the requests your site receives:

Fenêtre de terminal
curl -X POST https://stats.example.com/collect/server/erase \
-H "Authorization: Bearer $EODIA_SERVER_KEY" \
-H "Content-Type: application/json" \
-d '{"user_id":"client-1042"}'

One of the two: user_id or visitor (the cookie value). See data subject rights.

eodia analytics is free software by Eodia.