POST /api/collect
Ingest a single event or a batch of up to 50 events. This is the core endpoint used by the Sparklytics SDK and direct integrations.Authentication
None required. Events for unknownwebsite_id values are rejected with 404 Not Found.
Rate Limits
- 60 requests/minute per IP address
- Enforced via Tower middleware
- Response headers include:
X-RateLimit-Limit: Maximum requests per windowX-RateLimit-Remaining: Remaining requestsX-RateLimit-Reset: Unix timestamp when limit resets
- Returns
429 Too Many Requestswhen exceeded
Payload Limits
- Maximum body size: 100 KB (102,400 bytes)
- Maximum batch size: 50 events per request
- Maximum
event_datasize: 4 KB (4,096 bytes) per event when serialized to JSON string - Returns
400 Bad Requestif limits are exceeded
Single Event
Send a single event object in the request body.Request Body
The website identifier created in the dashboard (UUID format).
Event type. Use
"pageview" for page visits or "event" for custom events.Full URL of the page where the event occurred (e.g.,
"https://example.com/pricing").Referrer URL. Server automatically extracts the domain into
referrer_domain.Combined screen resolution string (e.g.,
"1920x1080").Screen width in pixels. If both
screen_width and screen_height are provided and screen is absent, the server combines them as "{width}x{height}".Screen height in pixels.
Browser language code (e.g.,
"en-US", "fr-FR").Custom event name (e.g.,
"signup_click", "form_submit"). Required when type="event".Custom event metadata as a JSON object (e.g.,
{"plan": "pro", "amount": 49}). Server serializes to a string before storage. Maximum 4 KB when serialized.UTM source parameter. If not provided, server attempts to extract from URL query string.
UTM medium parameter. Falls back to URL extraction.
UTM campaign parameter. Falls back to URL extraction.
UTM term parameter. Falls back to URL extraction.
UTM content parameter. Falls back to URL extraction.
Optional client-supplied visitor ID for cross-session stitching (max 64 characters).When present, the server uses this instead of computing from IP + User-Agent. Should be a hashed/tokenized identifier, never a raw email or user ID.If omitted or empty, server computes:
sha256(salt_epoch + ip + user_agent)[0:16] (16 hex characters). Salt rotates daily at midnight UTC.Example Request
Example Custom Event
Batch Ingestion
Send an array of events in a single request (maximum 50 events).Request Body
Send a JSON array of event objects. Each object has the same schema as the single event request.Batch Rules
- Maximum 50 events per batch
- All events must belong to known websites
- In cloud mode, all events must belong to websites owned by the same tenant
- Returns
400 Bad Requestwith error codebatch_too_largeif limit is exceeded
Example Batch Request
Response
Successful ingestion returns202 Accepted (the event is queued for processing).
Response Fields
Always
true when the request is accepted.Response Headers
Always
"queued" to confirm the event was accepted into the ingestion queue.Current number of events waiting in the ingestion queue.
Maximum capacity of the ingestion queue.
Example Response
Server-Side Enrichment
The server automatically enriches every event with additional metadata:Visitor Identification
visitor_id: 16-character hex string derived fromsha256(salt_epoch + ip + user_agent)[0:16]- Salt rotates daily at midnight UTC (
salt_epoch = floor(unix_timestamp / 86400)) - Client can override by providing explicit
visitor_idin request (max 64 chars)
Geographic Data (GeoIP)
Extracted from client IP using MaxMind GeoLite2-City or DB-IP City Lite database:country: ISO country code (e.g.,"US","FR")region: Region/state name (e.g.,"California")city: City name (e.g.,"San Francisco")
NULL (non-fatal).
User Agent Parsing
Parsed via thewoothee crate:
browser: Browser name (e.g.,"Chrome","Firefox")browser_version: Version string (e.g.,"120.0.0")os: Operating system (e.g.,"Mac OSX","Windows")os_version: OS version (e.g.,"10.15.7")device_type:"desktop","mobile", or"tablet"
UTM Parameters
If not explicitly provided in the request body, the server extracts UTM parameters from the URL query string:utm_sourceutm_mediumutm_campaignutm_termutm_content
Session Resolution
Sessions are resolved asynchronously in the ingest worker using a 30-minute inactivity timeout:- Events from the same
visitor_idwithin 30 minutes are grouped into a session - New session created if gap > 30 minutes or if referrer domain changes
- No cookies required — session logic is entirely server-side
Bot Detection
Each event is classified using configurable bot detection rules:is_bot: Boolean flagbot_score: Integer score (0-100)bot_reason: Human-readable classification reason
- User-Agent patterns
- Presence of
AcceptandAccept-Languageheaders - IP-based overrides (configured per website)
- Visitor ID patterns
Error Responses
400 Bad Request
- Batch size exceeds 50 events
- Empty batch array
event_dataexceeds 4 KB when serialized- Missing required fields
- Invalid JSON structure
404 Not Found
website_id does not exist in the database.
413 Payload Too Large
429 Too Many Requests
event_data Structure
Theevent_data field accepts any valid JSON object. Common patterns:
E-commerce Events
Form Interactions
Feature Usage
Search Queries
Notes
- Events are processed asynchronously — the
202 Acceptedresponse only confirms the event was queued, not that it was persisted - The ingestion queue has bounded capacity (default 10,000 events). If the queue is full, the server may reject requests with
503 Service Unavailable - In cloud mode, billing limits are enforced before ingestion — requests may be rejected with
402 Payment Requiredif the tenant’s plan limit is exceeded - The
tenant_idfield is alwaysNULLin self-hosted mode and is automatically set to the Clerk organization ID in cloud mode - Client IP is extracted from the socket address or
X-Forwarded-Forheader (when behind a trusted proxy configured viaSPARKLYTICS_TRUSTED_PROXIESenvironment variable)