---
title: Browser checks API: test runs, runs and script versions
description: Work with browser checks from code — start a test run, read runs and their failed steps, list script versions and manage variables over the REST API, the MCP server and the TypeScript, Python and Ruby SDKs.
canonical: https://watchfor.io/docs/monitors/browser-checks/api
---

# Browser checks API: test runs, runs and script versions

Work with browser checks from code — start a test run, read runs and their failed steps, list script versions and manage variables over the REST API, the MCP server and the TypeScript, Python and Ruby SDKs.

Everything the editor does is available from code, with the same validation,
limits and masking. Authentication and errors work as for the rest of the
[REST API](/docs/api).

## REST endpoints

| Method | Path | What it does |
|---|---|---|
| `POST` | `/v1/playwright/test-runs` | Run a script once without saving it (`script`, `target`, optional `location_id`, `timeout_seconds`, `retry`). Returns `202` with an `id` to poll and `missing_variables`. Write scope; counts against test runs per hour; up to 3 test runs at once per organization (`429` beyond). |
| `GET` | `/v1/playwright/test-runs/{id}` | The test run: `queued`, `running`, `done` or `error`, and the result when done |
| `GET` | `/v1/monitors/{id}/runs` | A check's runs, newest first; `status=failed` or `flaky`, `limit`, `cursor` |
| `GET` | `/v1/monitors/{id}/runs/{runId}` | One run: steps with errors and code frames, failure, console and page errors, failed and blocked requests, Web Vitals, runtime versions, signed screenshot links |
| `GET` | `/v1/monitors/{id}/script/versions` | The script's saved versions (the last 50) |
| `GET` | `/v1/monitors/{id}/script/versions/{version}` | One version's script |
| `GET` | `/v1/variables` | Organisation variables (secret values never returned) |
| `PUT` | `/v1/variables/{name}` | Create or change a variable or secret (`value`, `secret`) |
| `DELETE` | `/v1/variables/{name}` | Delete one |

Create and change checks with the ordinary monitor endpoints: `POST /v1/monitors`
with `type: "playwright"`, the site as `target` and `config: { script,
timeoutSeconds, retry }`. A script with an error is rejected with `400` naming
the line, before anything runs.

The type id is `playwright`. The `browser` type is something else: a
[Core Web Vitals](/docs/monitors/performance#core-web-vitals-browser)
(Lighthouse) audit of one page.

```bash
curl -X POST https://watchfor.io/api/v1/playwright/test-runs \
  -H "Authorization: Bearer $WATCHFOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<'JSON'
{
  "target": "https://playwright.dev/",
  "script": "import { test, expect } from '@playwright/test';\ntest('home', async ({ page }) => {\n  await page.goto(process.env.TARGET_URL!);\n  await expect(page.locator('h1')).toBeVisible();\n});\n"
}
JSON
```

## MCP tools

For agents, the [MCP server](/docs/api/mcp) has `test_playwright_script`
(starts a test run and waits up to about a minute for the result),
`get_playwright_run` and `list_playwright_runs`, next to `create_monitor` and
`update_monitor`. [Ask your agent](/docs/monitors/browser-checks/agents) has a
ready prompt that uses them.

## SDKs

```ts

const wf = new WatchFor({ apiKey: process.env.WATCHFOR_API_KEY! });

const { id } = await wf.playwright.testRun({ script, target: 'https://shop.example.com' });
const testRun = await wf.playwright.getTestRun(id); // poll until status is done

const runs = await wf.monitors.runs(checkId, { status: 'failed' });
await wf.variables.put('LOGIN_PASSWORD', { value: process.env.PW!, secret: true });
```

The Python and Ruby SDKs have the same methods. See [SDKs](/docs/api/openapi).

---

Canonical page: https://watchfor.io/docs/monitors/browser-checks/api · All docs: https://watchfor.io/docs · Site guide: https://watchfor.io/llms.txt
