Skip to main content

Analytics

Endpoints for recording pageviews and querying analytics reports. All analytics data is privacy-first -- no cookies, no PII, no raw IP storage.

Endpoints

MethodPathPermissionDescription
POST/sites/{site_id}/analytics/pageviewReadRecord a pageview event
GET/sites/{site_id}/analytics/reportReadFetch analytics report
POST/sites/{site_id}/analytics/aggregateAdminAggregate raw events and prune old data

Record a Pageview

Records a single pageview event. The server computes the daily visitor hash from the client's IP and User-Agent (neither is stored). The referrer is reduced to its domain.

curl -X POST https://your-site.com/api/v1/sites/{site_id}/analytics/pageview \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"path": "/blog/hello-world",
"referrer": "https://twitter.com/user/status/123"
}'

Request Body

FieldTypeRequiredDescription
pathstringYesThe page path (e.g. /blog/my-post)
referrerstringNoThe full referrer URL. Only the domain is stored.
user_agent_hashstringNoOptional client-side hash (server computes its own)

Response -- 201 Created

{
"ok": true
}
info

This endpoint is designed to be called from the @forja/analytics tracking library on your public site. It uses a Read-level API key so the same key that fetches content can also record pageviews.

Get Analytics Report

Returns a summary of pageview data including totals, top content, and daily trend data for charting.

curl https://your-site.com/api/v1/sites/{site_id}/analytics/report \
-H "X-API-Key: your_api_key"

Query Parameters

ParameterDefaultMaxDescription
days30365Number of days to look back
top_n1050Number of top content items to return

Response -- 200 OK

{
"total_views": 1234,
"total_unique_visitors": 567,
"top_content": [
{
"path": "/blog/hello-world",
"total_views": 142,
"unique_visitors": 89
},
{
"path": "/blog/getting-started",
"total_views": 98,
"unique_visitors": 71
}
],
"trend": [
{
"date": "2026-03-07",
"total_views": 42,
"unique_visitors": 28
},
{
"date": "2026-03-08",
"total_views": 38,
"unique_visitors": 25
}
]
}

Response Fields

FieldDescription
total_viewsTotal pageviews in the period
total_unique_visitorsDistinct visitor hashes in the period
top_contentPaths ranked by view count, each with total_views and unique_visitors
trendOne entry per day with date, total_views, and unique_visitors

Aggregate and Prune

Admin-only maintenance endpoint that rolls up raw pageview events into daily aggregated statistics and deletes raw events older than the retention period. This is typically run as a scheduled job.

curl -X POST https://your-site.com/api/v1/sites/{site_id}/analytics/aggregate \
-H "X-API-Key: your_admin_api_key"

Query Parameters

ParameterDefaultDescription
retention_days90Delete raw events older than this many days

Response -- 200 OK

{
"rows_affected": 15000,
"action": "Aggregated 10000 rows, pruned 5000 raw events older than 90 days"
}

The aggregation is idempotent -- running it multiple times for the same date range produces the same result (upsert on conflict).