Browser Experience
Browser Experience provides narrow, developer-labelled click autocapture: after the observer
starts, it records clicks on controls with stable data-poolstatis-label values, normalized
coordinates, scroll milestones, registered section exposures, and coarse client error types.
Those signals power bounded click/interaction heat maps and a per-session interaction timeline.
This observer is deliberately not broad arbitrary-DOM autocapture or full error tracking. It does not collect page text, input values, CSS selectors, raw URLs, query strings, cursor movement, error messages, or stack traces. Its timeline shows ordered labelled signals rather than reconstructing the page. Poolstatis also ships a separate explicit-consent Session Replay source module with a stricter masking, retention, storage, and sandboxed-playback contract.
Browser analytics collection
The separate @poolstatis/sdk/browser module starts collecting immediately after start().
Poolstatis does not require a consent state and does not inspect Global Privacy Control.
Integrating products own any notice, consent, pause, or deletion workflow. This never expands
the fixed property allowlist.
On its own public poolstatis.xyz site Poolstatis counts anonymous
visitors, sessions, allowlisted page categories, labelled CTA clicks, scroll milestones,
bounded campaign source, primary language, timezone and coarse device/browser/OS,
viewport/screen buckets. The public site does not render a global analytics-control footer.
Its current Browser Analytics/Experience integration does not send exact dimensions, form
values, page text, replay data, full URLs/query strings, full referrers, raw IP, precise location,
stacks, pointer paths, email or direct identifiers. That site configuration is separate from the
product's opt-in replay module and is not a claim of legal compliance.
1. Create a semantic surface
Use MCP so the surface has a real purpose before any interaction is stored:
create_experience_surface({
project: "acme-product",
key: "marketing",
name: "Marketing site",
purpose: "Find which public-page sections lose qualified visitors before setup.",
status: "active"
})
Register canonical route keys separately:
register_experience_route({
project: "acme-product",
surface: "marketing",
route: { key: "home", name: "Landing home", path_pattern: "/" }
})
2. Mark meaningful controls
The observer ignores arbitrary clicks. Label only controls that correspond to a product or content decision:
<section data-poolstatis-section="hero">
<a href="/docs/quickstart" data-poolstatis-label="hero.open_docs">
Read quickstart
</a>
</section>
Labels must be stable semantic keys. Never put user text or identifiers in
data-poolstatis-label.
3. Start only when the host policy allows
import { createClient } from '@poolstatis/sdk';
import { BrowserExperience } from '@poolstatis/sdk/experience';
const client = createClient({
url: 'https://analytics.example.com',
ingestKey: 'pk_write_only',
});
const experience = new BrowserExperience({
client,
surface: 'marketing',
distinctId: anonymousVisitorId,
sessionId: anonymousSessionId,
route: 'home',
version: import.meta.env.VITE_RELEASE_SHA,
});
await experience.start();
Use a finite route vocabulary; never pass location.href or location.pathname. If the
host chooses to pause collection, call experience.stop() so unsent interaction data is
discarded. Capture is chunked to at most
25 signals per request, held within a bounded queue, and guarded by a default
120-signals/minute browser limit.
4. Ask the agent
get_visual_experience_mapoverlays normalized clicks, scroll reach and named-section drop-off on an immutable desktop/mobile release snapshot.compare_visual_experiencecompares two bounded route/version/device cohorts without claiming causality.get_experience_sessionreturns one known session timeline.
The primary map is valid only when the project has an exact snapshot matching
surface + route + version + device + env; events then also match its viewport and document
dimensions. The human UI renders the overlay. MCP returns bounded aggregates and snapshot
metadata, not the image. Without an exact snapshot, normalized aggregate coordinates remain a
secondary fallback: they can mix layouts and devices unless the query is filtered and must
not be interpreted as layout-accurate.
Snapshot upload accepts raw PNG/WebP bytes up to 5 MiB; the server does not fetch a caller-supplied URL. Self-hosted backups must preserve the database and snapshot artifact volume together.
Treat these as observational signals. A click pattern can suggest a usability problem, but it does not prove why a visitor behaved that way.