The score your users gave you
Core Web Vitals at p75 from real sessions — LCP, INP, CLS, TTFB — weighted into one score that is computed server-side, versioned, and never influenced by the client.
Every page they load is a measurement you already own. Ritim collects it, ties it to the build it came from — and to the pull request that has not merged yet — and tells you which one made things worse. Cookieless, and 4 kB on the wire.
No cookies · no persistent identifiers · no surprise invoices
Either one is the whole install. The key is public — it names a project, it authorises nothing.
CDNone tag in your head, no build step
<script
async
src="https://cdn.ritim.io/v1/browser.min.js"
data-project-key="P-ABC123"
></script>npmbundled with your app
$ npm install @ritim/browser-sdkimport { init }from '@ritim/browser-sdk';
init({ projectKey: 'P-ABC123' });No router plugin, nothing to call per navigation, and nothing to configure for an SPA. The tag is async, and buffered performance entries mean loading late costs almost nothing.
Ritim tells one deployment of a Next.js or Nuxt app from the next on its own, so every build you ship already arrives as its own release.
That separates one deploy from the next, but it does not carry a name you would recognise. To read v2.4.1 in the dashboard instead, declare one — and anything you declare wins:
init({ release: 'v2.4.1' })<meta name="rum-release" content="v2.4.1">data-release="v2.4.1"Anywhere else — a plain HTML page, a framework we do not recognise — Ritim still tells one deploy from the next, and marks that release as inferred rather than declared. A version worked out for you and a version you chose are not the same claim, so the dashboard never has to pretend they are.
Not a lab machine on a fibre line. Theirs, wherever they are.
3.9s
184ms
0.02
Route changes count too. The SDK detects same-document navigations itself — it wraps pushState, listens for popstate, the Navigation API and bfcache restores — and pins the path when the measurement starts, so a view is never filed under the page that came after it.
About two seconds after the view settles — not when the tab closes.
Waiting for page hide loses every measurement to a crash or a killed tab, so the SDK waits for a quiet period instead — no new LCP candidate, layout shift or interaction — and page hide is only the backstop. INP travels as its own event, because the worst interaction of a view is usually not final when the page settles.
Scored server-side, from what your visitors actually recorded.
The same comparison runs on branches: every preview build a pull request produces is scored against what is live, because merging it replaces what is live.
Awareness
Synthetic tests measure one machine on one connection. Ritim measures the ones you have — every device, every network, every route — and keeps the reading honest: sampled rows are weighted back up, and a metric nobody recorded stays empty rather than being scored as perfect.
Performance score
Weighted from the vitals your visitors actually recorded — not a lab run on a machine nobody uses.
0s
0ms
0
LCP p75 by release
Hover a marker to see what shipped.
Image CDN rollout
LCP p75 1.9s → 3.5s
Hotfix: hero preload restored
Release candidates
Preview builds, scored against what is live.
3 candidate builds measured on preview
5 candidate builds measured on preview
1 candidate build measured on preview
Core Web Vitals at p75 from real sessions — LCP, INP, CLS, TTFB — weighted into one score that is computed server-side, versioned, and never influenced by the client.
Each (domain, route) pair with its own vitals, page weight and score. Find the one template that is dragging the whole site down instead of guessing from an average.
Needs work is the triage view: the pages failing a metric, worst first, with the reading that failed and the traffic behind it. The answer to "where do I start on Monday".
Desktop and mobile split apart, because they are two different products. A p75 that mixes them tells you about neither.
Staging, preview and production hosts under one project, each with its own history — grouped where it helps, never averaged where it lies.
Run a PageSpeed Insights audit on a domain, mobile and desktop, and read it beside the real-user numbers — clearly labelled as Google's hardware, never mixed into your p75.
Release awareness
Every measurement carries the build it came from — identified for you on Next.js and Nuxt, or set to a name you chose. Ritim then tells you when each release first appeared in the wild, how much traffic it has seen, and whether the numbers moved — so "the site feels slower this week" becomes "v2.4.0, two days ago, LCP p75 1.9s → 3.5s".
shop.acme.com
Ships every 2.4 days
From deploy to verdict
You ship
A build goes out. On Next.js and Nuxt, Ritim identifies the deployment on its own.
release: identified
Someone loads it
A real visitor, on their own device and their own network.
4 kB · no wiring
It reports itself
The SDK waits for the view to settle, then sends — it does not wait for the tab to close.
~2s quiet period
You know
The release exists in Ritim because that measurement arrived, and it is scored against what was live before it.
score −21 vs v2.3.9
Footprint
A performance tool that costs performance is a contradiction. The browser SDK ships as a single minified file of about 10 kB — roughly 4 kB gzipped, 3.7 kB brotli — and that is everything: vitals collection, INP tracking, sampling, navigation detection and transport.
Measured from the build that is on the CDN right now — not a target, and not the number before tree-shaking.
Its only import is the shared event schema. No framework, no polyfill bundle, nothing to keep in step with your build.
Loaded async, failure-isolated, and it never blocks rendering. The page it measures is the page it must not affect.
It detects same-document navigations itself — synchronously, before your router's hooks run — so SPA routes are measured without a plugin or a per-route call.
Pull requests
Your trunk, the branches forking off it, and what each preview build did to the numbers — so a slow page is something you catch in review, not in production on Monday.
Every candidate a branch produced, in order, with the traffic it saw.
Merging replaces what is live, so that is the comparison it makes.
Your preview host already serves the SDK. The branch build is its release.
3 candidate builds · last 7 days
5 candidate builds · last 7 days
1 candidate build · last 7 days
GitHub Action
Point it at the preview you just deployed. Everything else — the branch, the commit, the author — comes from the pull request event GitHub already handed the job.
permissions:
pull-requests: write
steps:
- uses: ritim-io/pr-review-action@v1
with:
project-secret: ${{ secrets.RITIM_PROJECT_SECRET }}
preview-url: ${{ steps.deploy.outputs.url }}⚡ Ritim performance report
Mobile · preview · 9f2a1c4
Lighthouse, on Google's hardware — labelled as such, because it is not the real-visitor stream the rest of Ritim reports.
Pricing
A monitoring bill should be the least interesting thing about monitoring. Ritim has no usage meter running behind your back: every limit is a stop, you can watch it approach, and the number you agreed to is the number you pay.
Every allowance is a hard stop. Spend a project’s month and the collector stops accepting, the SDK stops sending for the life of the page — and nothing keeps running up a total on your behalf.
Usage is a page, not a line item you meet at the end of the month. What has been used, per project, is visible while you can still do something about it.
There is no per-seat maths and no module to unlock. Overview, pages, releases, triage, pull request audits and synthetic runs are the product, not the upsell.
An allowance running out is a thing you see coming, not a service that goes quiet. The dashboard shows the month against the limit that applies to it.
Plans and prices are published before the beta ends. Start now without a card, and nothing turns itself into a paid plan while you are not looking.
What you are choosing between
A full observability suite
Built for a platform team standardising a whole estate. That is a real job, and the price is the price of doing all of it.
Ritim
Built for the team shipping the site, and priced like the one tool it is — the same whether you check it once a quarter or every morning. Exact plans are published before the beta ends.
If you need the whole estate instrumented, buy the suite — it is the right tool and Ritim is not trying to replace it. If the question is whether your site is fast for the people using it, that is a smaller thing to buy, and it should be priced like one.
Install
No build step and no bundler. The SDK reads data-project-key off the tag that loaded it and starts itself.
Bundled with everything else you ship, typed, and versioned in your lockfile instead of on a CDN path.
Cookieless and without persistent user identification by default — the honest version of the claim, rather than promising you out of every regulation.
<script
async
src="https://cdn.ritim.io/v1/browser.min.js"
data-project-key="P-ABC123"
></script>npm install @ritim/browser-sdkimport { init } from '@ritim/browser-sdk';
init({ projectKey: 'P-ABC123' });Add one script tag and watch the next deploy land in real user data — usually within minutes of the first page view that carries it. No cookies, no consent banner, and no invoice you did not see coming.