---
title: "Insights API"
description: "Run trends, funnel, retention, segmentation and user-flow queries programmatically with a private key."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.pug.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Insights API

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](/get-started/authentication).

## Methods

### `Query`

```
POST /shared.insights.v1.InsightsService/Query
```

Runs an analytics query and returns a typed result. The shape of the result depends on `spec.insight_type` (see [Insight types](#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](#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/SegmentUsers
```

Returns 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/GetFilterSchema
```

Returns 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/GetPropertyValues
```

Returns 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.

```json
{ "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; supports `breakdowns` (max 5); supports `conversion_window` (whole seconds, min 1 s); supports `include_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 support `breakdowns`.
- **`INSIGHT_TYPE_USER_FLOW`** — requires a `user_flow` sub-spec; `events` must be empty; `breakdowns` are 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`

```json
{
  "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](/reference/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.

```http
POST /shared.insights.v1.InsightsService/Query
Content-Type: application/json
Connect-Protocol-Version: 1
x-api-key: prv_…
```

```json
{
  "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:

```json
{
  "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

```http
POST /shared.insights.v1.InsightsService/Query
Content-Type: application/json
Connect-Protocol-Version: 1
x-api-key: prv_…
```

```json
{
  "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:

```json
{
  "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:

```json
{
  "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_limit` to cap result size.
- **Funnel step count** — funnel supports at most 20 steps.

## Related

- [API reference](/api) — base URL, auth, error codes
- [Auto-properties](/reference/auto-properties) — filterable `$`-prefixed properties
- [RPC services](/reference/rpc-services) — full method index

Source: https://docs.pug.sh/api/insights/index.mdx
