---
title: Playwright Monitoring: Synthetic Browser Checks
description: Run your Playwright tests as synthetic browser checks. Monitor login, 2FA, checkout and search journeys with step screenshots, traces and confirmed alerts.
canonical: https://watchfor.io/playwright-monitoring
---

New

# Playwright monitoring: your browser tests, running as monitors

Sign in, add to cart, search, pay. A status code can't tell you whether a customer can still do any of that. A browser check runs a real Playwright Test file against production on a schedule, shows every step with its timing and a screenshot, and opens an incident only when a failure is confirmed.

[Create your first browser check](/auth/sign-up)[Read the quickstart](/docs/monitors/browser-checks/quickstart)

On every plan, including Free: one check every hour to try it on your own site.

Test run before you save: the script runs once from a browser location while the steps tick past.

## Synthetic monitoring with the Playwright you already write

[Synthetic monitoring](/synthetic-monitoring) means a script plays the customer on a schedule. Here the script is plain Playwright code you own: no proprietary step format and no dialect. A check is one TypeScript or JavaScript file with up to 10 tests, the same file you can run with npx playwright test . Name what matters with test.step() : steps are what results, alerts and trends are about.

Everything the script reads from process.env comes from your organisation's variables and secrets. TARGET_URL is the check's URL. Imports: @playwright/test , otpauth for one-time codes, @faker-js/faker and Node built-ins.

[Run it locally with the exact same versions →](/docs/monitors/browser-checks/run-locally)

import { test, expect } from '@playwright/test';

test('customer can sign in', async ({ page }) => {
await test.step('Open the sign-in page', async () => {
await page.goto(process.env.TARGET_URL!);
await expect(
page.getByRole('heading', { name: 'Sign in' }),
).toBeVisible();
});

await test.step('Sign in', async () => {
const { LOGIN_EMAIL, LOGIN_PASSWORD } = process.env;
await page.getByLabel('Email').fill(LOGIN_EMAIL!);
await page.getByLabel('Password').fill(LOGIN_PASSWORD!);
await page.getByRole('button', { name: 'Sign in' }).click();
});

await test.step('Dashboard loads', async () => {
await expect(page).toHaveURL(/\/dashboard/);
await expect(
page.getByRole('heading', { name: 'Dashboard' }),
).toBeVisible();
});
});

## Website transaction monitoring for login, checkout and search

A transaction is what a customer came to do: sign in, find something, pay. Each one crosses several pages, an API or two and often a third-party script, and any of them can break while the homepage still returns 200. A browser check walks the whole path in a real Chromium and names the step that failed.

A checkout check goes as far as the step before money moves, with a product that is always in stock. To test the payment itself, point the check at a staging shop in your payment provider's test mode.

[Login recipe →](/docs/monitors/browser-checks/recipes#login)[Checkout recipe →](/docs/monitors/browser-checks/recipes#checkout)[Search recipe →](/docs/monitors/browser-checks/recipes#search)

## Logins with 2FA

Two-factor authentication is the part most login monitors skip. A browser check enters a real one-time code: store the test account's TOTP secret as an organisation secret, and the preinstalled otpauth library generates the same six-digit code an authenticator app shows. The secret is masked in every log, trace and screenshot.

Codes sent by SMS or email can't be read by a check, so give the test account an authenticator factor.

[How to monitor a login with 2FA →](/blog/monitor-a-2fa-login-with-playwright)[TOTP recipe →](/docs/monitors/browser-checks/recipes#totp)

## How a browser check runs

Real Playwright in a disposable sandbox, results you can read, and alerts that wait for a confirmed failure

### The real Playwright runner

Your file runs under @playwright/test 1.63.0 with the Chromium and Node it ships with, on a pinned runtime. test.step, expect, fixtures, test.use and request work as they do on your laptop. A check never moves to a new Playwright version unless you move it.

### Every step, timed and pictured

Each test.step becomes a row with its duration and a screenshot. A failed step shows the error in one line, the code frame and the page at the moment it failed, with a hint when the error is a known one.

### The trace viewer, on our own origin

Failed runs keep a Playwright trace: DOM snapshots, network, console and a film strip. It opens in the Playwright trace viewer hosted by WatchFor, so a trace of your logged-in session is never sent to a third party.

### A disposable sandbox per run

Every run starts in a fresh, disposable sandbox with a memory and time limit and no access to our network or anyone else's runs. It reaches the public internet only; requests to private addresses are refused and listed under Errors.

### Write-only secrets

Passwords, tokens and TOTP secrets are organisation secrets, encrypted at rest and read as process.env.NAME. Nobody can view one after saving it, and the value is masked as •••••• in logs, errors, step titles, trace text and screenshots.

### Flakes don't page anyone

A failed test is retried once in a fresh browser inside the same run. A pass on the retry is reported as flaky. A run that still fails is confirmed by a second run about a minute later, from another location when the check has one, before an incident opens. Neither counts against your plan.

A failed run: the step, expected vs got, a hint, the code and the page.

The Playwright trace at the failed assertion, served from WatchFor.

## Built for the morning after a failure

Three things that make a failed run quick to understand and safe to keep

### Last-green comparison with step timings and screenshots

Open a failed run next to the last passing one: each step's change in duration and the two screenshots side by side. One passing run a day keeps full screenshots, so there is always a recent one to compare with.

### Secrets scrubbed in scheduled runs too

Masking isn't only for the test run in the editor. Logs, error messages, step titles, trace text and screenshots of every scheduled run show a secret as ••••••. [Where masking stops](/docs/monitors/browser-checks/variables).

### Chrome Recorder JSON becomes Playwright code you own

Record a journey with Chrome DevTools Recorder, export it as JSON and import it. It becomes an editable Playwright test, not a proprietary step list, so you can take it anywhere Playwright runs.

## Three ways to your first green run

Every example passes on a public practice site as it is, then switches to your site and your secrets in one click

### Start from a working example

Page loads cleanly, Login, Login with 2FA (TOTP), Search, Checkout, API + UI, and Blank. [See the recipes](/docs/monitors/browser-checks/recipes).

### Import a script

Paste or upload a .spec.ts file, the output of npx playwright codegen , or a Chrome DevTools Recorder export. The editor flags anything the runtime can't import before you run it.

### Ask your agent

Through the WatchFor MCP server an agent writes the script, tests it with test_playwright_script , reads the result with get_playwright_run and creates the check with create_monitor . [The prompt](/docs/monitors/browser-checks/agents).

## Alerts that name the step

An incident says which step broke, with the error and the screenshot of the page at that moment. It reaches the same channels, on-call schedules and status pages as the rest of your monitoring.

-

Journey failed: on by default, after the retry and a confirmation run
-

Journey slow: the whole run takes longer than your budget
-

Step budgets: one duration limit per named step
-

Console errors and failed requests (4xx, 5xx or network errors)
-

Slow page (LCP), with layout shift (CLS) available as a rule
-

Flaky journey: passes that needed the retry, if you want to know
-

A run that can't start on our side shows Couldn't run and never opens an incident

## Browser checks on every plan

Runs a month is a budget your checks share: each check's runs are worked out from its interval and locations when you save it , so Pro's 45,000 runs are 5 journeys every 5 minutes or 10 every 10 minutes . Retries and confirmation runs are not counted.

Plan Browser checks Fastest interval Runs per month What fits Longest run

Free 1 1 h 750 1 journey every hour 60 s

Starter 2 10 min 9,000 2 journeys every 10 minutes 90 s

Pro 10 5 min 45,000 5 journeys every 5 minutes or 10 every 10 minutes 120 s

Business 25 1 min 110,000 2 journeys every minute or 25 every 10 minutes — at 1 min, runs up to 14 s 180 s

[Compare every plan →](/pricing)

## Frequently asked questions

What developers ask before pointing a browser check at production

Does my existing Playwright test work unchanged? Usually, yes. A check is one Playwright Test file in TypeScript or JavaScript with up to 10 tests, run by the real @playwright/test runner (1.63.0 on the current runtime). test.step, expect, fixtures, test.use and request behave as they do locally, and npx playwright codegen output works as it is. What differs: we supply the config (Chromium, 1280×720, one worker), there is no npm install, and a test that reads a local file or a relative import needs that helper pasted into the script.

Which plans include browser checks? Every plan, including Free: one check every hour with 60 s runs, from one location, to try it on your own site. Paid plans give you a monthly runs budget that all your checks' schedules share: Starter 9,000 runs (2 journeys every 10 minutes), Pro 45,000 runs (5 journeys every 5 minutes or 10 every 10 minutes), Business 110,000 runs (2 journeys every minute or 25 every 10 minutes — at 1 min, runs up to 14 s). Enterprise budgets are sized to the contract. The plan table above has each plan's checks, fastest interval, runs and longest run.

What counts as a run? Are retries billed? Runs per month is a budget for your schedules: when you save a check, its scheduled runs for a month are worked out from its interval and locations, and all your checks together must fit the plan. 45,000 runs a month is 5 journeys every 5 minutes or 10 every 10 minutes. Nothing is metered per run, so the retry inside a run and the confirmation run before an incident never use it up, and a paused check counts nothing.

What if a run takes longer than the interval? It can't overlap the next one. A run with its retry can take up to 2 × the timeout + 30 seconds, so a check's timeout has to fit its interval (every minute allows up to 14 s, every 5 minutes up to 134 s), and the editor only offers timeouts that fit. If a scheduled run still comes due while the previous one is going, for example while an incident has sped the check up, it is skipped: it shows as Skipped, is never counted as a failure and never opens an incident.

Which imports and npm packages can a script use? @playwright/test, otpauth for one-time codes, @faker-js/faker for test data, and Node built-ins such as node:crypto and node:path. child_process, cluster, worker_threads, net, dgram, http2, inspector and vm are not available, and imports from URLs are refused. The editor flags an import the runtime doesn't have before you run it.

How are passwords and other secrets handled? Store them as organisation secrets and read them as process.env.NAME. They are encrypted at rest, can't be viewed after saving, and are masked as •••••• in logs, error messages, step titles, trace text and screenshots of every run, scheduled runs included. Masking covers the exact value; a value derived from a secret, such as a hash, is not recognised.

Can a browser check reach my staging or internal site? No. Runs reach the public internet only, through a guard that refuses private and internal addresses, and such a request is listed under the run's Errors. Point the check at a publicly reachable URL; you can protect it with a login the script performs.

Can an AI agent write the check for me? Yes. Connect your agent to the WatchFor MCP server and give it the prompt from the docs. It writes the script, tests it with test_playwright_script, reads the steps and errors with get_playwright_run, and creates the check with create_monitor once a run passes. It asks you for any secret the script needs instead of putting it in the code.

What is synthetic transaction monitoring? Synthetic transaction monitoring, also called website transaction monitoring or user journey monitoring, means a scripted browser completing a real task on your site on a schedule: signing in, searching, reaching checkout. A broken journey is found before a customer reports it. WatchFor's browser checks do this with standard Playwright Test files: each run opens a fresh Chromium, walks through your steps, records each step's time and a screenshot, and opens an incident only after a second run confirms the failure.

How are browser checks different from Core Web Vitals monitoring? They answer different questions. A Core Web Vitals check loads one URL and runs a Lighthouse audit: LCP, CLS, Total Blocking Time and the performance score, tracked over time. A browser check runs your script through a whole journey and tells you whether a customer can still finish it, and which step broke if not. Browser check runs also record LCP and CLS for the pages they visit, but for one page's performance trend, Core Web Vitals monitoring is the better fit. Many teams run both.

Browser checks or real user monitoring (RUM)? A browser check is synthetic: our browsers run the same scripted journey from the locations you pick, on a schedule. It catches a broken login at 3 a.m. when nobody is visiting, and every run is comparable with the last. Real user monitoring collects timings from your visitors' own browsers, so it shows how the site feels across real devices, networks and pages nobody scripted, but only once people arrive, and it learns a journey is broken when customers hit it. WatchFor doesn't offer RUM; the two complement each other.

Do you support Firefox or WebKit? Not yet. Browser checks run on Chromium, headless, with desktop and mobile viewports and device presets through test.use. Every run shows the Playwright and Chromium versions it used.

## From our blog

Guides, deep-dives, and best practices from the WatchFor team

[Monitoring

### Monitor a checkout flow with Playwright, step by step

Oct 03, 2026·12 min readRead article](/blog/monitor-checkout-flow-with-playwright)[Monitoring

### How to monitor a login with 2FA (TOTP) in Playwright

Sep 29, 2026·5 min readRead article](/blog/monitor-a-2fa-login-with-playwright)[Monitoring

### Synthetic vs Real User Monitoring (RUM): what's the difference?

Jun 06, 2026·4 min readRead article](/blog/synthetic-vs-real-user-monitoring)

[Documentation](/docs/monitors/browser-checks)[Troubleshooting](/docs/monitors/browser-checks/troubleshooting)[Runtime and versions](/docs/monitors/browser-checks/runtime)[Core Web Vitals monitoring](/core-web-vitals-monitoring)[API monitoring](/api-monitoring)

## Watch the journey, not just the page

Pick an example that passes as it is, point it at your site, and run it before you save. The account takes a minute to create and no credit card is needed to start.

[Create a browser check](/auth/sign-up)[View documentation](/docs/monitors/browser-checks)

---

Canonical page: https://watchfor.io/playwright-monitoring · Site guide: https://watchfor.io/llms.txt
