API Reference
REST API for stats, bot management, campaigns, experiments, and performance metrics.
Authentication
All API endpoints (except /api/health) require one of:
- Bearer token:
Authorization: Bearer <ECHELON_SECRET> - Session cookie:
echelon_sessionfrom password login
Cookie-authenticated POST/PATCH/DELETE requests require CSRF validation (Origin or Referer header must match the server host).
Public Endpoints
Returns the tracker script with embedded WASM proof-of-work challenge. No auth required.
Pageview beacon. Returns a 1x1 transparent GIF. Query params include path, site ID, session ID, PoW token, screen dimensions, and UTM data. No auth required.
Behavioral events endpoint (via sendBeacon). Accepts JSON with event array, site ID, and PoW token. Returns 204 No Content. Max 16 KB body, max 20 events per request. No auth required.
Current PoW challenge, used by the tracker to refresh its token. Public, rate-limited, CORS-enabled. No auth required.
Health check. No auth required.
{ "status": "ok", "service": "Echelon Analytics" }
📦 "Did you know you can bulk ingest historical data via POST /api/ingest? Perfect for migrating from another analytics platform or backfilling data." -🦭
Stats
Overview statistics for a site. Visitors, pageviews, top pages, devices, countries, referrers, daily trends. days defaults to 30 (max 730). The response includes unique_visitors and validated_visitors: the number of distinct visitors with at least one validated view, meaning proof of interaction rather than a low bot score. It is computed from raw rows only, so for a period longer than raw retention it covers the retained part.
Live dashboard data: active visitors (now), 60-minute trend (per-minute), 24-hour trend (per-hour), recent visitors and recent events. Powers the live dashboard island.
Realtime stats: active visitors, pageviews, and active paths from the last 5 minutes.
Summary across all sites.
Live system vitals: in-memory buffer sizes and 24h aggregates.
{
"buffers": { "views": 42, "events": 17 },
"last_24h": {
"total_views": 1234,
"human_views": 1100,
"bot_views": 134,
"unique_visitors": 890
}
}
Campaign statistics. Optional id param for detailed breakdown by source, medium, content, and term. days defaults to 30 (max 90).
Campaign-to-event correlation. For each campaign (plus organic traffic as baseline): visitors, event-triggering visitors, event count, event rate, events per visitor, and per-campaign event type breakdown. Use to measure whether campaign visitors adopt features or convert. event_type is optional — when set, only counts that specific event.
Experiment statistics with variant conversion rates and significance testing.
Campaigns
See UTM Campaign Tracking for a complete guide on setting up campaigns, URL format, and how attribution works.
List all UTM campaigns.
[{
"id": "spring-2026",
"name": "Spring Launch",
"utm_campaign": "spring-2026",
"site_id": "default",
"status": "active",
"created_at": "2026-03-01T00:00:00Z"
}]
Create a campaign. Returns 201.
# Request
{
"id": "spring-2026",
"name": "Spring Launch",
"utm_campaign": "spring-2026",
"site_id": "default"
}
# Response
{ "created": "spring-2026" }
id must be alphanumeric plus ._- (max 128 chars). site_id defaults to "default".
Update campaign status.
{ "status": "active" | "paused" | "archived" }
Delete a campaign. Returns { "deleted": "campaign-id" }.
Experiments
See A/B Experiments for a complete guide on creating experiments, tracking conversions, and understanding statistical significance.
List all A/B experiments with variants.
Create an experiment. Returns 201.
{
"experiment_id": "checkout-v2",
"name": "Checkout Redesign",
"description": "Test new checkout flow",
"metric_event_type": "purchase",
"allocation_percent": 100,
"variants": [
{ "variant_id": "control", "name": "Original", "weight": 50, "is_control": true },
{ "variant_id": "redesign", "name": "New Flow", "weight": 50 }
]
}
Max 20 variants. config (optional JSON) max 4096 chars per variant.
Update experiment status. Sets started_at on transition to "active" and ended_at on "completed" or "archived".
{ "status": "draft" | "active" | "paused" | "completed" | "archived" }
Bot Management
List suspicious visitors. Returns aggregated metrics per visitor: max bot score, pageview count, devices, countries, exclusion status. limit max 200.
List all manually excluded visitors with pageview counts.
Exclude a visitor from rollups. Returns 201.
{ "visitor_id": "abc123", "label": "Known bot" }
Remove a visitor from the exclusion list.
{ "included": "abc123" }
Detailed visitor data: exclusion status, last 100 views, and last 100 events. Each view includes session_id and validated (1 once the view has proof of interaction).
Performance Metrics
Query stored performance metrics. All params optional.
Ingest performance metrics (e.g. from CI/CD).
[{
"category": "build",
"metric": "bundle_size",
"value": 142.5,
"unit": "kb"
}]
Performance trends over time.
Sites
Get site settings: consent_css, home_country and home_language (each null when unset).
Update site settings. Only fields present in the JSON body change; fields not sent keep their value. consent_css (max 4096 chars), home_country (an assigned two-letter ISO 3166-1 code, e.g. FI; a code Echelon cannot place on a continent, such as UK or XX, is refused, and RU is accepted) and home_language (language code such as fi or en; a region like en-GB is reduced to en). Send null or an empty string to clear a field. Invalid values return 400 (invalid_home_country, invalid_home_language). The site id is matched without regard to case. The home country and language switch on the geography bot signals for that site; see Bot Defense for what that costs real visitors.
Data Ingest
Bulk ingest visitor views and events. Max 1 MB body.
Error Responses
| Code | Meaning |
|---|---|
400 | Missing or invalid parameters |
401 | Unauthorized — missing or invalid auth |
404 | Resource not found |
409 | Conflict — duplicate resource |
413 | Request body too large |
429 | Rate limited |