Lightweight, privacy-first browser analytics — setup, configuration, data attributes, and collection control
Last updated September 14, 2026
Browser Analytics
Flaggr includes a lightweight browser analytics script that captures Web Vitals, page views, and user interactions — and automatically correlates them with active feature flag variants. This lets you measure real-world performance impact of every flag change.
The script is under 5KB gzipped, uses no cookies, collects no PII, and respects Do Not Track by default.
Quick Start
Add the script tag to your HTML:
<script
src="https://cdn.flaggr.dev/a.js"
data-site-id="proj_abc123"
defer
></script>That's it. The script automatically collects:
- Web Vitals — LCP, CLS, INP, TTFB, FCP
- Page views — initial load and SPA navigations
- Sessions — anonymous session tracking via
sessionStorage - Flag variants — auto-detected from Flaggr SDK globals
Events are batched and sent to https://ingest.flaggr.dev/e via fetch with keepalive, falling back to navigator.sendBeacon on page unload.
Configuration
All configuration is via data-* attributes on the script tag. No JavaScript API is needed.
Required attributes
| Attribute | Description |
|---|---|
data-site-id | Your project ID. Used to associate events with your Flaggr project. |
Optional attributes
| Attribute | Default | Description |
|---|---|---|
data-endpoint | https://ingest.flaggr.dev/e | Custom analytics ingestion endpoint |
data-track-clicks | false | Enable click tracking on interactive elements |
data-track-errors | false | Enable JavaScript error tracking |
data-track-scroll | false | Enable scroll depth milestone tracking |
data-respect-dnt | true | Respect the browser's Do Not Track setting |
data-debug | false | Enable [flaggr:analytics] console logging |
Full example
<script
src="https://cdn.flaggr.dev/a.js"
data-site-id="proj_abc123"
data-endpoint="https://ingest.flaggr.dev/e"
data-track-clicks="true"
data-track-errors="true"
data-track-scroll="false"
data-respect-dnt="true"
data-debug="false"
defer
></script>Event Types
Page views (always on)
Captured on initial page load and SPA navigations (History API). Each event includes:
path— URL pathtitle— Document titlereferrer— Referring pageviewportWidth,viewportHeight— Browser viewport dimensionsconnectionType— Network connection type (if available)renderServerMs,renderNetworkMs,renderTotalMs— Backend-aware timing derived from the document navigation entry or recent same-origin API responsesrenderServerTimings— ParsedServer-Timingspans for the page load or correlated backend requestsrenderBackendRequests— Recent same-origin/api/*responses that contributed to an SPA navigation, including status, duration, request ID, and parsed server timing spans
Web Vitals (always on)
Collected via PerformanceObserver. Each vital includes a numeric value and a rating:
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP | ≤ 2500ms | ≤ 4000ms | > 4000ms |
| CLS | ≤ 0.1 | ≤ 0.25 | > 0.25 |
| INP | ≤ 200ms | ≤ 500ms | > 500ms |
| TTFB | ≤ 800ms | ≤ 1800ms | > 1800ms |
| FCP | ≤ 1800ms | ≤ 3000ms | > 3000ms |
Click tracking (opt-in)
When data-track-clicks="true", captures clicks on interactive elements:
selector— CSS selector of the clicked elementtag— HTML tag nametext— Button/link text (truncated to 100 characters)trackId— Value ofdata-trackattribute, if set on the elementhref— Link URL, if applicable
Use data-track="signup-cta" on elements to give them stable identifiers for analytics.
Error tracking (opt-in)
When data-track-errors="true", captures unhandled JavaScript errors and promise rejections:
message— Error messagesource— Source fileline,column— Error locationstack— Stack trace (truncated to 500 characters)
Scroll depth (opt-in)
When data-track-scroll="true", captures scroll depth milestones at 25%, 50%, 75%, and 100%. Uses requestAnimationFrame throttling for minimal performance impact.
Flag Variant Correlation
The analytics script automatically detects active feature flag variants and attaches them to every event. This enables per-variant performance analysis in the Analytics Dashboard.
Detection order
window.__FLAGGR_BOOTSTRAP__— SSR-injected flag values (set by Next.js server components)window.__FLAGGR_FLAGS__— Live SDK state (updated after client-side evaluation)flaggr:flags-changedevent — Custom event dispatched when flag values change
The Flaggr Web Provider automatically populates these globals. If you use a custom provider, expose flag values on window.__FLAGGR_FLAGS__ and dispatch a flaggr:flags-changed CustomEvent with { detail: Record<string, unknown> } when values change.
Dynamic Collection Control
Collection can be controlled remotely via the _flaggr_analytics feature flag, allowing you to adjust what data is collected without redeploying.
String levels
Set the _flaggr_analytics flag to one of these string values:
| Level | Collects |
|---|---|
"off" | Nothing (sampling = 0) |
"minimal" | Page views + Web Vitals |
"standard" | Page views + Web Vitals |
"detailed" | Page views + Web Vitals + clicks + errors |
"full" | Everything (page views + vitals + clicks + errors + scroll) |
Object config
For fine-grained control, set _flaggr_analytics to a JSON object:
{
"pageviews": true,
"vitals": true,
"clicks": false,
"errors": false,
"scroll": false,
"sampling": 1.0
}Sampling
The sampling field controls probabilistic collection:
0— Block all events1— Collect all events (default)0.5— Collect from 50% of sessions
Sampling is decided once per session and remains stable until the page is reloaded.
Elevation rules
The data-* attributes on the script tag define a static floor. The _flaggr_analytics flag can only elevate collection above this floor, never reduce below it. For example, if data-track-clicks="true" is set, clicks will always be collected regardless of the flag value.
Transport & Delivery
Events are queued in memory and flushed:
- Every 5 seconds (periodic flush)
- When 20 events accumulate (queue size limit)
- On page unload via
navigator.sendBeacon()
Failed requests are retried once with a 1-second backoff. The transport uses fetch with keepalive: true for reliability during page transitions.
Privacy
The analytics script is designed to be privacy-friendly by default:
- No cookies — Session IDs use
sessionStorageonly (scoped to tab, cleared on close) - No PII — Never collects user IDs, emails, names, or IP addresses
- No third-party sharing — All data stays in your project's database
- Do Not Track — Respects
navigator.doNotTrackby default (opt out withdata-respect-dnt="false") - Country-level geo only — Derived from Cloudflare edge headers, not IP geolocation
- GDPR-friendly — Minimal data collection with anonymous sessions
Ingestion Pipeline
Events flow through a Cloudflare Worker at ingest.flaggr.dev/e:
- Validation — Payload size, event count, required fields
- Authentication — Site ID verified against project registry
- Enrichment — Country, browser, OS, device from request headers
- Session upsert — Page count incremented, duration calculated, flags merged
- Bulk insert — Valid events written to
analytics_eventstable
The worker responds with 202 Accepted and returns { accepted: N, rejected: M }.
Backend Performance and SLOs
Browser analytics can now correlate render timing with backend response metadata, but it should not be your SLO source of truth by itself.
- Use browser analytics to answer user-experience questions such as "was this slow render caused by backend work or client work?"
- Use Flaggr's server-side Prometheus and OpenTelemetry metrics to define backend latency and availability SLOs
- Emit meaningful
Server-Timingheaders from your document and API responses so the browser analytics payload can carry backend spans alongside page load data
Next Steps
- Analytics Dashboard — Interpret vitals, flag impact, and session data
- Analytics API Reference — Query analytics data programmatically
- Analytics & A/B Testing — Measure experiment outcomes with analytics