Skip to Content
DocsAPIInsights

Insights API

Run analytics queries programmatically. The same query spec powers dashboard Insights, Overview KPIs, and dashboard tiles.

Service: InsightsService
Auth: Shared API key or JWT

Query

Method: InsightsService.Query

Query spec structure

{ "query": { "events": [ { "name": "page_view" } ], "timeRange": { "start": "2026-05-01T00:00:00Z", "end": "2026-06-01T00:00:00Z" }, "granularity": "GRANULARITY_DAY", "aggregation": "AGGREGATION_UNIQUE_USERS", "breakdown": { "property": "$geo.country" }, "filters": [ { "property": "plan", "operator": "OPERATOR_EQUALS", "value": "pro" } ] } }

Query fields

FieldDescription
eventsOne or more event names; optional per-event filters
timeRange.start/endISO 8601 timestamps; boundaries use project timezone
granularityHOUR, DAY, WEEK
aggregationCOUNT, UNIQUE_USERS, SUM, AVERAGE
aggregationPropertyRequired for SUM/AVERAGE (e.g. revenue)
breakdown.propertyProperty to group by (e.g. $geo.country, plan)
filtersGlobal property filters applied to all events
conversionWindowDuration for funnel queries (e.g. 604800s = 7 days)

Example: Daily active users

import { InsightsService } from './gen/insights/v1/insights_connect' const client = createClient(InsightsService, sharedTransport) const result = await client.query({ query: { events: [{ name: 'page_view' }], timeRange: { start: new Date('2026-05-01'), end: new Date('2026-06-01') }, granularity: 'GRANULARITY_DAY', aggregation: 'AGGREGATION_UNIQUE_USERS' } }) // result.series = [{ timestamp, value }, ...]

Example: Revenue by country

{ "query": { "events": [{ "name": "purchase" }], "timeRange": { "start": "2026-05-01T00:00:00Z", "end": "2026-06-01T00:00:00Z" }, "granularity": "GRANULARITY_DAY", "aggregation": "AGGREGATION_SUM", "aggregationProperty": "revenue", "breakdown": { "property": "$geo.country" } } }

Example: Signup funnel

{ "query": { "events": [ { "name": "signup_started" }, { "name": "signup_completed" }, { "name": "purchase" } ], "timeRange": { "start": "2026-05-01T00:00:00Z", "end": "2026-06-01T00:00:00Z" }, "visualization": "VISUALIZATION_FUNNEL", "conversionWindow": "604800s" } }

Response includes step counts and conversion rates:

{ "funnel": { "steps": [ { "event": "signup_started", "count": 1000, "conversionRate": 1.0 }, { "event": "signup_completed", "count": 650, "conversionRate": 0.65 }, { "event": "purchase", "count": 120, "conversionRate": 0.12 } ] } }

Example: Retention

{ "query": { "visualization": "VISUALIZATION_RETENTION", "startingEvent": { "name": "signup_completed" }, "returnEvent": { "name": "page_view" }, "timeRange": { "start": "2026-01-01T00:00:00Z", "end": "2026-06-01T00:00:00Z" }, "granularity": "GRANULARITY_WEEK" } }

Response shapes

VisualizationResponse fieldContains
Line / Area / Barseries[]{ timestamp, value, breakdown? }
Funnelfunnel.steps[]{ event, count, conversionRate }
Retentionretention.cohorts[]{ cohortDate, periods[] }
Tablerows[]{ dimensions[], value }

Exact field names are defined in the protobuf schema. Generate clients with buf generate.

TypeScript client setup

import { createClient } from '@connectrpc/connect' import { createConnectTransport } from '@connectrpc/connect-web' import { InsightsService } from './gen/insights/v1/insights_connect' const transport = createConnectTransport({ baseUrl: 'https://api.pug.sh', interceptors: [ next => async req => { req.header.set('Authorization', `Bearer ${process.env.PUG_SHARED_API_KEY}`) req.header.set('x-project-id', process.env.PUG_PROJECT_ID!) return next(req) } ] }) const client = createClient(InsightsService, transport)

Use a shared API key for server-side scripts. Never expose it in client-side code.

Dashboard equivalents

API queryDashboard location
Line chartInsights
KPI tileOverview
Saved chartDashboards

Build queries in the dashboard first, then copy the query spec for API use.

ClickHouse

Insights queries run against ClickHouse. Query performance depends on time range, event volume, and breakdown cardinality. Very high-cardinality breakdowns (e.g. user ID) may be slow or truncated.

See backend architecture docs in the cotton  repo.

Further reading

Last updated on