Skip to main content
If you’re using a framework not covered by our SDKs, or need full control over tracking, you can integrate directly with the Sparklytics HTTP API.

API Endpoint

All events are sent to:
POST https://your-sparklytics-server.com/api/collect

Authentication

No authentication required for event collection. Events are associated with websites via the website_id field.
Events with unknown website_id values are rejected with 404 Not Found.

Event Schema

Every event must include:
{
  "website_id": "YOUR_WEBSITE_ID",
  "type": "pageview" | "event",
  "url": "https://example.com/page"
}

Pageview Event

{
  "website_id": "abc123",
  "type": "pageview",
  "url": "https://example.com/pricing",
  "referrer": "https://google.com/search?q=analytics",
  "language": "en-US",
  "screen": "1920x1080",
  "screen_width": 1920,
  "screen_height": 1080,
  "utm_source": "google",
  "utm_medium": "cpc",
  "utm_campaign": "spring-sale"
}

Custom Event

{
  "website_id": "abc123",
  "type": "event",
  "url": "https://example.com/pricing",
  "event_name": "signup_click",
  "event_data": {
    "plan": "pro",
    "source": "hero_cta"
  },
  "referrer": "https://example.com/home",
  "language": "en-US"
}

Field Reference

FieldTypeRequiredMax LengthDescription
website_idstringYes64 charsYour website ID from dashboard
type"pageview" | "event"Yes-Event type
urlstringYes2048 charsCurrent page URL
event_namestringFor type=event50 charsCustom event name
event_dataobjectNo4 KB serializedCustom event properties
referrerstringNo2048 charsHTTP Referer header
visitor_idstringNo64 charsStable visitor identifier
languagestringNo10 charsBrowser language (e.g., en-US)
screenstringNo20 charsScreen resolution (e.g., 1920x1080)
screen_widthnumberNo-Screen width in pixels
screen_heightnumberNo-Screen height in pixels
utm_sourcestringNo100 charsUTM source parameter
utm_mediumstringNo100 charsUTM medium parameter
utm_campaignstringNo100 charsUTM campaign parameter
utm_termstringNo100 charsUTM term parameter
utm_contentstringNo100 charsUTM content parameter

Automatic Enrichment

The server automatically enriches events with:
  • GeoIP data: country, region, city (from client IP)
  • User agent parsing: browser, browser_version, os, os_version, device_type
  • Referrer domain: Extracted from referrer URL
  • Visitor ID: If not provided, computed as sha256(salt_epoch + ip + user_agent)[0:16]
  • Session ID: Automatically assigned (30-minute inactivity timeout)
You don’t need to parse user agents or do GeoIP lookups yourself — the server handles this automatically.

Batch API

Send up to 50 events in a single request:
[
  {
    "website_id": "abc123",
    "type": "pageview",
    "url": "https://example.com/home"
  },
  {
    "website_id": "abc123",
    "type": "event",
    "url": "https://example.com/home",
    "event_name": "cta_click",
    "event_data": { "button": "hero" }
  }
]
Batches larger than 50 events return 400 Bad Request with error code batch_too_large.

Response

Success

HTTP/1.1 202 Accepted
Content-Type: application/json
x-sparklytics-ingest-ack: queued

{
  "ok": true
}

Error: Unknown Website

HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": "Unknown website_id: abc123"
}

Error: Rate Limited

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1678901234

{
  "error": "Rate limit exceeded"
}
Rate limit: 60 requests per minute per IP address. The limit applies to the /api/collect endpoint only.

Example Implementations

const SPARKLYTICS_HOST = 'https://analytics.example.com'
const WEBSITE_ID = 'abc123'

async function trackPageview(url) {
  const payload = {
    website_id: WEBSITE_ID,
    type: 'pageview',
    url: url || window.location.href,
    referrer: document.referrer || undefined,
    language: navigator.language,
    screen: `${screen.width}x${screen.height}`
  }

  await fetch(`${SPARKLYTICS_HOST}/api/collect`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
    keepalive: true
  })
}

async function trackEvent(eventName, eventData) {
  const payload = {
    website_id: WEBSITE_ID,
    type: 'event',
    url: window.location.href,
    event_name: eventName,
    event_data: eventData,
    language: navigator.language
  }

  await fetch(`${SPARKLYTICS_HOST}/api/collect`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
    keepalive: true
  })
}

// Track initial pageview
trackPageview()

// Track custom event
document.querySelector('#signup-btn').addEventListener('click', () => {
  trackEvent('signup_click', { plan: 'pro' })
})

Server-Side Tracking

When tracking from a server (e.g., API endpoints, webhooks), you should:
  1. Set a stable visitor_id (e.g., user ID or session ID)
  2. Pass the original url (the page the user was on)
  3. Avoid tracking internal requests (only track user-facing actions)

Example: Track Server-Side Conversions

import requests

def track_conversion(user_id: str, plan: str, price: float):
    """Track a successful subscription from Stripe webhook"""
    requests.post(
        'https://analytics.example.com/api/collect',
        json={
            'website_id': 'abc123',
            'type': 'event',
            'url': 'https://example.com/checkout',  # Original page
            'event_name': 'subscription_created',
            'event_data': {
                'plan': plan,
                'price': price,
                'currency': 'USD'
            },
            'visitor_id': user_id  # Stable user ID
        },
        timeout=5
    )

CORS Configuration

If you’re tracking from a different domain than your Sparklytics server, configure CORS:
# Add to your .env or docker-compose.yml
SPARKLYTICS_CORS_ORIGINS=https://example.com,https://www.example.com
The /api/collect endpoint is designed for client-side tracking. Use SPARKLYTICS_CORS_ORIGINS to allow cross-origin requests from your frontend domains.

Rate Limiting

  • Limit: 60 requests per minute per IP
  • Scope: Applies to /api/collect only
  • Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset

Handling Rate Limits

async function trackWithRetry(payload, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch('https://analytics.example.com/api/collect', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    })

    if (response.status === 202) {
      return // Success
    }

    if (response.status === 429) {
      const resetTime = parseInt(response.headers.get('X-RateLimit-Reset'))
      const waitMs = (resetTime * 1000) - Date.now()
      await new Promise(resolve => setTimeout(resolve, waitMs))
      continue
    }

    throw new Error(`HTTP ${response.status}`)
  }
}

Best Practices

When tracking pageviews during navigation, use keepalive: true to ensure the request completes even if the page unloads:
fetch('/api/collect', {
  method: 'POST',
  body: JSON.stringify(payload),
  keepalive: true // Important!
})
Prevent duplicate pageviews when using client-side routers:
let lastUrl = ''
let lastTimestamp = 0

function trackPageview(url) {
  const now = Date.now()
  if (url === lastUrl && now - lastTimestamp < 100) {
    return // Skip duplicate
  }
  lastUrl = url
  lastTimestamp = now
  // ... send event
}
Reduce network overhead by batching multiple events:
const eventQueue = []

function queueEvent(event) {
  eventQueue.push(event)
  if (eventQueue.length >= 10) {
    flushEvents()
  }
}

function flushEvents() {
  if (eventQueue.length === 0) return
  fetch('/api/collect', {
    method: 'POST',
    body: JSON.stringify(eventQueue),
    keepalive: true
  })
  eventQueue.length = 0
}

// Flush on page unload
window.addEventListener('beforeunload', flushEvents)
Honor Do Not Track and Global Privacy Control:
function shouldTrack() {
  if (navigator.doNotTrack === '1') return false
  if (navigator.globalPrivacyControl === true) return false
  return true
}

Testing Your Integration

Use curl to verify your setup:
curl -X POST https://analytics.example.com/api/collect \
  -H "Content-Type: application/json" \
  -d '{
    "website_id": "abc123",
    "type": "pageview",
    "url": "https://example.com/test"
  }'
Expected response:
{"ok":true}

Next Steps

HTML Snippet

Use the pre-built snippet for standard websites

API Reference

Full API documentation for all endpoints

Build docs developers (and LLMs) love