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.
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.
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();
});A monitor group keeps the checks together in the dashboard and lets you list them again later.
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" }'{
"group_id": 12,
"group_name": "Help centers",
"sort_order": 3
}List the sites in a CSV file, one id,url per line. The id is yours: it becomes the check's external_id.
acme,https://help.acme.com
globex,https://faq.globex.com
initech,https://support.initech.com/faqThen 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.
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.csvEach call returns the check, with its script and the names of its variables. Values are never returned.
{
"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 ..."
}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.
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.
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"
doneenv_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:
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" }
]
}'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 }'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.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.