- Active in last 7 days —
count(any_event, last 7d) ≥ 1 - Power user —
count(feature_used, last 30d) ≥ 50 - Has ever exported —
count(export_run, all_time) ≥ 1 - Logins last 30 days —
count(login, last 30d)(returns a number, not yes/no) - Unique users last 7 days —
unique_users(any_event, last 7d)
Result types
Every indicator returns one of two shapes:| Type | Returns | Use when |
|---|---|---|
| Yes / no | A boolean (predicate match) | The signal is binary — power user vs. not, churned-likely vs. not. |
| Number | A raw count or sum | You want to graph it, threshold it later, or compose it into a smart trait. |
Build an indicator
Name and describe
Give it a clear name like Power user or Logins last 30 days. Description is optional but helps teammates know
what it captures.
Pick a result type
Yes / no (predicate) for binary signals, or Number (count) for raw values you want to graph or threshold
separately.
Configure the aggregation
Each event row is an aggregation:
- Function:
Count of events(default),Unique users, orSum of property(requires a property dot-path). - Event name: the exact event name as it appears in your Segment / PostHog data (e.g.
login,Item Viewed). This dropdown lists allowlisted events from your connected sources. - Time window:
Rolling N days(most common),All time, orSince first seen(uses the account’s creation date as the lower bound).
Add filters (optional)
Refine which events count by filtering on payload properties — for example, only
feature_used events where
properties.feature == "export". Filters are AND-only and use a dot-path into the original event payload.Filtered indicators read from the event staging table, which is bounded by a 7-day TTL. If you set a window longer
than 7 days on a filtered indicator, only the most recent 7 days of payload-level filtering will be exact —
earlier days fall back to the unfiltered rollup. For most use cases this is fine; if exact long-window filtered
counts matter, prefer indicators without filters.
Set a threshold (yes/no only)
For boolean indicators, pick a comparator (
≥, >, ≤, <, =, ≠, between) and a value per event row. The
indicator returns true when the aggregation passes the comparator.Combine multiple events (yes/no only)
Boolean indicators can combine more than one event with AND / OR. Click + Add event to add another
aggregation row at the top level — they’re combined with the operator pill (
AND or OR) shown above the rows.For nested logic, click + Add group to start a sub-group with its own operator. One level of nesting is supported,
mirroring how segments work. Example: logged in AND (used export ≥ 5x OR ran a report ≥ 10x) — a top-level
AND with a single OR group inside.Each event row carries its own threshold, so different events can require different counts (e.g. login ≥ 1 AND
export ≥ 5).Preview
Click Preview match to see how many of your active accounts currently match the indicator before saving. Useful to
sanity-check the threshold.
Where indicators show up
On every account page
The Indicators panel sits at the top of the account activity timeline. Each indicator renders as a chip:- Yes / no indicators — green chip with a ✓ when true, gray with ✗ when false, yellow when no value has been computed yet.
- Number indicators — labeled badge with the current numeric value.
In segments
When building a segment, you can use indicator values as condition fields:- Indicator field type — references a saved indicator by name. The condition reads the indicator’s current value (boolean or number) and applies an operator.
- Event aggregate field type — inline aggregation defined directly on the condition, no saved indicator required. Useful for one-off filters.
In smart traits
Smart trait formulas can reference indicators by their slug (auto-generated from the name —power_user, active_last_7_days):
undefined and won’t crash the formula.
In account health scores
Indicators can contribute to the health score as a single weighted Indicators factor. See health-score config for the setup flow.Slugs
Each indicator gets a stable slug derived from its name (lowercase, snake_case, max 60 chars). The slug is what smart-trait formulas reference —indicators.power_user. You can override the auto-generated slug from the builder.
Renaming an indicator does not change its slug. This is intentional: existing formulas keep working when you rewrite the human-readable name.
How values get computed
Indicators are computed in two paths depending on whether your indicator has filters:- Fast path (no filters, function = count or unique_users) — a single SQL aggregation over the daily rollup table. Fast even for orgs with thousands of accounts.
- Slow path (any filter clauses, or function = sum) — scans the event staging table for the time window. Bounded by the 7-day staging TTL.
Disable vs. delete
The Enabled toggle on each indicator stops the compute job from updating its value. Existing values stay in place but get older. Indicators that participate in the health score are silently skipped while disabled — no need to remove them from the health score config. Delete removes the indicator and all its computed values. Smart-trait formulas referencing the slug start returningundefined after delete; segments referencing it stop matching.
Volume notes
- Indicators read from per-account daily rollups. The cost of a single indicator is roughly proportional to (accounts × days in window) but most orgs see this measured in hundreds of milliseconds.
- The
unique_usersfunction is approximate — it sums each day’s distinct-user count without cross-day deduplication. For a strict per-account “unique users in the last 7 days” you’ll see a small over-count when the same user appears on multiple days. Trends are still meaningful; if exact counts matter, file a support request and we can plug in a HyperLogLog sketch. - The All time window doesn’t actually scan all of history when filters are present — it’s bounded by the 7-day staging TTL. Use unfiltered all-time counts (which read directly from the rollup) for true lifetime totals.
