This is the public record. Every release below is cut by CI from Conventional Commits, and each published version — with its own release notes and the exact files that shipped — is on npm under the @browsonic scope. The source repository is private, so npm is where the per-version detail lives.
SDK & adapters
The SDK is on the 3.27.x line — five releases in the first week of September. Sessions now end (30 minutes idle, destroy(), newSession()), a consent gate that has not answered yet holds events instead of dropping them, errors carry their own data and a link to the replay moment, Web Vitals explain themselves, and fifteen tuning knobs became internal constants so a mistyped number can no longer switch error tracking off.
errorDataon every error — the Error's own properties, HTTP status / url / method, a plain-object rejection reason — and_replay { seq, offsetMs }while the replay plugin records, so an error opens at its moment in the recording.- Web Vitals attribution: LCP element and resource URL, INP target and phases, CLS shift source, TTFB breakdown, plus long-animation-frame breadcrumbs (3.27).
newSession();captureError(error, { handled, mechanism });networkDetailwith method / url / status / duration on network failures; lifecycle breadcrumbs (hidden / visible / online / offline) (3.26–3.27).- Replay reports its mask policy (
X-Replay-Mask) so the dashboard can explain a grey recording instead of guessing (3.24). - A script-tag host can turn Web Vitals on with
trackWebVitals: true(3.23).
- Fifteen settings became internal constants (
flushIntervalMs,maxBatchSize,cooldownMs,maxQueueSize, …). They are still accepted, named once atinit(), and ignored — none had a per-deployment right answer and each one a host got wrong took the SDK down silently (3.25). - Repeats inside the 60-second dedup window are counted and stamped on the next admitted occurrence as
_suppressed; dropped events name their reason in the diagnostics. - Fewer requests: the config pull happens once an hour from a trusted cache, page views ride in batches against a current server, and event bodies are gzipped by default.
- A built-in session / CSRF cookie-name blocklist (
JSESSIONID,PHPSESSID,connect.sid,csrftoken,__Host-*,__Secure-*, …) that no configuration can widen. - Bundle: ~28 kB core / ~46 kB with every plugin, minified and gzipped (measured 27.66 / 46.22 kB on 3.27.0).
- Packages are published with
publishConfig.provenance: falsewhile the repository is private; every release attachesSHA256SUMSfor the tarballs instead — see the security page. - For every per-version diff, see the npm release history linked at the bottom of this page.
Four releases between 2 and 5 September that made the event self-describing: what the request was, which control the user touched, what the framework already knew, and a stack that actually reaches application code.
- 3.26 —
networkDetailcarries the request (method, url, status); Angular's defaultErrorHandleroutput is recognised;errorTypepreferserror.name; the interaction timeline names the field; storage snapshots skip the SDK's own keys. - 3.25 — user interactions get their own slots in the telemetry timeline; a route that resolves to where it already was is no longer a navigation.
- 3.24 — the replay plugin reports which rrweb masks were active, so the product can explain a grey screen.
- 3.23 —
trackWebVitals: truefor script-tag hosts; the identity channel (identify) is documented.
- Stack capture that reaches application code: V8 caps
Error.stackatstackTraceLimit(10 frames); the SDK raises it while capturing, and the raw stack string is redacted with the frame-aware rule so URLs stay readable (3.26). - One fault reports once from the framework adapters, the component is named, and action arguments no longer leak (3.23).
- Three collectors stopped reporting things that did not happen; page-view collection no longer collapses a list walk into one view (3.23).
- Published packages are loadable, tree-shake-safe and typed; stale build output no longer ships (3.23).
A sustained pass over what can leave the browser, plus the fix for a regression worth knowing about if you are pinned to an early 3.21.x.
sessionContext— app-defined session-level context with an explicitallowKeysegress policy. An allow list, not a deny list: forgetting to list a key over-redacts and you notice.
- Turkish national IDs (checksum-validated TCKN) and phone / MSISDN shapes are redacted before events leave the browser, matching the server-side scrubber instead of relying on it.
stack,stackFrames[]andlinkedErrors[]go through redaction; symbolication is unaffected because debug ids resolve from the raw frames.- Nested values past the depth bound now fail closed — an over-deep object becomes
[REDACTED_DEPTH_LIMIT]instead of egressing verbatim under scrubbed shallow levels. - Numbers reach the redaction pass at all:
{ msisdn: 905321110001 }used to bypass it because the value was not a string.
- ⚠️ 3.21.0 and 3.21.1 ship no Web Vitals at all. The page-hide flush ran before the plugin enqueued its sample, so LCP / INP / CLS never left the browser and the Performance page went to dashes. Fixed in 3.21.2 — upgrade if you are on either.
The SDK half of App Atlas. Route maps needed no integration; describing what a user was *trying to do* does, and this is that surface.
atlas.startTask({ task })— a no-throw handle withstep/complete/abandon/fail. Open tasks auto-end as abandoned on page dismissal; flood guards cap events per session and concurrent tasks.atlas.handoff.start({ intent })/close(outcome)— journey continuity across two apps of the same organisation. The ticket travels only in the URL fragment (#bhid=), so it never reaches a server log or a Referer header.- Screen context on page views — a stable screen id, an archetype (
list/detail/form/wizard/ …) and a zone, all optional and validated silently. - Task lifecycle events mirror into a live Session Replay recording as rrweb custom events, so playback lines up with task state.
- The es2015 IIFE build no longer throws at load on engines without regex lookbehind (Safari ≤ 16.3, older Chrome/Firefox) — precisely the legacy audience that artifact exists for.
Page-view telemetry stops being a URL list and starts being a navigation record — and turning it on becomes one flag.
atlas: true— one init flag replaces themanualPageViews+ adapter pairing. Organic tracking runs from first paint and the first templatedtrackPageView()from an adapter takes the channel over automatically.- Navigation Context — the trigger behind each navigation: the interacted element's accessible name, the trigger kind, navigation type, previous route and dwell time.
[data-browsonic-mask]subtrees yield nothing. - Screen names via
trackPageView(route, { name })or a[data-browsonic-screen]annotation. - A maintained self-hosted es2015 IIFE artifact for bundler stacks that cannot parse the ES2020 dist.
- Routes are normalised at source —
/orders/order12345collapses to/orders/order:id, so id-suffixed URLs stop minting unbounded distinct routes. - ⚠️
updateConfig()now refuses runtime changes to collector-snapshot keys such ascaptureDocumentTitle, instead of merging them as a silent no-op. The running collector never honoured them, so the old behaviour was a privacy control that lied. - Page-view sampling is session-consistent: a whole session is kept or dropped, replacing the per-navigation coin flip that put phantom edges in journey topology.
- A transient HTTP 429 no longer permanently loses the rate-limited batch.
- Session Replay's final dismissal flush ships synchronously instead of awaiting a gzip pipe whose reads never complete in a dying page.
Source-side control over what page-view telemetry is produced, and a ceiling on how much a replay recording can cost.
trackPageView(route)plus manual mode, so an adapter can send route templates rather than raw URLs.- Source-side route controls — patterns, a normalisation hook, hash-routing support and sampling.
- Session Replay idle / max-duration auto-stop and rrweb throttles.
- Error-event
url/referrergo through the full URL sanitiser rather than the weaker string redactor.
End-to-end source-map upload pipeline: build-tool plugins for Vite / Webpack / Rollup, a service-side ingest endpoint, and a dashboard view for symbolicated stack frames.
@browsonic/clisource-map upload command — drop-in build step.- Vite / Webpack / Rollup plugins emit and upload maps in CI.
- Dashboard surfaces symbolicated frames inline on the event timeline.
- Token CRUD + id-keyed list/delete deferred to v0.2.
Framework adapters reached parity on router instrumentation, navigation breadcrumbs and framework-specific helpers. Vue and Svelte fully completed the 0.3 milestone; Remix, Angular and Astro shipped a partial set.
@browsonic/vue— Pinia plugin and route hierarchy breadcrumbs.@browsonic/svelte— form-action capture and HTTP reporter.@browsonic/nextjs,@browsonic/remix,@browsonic/astro— router instrumentation + navigation breadcrumbs.@browsonic/angular— router-aware error handler.
First public release of the SDK. Previously distributed privately as @leguides/browsonic-sdk (latest internal version 2.1.1); the public API and /v1/events wire format are unchanged.
- Apache 2.0 licence (
LICENSE,NOTICE). - Public-facing docs:
README,CONTRIBUTING,CODE_OF_CONDUCT,SECURITY,BENCHMARKS. - GitHub issue and pull-request templates.
- npm provenance via sigstore on every published version.
- Package name:
@leguides/browsonic-sdk→@browsonic/sdk. - Registry: GitHub Packages → public npm.
- Repository:
leguides/browsonic-sdk→Sangaibisi/browsonic-sdk. - License: proprietary → Apache 2.0.
Platform
A same-day pass over the service and dashboard against the product's own rules. Every finding except e-mail delivery shipped to production on 5 September.
- Every paid plan is metered against its own monthly event ceiling. A lazy database read on the ingest path had collapsed every tenant to the Free limit; the fix is a scalar read guarded by a real-database test.
- Invitations work for people who already have an account: accept on the invitation page with your password (and authenticator code), or sign in and open
/accept-invite. Removed teammates can be invited again; the only owner of a workspace cannot leave it stranded. - Reads reach the full plan retention: Professional and Enterprise can look back 90 / 365 days in Issues, URLs, Events and Performance instead of 30.
- Session Replay recordings are stamped with the plan's retention on every plan change, and the SDK is told when a workspace's replay storage is nearly full or full so it stops recording what ingest would refuse.
- The Performance page groups by route template (
/orders/:id) and its headline error rate is the whole window, not the routes on the current page.
- Settings → Alerts: notification webhook endpoints (error storms, quota alerts, security events) with a signed test delivery.
- Atlas catalog page: the per-app task-mode switch.
- The Free plan holds two active API keys, so a key can be rotated without revoking the only one every deployed SDK carries.
- Refresh tokens are bound to the session that presents them (cookie-tossing defence); noise-filter rules are owner-only, audited, and their regular expressions are evaluated under a hard time budget.
The production database audit of 4 September, applied the next day: actor e-mail and IP in the audit log are encrypted at rest, the ingest tables carry row-level security like the rest of the schema, foreign keys got their indexes, and a broken source-map object key no longer answers 500.
- Audit log actor e-mail / IP encrypted at rest (existing rows rewritten once, idempotently).
- Row-level security on the ingest tables; foreign-key indexes across the schema.
- Kafka data on a named volume, ClickHouse system-log retention and memory limits, Redis credential rotation, MFA required on the platform console.
Call identify() in each of your applications and Browsonic stitches a single subscriber's activity across all of them into one ordered timeline — the error in the billing app and the failed step in the self-service app become the same story instead of two unrelated incidents. Professional-tier.
identify(subscriber)in@browsonic/sdk3.22.0 — the SDK half.- Journey view in the dashboard: one identity, ordered events across every app in the organisation.
- The SDK's
atlas.handoffticket links two apps within a single visit;identify()links them across visits.
Export the Atlas map into Figma as five pages — the route map, a retina screenshot wall, design tokens, wireframes and flow diagrams — with Figma Styles, Variables and a DTCG token file. Re-importing is idempotent, so an export can be repeated as the app changes without duplicating pages.
- A Figma plugin fed by a single-use, TTL-bounded export ticket.
- Styles + Variables + DTCG tokens, not just flattened images.
- No other session-replay product exports to Figma; this is the one place your production reality and your design source of truth meet.
The route graph shows where users went. The Task Map shows what they were trying to do and whether they finished: named tasks with per-step completion, abandonment and failure rates, built from the SDK's task-lifecycle events. Professional-tier.
- Task definitions with steps, outcomes and completion / abandonment / failure rates.
- Entry-source breakdown, including arrivals via a cross-app hand-off.
Alert rules on error volume and rate, delivered by email and webhook. Included from Starter upward — not gated behind an enterprise plan.
- Rule builder with thresholds and windows; email + webhook delivery.
- Widget / noise rules so a known-loud source can be filtered without silencing everything.
- Slack, PagerDuty and Linear are not built yet, so they are not advertised as available.
A fog-of-war map of your application, built server-side from captured page views — zero SDK changes required. It renders your real route graph and, via the screenshot worker, a thumbnail of each page. Professional-tier; it shows up as Atlas in the dashboard sidebar.
- Route graph derived on-read from page-view telemetry — no integration work.
- Per-node screenshot thumbnails via the Atlas screenshot worker.
DOM-level session recordings that play back next to the stack trace. Opt in via sessionReplayPlugin from the @browsonic/sdk/replay sub-path, registered before init(). Professional-tier, with privacy-first masking on by default (Sentry parity).
@browsonic/sdk/replay— opt-insessionReplayPlugin.- Masking on by default:
maskAllText,maskAllInputs,blockAllMedia— password inputs always masked. - Dashboard playback plus an Admin settings page for the sample ceiling.
Release process
The SDK monorepo retired semantic-release in favour of release-please. PR-based releases, signed commits, and OSS-protection-friendly automation.
- Release flow now opens a release PR per package; merging it publishes.
- Conventional Commits still drive version bumps and changelog entries.
- CI publishes via
release.ymlwith NPM_TOKEN and provenance.
Full release history
Every published version of every @browsonic/* package has its own entry on npm:
- npm version history — @browsonic/sdk — every published version, with the files and integrity hash that shipped. Releases from 3.21.0 onwards carry no sigstore provenance attestation; the security page explains why, and what to check instead.