Saved Segments
Saved Segments let you build a named filter once and re-apply it across Globe, Pages, Sources, Journeys, Users, and Funnels in a single click. They go beyond regular filters in three ways:
- They're persistent. A regular filter lives only in the URL and disappears when you close the tab. A segment lives in your team's workspace.
- They support OR logic. Regular filters AND every condition together. Segments support up to 3 AND-groups joined by OR — e.g. (paying users from Germany) OR (visitors who scrolled past 75% on /pricing).
- They unlock cohort dimensions that regular filters don't expose: user type (anonymous / identified / paying), scroll depth, sessions count, page count, conversion status, custom traits, and the AI visitor score.
Segments are scoped to a single website and are visible to every active member of that website's team. They are never exposed on public dashboards — share-token visitors only see the metrics, not the segment definition.
Building a segment
Open the Filter funnel icon in the dashboard header. At the bottom of that dropdown, the Saved Segments section lists every segment for this website. Click any row to load it instantly. Click + New segment to open the builder.
The builder is a vertical list of groups. Within each group, conditions are joined with AND. Between groups, conditions are joined with OR.
[ Group 1: country is "Germany" AND user_type is "paying" ]
OR
[ Group 2: scroll_depth_max ≥ 75 AND page is "/pricing" ]
V1 caps:
| Limit | Value |
|---|---|
| AND-groups | 3 |
| Conditions / group | 5 |
| Saved segments / website | 50 |
| Nested grouping | Not supported |
Once saved, the segment appears in the dropdown and is auto-applied. A blue chip in the dashboard header shows the active segment name; click the (×) to clear.
Managing existing segments
Hover any row in the Saved Segments list:
- Pencil ✏️ opens the segment in the builder, pre-filled, so you can adjust conditions or rename it without recreating from scratch.
- Trash 🗑 deletes immediately. A green confirmation appears at the bottom of the screen.
Clicking a saved segment loads it across every chart and panel on the dashboard. The active period selector (e.g. Last 7 days) still applies — the segment defines who, the period selector defines when.
Why the value counts in the builder match what you see
Each option in the dimension dropdowns shows a count (e.g. United States · 230). That count reflects the dashboard's current period, not a fixed 30-day window. If you're viewing Last 7 days, the count is the 7-day count. Applying the segment will produce numbers that line up with what you saw next to each option.
A common pitfall — AND inside one group ≠ OR
If you add country is Italy and country is Australia to the same group, you've built country IS Italy AND country IS Australia — which matches zero visitors, because no visitor is from both countries simultaneously. To match either, put each country in its own OR group. The builder shows an amber heads-up when it detects this pattern.
Dimensions
Saved segments expose every dimension available to regular filters, plus 11 new ones:
URL & Source (existing)
hostname, page, entry_page, country, region, city, channel, referrer, campaign
UTM (new in P1-1)
utm_source, utm_medium, utm_content, utm_term
System (existing)
browser, os, device
Engagement (new in P1-1)
| Dimension | Description | Operators |
|---|---|---|
scroll_depth_max | Max scroll depth percentage reached on a page (0–100) | gt gte lt lte is is_not |
sessions_count | Total distinct sessions a visitor has had on this website | gt gte lt lte is is_not |
pages_count | Total page views the visitor has accumulated in the last 90 days | gt gte lt lte is is_not |
has_converted | Whether the visitor has triggered any conversion event or revenue >0 | is_true is_false |
ai_score | Visitor value score (0–100) — backed by visitors.value_score | gt gte lt lte is is_not |
Identity (new in P1-1)
| Dimension | Description | Values |
|---|---|---|
user_type | Derived from the identity-badge logic: paying / identified / anonymous | paying identified anon |
A visitor is paying if they have any payment-provider customer ID (Stripe / Lemon Squeezy / Polar / PayPal), total_revenue > 0, or an active subscription_status. A visitor is identified if they have an email or customer_id sent via zenovay.identify(...). Otherwise they are anonymous.
Custom traits (new in P1-1)
| Dimension | Description |
|---|---|
custom_prop:<key> | Match against any top-level key of identified_users.custom_attributes you've sent via zenovay.identify(...). The dropdown auto-suggests keys observed in the last 30 days. |
zenovay('identify', {
customer_id: 'cust_42',
email: '[email protected]',
// Custom traits — top-level keys are queryable via custom_prop:<key>
custom_attributes: {
plan: 'enterprise',
industry: 'fintech',
seats: 25,
},
});In the segment builder, the dimension dropdown will offer Trait: plan, Trait: industry, Trait: seats under the CUSTOM TRAITS section.
Operators
| Operator | Type | Notes |
|---|---|---|
is, is_not | All | Exact match (case-sensitive for string values). |
contains, does_not_contain | String | ILIKE substring search. |
gt, gte, lt, lte | Numeric | For scroll_depth_max, sessions_count, pages_count, ai_score. |
in, not_in | Set | Comma-separated list (used by user_type). |
is_true, is_false | Boolean | Used by has_converted. |
Examples
Paying users from Germany who bounced on /pricing
Three conditions, one group:
Group 1 (AND):
user_type is paying
country is DE
page is /pricing
Engaged users OR converters
Two groups, joined by OR:
Group 1 (AND):
scroll_depth_max gte 75
sessions_count gte 3
OR
Group 2 (AND):
has_converted is_true
Enterprise plan trait + Chrome on macOS
Group 1 (AND):
custom_prop:plan is enterprise
browser is Chrome
os is macOS
Public dashboards
Saved segments are never applied via share-token authentication. The public view honours regular URL filters but ignores ?segment_id= and ?segment_def= query parameters by design — the audience of a share link should not see your team's named cohorts.
If you need to share a single composed view publicly, the cleanest approach is:
- Apply the segment privately.
- Recreate the same conditions as flat filters in a public-friendly URL.
- Share the resulting URL.
Permissions
| Action | Required role |
|---|---|
| View segments | Any active team member |
| Create / edit | Owner, Admin, Editor |
| Delete | Owner, Admin, Editor |
Viewers can apply existing segments but cannot create or modify them.
Performance & caps
- Per-website segment count is capped at 50 to prevent runaway list growth. The same cap applies on every plan; segments are not paywalled.
- Resolution model: when a segment loads, each AND-group is resolved server-side to a list of matching visitor IDs, then the lists are unioned across groups. Result limit per group is 50,000 visitor IDs — adequate for nearly every use case.
- Aggregate dimensions (
sessions_count,pages_count) execute via SECURITY DEFINER Postgres helpers (segment_visitors_by_session_count,segment_visitors_by_page_count). Page-count lookups consider the last 90 days. - Custom traits are looked up via JSONB key access on
identified_users.custom_attributes. Top-level keys only — nested paths are not supported in V1.
Related
- Dashboard Overview — how filters and segments compose with the dashboard's date range.
- Visitor Identification — how to send
zenovay.identify(...)souser_typeand custom traits are populated. - Visitor Value Scoring — how
ai_scoreis computed.