Analytics API Reference
The analytics system exposes four endpoints. The tracking script and collection endpoint are public (used by your website visitors). The analytics and sites endpoints require authentication.
Public endpoints
GET /api/script.js
Serves the lightweight tracking script. This is what your website visitors load.
Headers:
Content-Type: application/javascriptAccess-Control-Allow-Origin: *Cache-Control: public, max-age=3600
Usage:
<script defer data-site="SITE_ID" src="https://your-app.com/api/script.js"></script>The script reads data-site from its own <script> tag and sends a single POST to /api/collect on page load.
POST /api/collect
Receives page view events from the tracking script. No authentication required — the site ID is validated against the database.
Headers:
Access-Control-Allow-Origin: *Content-Type: text/plain(sent viasendBeacon)
Request body:
{
"sid": "site-uuid-here",
"url": "/pricing",
"ref": "https://reddit.com/r/SideProject",
"us": "reddit",
"um": "social",
"uc": "launch",
"ut": "SideProject",
"uk": "",
"sw": 1440,
"tz": "America/New_York"
}| Field | Type | Description |
|---|---|---|
sid | string (UUID) | Required. Your site ID |
url | string | Required. Page pathname (e.g., /pricing) |
ref | string | Referrer URL |
us | string | utm_source parameter |
um | string | utm_medium parameter |
uc | string | utm_campaign parameter |
ut | string | utm_content parameter |
uk | string | utm_term parameter |
sw | number | Screen width in pixels |
tz | string | IANA timezone (e.g., America/New_York) |
Responses:
202 Accepted— Event recorded400 Bad Request— Invalid payload404 Not Found— Unknown site ID
Authenticated endpoints
These endpoints require a valid session cookie (you must be logged in).
GET /api/analytics
Returns aggregated analytics data for the dashboard.
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
siteId | string (UUID) | Yes | The site to query |
period | string | No | Time range: today, 7d (default), 30d, 90d |
Response:
{
"site": {
"id": "uuid",
"domain": "myapp.com",
"name": "My App"
},
"period": "7d",
"totalPageViews": 1247,
"topSource": "Reddit",
"sources": [
{
"name": "Reddit",
"icon": "R",
"color": "#FF4500",
"count": 523
},
{
"name": "Hacker News",
"icon": "Y",
"color": "#FF6600",
"count": 389
}
],
"topPages": [
{ "pathname": "/", "count": 834 },
{ "pathname": "/pricing", "count": 213 }
],
"devices": [
{ "type": "desktop", "count": 891 },
{ "type": "mobile", "count": 312 },
{ "type": "tablet", "count": 44 }
],
"countries": [
{ "country": "US", "count": 634 },
{ "country": "GB", "count": 189 }
],
"daily": [
{ "date": "2025-01-10", "count": 45 },
{ "date": "2025-01-11", "count": 67 }
]
}Errors:
401 Unauthorized— Not logged in400 Bad Request— MissingsiteId404 Not Found— Site not found or doesn't belong to you
GET /api/sites
List all tracked sites for the authenticated user.
Response:
[
{
"id": "uuid",
"userId": "user-uuid",
"domain": "myapp.com",
"name": "My App",
"createdAt": "2025-01-01T00:00:00.000Z"
}
]POST /api/sites
Register a new site for tracking.
Request body:
{
"domain": "myapp.com",
"name": "My App"
}| Field | Type | Description |
|---|---|---|
domain | string | Required. Your product's domain (protocol and paths are stripped) |
name | string | Required. A display name for the site |
Response: 201 Created with the created site object.
Errors:
401 Unauthorized— Not logged in400 Bad Request— Invalid input