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

# Events

> Analyze event counts, top events, property breakdowns, and custom aggregations.

Events are the core of product analytics. When a user signs up, views a page, or makes a purchase, Tell records it as an event with a name and properties. The analytics engine lets you count events, rank them, break them down by property values, and run aggregations like sum and average.

## Quick start

```bash theme={null}
# Total event count over 30 days
tell metrics events --range 30d

# Top 10 most frequent events
tell metrics events --top --range 30d --limit 10
```

Via the API:

```bash theme={null}
curl "https://your-tell-server/api/v1/metrics/events?range=30d&granularity=daily" \
  -H "Authorization: Bearer $TOKEN"
```

## Event counts

Count all events or filter to a specific event name:

```bash theme={null}
# All events over time
tell metrics events --range 7d

# Just sign_up events
tell metrics events --range 7d --event sign_up
```

API:

```bash theme={null}
# Count a specific event
curl "https://your-tell-server/api/v1/metrics/events?range=7d&event=sign_up" \
  -H "Authorization: Bearer $TOKEN"
```

## Top events

See which events happen most often:

```bash theme={null}
curl "https://your-tell-server/api/v1/metrics/events/top?range=30d&limit=10" \
  -H "Authorization: Bearer $TOKEN"
```

Returns event names ranked by count, so you can quickly see what's driving volume.

## Property breakdowns

Break down a specific event by its properties to understand the distribution:

```bash theme={null}
# sign_up events broken down by plan property
curl "https://your-tell-server/api/v1/metrics/events/properties?range=30d&event=sign_up&property=properties.plan" \
  -H "Authorization: Bearer $TOKEN"
```

This returns time series data grouped by each property value (e.g., "free", "pro", "enterprise").

For top-level fields, use the field name directly (`device_type`, `country`). For custom properties stored in the JSON `properties` column, prefix with `properties.` (e.g., `properties.plan`, `properties.amount`).

## Custom aggregations

Run sum, average, min, max, or count on numeric event properties:

```bash theme={null}
# Average order amount for purchase events
curl "https://your-tell-server/api/v1/metrics/events/custom?\
event=purchase&property=properties.amount&metric=avg&range=30d" \
  -H "Authorization: Bearer $TOKEN"

# Total revenue
curl "https://your-tell-server/api/v1/metrics/events/custom?\
event=purchase&property=properties.amount&metric=sum&range=30d" \
  -H "Authorization: Bearer $TOKEN"
```

Supported aggregation functions: `sum`, `avg`, `min`, `max`, `count`.

## First-time events

Count users who did an event for the first time within a period. This answers questions like "how many users signed up for the first time this week?" — distinct from total event counts, which include repeat actions.

```bash theme={null}
curl "https://your-tell-server/api/v1/metrics/events/first-time?event=sign_up&range=30d&granularity=daily" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-ID: ws_abc123"
```

Tell scans each user's full event history to find their earliest occurrence, then counts only those whose first occurrence falls within the query range. The result is a time series of new user acquisition per period.

### First-time vs first-match

Two modes control how filter conditions interact with the historical scan:

| Mode             | `match_mode`      | Behavior                                                                                                                                                           |
| ---------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **first\_time**  | `false` (default) | Finds user's first occurrence of the event, regardless of conditions. Conditions only filter the output range.                                                     |
| **first\_match** | `true`            | Finds user's first occurrence that matches ALL conditions. A user who did `purchase` before but never with `amount > 100` counts as first-time for that condition. |

**first\_time** (default) — "How many users made their first purchase this month?"

```bash theme={null}
curl "https://your-tell-server/api/v1/metrics/events/first-time?event=purchase&range=30d" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-ID: ws_abc123"
```

**first\_match** — "How many users made their first purchase over \$100 this month?"

```bash theme={null}
curl "https://your-tell-server/api/v1/metrics/events/first-time?\
event=purchase&match_mode=true&range=30d&\
conditions[0][field]=properties.amount&conditions[0][op]=gt&conditions[0][value]=100" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-ID: ws_abc123"
```

### Lookback window

By default, Tell scans the entire event history to find true first occurrences. For large datasets, limit the scan with `lookback_days`:

```bash theme={null}
# Only scan the last 365 days of history
curl "https://your-tell-server/api/v1/metrics/events/first-time?\
event=sign_up&range=30d&lookback_days=365" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-ID: ws_abc123"
```

This trades accuracy for speed — a user who first did the event 400 days ago would be miscounted as first-time if their next occurrence falls within the range. Use this when you know your product's age or only care about recent cohorts.

First-time events support [breakdowns](/analytics/filtering), [comparison](/analytics/filtering), and [audience filtering](/analytics/audiences). When combined with a breakdown, Tell captures the property value at the time of the first event using `argMin`.

See the [first-time events API reference](/api/queries#first-time-events) for full endpoint documentation.

## Per-actor metrics

Regular event counts tell you totals. Per-actor metrics tell you about user behavior — how many events does a typical user trigger? What does the 90th percentile look like? Tell computes this with a two-level aggregation: first per user, then across users.

```bash theme={null}
# Average page views per user, daily over 30 days
curl "https://your-tell-server/api/v1/metrics/events/per-actor?\
event=page_view&metric=avg&range=30d&granularity=daily" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-ID: ws_abc123"
```

This returns a time series where each point is the average number of `page_view` events per user for that day — not the total count, but the per-user average.

### Aggregation functions

| Function         | Description                              |
| ---------------- | ---------------------------------------- |
| `avg`            | Average per user (default)               |
| `median` / `p50` | Median per user (robust to outliers)     |
| `p75`            | 75th percentile                          |
| `p90`            | 90th percentile — identifies power users |
| `p95`            | 95th percentile                          |
| `p99`            | 99th percentile — extreme behavior       |
| `min`            | Minimum per-user value                   |
| `max`            | Maximum per-user value                   |

### Property aggregation

By default, per-actor counts events. Add `property` to aggregate a numeric property instead:

```bash theme={null}
# P90 revenue per user from purchase events
curl "https://your-tell-server/api/v1/metrics/events/per-actor?\
event=purchase&metric=p90&property=properties.amount&range=30d" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-ID: ws_abc123"
```

Without `property`: inner aggregation is `COUNT(*)` per user (event count).
With `property`: inner aggregation is `SUM(property)` per user (property total).

The outer function (`avg`, `p90`, etc.) then operates on those per-user values.

### How it differs from other metrics

* **Event counts** — total events across all users. "50,000 purchases happened."
* **Per-actor metrics** — distribution across users. "The average user made 2.3 purchases. The p90 user made 8."
* **Custom aggregations** — single-level property aggregation. "Average purchase amount is \$42." (not per-user)
* **Grouped metrics** — per-actor logic applied per group for treemap visualization

Per-actor metrics support [breakdowns](/analytics/filtering), all [granularity levels](/analytics/filtering), and [audience filtering](/analytics/audiences).

See the [per-actor API reference](/api/queries#per-actor-metrics) for full endpoint documentation.

## Drill-down

Inspect raw event data when you need to see individual records:

```bash theme={null}
curl "https://your-tell-server/api/v1/metrics/events/raw?range=7d&limit=50" \
  -H "Authorization: Bearer $TOKEN"
```

Returns rows with `timestamp`, `event_name`, `device_id`, and `session_id`. Add [filter conditions](/analytics/filtering) to narrow down the results.

## Formulas

Combine multiple metric series with math. Define series A, B, C (up to 26), then write an expression:

```bash theme={null}
curl -X POST https://your-tell-server/api/v1/metrics/formula \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-ID: ws_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "series": [
      { "metric": "event:sign_up" },
      { "metric": "event:purchase" }
    ],
    "formula": "B / A * 100",
    "range": "30d",
    "granularity": "daily"
  }'
```

This computes the daily conversion rate from sign-up to purchase. Series A is sign-up count, series B is purchase count, and the formula `B / A * 100` gives a percentage.

### Series references

Each series maps to a letter: the first is `A`, the second is `B`, and so on up to `Z`. Reference them in your formula by letter.

Available series metrics: `dau`, `wau`, `mau`, `events`, `event:<name>`, `sessions`, `users`, `logs`.

### Operators

| Operator    | Description | Example  |
| ----------- | ----------- | -------- |
| `+`         | Add         | `A + B`  |
| `-`         | Subtract    | `A - B`  |
| `*`         | Multiply    | `A * B`  |
| `/`         | Divide      | `A / B`  |
| `%`         | Modulo      | `A % B`  |
| `**`        | Power       | `A ** 2` |
| `-` (unary) | Negate      | `-A`     |

Standard math precedence applies. Use parentheses to override: `(A + B) / C`.

Division by zero returns `0` instead of an error.

### Evaluation modes

Formulas evaluate in two modes depending on context:

* **Time series** — per-bucket evaluation, used for charts. Missing values default to `0`.
* **Total** — evaluates on aggregate totals, used for KPI number blocks on [boards](/analytics/boards).

### Formulas on boards

Add formulas to any metric [block](/analytics/boards) on a board. Define your series, write the expression, and the board evaluates it on every refresh. Use this for computed metrics like conversion rates, ratios, or derived KPIs.

See the [formula API reference](/api/queries#formulas) for full endpoint documentation.

## Grouped metrics

Grouped metrics show proportional composition — which countries, events, or plans make up your traffic, and how engaged each group is. The result powers treemap visualizations on [boards](/analytics/boards).

Each group has two values:

* **Size** — determines area (event count, unique users, or sum of a property)
* **Intensity** — determines color (average events per user, percentile, or average of a property)

```bash theme={null}
curl -X POST https://your-tell-server/api/v1/metrics/grouped \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-ID: ws_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "group_by": "country",
    "size": { "type": "unique_actors" },
    "intensity": { "type": "avg_per_actor" },
    "range": "30d"
  }'
```

This returns groups ordered by size, each with a size value (user count) and intensity value (average events per user). The US might have 1,500 users averaging 3.2 events each, while Canada has 800 users averaging 2.8.

### Size metrics

| Type            | Description                                                                       |
| --------------- | --------------------------------------------------------------------------------- |
| `count`         | Total event count per group                                                       |
| `unique_actors` | Distinct users per group                                                          |
| `sum`           | Sum of a numeric property (requires `property` field, e.g., `properties.revenue`) |

### Intensity metrics

| Type                   | Description                                                                |
| ---------------------- | -------------------------------------------------------------------------- |
| `avg_per_actor`        | Average events per user                                                    |
| `percentile_per_actor` | Percentile of events per user (default: p90, set `percentile` to override) |
| `unique_actors`        | Distinct users (useful when size is `count`)                               |
| `avg`                  | Average of a numeric property (requires `property` field)                  |

### Options

| Field        | Default        | Description                                                                            |
| ------------ | -------------- | -------------------------------------------------------------------------------------- |
| `group_by`   | *(required)*   | Field to group by: `country`, `event_name`, `device_type`, or any `properties.*` field |
| `event`      | *(all events)* | Filter to a specific event                                                             |
| `max_groups` | `20`           | Maximum number of groups returned                                                      |
| `range`      | `30d`          | Time range                                                                             |

Unlike [breakdowns](/analytics/filtering#breakdowns), grouped metrics always return a snapshot (not a time series) and use two-level aggregation — first per user, then per group — to reveal engagement patterns, not just raw counts.

See the [grouped metrics API reference](/api/queries#grouped-metrics) for full endpoint documentation.

## Lifecycle

The lifecycle metric tracks how your active user base evolves over time. Each period, Tell classifies every active user into one of three states:

| State           | Meaning                                         |
| --------------- | ----------------------------------------------- |
| **new**         | First ever activity falls within this period    |
| **returning**   | Active in both this period and the previous one |
| **resurrected** | Was inactive in the previous period, came back  |

```bash theme={null}
curl "https://your-tell-server/api/v1/metrics/lifecycle?range=30d&granularity=weekly" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-ID: ws_abc123"
```

Returns a time series with one point per state per period:

```json theme={null}
{
  "data": {
    "points": [
      {"date": "2025-02-03", "value": 150, "dimension": "new"},
      {"date": "2025-02-03", "value": 800, "dimension": "returning"},
      {"date": "2025-02-03", "value": 50, "dimension": "resurrected"},
      {"date": "2025-02-10", "value": 200, "dimension": "new"},
      {"date": "2025-02-10", "value": 750, "dimension": "returning"},
      {"date": "2025-02-10", "value": 80, "dimension": "resurrected"}
    ],
    "total": 2030
  }
}
```

A healthy product has a large returning base with steady new user inflow. If resurrected starts outpacing new, your acquisition may be slowing while re-engagement improves. If returning shrinks, users aren't sticking around.

The default granularity is `weekly`. Supports `daily`, `monthly`, and all other [granularity levels](/analytics/filtering). Add `compare=previous` for period-over-period comparison.

<Note>
  This is different from [lifecycle segments](/analytics/segments#lifecycle-segments). The lifecycle metric is a **time series** — it classifies users per period with relative lookback. Segments are a **snapshot** — they classify all users right now using fixed 7/30-day windows and include `dormant` and `churned` states.
</Note>

See the [lifecycle API reference](/api/queries#lifecycle) for full endpoint documentation.

## Breakdowns and comparison

Event metrics support the full [filtering system](/analytics/filtering) — breakdowns by any field, period comparison, and all granularity levels.

```bash theme={null}
# Event count by device type, compared to previous period
tell metrics events --range 30d --breakdown device_type --compare previous
```
