OpenAnalyst Product Docs
Query analytics, export data, and understand how metrics are calculated and aggregated.
Analytics Exports and Reconciliation
Use this guide to query analytics, export data, and understand how metrics are calculated and aggregated.
When to use
- You want to export click or conversion data for reporting.
- You need to understand what a metric means and how it is calculated.
- You want to know why analytics numbers may differ from other sources.
Available dimensions
| Dimension | groupBy value | What it shows |
|---|---|---|
| Time series | day | Click counts per day |
| Link | slug | Clicks per link slug |
| Country | country | Clicks by ISO country code |
| Device | device | Clicks by MOBILE, TABLET, DESKTOP, BOT, UNKNOWN |
| Referrer | referrer | Clicks by referring domain (or "direct") |
| Segment | segment | Clicks by visitor behavior segment |
| AI crawler | ai_crawler | Traffic broken down by crawler/bot family |
| AI referrer | ai_referrer | Visits attributed to AI assistants and answer engines |
Metric definitions
| Metric | Definition |
|---|---|
| clicks | Total redirect events (HTTP 302/307 responses) |
| qualifiedClicks | Clicks minus bot clicks |
| botClicks | Clicks from detected bot user agents |
| conversions | Post-click events ingested via POST /v2/public/conversions |
| impressions | Intent observation events (segment analytics only) |
| revenue | Sum of value fields from conversion payloads |
Freshness
Analytics are aggregated from CloudFront real-time logs. The target latency is under 60 minutes.
Each response includes a freshness block:
{
"freshness": {
"status": "FRESH",
"lastUpdatedAt": "2026-02-25T12:05:00Z",
"slaMinutes": 60
}
}
| Status | Meaning |
|---|---|
| FRESH | Updated within the last 60 minutes |
| STALE | Older than 60 minutes |
| UNKNOWN | No data available yet |
Confidence score
When ?confidence=true is passed, the response includes a confidence score (0-100) based on:
- Whether any clicks exist
- Whether conversions exceed clicks (anomaly)
- Bot traffic ratio
- Data staleness
Higher scores indicate more reliable data.
UI path
- Open
https://app.openanalyst.com. - Navigate to your handle and open Analytics.
- Choose a dimension (slug, country, device, referrer, segment).
- Optionally filter by date range or campaign.
- Use the Export button to download CSV or JSON.
Required auth
- CREATOR-level
JWTor above to query analytics. PATwithanalytics.*scope for automation.- PRO or ENTERPRISE plan required for exports (
exportsfeature gate).
API fallback
Query analytics with JWT
GET /v2/handles/{handle}/analytics
Use this control-plane route when you are authenticated with a JWT from the app.
Query parameters:
groupBy(required):day,slug,country,device,referrer,segment,ai_crawler,ai_referrerfromDay,toDay(optional): Date range inyyyymmddformatcampaignId(optional): Filter to a specific campaignslug(optional): Filter to a specific linkconfidence(optional): Include confidence scorefunnel(optional): Include funnel metricssort(optional):ascordesc
Query analytics with PAT
GET /v2/public/handles/{handle}/analytics
Use this public-handle automation route when you authenticate with a PAT that includes analytics.*.
Query parameters:
groupBy(required):day,slug,country,device,referrer,segment,ai_crawler,ai_referrerfromDay,toDay(optional): Date range inyyyymmddformatcampaignId(optional): Filter to a specific campaignslug(optional): Filter to a specific linkconfidence(optional): Include confidence scorefunnel(optional): Include funnel metricssort(optional):ascordesc
Export analytics with JWT
GET /v2/handles/{handle}/analytics/export
Use this control-plane export route when you are authenticated with a JWT and your plan includes exports.
Export analytics with PAT
GET /v2/public/handles/{handle}/analytics/export
Use this public-handle export route when you authenticate with a PAT that includes analytics.*.
Shared query parameters for both export routes:
format:jsonorcsvgroupBy: Same options as abovefromDay,toDay: Date rangecampaignId: Optional campaign filter
Requires PRO or ENTERPRISE plan.
Submit a conversion
POST /v2/public/conversions
{
"ctx": "signed_context_token",
"eventType": "conversion",
"idempotencyKey": "unique_key",
"value": 99.99,
"currency": "USD"
}
The ctx token is minted at redirect time and must be submitted within its TTL (default 15 minutes). Duplicate submissions with the same idempotencyKey are safely deduplicated.
Rate limit: 120 conversions per IP per hour.
Reconciliation notes
- Click counts come from CloudFront logs, not from application-level records. This means analytics reflect actual network-level redirect events.
- Dimension rollups are forward-only. Country, device, and referrer breakdowns are only available from the date dimension tracking was enabled.
- Conversions require a valid
ctxtoken. If the context token has expired, the conversion cannot be attributed. This means total clicks will typically be higher than attributable conversions. - Duplicate conversions are deduplicated by idempotency key. Replaying the same conversion does not double-count.
- Bot detection filters known user agents but cannot catch all automated traffic. The
botClicksmetric provides transparency. - Rollup counts are approximate. The at-least-once delivery model means occasional recounts during retries.
Common errors
| Code | Error | Cause |
|---|---|---|
| 400 | invalid_group_by | Unrecognized groupBy value |
| 400 | invalid_ctx | Context token expired or malformed |
| 403 | feature_locked | Export requires PRO plan |
| 429 | rate_limited | Conversion ingestion rate limit exceeded |
Related: