Bulk import monitors
Create dozens of monitors at once from a CSV or JSON file, including screenshots, SSL checks, regions, and TCP/DNS fields.
Instead of adding monitors one at a time, upload a CSV or JSON file and create up to 200 at once. The import is all-or-nothing: if any row is invalid, or the batch would exceed your plan's monitor limit, nothing is created and every reason is listed so you can fix the file and retry.
The fastest path
- Go to Monitors, then click Bulk import in the top right.
- Drag and drop a
.csvor.jsonfile, or click to browse for one. - Review the parsed rows. Optionally pick a team and default regions for the whole batch, and tick Enable screenshots for all and/or Enable SSL check for all if you want every imported monitor to have those on regardless of what the file says.
- Optionally click Check reachability to probe every URL once and see an UP/DOWN badge per row before you commit. This is advisory only: a site that blocks automated probes may show DOWN yet still be worth importing, so a DOWN badge never stops the import.
- Click Import N monitors.
CSV columns
Only name and url are required (url is optional for ping, tcp, dns, and group
monitors, which target a host instead of a URL). Every other column is optional:
| Column | Meaning |
|---|---|
method | HTTP method (default GET) |
interval, timeout | Seconds (defaults 60 / 30) |
type | http (default), ping, tcp, or dns |
ping_target | Host to ping (type ping) |
host | Host to check (type tcp or dns) |
tcp_port | Port number (type tcp) |
dns_record_type | A, AAAA, A_AAAA, CNAME, MX, TXT, or NS (type dns) |
dns_expected_value | Optional substring the resolved record must contain (type dns) |
ssl_check | true/false: HTTPS certificate expiry check |
screenshot_enabled (aliases: screenshot, screenshots) | true/false: capture a screenshot when the monitor goes down |
follow_redirects | true/false |
keyword, keyword_type | Body keyword to assert (contains, not_contains, or regex) |
valid_status_codes | e.g. 200-299 |
regions (alias: prober_regions) | Which prober regions to check from |
tags | Free-text tags |
headers (alias: request_headers) | Custom request headers, as Key: value pairs separated by ; |
body (alias: request_body) | Custom request body — raw text, sent as-is |
Multi-value cells (valid_status_codes, regions, tags) use ; or | to separate values
(commas are the CSV delimiter). headers also uses ; to separate multiple header pairs, but
| is a valid character inside an HTTP header value, so it is never treated as a header
separator — see below.
The regions column is a technical import field, so it uses machine-readable region IDs from
the current prober fleet. To avoid working with IDs, leave the column empty and choose default
regions for the whole batch in the import screen.
name,url,method,interval,timeout,ssl_check,screenshot_enabled,regions,valid_status_codes,tags,headers,body
"My API",https://api.example.com,GET,300,10,true,false,,200-299,"prod;api","X-Api-Key: abc123;Accept: application/json","{""ping"": true}"
"Health",https://app.example.com/health,GET,300,5,false,false,,200-299|301,prod,,
headers holds one or more Key: value pairs joined with ;, e.g.
X-Api-Key: abc123;Accept: application/json. body is sent as written, with two exceptions:
leading and trailing whitespace is trimmed from every cell (including body), and a Windows-style
\r\n line ending anywhere inside it — even inside a quoted, multi-line value — is converted to a
plain \n. Either cell that contains a comma (a JSON body almost always does) must be wrapped in
double quotes, with any inner double quote doubled ("") — the row above's body cell shows
this: "{""ping"": true}" becomes the request body {"ping": true}. A header line with no colon
(e.g. a pasted curl -H argument without one) fails the whole import and names the offending
row, the same way a missing name/url does. A structurally broken CSV file — most commonly a
stray or unmatched double quote inside an unquoted value (an inch mark like 15" wide, for
example) — also fails the whole import and names the line where the parser gave up, rather than
importing only the rows that came before it.
JSON files use the same field names as an array of objects. headers is a plain JSON object
({"X-Api-Key": "abc123"}) instead of the Key: value; string form, and every other field uses
regular JSON arrays and booleans instead of the ;/| and true/false string conventions.
The API validates each row against the workspace's current Uptime capabilities. Failure
screenshots require screenshot_monitoring, multiple selected regions require multi_region,
custom request headers or a request body require a paid Uptime plan (the same gate the
single-monitor create form's Behaviour section applies), and the check interval must respect the
current minimum. If a row asks for an unavailable capability, the whole import is rejected and
the response lists each offending row. Adjust the file or the workspace capability, then import
it again. See Screenshot debugging
and the current pricing page.
Toggling screenshots or SSL for monitors you already have
You don't need to re-import to change these settings in bulk. On the Monitors page, select the monitors with the checkboxes, and the yellow bulk action bar that appears has two more icons alongside pause/resume/interval/regions/tags/team/delete: a camera icon for screenshots and a lock icon for SSL checks. Click one and choose Enable or Disable. The change applies to every selected monitor immediately, and your selection stays in place afterward so you can keep going.
Selecting monitors without losing your place
While you're ticking checkboxes to build a selection, clicking anywhere else on a row toggles that row's selection too, instead of navigating away and clearing everything you'd already picked. To open a monitor's detail page while you have a selection in progress, click its name (or use the kebab menu): both still navigate normally.
See also
Was this page helpful?