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/javascript
  • Access-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 via sendBeacon)

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"
}
FieldTypeDescription
sidstring (UUID)Required. Your site ID
urlstringRequired. Page pathname (e.g., /pricing)
refstringReferrer URL
usstringutm_source parameter
umstringutm_medium parameter
ucstringutm_campaign parameter
utstringutm_content parameter
ukstringutm_term parameter
swnumberScreen width in pixels
tzstringIANA timezone (e.g., America/New_York)

Responses:

  • 202 Accepted — Event recorded
  • 400 Bad Request — Invalid payload
  • 404 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:

ParameterTypeRequiredDescription
siteIdstring (UUID)YesThe site to query
periodstringNoTime 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 in
  • 400 Bad Request — Missing siteId
  • 404 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"
}
FieldTypeDescription
domainstringRequired. Your product's domain (protocol and paths are stripped)
namestringRequired. A display name for the site

Response: 201 Created with the created site object.

Errors:

  • 401 Unauthorized — Not logged in
  • 400 Bad Request — Invalid input