Create browser checks with the API

Updated October 15, 2026

Create, update, and delete Playwright browser checks with the Monitors API. This guide runs the same test against many sites: one script, one check per site with its own variables, all in one group, kept in sync with a list you can edit and run again.

Endpoint
PUT /v1/monitors/external/{id}
Runtime
2026.05 · Playwright 1.59.1
Intervals
5 minutes to 24 hours
Regions
frankfurt · sanfrancisco

1. Write the script once

Write the test the way you would paste it in the dashboard editor, and read what changes from one site to the next from process.env. Here, the site to open comes from BASE_URL. Run it on your laptop first with the same Playwright version as the runtime.

help-center.spec.tsTS
import { test, expect } from '@playwright/test';

test('help center answers a search', async ({ page }) => {
  await page.goto(process.env.BASE_URL);

  const search = page.getByRole('searchbox');
  await expect(search).toBeVisible();
  await search.fill('delivery');
  await search.press('Enter');

  await expect(page.getByRole('article').first()).toBeVisible();
});

2. Create a group

A monitor group keeps the checks together in the dashboard and lets you list them again later.

TerminalBASH
curl -s -X POST https://api.hyperping.io/v1/monitor-groups \
  -H "Authorization: Bearer $HYPERPING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "group_name": "Help centers" }'
201 CreatedJSON
{
  "group_id": 12,
  "group_name": "Help centers",
  "sort_order": 3
}

3. Create one check per site

List the sites in a CSV file, one id,url per line. The id is yours: it becomes the check's external_id.

sites.csvCSV
acme,https://help.acme.com
globex,https://faq.globex.com
initech,https://support.initech.com/faq

Then send one create-or-update request per line. PUT /v1/monitors/external/{id} creates the check the first time and updates the same check every time after, so the loop can run as often as you like without creating duplicates. jq builds each request body: --rawfile puts the script in the JSON with its quotes and line breaks escaped, so the script file stays readable.

TerminalBASH
GROUP_ID=12

while IFS=, read -r id url || [ -n "$id" ]; do
  jq -n \
    --arg name "Help center - $id" \
    --arg url "$url" \
    --rawfile script help-center.spec.ts \
    --argjson group "$GROUP_ID" \
    '{
      name: $name,
      protocol: "browser",
      url: $url,
      script: $script,
      check_frequency: 300,
      group_id: $group,
      env_variables: [{ name: "BASE_URL", value: $url }]
    }' |
  curl -s -X PUT "https://api.hyperping.io/v1/monitors/external/help-center-$id" \
    -H "Authorization: Bearer $HYPERPING_API_KEY" \
    -H "Content-Type: application/json" \
    -d @- |
  jq -r '.uuid + "  " + .external_id'
done < sites.csv

Each call returns the check, with its script and the names of its variables. Values are never returned.

201 CreatedJSON
{
  "uuid": "mon_7BLzvBqgJYdvpm",
  "external_id": "help-center-acme",
  "name": "Help center - acme",
  "protocol": "browser",
  "url": "https://help.acme.com",
  "paused": false,
  "regions": ["frankfurt", "sanfrancisco"],
  "check_frequency": 300,
  "status": "up",
  "group_id": 12,
  "sort_order": 1,
  "escalation_policy": null,
  "env_variables": [
    { "name": "BASE_URL" }
  ],
  "script": "import { test, expect } from '@playwright/test';\n\ntest('help center answers a search', async ({ page }) => {\n  ..."
}

4. Change the script

Edit help-center.spec.ts and run the loop of step 3 again. Every check gets the new script, and it runs from the next check on. The same goes for a site added to sites.csv: the next run creates its check.

5. Remove the sites that left the list

List the browser checks of the group with the list filters, and delete those whose id is no longer in sites.csv. Only checks whose external_id starts with help-center- are considered, so other monitors of the group are left alone. Deleting a check also deletes its variables.

TerminalBASH
curl -s "https://api.hyperping.io/v1/monitors?protocol=browser&group_id=$GROUP_ID" \
  -H "Authorization: Bearer $HYPERPING_API_KEY" |
jq -r '.[] | select((.external_id // "") | startswith("help-center-"))
  | [.uuid, (.external_id | ltrimstr("help-center-"))] | @tsv' |
while IFS=$'\t' read -r uuid id; do
  grep -q "^$id," sites.csv && continue
  curl -s -o /dev/null -w "deleted help-center-$id %{http_code}\n" \
    -X DELETE "https://api.hyperping.io/v1/monitors/$uuid" \
    -H "Authorization: Bearer $HYPERPING_API_KEY"
done

Change the variables of one check

env_variables is the full list the check should have: variables left out are deleted. An entry with a name and no value keeps the value already stored, so you can change one variable without sending the others again. For a check that also has a PASSWORD variable, this changes BASE_URL and keeps PASSWORD:

TerminalBASH
curl -s -X PUT https://api.hyperping.io/v1/monitors/external/help-center-acme \
  -H "Authorization: Bearer $HYPERPING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "env_variables": [
      { "name": "BASE_URL", "value": "https://help.acme.com/en" },
      { "name": "PASSWORD" }
    ]
  }'

Pause a check

TerminalBASH
curl -s -X PUT https://api.hyperping.io/v1/monitors/external/help-center-acme \
  -H "Authorization: Bearer $HYPERPING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "paused": true }'

Rules

  • check_frequency is in seconds: 300, 600, 900, 1800, 3600, 21600, 43200 or 86400. The default is 300.
  • regions can be frankfurt and sanfrancisco, and both are used by default.
  • script is required to create a check and holds up to 100,000 characters.
  • A check takes up to 50 env_variables. Names use letters, digits, and _, and don't start with a digit. Values are up to 4096 bytes, stored encrypted, and never returned by the API. A changed value can take up to 90 seconds to reach the runner.
  • external_id is unique within the project: 1 to 128 letters, digits, ., _, : or -, starting with a letter or a digit.
  • A monitor can't be turned into a browser check or back: create a new one instead.

Next steps