Skip to content

Server-Side Tracking

Tracking is not limited to the browser. The endpoints the SDK calls are a plain authenticated HTTP API, so you can send events from any backend, background job, or script. Server-side tracking is the right choice for events that happen off the page:

  • An order confirmed by a payment or fulfilment webhook.
  • A trial that converts, detected by a scheduled job.
  • Subscription lifecycle events (created, skipped, cancelled, billed).
  • Anything a customer does in a native app or another service.

A common assumption is that events must come from a real browser and that non-browser calls get dropped by bot filtering. That is not the case for track and page events.

  • Track and page events are authenticated by API key, not by browser detection. Any request with a valid key is accepted and stored.
  • There is no bot filter on custom events. A request from curl, a server, or a background job lands in exactly the same place as one from the SDK.
  • Bot filtering in Gro applies only to email open and click tracking, which is a separate pipeline. It never touches your custom events.

The only thing that rejects a track call is a missing or invalid API key.

Server-side calls use the same key format as the SDK. In the dashboard go to Settings › API Keys, create a key, and copy it (it is shown only once). You can reuse an existing SDK key, since SDK keys are already public and safe to send from a server.

Send the key in the X-Gro-API-Key header on every request.

All three tracking endpoints share the same shape.

EndpointPurpose
POST /api/trackRecord a custom event
POST /api/pageRecord a page view
POST /api/identifyLink an anonymous visitor to a known customer
  • Base URL: https://tracking.usegro.net
  • Auth header: X-Gro-API-Key: gro_live_your_api_key_here
  • Body: JSON
  • Response: { "success": true }

The endpoint returns success as soon as the event is accepted. Ingestion into your analytics store happens asynchronously.

With curl:

Terminal window
curl -X POST https://tracking.usegro.net/api/track \
-H "Content-Type: application/json" \
-H "X-Gro-API-Key: gro_live_your_api_key_here" \
-d '{
"event_name": "Order Completed",
"user_id": "user_123",
"properties": {
"order_id": "ord_123",
"total": 99.99
}
}'

From Node with fetch:

await fetch("https://tracking.usegro.net/api/track", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Gro-API-Key": "gro_live_your_api_key_here",
},
body: JSON.stringify({
event_name: "Trial Converted",
user_id: "user_123",
properties: {
plan: "premium",
amount: 29.99,
},
}),
});

page and identify work the same way. For an identify call, send the customer’s email (and any traits) so their server-side activity stitches to the same profile as their browser activity:

Terminal window
curl -X POST https://tracking.usegro.net/api/identify \
-H "Content-Type: application/json" \
-H "X-Gro-API-Key: gro_live_your_api_key_here" \
-d '{
"email": "user@example.com",
"user_id": "user_123",
"properties": { "plan": "premium" }
}'

There is no cookie to read on the server, so the SDK cannot generate anonymous or session IDs for you. Supply the identity yourself in the body:

  • user_id and/or email: who the event belongs to. Send these whenever you know the customer, so server-side events join their profile.
  • anonymous_id: if you already captured the SDK’s anonymous ID for this visitor (from the _gro_aid cookie), pass it through to tie server events to their earlier anonymous browsing.

Deduplication works exactly as it does client-side. Pass your own event_id and events sharing it are stored only once. This matters more on the server, where webhooks are often retried:

body: JSON.stringify({
event_name: "Order Completed",
user_id: "user_123",
event_id: "ord_123", // Retried webhooks with the same id are deduped
properties: { order_id: "ord_123", total: 99.99 },
});

The endpoint automatically adds a timestamp plus the user agent, IP address, and geo of the caller. On a server-side call that caller is your backend, not the end customer, so those fields describe your server. If you need the customer’s real location or device, capture it at the edge and pass it in properties.