ProductJune 11, 2026 · 6 min read

Real Browser Monitoring: How SiteBrief Uses Headless Chromium for Checks That Actually Work

Plain HTTP checks are fast — but they lie. A React site returns HTTP 200 with an empty shell. A Next.js page loads a keyword three seconds after the HTTP response. A login-protected dashboard is completely invisible to a curl-based checker. SiteBrief runs a self-hosted headless Chromium for every check that matters.

The problem with HTTP-only monitoring

Most website monitors work like this: send an HTTP request, read the status code, check the response body, done. It's fast and cheap — a checker can verify thousands of sites per minute this way. But the web isn't HTTP responses anymore. The web is JavaScript.

Consider a typical Next.js app. The server returns something like this:

HTTP 200 OK
Content-Length: 4821

<!DOCTYPE html>
<html>
  <head>...</head>
  <body>
    <div id="__next"></div>
    <script src="/_next/static/chunks/main.js"></script>
  </body>
</html>

An HTTP checker sees HTTP 200 and a body — that's technically "up." But your users see a blank screen until the JavaScript bundle downloads, parses, and renders. If that JS bundle is throwing an exception, your monitoring says green while your users see a white page.

What SiteBrief now runs in a real browser

1. Accessibility scan — axe-core 4.9.1 in headless Chrome

The most common way to run an accessibility audit is to check the static HTML — parse the markup and look for missingalt attributes, wrong heading order, insufficient colour contrast. This catches some things, but it misses anything rendered by JavaScript: modals, dynamic form labels, client-side navigation, ARIA attributes added after hydration.

SiteBrief injects axe-core 4.9.1 into a live Chromium session after the page has fully loaded (networkidle2). Axe sees the real DOM — the same DOM your users do — and runs 80+ WCAG 2.1 AA rules against it.

The raw violations go to Claude Haiku, which returns:

  • A risk score from 0–100
  • Risk level (critical / high / medium / low)
  • Legal exposure notes — EU EAA / EN 301 549 and US ADA / Section 508
  • Top issues with a one-sentence explanation and one-sentence fix per issue
  • Three priority actions

If the AI is unavailable, SiteBrief falls back to calculating the risk level from raw axe data — the result is still useful, just without the narrative.

2. Core Web Vitals — PerformanceObserver without a Google API quota

Google PageSpeed Insights is excellent — it runs a throttled Lighthouse audit that simulates a mid-range mobile device on a slow 4G connection. That's great for getting a realistic score. But it has rate limits, requires an API key for production use, and sometimes returns errors for sites behind auth or with unusual CSP headers.

SiteBrief now has a fallback: when PSI isn't configured or fails, it measures Core Web Vitals directly in Chromium:

  • LCP — via PerformanceObserver watching largest-contentful-paint entries, set up before navigation so no events are missed
  • CLS — accumulates all layout-shift entries without recent user input
  • FCP — from the paint performance entry
  • TTFBresponseStart - requestStart from Navigation Timing API
  • TBT — sum of max(0, task.duration - 50) from Long Tasks API

No performance score (PSI's scoring model involves throttling we don't replicate), no INP (requires real interaction). But for users without an API key, this gives real, free, unthrottled metrics from an actual browser.

3. Broken links on React and Next.js sites

The broken links crawler used to fetch the page HTML with a plain HTTP GET and extract all href attributes. This works fine for server-rendered HTML. It completely fails for client-side routers.

A typical React app's HTML payload is 3–8 KB with no navigation links — they're all rendered by react-routerafter the JS loads. The crawler would check zero links and report "no broken links found" — technically accurate, thoroughly useless.

SiteBrief now detects SPA shells automatically: if the HTML body is under 8 KB or contains fewer than 3 links, it re-fetches using Browserless renderHTML (with networkidle2 wait). The fully rendered DOM — including every link React Router injected into the page — is then crawled and checked normally.

4. Auth-protected page monitoring — cookie inject step

The Browser Scenario Builder (used for synthetic transactions) has a new step type: Set cookie.

Previously, monitoring an authenticated page required building a full login flow as the first steps of every scenario: go to login page, fill username, fill password, click submit, wait for redirect. That works, but it's slow (~3–5 seconds per run) and breaks if the login page changes or if the site uses OAuth / SSO.

With the Set cookie step, you can inject a session token directly into the browser before navigating anywhere. The cookie is set at the domain level before the first navigation, so the first page load sees it as if the user was already logged in. Cookie values are masked in the UI and never appear in run logs.

Step 1 — Set cookie
  Name: session_token
  Value: ••••••••••••••••
  Domain: app.example.com

Step 2 — Go to URL
  https://app.example.com/dashboard

Step 3 — Assert text
  "Welcome back, "

Step 4 — Assert selector
  .subscription-status

This scenario verifies that your authenticated dashboard loads and shows the right content — a check that is completely impossible with HTTP-only monitoring.

Why self-hosted Browserless instead of a third-party API

SiteBrief runs Browserless on Fly.io — a dedicated Chromium instance that we control. This matters for a few reasons:

  • No per-check pricing — a flat monthly cost regardless of how many checks run.
  • No rate limits — checks run whenever they need to, not when a quota allows.
  • Data stays in our infrastructure — URLs, screenshots, and page content never pass through a third-party API.
  • Predictable latency — Fly machines in the same region as our Supabase instance.

What this means for your monitoring setup

If you're using SiteBrief to monitor React, Next.js, Nuxt, SvelteKit, or any other JavaScript-heavy site — these updates mean your checks are now accurate in ways they weren't before:

  • Keyword checks won't false-positive on SPAs
  • Broken link scans will actually find links on client-rendered pages
  • Accessibility audits cover dynamic UI, not just static markup
  • You can monitor protected pages without storing passwords in the scenario

All of these features are on Pro and Agency plans. The browser-based CWV fallback is active automatically for any account where PAGESPEED_API_KEY is not configured.


Full documentation for all browser-based features is at /docs/browser-monitoring.