Skip to content

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?
  • 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.
  • 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 the cloud locations you pick, not your users’ experience.
  • For low-priority pages. Reserve browser checks for the 5–10 most important user flows.
  1. You write a Playwright script in JavaScript, driving the browser with the page API and step() helpers.
  2. Site Qwality runs your script in headless Chromium on the schedule (5m, 10m, 15m, 30m, 1h), once in each location you select.
  3. Each step’s pass/fail, duration, and a screenshot are captured.
  4. On every run, a HAR file (full network log) and a video are recorded.
  5. Web vitals (LCP, FCP, CLS, TTFB) are extracted from the page and reported.
  6. Console errors and unhandled exceptions are captured.
  7. A run fails when fewer locations pass than min_healthy_regions requires. Status flips to failed when a run fails, and alerts fire on that first confirmed failure (see rerun and confirmation). A check that keeps passing and failing is held like a flapping HTTP monitor: one notice instead of an alert pair per change. See flap hold.

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.

ArtifactWhere
Step resultsPass/fail, duration, error message per step.
ScreenshotsAuto-captured after each step (pass or fail).
HAR fileFull network capture, downloadable from the run page.
Video1280×720 WebM of the entire run.
Web vitalsLCP, FCP, CLS, TTFB extracted via PerformanceObserver.
Console errorsAnything logged at console.error or thrown.
Trace IDsEvery request the browser makes, to any origin, carries a W3C traceparent header, and the run records those trace IDs. If the receiving server sends its OpenTelemetry traces to Site Qwality, the ID opens that backend trace; otherwise the trace has no spans.

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 email and Slack alerts name the first failed step and link to the screenshot captured at that step. Other channels get the monitor name and error message only.

You get this only when:

  • The failure happens 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.
  • The step has a name. An unnamed step yields no enrichment, including no screenshot link.
  • The alert is not delayed. If a notification group has delay_send_after_minutes set, the delayed alert arrives without the step name or screenshot; the immediate alert is the enriched one.

The screenshot link in an alert usually stops working within a few hours. After that, open the screenshot from the check’s run detail in the dashboard, where it does not expire.

Browser checks run from the 20 AWS check locations, in 18 countries and territories. The Google Cloud and Microsoft Azure locations do not run browser checks. In GET /check-locations, a location that runs browser checks lists "browser" in its capabilities; the reference has the full table.

  • Default. With check_regions unset or empty, a new check runs from the default location, Virginia (aws-us-east-1).
  • Plans. The free plan checks from one location. More than one needs a paid Synthetic plan; an uptime plan does not count. Without one the API returns 403 with multi_region_requires_paid_plan.
  • Minutes. The script runs once in every selected location, and each run uses browser check minutes, so a check on three locations uses about three times the minutes of a check on one.
  • Minimum healthy locations. min_healthy_regions (Minimum Healthy Locations in the dashboard) sets how many locations must pass. The check is down when fewer than that many pass.
  • No data is not a failure. A location with no result for two runs plus 10 minutes (20 minutes on a 5m check) is left out of the count. The minimum is capped at the number of locations reporting, so a silent location never holds a check down.
  • Confirmation. confirmation_threshold counts failed runs of that quorum, and rerun_on_failure reruns a failed attempt once from the same location.
  • Run now. POST /browser_check/{id}/run runs the script in every location the check selects, and the response’s regions lists them.
  • Storage. Wherever the script runs, its results, screenshots, HAR and video are stored in us-east-1.

Start with a location near your users, and add locations on other continents to cover a global audience.

  • Script size: under 50KB.
  • Timeout: 1–300 seconds per run, including browser startup; the user script gets timeout - 30s.
  • Locations: AWS locations only; see locations above.