A simple and powerful analytics API built with Cloudflare Workers, KV storage, and Hono.js. Track any kind of user events, calculate session durations, and get insights about user behavior.
- Install the dependencies:
npm install hono @hono/zod-validator zod
- Set up your Cloudflare Worker:
npm install -g wrangler
wrangler login
- Create a KV namespace:
wrangler kv:namespace create "ANALYTICS_KV"
- Set up your configuration:
# Copy the example config
cp wrangler.toml.example wrangler.toml
# Update wrangler.toml with your KV namespace IDs and other settings
Example wrangler.toml structure:
name = "analytics-api"
main = "src/index.ts"
compatibility_date = "2024-01-18"
[[kv_namespaces]]
binding = "ANALYTICS_KV"
id = "your-kv-namespace-id" # Replace with your production KV ID
preview_id = "your-preview-id" # Replace with your preview KV ID
- Deploy:
wrangler deploy
Used to log any type of event. Events are stored with metadata and automatically expire after 30 days.
POST /track
{
"event": "play",
"user_id": "user123",
"timestamp": "2025-01-18T14:30:00Z",
"metadata": {
"song_id": "song456",
"device": "mobile",
"platform": "ios"
}
}
Response:
{
"status": "success",
"message": "Event logged."
}
timestamp
is optional - defaults to server time- Future timestamps are automatically set to current server time
metadata
is optional and limited to 4KB- If metadata exceeds 4KB, it's truncated with a warning
- Each event is stored for 30 days
- Events are automatically counted for metrics
Get counts of different events over time, grouped by day, week, or month.
GET /metrics?start_date=2025-01-01&end_date=2025-01-31&group_by=day&user_id=user123
Required parameters:
start_date
: YYYY-MM-DD formatend_date
: YYYY-MM-DD format
Optional parameters:
group_by
: "day" (default), "week", or "month"user_id
: Filter metrics for specific user
Response:
{
"status": "success",
"data": [
{
"date": "2025-01-01",
"play": 24,
"stop": 22,
"pause": 5
}
]
}
Get session statistics grouped by time period. Sessions are created from play/stop event pairs.
GET /sessions?start_date=2025-01-01&end_date=2025-01-31&group_by=day&user_id=user123
Required parameters:
start_date
: YYYY-MM-DD formatend_date
: YYYY-MM-DD format
Optional parameters:
group_by
: "day" (default), "week", or "month"user_id
: Filter sessions for specific user
Response:
{
"status": "success",
"data": [
{
"date": "2025-01-01",
"totalDuration": 7200,
"sessionCount": 15,
"averageDuration": 480
}
]
}
The same user starts multiple sessions?
- Each play/stop pair creates a separate session
- We match each stop event with the most recent play event for that user
A stop event comes without a play event?
- The stop event is logged but no session is created
- This won't break anything, but won't show up in session stats
A play event never gets a stop event?
- The play event is logged but no session duration is calculated
- These incomplete sessions won't appear in session stats
The timestamp is in the future?
- The event is logged but marked with the server time instead
- A warning is added to the metadata
The metadata is really large?
- There's a 4KB limit on metadata size
- If exceeded, the event is logged but metadata is truncated
- Always use consistent user IDs for the same user
- Send events in real-time when possible
- Include relevant metadata that you might want to analyze later
- Use descriptive event names (like "play", "pause", "skip" instead of "event1", "event2")
- Keep metadata size reasonable (under 4KB)
// Track song play
POST /track
{
"event": "play",
"user_id": "user123",
"metadata": {
"song_id": "song456",
"playlist": "workout_mix",
"device": "iphone"
}
}
// Track song completion
POST /track
{
"event": "complete",
"user_id": "user123",
"metadata": {
"song_id": "song456",
"listened_seconds": 180
}
}
// Track product view
POST /track
{
"event": "product_view",
"user_id": "user123",
"metadata": {
"product_id": "prod789",
"category": "electronics",
"price": 299.99
}
}
// Track purchase
POST /track
{
"event": "purchase",
"user_id": "user123",
"metadata": {
"order_id": "order123",
"total": 299.99,
"items": ["prod789"]
}
}
All errors follow this format:
{
"status": "error",
"message": "Description of what went wrong"
}
Common error messages:
- "Failed to log event"
- "Failed to fetch metrics"
- "Failed to fetch session metrics"
- "start_date and end_date are required"
- "Invalid date format. Use YYYY-MM-DD"
- Events expire after 30 days
- Metadata size limit: 4KB
- CORS is enabled for all origins
- SSL/TLS is required for all API calls
Need help? Found a bug? Check our GitHub issues or contact [email protected]
We provide a shell script with curl examples for testing all endpoints:
# Make the script executable
chmod +x examples.sh
./examples.sh
The script includes examples for:
- Tracking play/stop events
- Getting metrics with different time ranges
- Testing session analytics
- Testing error cases
- Testing metadata size limits
For easier testing, import our Postman collection:
- Download
analytics-api.postman_collection.json
- Import into Postman
- Set your
baseUrl
variable in the collection variables - Start testing!
The collection includes:
- Track Events (play, stop, future timestamps, large metadata)
- Get Metrics (daily, weekly, error cases)
- Get Sessions (daily, weekly aggregation)
This repository is created by ThisUX.com, a design studio specializing in building beautiful and functional apps. We combine technical excellence with stunning design to create exceptional user experiences.
Need help with your next project? Schedule a 15-min call with us to discuss how we can help bring your vision to life.