Current as of July 30, 2026.This article reflects the public Poolstatis contracts available on its publication date.

Privacy-bounded browser analytics immediately collects a predefined set of product signals and excludes page content by design. The browser sends stable route keys, developer-labelled interactions, normalized coordinates, scroll milestones, coarse error types, and limited campaign fields. It does not send DOM snapshots, form values, page text, CSS selectors, stack traces, or raw URLs. As of July 2026, this is the contract used by the optional Poolstatis Browser Experience module.

The boundary is useful for product teams because most interface decisions do not require a copy of the interface. A team can learn whether people reach the pricing section, activate a setup CTA, complete a route sequence, or repeatedly hit a labelled control without recording what they typed or which private query parameters appeared in the address bar.

Privacy-bounded analytics is narrower than general session replay. That is a feature, not a euphemism. The team should know in advance which questions the system can answer and which questions require another method.

What is privacy-bounded browser analytics?

Privacy-bounded browser analytics is an allowlist-based measurement design. The client starts immediately and sends only named fields that have a product purpose; the server rejects or ignores data outside that contract.

The design has three parts:

  1. A declared surface. The team registers a stable surface key such as pricing, checkout, or workspace_setup, plus a purpose explaining which interface decision the signals support.
  2. A labelled client. Important controls receive developer-owned labels such as pricing.start_cloud or setup.copy_mcp. Routes use finite keys such as docs_quickstart, not the browser’s full URL.
  3. A narrow wire format. The SDK serializes supported interaction types and drops everything else. The payload is not an arbitrary property bag for page content.

This differs from a policy document placed on top of broad capture. In an allowlist system, the forbidden fields are absent from the API model and from the client implementation. A developer cannot accidentally enable DOM capture through a configuration switch because there is no DOM capture path.

The registered purpose keeps the measurement honest. “Capture the pricing page” is not a purpose. “Decide whether the primary Cloud CTA remains discoverable after the pricing layout change” names the surface, the product change, and the decision.

What should the browser collect?

The browser should collect the smallest stable signals that answer the declared product question. Good signals survive visual refactors, avoid user-authored content, and map to a finite vocabulary that a reviewer can inspect.

SignalSafe shapeProduct question it can support
Route visitroute: "docs_quickstart"Do sessions reach the setup guide?
Labelled clicklabel: "hero.start_cloud"Which intentional CTA receives interaction?
Normalized positionx: 0.72, y: 0.31 on a declared surfaceWhere do clicks cluster within a known layout?
Scroll milestonedepth: 75How far do sessions progress through the page?
Coarse error typetype: "resource"Is a known surface experiencing a broad client failure class?
Canonical campaign contextbounded utm_source, utm_medium, utm_campaign, utm_term, utm_contentWhich landing context is associated with later activity?

The route key should be finite. A public documentation site might use docs, docs_quickstart, and docs_mcp_tools. It should not send /docs/quickstart?token=...#step-4. The first form supports aggregation and review. The second can contain secrets, identifiers, arbitrary search text, and cardinality that makes analysis unstable.

Interaction labels should describe product intent rather than element structure. hero.start_cloud remains meaningful if the control changes from an <a> to a button or moves into a different container. div:nth-child(3) > a encodes the DOM, breaks during refactors, and tells a product reviewer almost nothing.

Normalized coordinates can support a click map when the surface is registered and the event refers to an actual click. The interpretation must stay narrow: a click map shows click locations, not gaze, attention, or cursor intent. A region with no clicks may be invisible, irrelevant, or simply outside the current sample.

What should never be in the payload?

The payload should never include raw page content or open-ended browser state when the product question can be answered with a stable label. Exclusions should be documented in code, tests, and public product copy.

The Poolstatis boundary excludes:

  • DOM snapshots or serialized elements;
  • text content from the page;
  • form values and input values;
  • CSS selectors and XPath;
  • raw URLs, query strings, and hash fragments;
  • full user-agent strings;
  • stack traces and raw error messages;
  • cursor movement presented as attention;
  • session video or visual replay.

Each exclusion closes a concrete risk.

DOM and text capture can copy personal information that the analytics team never intended to receive. Form values can include credentials, health details, payment data, or customer messages. Raw URLs often carry email addresses, search terms, invite tokens, and internal object IDs. Stack traces and error strings can include request data. Full user-agent strings increase fingerprinting detail without being necessary for most product decisions.

Selectors create a second problem beyond privacy: they tie historical data to implementation structure. A labelled control preserves intent. A selector preserves where the element happened to sit in one release.

Removing these fields reduces forensic power. A privacy-bounded system cannot replay the exact screen a user saw or read the error that appeared. Teams should acknowledge that limit. When a decision requires qualitative context, use user research, support evidence, targeted debugging, or a separately governed replay system with its own access and retention controls.

How do stable labels replace DOM capture?

Stable labels replace DOM capture by moving meaning into developer-reviewed instrumentation. The application declares which interactions matter and names them in product language. The analytics system stores the label, route key, timestamp, actor or session identifier, and supported coarse context.

Example:

<Link
  to="/signup"
  data-poolstatis-label="pricing.start_cloud"
>
  Start Cloud beta
</Link>

The label answers “which product action was offered?” without sending the anchor text, surrounding markup, or destination query string. A second label such as pricing.self_host separates the managed and source-available paths even if both controls share the same CSS class.

Labels should meet four conditions:

  1. Finite. The label comes from a reviewed vocabulary, not from user input or runtime text.
  2. Stable. The label survives refactors while the product action stays the same.
  3. Specific. The label distinguishes actions that lead to different decisions.
  4. Purpose-linked. The labelled interaction belongs to a declared surface with a measurement purpose.

Do not generate labels from button text. Localization, experiments, and copy edits would fragment the series. Do not include account IDs or route parameters in labels. Identity and context belong in separate, bounded fields.

A labelled system asks engineering to make a small choice during implementation. That cost is useful. It forces the team to decide whether an interaction is worth collecting and which decision will use it. Autocapture feels cheaper at first, then transfers the work to analysts who must reverse-engineer anonymous selectors after every redesign.

How should a click map be described?

A privacy-bounded click map aggregates normalized click coordinates for one declared surface. It does not measure eye movement, hesitation, or mouse movement. The map can show that sessions clicked an unexpected region or missed the intended CTA, but the team should pair the map with labelled click counts and route progression before changing the interface.

Key facts should exist as text, not only as a heat image. A useful report says: “In 126 sessions, 41 clicks landed in the secondary setup region and 18 clicks reached setup.copy_mcp.” The image helps a person scan the layout, while the text makes the evidence accessible to agents and reviewers.

Poolstatis starts collection immediately and does not impose a consent gate. The integrating product decides whether it needs a notice, consent flow, pause control, retention rule, or deletion workflow for its own customers and jurisdictions.

A practical integration starts directly:

const experience = createBrowserExperience({
  surface: 'workspace_setup',
  route: 'setup',
  distinctId: stableActorId,
});

experience.start();

If the host chooses to pause collection, it can call stop() and detach listeners. That host-owned choice does not broaden the payload: Poolstatis still excludes form values, session video, and other fields outside the allowlist.

Identity needs a separate decision. Anonymous session analysis may use a generated identifier with bounded lifetime. Cross-device or account analysis requires a stable actor link and a clear product reason. Raw IP addresses should not become a substitute identity key. The browser client should not receive trusted server tokens; it uses a write-only ingest key scoped to the project and environment.

Campaign attribution also stays bounded. Canonical UTM fields can be captured from the landing context and associated with later activity in the same supported scope. That association does not prove the campaign caused the outcome. Multi-touch attribution, view-through attribution, and identity stitching require additional evidence that a basic browser SDK does not provide.

What can and cannot be concluded?

Privacy-bounded browser analytics can support decisions about discoverability, route progression, labelled interaction frequency, scroll reach, coarse client failure patterns, and bounded campaign association. It cannot reconstruct a session, read user intent, or prove why a person acted.

Supported conclusionUnsupported upgrade
hero.start_cloud received more clicks than hero.read_docsThe Cloud CTA persuaded more users
62% of sessions reached the 75% scroll milestone62% read the page
Clicks clustered beside the intended controlUsers were confused by the layout
Sessions with utm_source=docs_partner reached setup more oftenThe partner caused higher activation
A coarse resource error appeared after a releaseThe exact client exception and affected content are known

The right-hand claims may become testable through experiments, qualitative research, support logs, or targeted technical diagnostics. They do not follow from the browser signals alone.

Sample scope should accompany every report. If collection was paused for part of the audience or date range, the report describes only the observed sessions. If an interaction label was added halfway through the time window, the before-and-after counts are not comparable. If mobile and desktop layouts differ, normalized coordinates should be segmented by a coarse device class before interpretation.

The system should expose these limits to coding agents. An agent that receives click cells without the surface purpose, sample size, route key, collection scope, and supported interpretation may produce a polished but false UX conclusion.

Privacy review checklist

Run this checklist before enabling browser analytics on a new surface:

  • The surface has a stable key, readable name, and decision-oriented purpose.
  • Collection starts immediately after the SDK starts.
  • Any host-owned pause and deletion workflow is tested separately.
  • Routes use finite keys rather than raw paths, query strings, or hashes.
  • Important interactions use developer-owned labels that contain no user input.
  • The payload schema has no DOM, text, form value, selector, stack, or full URL field.
  • Browser code uses only a write-only project and environment ingest key.
  • Click maps are described as clicks, not gaze or attention.
  • Reports state sample size, collection scope, date window, and label coverage.
  • UTM data is described as association unless a valid experiment supports causation.
  • Product teams know which questions require research, replay, or targeted debugging instead.

The current Poolstatis contracts are documented in Browser analytics, Browser Experience, and the HTTP integration guide. The source-available SDK makes the exclusions inspectable: the privacy boundary is a code path and schema, not only a promise.