Two drop-in integrations that reuse the SDKs you already run. Keep your
existing @sentry/* client and just repoint its DSN at us for
Sentry-style error grouping. Keep Google's web-vitals library
and beacon its readings to us for Core Web Vitals. No re-instrumentation,
no second agent, no per-seat bill — errors and vitals land in the same
Logs and metrics pipeline you already use.
Keep the free, open-source @sentry/* SDK exactly as it is.
Change one value — the DSN — to point at us. The unmodified SDK then
ships its error events to us instead of Sentry, and they flow straight
into the Error-tracking view you already have.
https://<obs_PAT>@api.24observe.com/<project>
<obs_PAT> is a 24Observe Personal Access Token with the logs:write scope. Like a normal Sentry DSN key, it's a public, write-only credential — safe to ship in your application bundle. It can write errors; it can't read your data.<project> can be any identifier you like — it labels the source of the events.
Under the hood, the unmodified SDK POSTs its envelope to
/api/<project>/envelope/?sentry_key=<obs_PAT> —
the standard Sentry envelope endpoint. You don't call this directly; the
SDK does, the moment you set the DSN.
import * as Sentry from '@sentry/node'; // or @sentry/browser, etc.
Sentry.init({
dsn: 'https://obs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@api.24observe.com/my-app',
});
// Then capture as usual — no other changes.
Sentry.captureException(new Error('something broke')); This works with any Sentry SDK — Node, browser, Python, and the rest — because they all speak the same envelope protocol. Initialize with the 24Observe DSN and your existing capture calls just work.
We translate each Sentry error event into one of our error-level log
events. The message becomes "ExceptionType: value" — the
same string Sentry groups on — so it fingerprints and groups exactly the
way you're used to. From there, everything downstream works unchanged:
The result: Sentry-style error grouping inside the same Logs pipeline you already pay for, with no separate per-seat bill. Grouped errors surface in the dashboard under Logs → Error tracking.
Keep Google's free, open-source web-vitals library on your
site. Report its readings to us and they become first-class metrics —
queryable and alertable like anything else. No new SDK, no bundle bloat.
POST https://api.24observe.com/api/v1/rum/vitals?key=<obs_PAT>
<obs_PAT> is a Personal Access Token with the
metrics:write scope — again a public, write-only key, safe to
ship in the page. The standard pattern is
navigator.sendBeacon(url, JSON.stringify(payload)), which
fires reliably even as the page is unloading.
The endpoint accepts three shapes, so you can wire it up however the library hands you data:
{ service, url, metrics: [ { name, value, rating?, id?, navigationType? } ] }onLCP / onCLS / … callbacks hand you, so you can forward each reading as it arrives.LCP, FCP, INP, FID, TTFB — recorded in milliseconds.CLS — the unitless cumulative layout-shift score.
Each reading becomes a metric named web_vitals.lcp,
web_vitals.cls, and so on — queryable and alertable like any
other metric in 24Observe. service defaults to the URL host
when omitted, so a single line of config tags every reading by site.
202.sendBeacon is a simple request and needs no CORS preflight — it just works from any page.fetch(url, { keepalive: true }) reporter from any origin works too, if you prefer fetch over beacon.import { onLCP, onCLS, onINP, onFCP, onTTFB } from 'web-vitals';
const URL = 'https://api.24observe.com/api/v1/rum/vitals?key=obs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
function report(metric) {
// metric = { name, value, rating, id, navigationType } from web-vitals
navigator.sendBeacon(URL, JSON.stringify(metric));
}
// Wire each Core Web Vital to the reporter.
onLCP(report);
onCLS(report);
onINP(report);
onFCP(report);
onTTFB(report);
Prefer to batch? Collect the callbacks into an array and send a single
{ service, url, metrics: [...] } beacon on
visibilitychange — the endpoint accepts that shape directly.