Overview
Beyond automatic pageview tracking, Sparklytics lets you track any custom event with optional structured properties. Use custom events to measure:
Button clicks and form submissions
User interactions (video plays, downloads, shares)
E-commerce events (add to cart, purchase, checkout)
Feature usage and engagement metrics
Tracking Events
JavaScript (Browser)
Use the global window.sparklytics object to track events:
// Simple event
window . sparklytics ?. track ( 'signup_click' )
// Event with properties
window . sparklytics ?. track ( 'purchase' , {
plan: 'pro' ,
amount: 49.99 ,
currency: 'USD'
})
Next.js SDK
Use the useSparklytics hook in React components:
'use client'
import { useSparklytics } from '@sparklytics/next'
export function PricingCard () {
const { track } = useSparklytics ()
return (
< button onClick = { () => track ( 'plan_selected' , { plan: 'pro' }) } >
Get Pro
</ button >
)
}
Declarative Tracking Component
The <SparklyticsEvent> component tracks events on click:
import { SparklyticsEvent } from '@sparklytics/next'
< SparklyticsEvent name = "demo_request" data = { { source: 'pricing' } } >
< button > Request Demo </ button >
</ SparklyticsEvent >
Event Properties
Event properties let you attach structured data to events for filtering and analysis.
Property Types
Properties are stored as JSON and support:
Strings : "pro", "credit_card"
Numbers : 49.99, 3
Booleans : true, false
Nested objects : { product: { id: 123, name: "Widget" } }
Limits
Each event’s event_data JSON must be under 4 KB. The total request body (including all events in a batch) is limited to 100 KB.
From crates/sparklytics-server/src/routes/collect.rs:15:
/// Maximum allowed body size for POST /api/collect (100 KB).
pub const COLLECT_BODY_LIMIT : usize = 102_400 ;
/// Maximum allowed size for a single event's `event_data` JSON string (4 KB).
const EVENT_DATA_MAX_BYTES : usize = 4_096 ;
Collecting Events
Ingest API
Events are sent to the collection endpoint:
POST /api/collect
Content-Type: application/json
Single Event
{
"website_id" : "cm5x9yz1a0001..." ,
"event_type" : "custom" ,
"event_name" : "signup_click" ,
"url" : "https://example.com/pricing" ,
"event_data" : "{ \" plan \" : \" pro \" }"
}
Batch Events
Send up to 50 events in a single request:
[
{
"website_id" : "cm5x9yz1a0001..." ,
"event_type" : "custom" ,
"event_name" : "add_to_cart" ,
"event_data" : "{ \" product_id \" :123}"
},
{
"website_id" : "cm5x9yz1a0001..." ,
"event_type" : "custom" ,
"event_name" : "checkout_start" ,
"event_data" : "{ \" cart_value \" :149.99}"
}
]
Response
Successful ingestion returns:
HTTP status: 202 Accepted
Querying Events
Sparklytics provides three endpoints for analyzing custom events.
List Event Names
Get all custom event names for a date range:
GET /api/websites/{website_id}/events?start_date=2026-02-01 & end_date = 2026-03-01
Response:
{
"data" : [
{ "event_name" : "signup_click" , "count" : 342 },
{ "event_name" : "purchase" , "count" : 89 },
{ "event_name" : "demo_request" , "count" : 156 }
]
}
Event Properties Breakdown
Analyze property key/value pairs for a specific event:
GET /api/websites/{website_id}/events/properties?event_name=purchase
Response:
{
"data" : [
{
"property_key" : "plan" ,
"values" : [
{ "value" : "pro" , "count" : 56 },
{ "value" : "enterprise" , "count" : 33 }
]
},
{
"property_key" : "currency" ,
"values" : [
{ "value" : "USD" , "count" : 72 },
{ "value" : "EUR" , "count" : 17 }
]
}
]
}
Event Time Series
Get time-series data for a specific event:
GET /api/websites/{website_id}/events/timeseries?event_name=signup_click & granularity = day
Response:
{
"data" : {
"series" : [
{ "date" : "2026-02-01" , "count" : 23 },
{ "date" : "2026-02-02" , "count" : 31 },
{ "date" : "2026-02-03" , "count" : 28 }
],
"granularity" : "day"
}
}
Implementation Details
Server-Side Enrichment
Custom events are enriched with the same metadata as pageviews:
Visitor ID : Privacy-preserving hash computed server-side
Session ID : 30-minute inactivity timeout
GeoIP data : Country, region, city (if GeoIP database is configured)
User agent parsing : Browser, OS, device type
Referrer extraction : Domain and full URL
UTM parameters : Source, medium, campaign
Buffering & Flushing
From the CHANGELOG:
In-memory event buffer with 5-second flush interval and 100-event immediate flush
Events are batched in memory and written to DuckDB/ClickHouse:
Every 5 seconds (time-based flush)
When 100 events accumulate (size-based flush)
On server shutdown (graceful flush)
Event Name Validation
From crates/sparklytics-server/src/routes/events.rs:100:
fn require_event_name ( event_name : Option < String >) -> Result < String , AppError > {
let Some ( event_name ) = event_name else {
return Err ( AppError :: BadRequest (
"event_name query parameter is required" . to_string (),
));
};
let trimmed = event_name . trim ();
if trimmed . is_empty () {
return Err ( AppError :: BadRequest (
"event_name must not be empty" . to_string (),
));
}
if trimmed . len () > 255 {
return Err ( AppError :: BadRequest (
"event_name must be 255 characters or fewer" . to_string (),
));
}
Ok ( trimmed . to_string ())
}
Best Practices
Naming Conventions
Use consistent, descriptive event names:
// Good
track ( 'checkout_completed' )
track ( 'video_played' )
track ( 'filter_applied' )
// Avoid
track ( 'click' )
track ( 'event1' )
track ( 'userAction' )
Property Structure
Keep properties flat and typed:
// Good
track ( 'purchase' , {
product_id: 123 ,
amount: 49.99 ,
currency: 'USD'
})
// Avoid deep nesting
track ( 'purchase' , {
details: {
product: {
info: { id: 123 }
}
}
})
Error Handling
The SDK handles offline tracking gracefully:
// SDK automatically queues events if offline
window . sparklytics ?. track ( 'offline_action' )
// Uses sendBeacon for reliability on page unload
window . addEventListener ( 'beforeunload' , () => {
// Events queued automatically flushed
})
Use Cases
E-commerce Tracking
// Product view
track ( 'product_viewed' , { product_id: 'widget-pro' , price: 99 })
// Add to cart
track ( 'add_to_cart' , { product_id: 'widget-pro' , quantity: 2 })
// Purchase
track ( 'purchase' , {
order_id: 'ord_123' ,
total: 198 ,
items: 2
})
Feature Engagement
// Track feature usage
track ( 'feature_used' , { feature: 'export' , format: 'csv' })
// Track settings changes
track ( 'setting_changed' , { setting: 'theme' , value: 'dark' })
Content Interaction
// Video engagement
track ( 'video_play' , { video_id: 'demo-2024' , duration: 0 })
track ( 'video_complete' , { video_id: 'demo-2024' , duration: 120 })
// Download tracking
track ( 'file_download' , { file: 'whitepaper.pdf' , size_mb: 2.4 })
Next Steps
Funnels Build conversion funnels from custom events
Journey Analysis Explore user paths between events