Skip to content
$ obsprov1 · MITGitHub

docs / getting-started

Web Monitor

Multi-tenant front-end monitoring: a browser SDK, a guarded ingest endpoint, and a GraphQL dashboard of issues, trends and alerts.

SaaS platform · Open source · MIT · 2025 – 2026

install.htmlsdk.js · 0 dependenciescopy
<script type="module">  import ObsPro from "/sdk/index.js";   const monitor = new ObsPro("obs_live_4f2c…", {    baseUrl: "https://obs.example.com", // batches POST to /ingest    sampleRate: 0.25, // performance only — errors are never sampled    slowRequestMs: 3000, // also report slow successful calls  });   const flow = monitor.startFlow("checkout");  flow.step("address"); // … later  flow.complete(); // or fail("card_declined")</script>
obspro --status
Monitoring layers
4performance, errors, flows, custom
Tests
236175 backend, 38 SDK, 23 dashboard
Default ingest cap
6000/minevents per key
Alert conditions
4each with cooldown

01 · Ingest

#Four guards before anything is written

A plain POST to /ingest — no preflight, and what sendBeacon sends on page hide. Each guard rejects a batch before it costs a database write.

one batch≤ 60 KB · sendBeacon-safe
01

API key → tenant

rejects an unknown key

02

Origin allowlist

rejects any other origin, or none

03

Rate limit

rejects a key over budget — charged per event, junk included

04

Batch validation

rejects over 500 events, or any field over its cap

ingestBatch8 writers, else 503

02 · Issues

#Errors group into issues

Each error hashes to a signature with hourly counts and a status.

2844

errors ingested, issues to look at

  1. Newfirst seen
  2. Resolvedclosed by a person
  3. Regressedreopened by the next matching error
ObsProlocalhost:5174 · seeded tenant
Issues — errors grouped by signature

Issues — errors grouped by signature

284 errors grouped into 4 issues, each with a 24-hour trend.

03 · Alerts

#Evaluated on a timer, never on ingest

Otherwise an error spike becomes its own denial-of-service.

a burst of

500

errors costs

1

evaluation

RuleWatches
NewIssuean issue seen for the first time
ErrorSpikeerror count against a threshold
ErrorRateerrors as a share of events
SlowPageLoadpage load time against a threshold

Each rule has a threshold and a cooldown, so a persistent condition alerts once. Windows under 20 events or 5 samples are ignored.

04 · Console

#What the dashboard shows

A local Docker run with a synthetic storefront reporting through the SDK.

ObsProlocalhost:5174 · seeded tenant
Frontend overview

Frontend overview

900 events: error rate, load time and the slowest page.

ObsProlocalhost:5174 · seeded tenant
Core Web Vitals at P75

Core Web Vitals at P75

LCP, FCP, CLS and TTFB at P75 across 616 page loads.

05 · Architecture

#The whole system, drawn

Fig. 1

The ingest path, and the work kept deliberately off it

Errors collapse to one atomic upsert per hash, so concurrent reports add up instead of racing; a retried batch is recognised by its id and skipped. Dashed lines run on the timer, off the ingest path.

Fig. 2

The stack, layer by layer

L01Browser SDKCollect, batch, survive the networkBounded queue, flushed by size, interval or page hideRepeated errors capped per page; only performance is sampledFailed flushes retry the same batch id, honouring Retry-AfterL02Node APIREST /ingest for the SDK, /graphql for the dashboardEnv validated at boot; GraphQL depth limited before resolversRate limits shared through Redis, falling back to memory/health skips the database, /ready checks itL03Service layerDomain logic behind the resolversPrisma over MySQL; uniqueness enforced by the databaseRefresh token in an httpOnly cookie, rotated; a replayed one revokes every sessionL04SchedulerWork kept off ingestOne leader per cluster, elected by a MySQL lease rowAlert sweep on an intervalRetention sweep in bounded chunks; issues exemptL05DashboardReact SPA over the same APIOverview, issues, performance, events and alerts viewsTypes generated from the schema; saveable layouts per user