Browser checks
A browser check is a synthetic monitor that runs a Playwright script in a real Chromium browser on a schedule. Use it for the things HTTP checks can’t tell you:
- Does the login flow work end-to-end with real JavaScript?
- Does the checkout button actually charge a card?
- Does the multi-step signup form submit correctly?
- Did the latest deploy break the homepage’s hero CTA?
When to use browser checks
Section titled “When to use browser checks”- You have a critical user flow with multiple steps and JavaScript-driven UI.
- You’ve ever shipped a deploy that broke a button without breaking any HTTP endpoint.
- You want to monitor third-party JavaScript (analytics, payment widgets, fonts) that an HTTP check can’t observe.
When NOT to use them
Section titled “When NOT to use them”- For “is my API up?” use HTTP checks. Browser checks cost ~30× more compute and are slower.
- For “is my page fast for real users?” use RUM. Browser checks measure synthetic latency from one IP, not your users’ experience.
- For low-priority pages. Reserve browser checks for the 5–10 most important user flows.
How it works
Section titled “How it works”- You write a Playwright script in JavaScript, driving the browser with the
pageAPI andstep()helpers. - SiteQwality runs your script in headless Chromium on Lambda on the schedule (
5m,10m,15m,30m,1h). - Each step’s pass/fail, duration, and a screenshot are captured.
- On every run, a HAR file (full network log) and a video are uploaded to S3.
- Web vitals (LCP, FCP, CLS, TTFB) are extracted from the page and reported.
- Console errors and unhandled exceptions are captured.
- Status flips to
failedwhen steps fail, and alerts fire on that first confirmed failure. Browser checks have no consecutive-failure debounce; theconfirmation_thresholdknob is HTTP-only.
The script runs inside a sandboxed async function with page (Playwright Page) and step (your wrapper for tracked steps) injected:
await step('Open homepage', async () => { await page.goto('https://example.com');});
await step('Click sign in', async () => { await page.click('text=Sign in');});
await step('Fill credentials', async () => { await page.fill('input[name="email"]', 'demo@example.com'); await page.fill('input[name="password"]', 'demo-password'); await page.click('button[type="submit"]');});
await step('Confirm dashboard loaded', async () => { await page.waitForSelector('h1:has-text("Dashboard")');});Anything you can do with Playwright works inside a step.
What’s captured
Section titled “What’s captured”| Artifact | Where |
|---|---|
| Step results | Pass/fail, duration, error message per step. |
| Screenshots | Auto-captured after each step (pass or fail). |
| HAR file | Full network capture, downloadable from the run page. |
| Video | 1280×720 MP4 of the entire run. |
| Web vitals | LCP, FCP, CLS, TTFB extracted via PerformanceObserver. |
| Console errors | Anything logged at console.error or thrown. |
| Trace IDs | Outgoing requests get a traceparent header injected, allowing distributed-tracing correlation. |
Frequencies and pricing
Section titled “Frequencies and pricing”Available frequencies: 5m, 10m, 15m, 30m, 1h. Browser checks are billed per run; the dashboard shows your current monthly count under Settings → Billing → Usage.
Failure alerts carry the failed step and a screenshot
Section titled “Failure alerts carry the failed step and a screenshot”When a browser check fails, the alert names the first failed step and links to the screenshot captured at that step, so you can often diagnose without opening the dashboard.
This enrichment appears on email and Slack alerts. Other channels get the monitor name and error message only.
Three things determine whether you get it:
- The failure must happen inside a
step()call. A script that throws at the top level, fails to navigate, or times out before any step runs produces no step results, so there is no step name and no screenshot. Wrap your actions instep('name', async () => { ... })if you want named failure context. - The step must have a name. An unnamed step yields no enrichment at all, including no screenshot link.
- Delayed alerts are not enriched. If a notification group has
delay_send_after_minutesset, the delayed alert arrives without the step name or screenshot. The immediate alert is the enriched one.
Regions
Section titled “Regions”Constraints
Section titled “Constraints”- Script size: anything under 50KB. The script is stored in Postgres alongside the check config.
- Timeout:
1–300seconds per run. Includes browser startup; the user script getstimeout - 30s. - Regions: accepts
aws-us-east-1,aws-us-east-2,aws-us-west-1,aws-eu-west-2, with the caveat above.