Insights
Run analytics queries programmatically against the same engine that powers dashboard charts, overview KPIs, and saved tiles. The Insights API is a server-side interface — it is not callable from browser clients.
Service: shared.insights.v1.InsightsService
Auth: Dual — private key (prv_…) via x-api-key or dashboard JWT via Authorization: Bearer. See Authentication.
Methods
Query
POST /shared.insights.v1.InsightsService/QueryRuns an analytics query and returns a typed result. The shape of the result depends on spec.insight_type (see Insight types).
Request — QueryRequest
| Field | Type | Required | Description |
|---|---|---|---|
spec | InsightQuerySpec | Yes | The query specification (insight type, events, breakdowns, filters). |
time_range | TimeRange | Yes | Absolute start/end (from, to) as RFC 3339 timestamps. from must be before to. |
granularity | Granularity | Yes | Time bucket size. See Granularities. |
Response — QueryResponse
The response carries exactly one of the following fields, selected by spec.insight_type:
| Field | Type | Populated when |
|---|---|---|
trends | TrendsResult | INSIGHT_TYPE_TRENDS |
segmentation | SegmentationResult | INSIGHT_TYPE_SEGMENTATION |
funnel | FunnelResult | INSIGHT_TYPE_FUNNEL |
retention | RetentionResult | INSIGHT_TYPE_RETENTION |
user_flow | UserFlowResult | INSIGHT_TYPE_USER_FLOW |
SegmentUsers
POST /shared.insights.v1.InsightsService/SegmentUsersReturns a paginated list of distinct user IDs that match a set of event conditions within a time range. Useful for audience export or cross-referencing profiles.
| Field | Type | Description |
|---|---|---|
time_range | TimeRange | Required. |
events | EventQuery[] | Required, at least one. |
filter_groups | FilterGroup[] | Optional top-level filters. |
filter_groups_operator | LogicalOperator | How groups are combined (default AND). |
page_size | int32 | 0–1000. |
page_token | string | Cursor from previous response. |
Response: { distinct_ids: string[], next_page_token: string }.
GetFilterSchema
POST /shared.insights.v1.InsightsService/GetFilterSchemaReturns the set of known event kinds and property keys (auto, custom, profile) for the project. Use this to populate filter pickers. The response shape is common.v1.GetFilterSchemaResponse. Optionally scoped to a single event kind or filtered to specific PropertyValueType values.
GetPropertyValues
POST /shared.insights.v1.InsightsService/GetPropertyValuesReturns the distinct observed values for a specific property key. Useful for populating FILTER_OPERATOR_IN value lists.
| Field | Type | Required | Description |
|---|---|---|---|
property_key | string | Yes | The property to enumerate (e.g. $country, plan). Include the $ prefix for auto-properties. |
source | PropertySource | Yes | Which namespace the key lives in: PROPERTY_SOURCE_AUTO, PROPERTY_SOURCE_CUSTOM, or PROPERTY_SOURCE_PROFILE. |
event_kind | string | No | Restrict observed values to a single event kind. Omit to scan across all events. |
Response: { "values": string[] } — the distinct observed values.
{ "propertyKey": "$country", "source": "PROPERTY_SOURCE_AUTO" }Insight types
InsightQuerySpec.insight_type selects the computation and the response field.
| Enum value | Description |
|---|---|
INSIGHT_TYPE_TRENDS | Time-series event counts or aggregations. One TrendSeries per (event, breakdown) combination. |
INSIGHT_TYPE_SEGMENTATION | Single scalar — total count or aggregation across the full time range, no time axis. |
INSIGHT_TYPE_FUNNEL | Multi-step conversion funnel. Steps are the events array in order. Each series carries per-step counts; optionally includes per-step timing statistics when include_step_timing is true. |
INSIGHT_TYPE_RETENTION | Cohort retention matrix. events[0] is the starting event; events[1] (optional) is the return event. Returns cohorts bucketed by the query granularity. |
INSIGHT_TYPE_USER_FLOW | Sankey / path graph showing transitions between events or property values. Requires a user_flow sub-spec; no events field. |
Insight type constraints
INSIGHT_TYPE_FUNNEL— requires at least one event; supportsbreakdowns(max 5); supportsconversion_window(whole seconds, min 1 s); supportsinclude_step_timing.INSIGHT_TYPE_RETENTION— requires at least one event; accepts at most 2 (events[0]= start,events[1]= return).INSIGHT_TYPE_SEGMENTATION— does not supportbreakdowns.INSIGHT_TYPE_USER_FLOW— requires auser_flowsub-spec;eventsmust be empty;breakdownsare not supported.INSIGHT_TYPE_TRENDS/INSIGHT_TYPE_SEGMENTATION— support numeric aggregations (AGGREGATION_TYPE_SUM,AVG,MIN,MAX); these are not valid for funnel or retention.
Granularities
QueryRequest.granularity controls the time-bucket width and imposes a maximum query range.
| Enum value | Bucket width | Maximum time range |
|---|---|---|
GRANULARITY_MINUTE | 1 minute | 6 hours |
GRANULARITY_HOUR | 1 hour | 14 days |
GRANULARITY_DAY | 1 day | 365 days |
GRANULARITY_WEEK | 1 week | ~4 years (1461 days) |
GRANULARITY_MONTH | 1 month | ~10 years (3652 days) |
InsightQuerySpec fields
| Field | Type | Description |
|---|---|---|
insight_type | InsightType | Required. Selects the computation and response shape. |
events | EventQuery[] | Event series (for trends, segmentation, funnel, retention). Each entry selects one event kind with optional filters and an aggregation type. |
breakdowns | Breakdown[] | Group results by up to 5 properties ({ property: string }). Not supported for segmentation or user flow. |
breakdown_limit | int32 | Cap on number of breakdown values returned (0–100). Requires at least one breakdown. |
filter_groups | FilterGroup[] | Top-level property filters. Multiple groups are combined by filter_groups_operator. |
filter_groups_operator | LogicalOperator | How filter groups are combined. Defaults to LOGICAL_OPERATOR_AND. |
conversion_window | Duration | Funnel only. Maximum time from step 1 to last step per user. Whole seconds, min 1 s. Absent = no constraint. |
include_step_timing | bool | Funnel only. When true, each non-entry step includes StepTiming (avg, median, p95, 8-bucket histogram). |
session | SessionQuery | Trends/segmentation only. Query session-level metrics instead of events. events must be empty when set. |
user_flow | UserFlowQuery | User-flow only. Configures the Sankey graph (node kind, max hops, max nodes, max links). |
EventQuery
| Field | Type | Description |
|---|---|---|
event | EventFilter | Event kind + optional per-event property filters. |
aggregation | AggregationType | Defaults to AGGREGATION_TYPE_TOTAL. |
aggregation_property | string | Required for SUM, AVG, MIN, MAX. Property name to aggregate (e.g. revenue). |
Aggregation types
| Enum value | Description |
|---|---|
AGGREGATION_TYPE_TOTAL | Total event occurrences. |
AGGREGATION_TYPE_UNIQUE_USERS | Count of distinct users. |
AGGREGATION_TYPE_PER_USER_AVG | Average events per user. |
AGGREGATION_TYPE_SUM | Sum of a numeric property. Requires aggregation_property. |
AGGREGATION_TYPE_AVG | Mean of a numeric property. Requires aggregation_property. |
AGGREGATION_TYPE_MIN | Minimum of a numeric property. Requires aggregation_property. |
AGGREGATION_TYPE_MAX | Maximum of a numeric property. Requires aggregation_property. |
Filter model
Filters are expressed as FilterGroup objects inside spec.filter_groups. Each group contains one or more PropertyFilter entries combined by the group’s own operator. Groups are then combined by spec.filter_groups_operator.
FilterGroup
{
"filters": [
{ "property": "plan", "operator": "FILTER_OPERATOR_EQUALS", "value": "pro" },
{ "property": "$country", "operator": "FILTER_OPERATOR_IN", "values": ["US", "CA"] }
],
"operator": "LOGICAL_OPERATOR_AND"
}Filter operators (FilterOperator)
| Enum value | Value fields used | Description |
|---|---|---|
FILTER_OPERATOR_EQUALS | value | Exact match. |
FILTER_OPERATOR_NOT_EQUALS | value | Excludes exact match. |
FILTER_OPERATOR_CONTAINS | value | Substring match. |
FILTER_OPERATOR_NOT_CONTAINS | value | Excludes substring match. |
FILTER_OPERATOR_IS_SET | — | Property exists. |
FILTER_OPERATOR_IS_NOT_SET | — | Property is absent. |
FILTER_OPERATOR_LTE | value (numeric) | Less than or equal. |
FILTER_OPERATOR_GTE | value (numeric) | Greater than or equal. |
FILTER_OPERATOR_LT | value (numeric) | Strictly less than. |
FILTER_OPERATOR_GT | value (numeric) | Strictly greater than. |
FILTER_OPERATOR_IN | values | Match any of a list. |
FILTER_OPERATOR_NOT_IN | values | Exclude all of a list. |
FILTER_OPERATOR_BETWEEN | values[0], values[1] (numeric, ordered) | Inclusive range. |
FILTER_OPERATOR_NOT_BETWEEN | values[0], values[1] (numeric, ordered) | Outside range. |
Logical operators (LogicalOperator)
| Enum value | Description |
|---|---|
LOGICAL_OPERATOR_AND | All conditions must match (default). |
LOGICAL_OPERATOR_OR | At least one condition must match. |
Property names follow the pattern ^\\$?[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)*$. Auto-properties use their flat $ key (e.g. $country, $browser); a dotted name addresses a nested key inside a custom property’s JSON (e.g. metadata.tier). For filterable auto-properties see Auto-properties.
Session metrics
When spec.session is set, the query measures session-level data instead of individual events. spec.events must be empty.
| Enum value | Description | Restrictions |
|---|---|---|
SESSION_METRIC_SESSIONS | Count of distinct sessions started in the window. | Trends or segmentation. |
SESSION_METRIC_AVG_DURATION | Average session duration in seconds (last event − first event). | Trends or segmentation. |
SESSION_METRIC_BOUNCE_RATE | Percentage of sessions with exactly one event (after optional scope filter). | Trends or segmentation. |
SESSION_METRIC_ENTRY | Count sessions by their first matching event’s breakdown value (entry page). | Trends + exactly one breakdown. |
SESSION_METRIC_EXIT | Count sessions by their last matching event’s breakdown value (exit page). | Trends + exactly one breakdown. |
SessionQuery.scope (optional EventFilter) restricts which events participate in the metric. An empty scope considers all events in the session.
Worked example: TRENDS query
A daily time series of unique users who fired page_view, broken down by $country, over the last 30 days.
POST /shared.insights.v1.InsightsService/Query
Content-Type: application/json
Connect-Protocol-Version: 1
x-api-key: prv_…{
"spec": {
"insight_type": "INSIGHT_TYPE_TRENDS",
"events": [
{
"event": { "kind": "page_view" },
"aggregation": "AGGREGATION_TYPE_UNIQUE_USERS"
}
],
"breakdowns": [
{ "property": "$country" }
],
"breakdown_limit": 10
},
"time_range": {
"from": "2026-05-06T00:00:00Z",
"to": "2026-06-05T00:00:00Z"
},
"granularity": "GRANULARITY_DAY"
}Response sketch:
{
"trends": {
"series": [
{
"event_kind": "page_view",
"breakdown": { "$country": "US" },
"points": [
{ "time": "2026-05-06T00:00:00Z", "value": 412 },
{ "time": "2026-05-07T00:00:00Z", "value": 389 }
]
},
{
"event_kind": "page_view",
"breakdown": { "$country": "GB" },
"points": [
{ "time": "2026-05-06T00:00:00Z", "value": 104 },
{ "time": "2026-05-07T00:00:00Z", "value": 97 }
]
}
]
}
}Each series entry corresponds to one (event_kind, breakdown) pair. points are in ascending time order with one entry per granularity bucket.
Worked example: FUNNEL query
POST /shared.insights.v1.InsightsService/Query
Content-Type: application/json
Connect-Protocol-Version: 1
x-api-key: prv_…{
"spec": {
"insight_type": "INSIGHT_TYPE_FUNNEL",
"events": [
{ "event": { "kind": "signup_started" } },
{ "event": { "kind": "signup_completed" } },
{ "event": { "kind": "purchase" } }
],
"conversion_window": "604800s"
},
"time_range": {
"from": "2026-05-01T00:00:00Z",
"to": "2026-06-01T00:00:00Z"
},
"granularity": "GRANULARITY_DAY"
}Response sketch:
{
"funnel": {
"series": [
{
"breakdown": {},
"steps": [
{ "event_kind": "signup_started", "total": 1000 },
{ "event_kind": "signup_completed", "total": 650 },
{ "event_kind": "purchase", "total": 120 }
]
}
]
}
}With include_step_timing: true, each non-entry step gains a timing object:
{
"event_kind": "signup_completed",
"total": 650,
"timing": {
"avg": "180s",
"median": "95s",
"p95": "1200s",
"distribution": [
{ "label": "0-30s", "upper_bound": "30s", "count": 78 },
{ "label": "30s-2m", "upper_bound": "120s", "count": 210 }
]
}
}The distribution array above is truncated for brevity — it always contains exactly 8 buckets in the canonical order, and the 8 boundaries are fixed (a full response returns all 8).
Performance notes
Insights queries run against ClickHouse. Query time scales with:
- Time range × granularity — wider ranges at fine granularities scan more partitions.
- Breakdown cardinality — avoid very high-cardinality breakdowns (e.g. user ID). Use
breakdown_limitto cap result size. - Funnel step count — funnel supports at most 20 steps.
Related
- API reference — base URL, auth, error codes
- Auto-properties — filterable
$-prefixed properties - RPC services — full method index