Pages & Features

Analyze → Pages & Features names the pages and features of your product so you can report on them by name: who uses them, how often, on which accounts, how that changes over time, and how engaged people are overall (the Product Engagement Score). Pages and features can be grouped into product areas, and the ones that matter most become core events.

Tags are retroactive: a tag is a set of rules evaluated against the page views and clicks the SDK already stored, so a page or feature tagged today shows its history for as long as events are kept. Changing a rule changes history too.

The automatic Pages report (every path, :id folding, ?section= splits) stays as it is; from a path's detail you can Tag this page, and from its most-clicked elements Tag as a feature.

Pages

A tagged page is one or more rules; a page view belongs to the page when it matches any include rule and no exclude rule.

RuleMatchesExample
URLthe path (query and hash removed), case-insensitive, trailing slash optional/accounts/:id/settings, /reports/*, /docs/**, //*/billing
URL with query conditionsalso requires query parameters to be present, absent, equal to or contain a value/search?tab=people, or a rule with tab equals people
URL with a hostthe full URL without query (scheme ignored)https://*.acme.com/home
Regexthe path, Postgres / JavaScript regular expression (no look-arounds or back-references)`^/reports/(daily\weekly)$`
Titlethe document title, equals or containscontains Invoice

In URL rules * matches within one path segment, ** any number of segments, :name exactly one segment, and a leading //* means any domain. Pages are matched against page_view events, so metrics are page views, visitors and accounts; time on page comes from page_leave.

Features

A tagged feature is one or more rules over click events (rage clicks are reported separately). Every condition filled in on a rule must hold; again any include rule and no exclude rule.

ConditionMatches
CSS selectorthe clicked element, evaluated server-side against the element snapshot the SDK stores with each click (see below); older clicks are matched through their stored selector string
Selector is / starts with / contains / matches *the stored selector string (button[data-testid="save"], #export, c-app >>> button.save). Mobile taps store their accessibility id / data-guidely-id here, so Selector is works for iOS and Android
Text is / containsthe element's visible text (never form values; nothing when masked)
Tagthe element name (button, a)
Linkthe link's path (same origin) or origin
On pagea tagged page, or a URL pattern
Appweb, iOS or Android (properties.platform)

The CSS subset supported server-side: type and *, #id, .class, [attr], [attr=v], [attr^=v], [attr$=v], [attr*=v], [attr~=v], [attr|=v] (with i), :nth-of-type(n|odd|even), :first-of-type, descendant and > combinators, selector lists and >>> for shadow DOM (c-app >>> c-form >>> button.save: each step left of >>> must match a shadow host further out). Sibling combinators and other pseudo-classes are rejected when you save.

Element snapshots

Every autocaptured click carries properties.el, a compact snapshot of the element: tag, stable id, stable classes (no CSS-in-JS hashes or state classes such as active), up to six data-* and safe attributes (role, name, type, aria-label, title, alt, for), its nth-of-type, five ancestors and up to three shadow hosts. Text-like attributes are dropped for masked elements and form values are never read. At ingest the server validates and trims it, adds the link path as href, and stores properties.elh, a hash of the selector and snapshot.

The project keeps a dictionary of distinct clicked elements (ClickElement, upserted per batch and backfilled once from stored clicks). A CSS rule is evaluated against the dictionary and becomes a list of element hashes; everything else compiles straight to SQL over ProductEvent. Clicks stored before snapshots existed are matched by reading their selector string (#form > div:nth-of-type(2) > button) into a partial snapshot, so #form button matches them too.

Automatic feature tagging

Settings → Automatic feature tagging names an attribute (default data-guidely-feature). Clicks on an element carrying it — or inside one, even when the element itself isn't interactive — are attributed to a feature named by its value, created on first sight with the rule [attr="value"], [attr="value"] * (marked auto). Turning it off stops creating features.

<section data-guidely-feature="Revenue chart">…</section>
<button data-guidely-feature="Export CSV">Export</button>

Event properties

A page or feature can list properties to read from the DOM at event time: the text or an attribute of an element (CSS selector, >>> allowed; for features, empty means the clicked element). The SDK receives them with its configuration (tagging.properties), evaluates which pages / features match the current page view or click in the browser, and attaches the values as properties.ep (≤ 100 characters each; never value, style or event-handler attributes, nothing from masked elements). The detail page breaks the tag down by each property. Page properties are read when the page view fires, so content rendered later in a single-page app may be missed.

Visual tagging

Tag in app opens your app (any page that loads the SDK with the environment's key) with the element picker in tag mode — the same authoring session the guide editor uses, without a guide (AuthoringSession.mode = tag). Click an element to propose a feature from its most stable selector (ids, data-*, aria, a short CSS path; shadow DOM elements get >>> selectors), or Tag this page to propose a page from the URL the app is on (ids folded to :id). The editor shows a live count of what the rules match over the last 30 days, and the guide editor's highlight message counts the matching elements on the page.

Suggestions and AI tagging

Suggested lists the busiest paths (ids folded) and most-clicked elements of the last 7 days that no tag covers yet, each one click from being tagged. Propose tags sends those suggestions (patterns, selectors, visible text, counts; no user data) and the existing product areas to Claude through the project's Anthropic key (Scout settings, or the server's ANTHROPIC_API_KEY), which proposes a name, description, product area and — where it can do better — a sturdier rule for each. Nothing is saved until you pick proposals and apply them; missing product areas are created.

Product areas and core events

Product areas group pages and features (lists, adoption and exports filter by them). Core events are up to 10 pages, features or track events (custom event names) that show someone gets value from the product; adoption in the engagement score is measured on them.

Product Engagement Score

For the 30 days ending at the period end, the average of the parts that can be computed:

  • Adoption — the average share of core events each active visitor used (Σ visitors per core event ÷ (core events × active visitors)). Needs core events.
  • Stickiness — average daily active visitors ÷ monthly active (DAU/MAU), or average weekly ÷ monthly (WAU/MAU, a project setting).
  • Growth — compares the 30 days with the 30 before: new (first seen), recovered (active now, not in the previous 30 days, but earlier) and dropped (active before, not now). The quick ratio q = (new + recovered) ÷ dropped is reported, and the score is q ÷ (1 + q) × 100 — 50 when as many people joined or came back as dropped off.

Active means any page view, click or custom event; visitors are end users (identified or anonymous). The trend recomputes the score weekly for the last six weeks. Feature adoption lists every feature with the share of active visitors who used it.

Tag health

Tag health flags rules that stopped matching after a release and tags nothing relies on:

  • Possibly broken — at least 5 matches a week over the 4 weeks before, and fewer than a quarter of that in the last 7 days.
  • No data — nothing in 35 days (tags younger than a week are New).
  • Unused — not referenced by any guide, audience, saved funnel / retention report or core event.

The health score averages tags at 1 (healthy, new), 0.25 (no data) or 0 (broken), minus 0.25 for unused.

Using pages and features elsewhere

  • Funnels and retention: steps page:<id> (its page views) and feature:<id> (its clicks), in the Insights event picker under Tagged pages / Tagged features, and in the MCP run_funnel tool.
  • Audiences: rules Viewed tagged page / Clicked tagged feature (times in the last 30 days, e.g. at least 1), evaluated by the server when the SDK identifies a user — so guides target them through audience membership.
  • Guide editor: page restrictions can add a tagged page's URL rules (as * patterns), and element triggers can use a tagged feature's CSS selector.
  • Heatmaps: Tagged features outlines each feature on the page snapshot, coloured by its share of the page's clicks (falling back to the box of its clicks when the selector doesn't resolve).
  • Screenshots: upload an image (stored like article media under media/{projectId}/, kept by the unused-media sweep) or use a frame of the latest recording of the page (rendered from the recording).

Other services can call the matching core in apps/web/src/server/services/tagging-sql.ts: pageEventsSql(page), featureEventsSql(projectId, feature), featuresEventsSql(projectId, features), tagEventsSql(projectId, "page:<id>" | "feature:<id>") and resolveFeatureMatches(projectId, ruleSets) return conditions over unqualified "ProductEvent" columns.

Bulk create and update (CSV)

Export and Import on the Pages and Features tabs use the same columns: id, name, description, product_area, rules, core_event. A row with an id (or the name of an existing tag) updates it; other rows create tags. Rules go one per line in their text form (or a JSON array):

PagesFeatures
url /invoices/:idcss button[data-testid="export"]
!url /invoices/new (exclude)selector= #save && text~ Save
url /search && ?tab=peopleselector^ nav > · selector* save · glob *export*
regex ^/reports/.*$text= Export && tag button && href^ /reports
title~ Invoice · title= Billingcss #save && page /invoices/* · pageid <id> · platform ios

product_area is created by name when missing; core_event = yes marks it (up to 10). Every row is checked first; nothing is saved when any row is invalid, and Check is a dry run.

Permissions

Viewing needs workspace access (viewer). Creating, editing, merging, deleting, importing, settings, core events and AI tagging need Manage insights & alerts (insights.manage, editors by default).

API

Management API (session cookie):

Endpoint
GET/POST /api/v1/projects/:id/tags/pages, …/tags/featuresList with metrics (env, from, to, q, areaId, createdBy, `data=with\without, core=1`) / create
GET/PATCH/DELETE /api/v1/tagged-pages/:id, /tagged-features/:idOne tag
GET …/:id/detail · POST …/:id/merge · POST/PUT/DELETE …/:id/screenshotDetail · merge sourceIds · upload image / recording frame / remove
POST /api/v1/projects/:id/tags/previewLive match count for rules being edited
GET …/tags/suggestions · POST …/tags/aiSuggested pages / features · AI proposals
GET …/tags/health · GET …/tags/adoption · GET …/tags/engagement · GET …/tags/overlay?path=Maintenance · feature adoption · PES · heatmap overlay
GET/POST …/tags/areas, POST …/tags/areas/assign, PATCH/DELETE /api/v1/product-areas/:idProduct areas
PUT …/tags/core-events · GET/PATCH …/tags/settings · GET …/tags/optionsCore events · settings · names for pickers
`GET …/tags/export?kind=page\feature · POST …/tags/import?kind=`CSV
POST /api/v1/projects/:id/tagging-sessionsVisual tagging session

MCP: list_tagged_pages_features, get_tagged_page_feature, get_feature_adoption, get_engagement_score (see mcp.md).