Unlike heartbeat checks, where your job pings us, an HTTP check polls a URL itself — the service sends a request at a fixed interval and alerts when the response stops looking right.
Create the check in the dashboard (type "HTTP") or via the
API — the http_config field:
| Parameter | Default | Description |
|---|---|---|
url | — | http/https, up to 2048 characters |
method | GET | GET / HEAD / POST |
timeout_sec | 10 | 1–30 s for the whole request |
expected_codes | 2xx, 3xx | up to 10 values: classes ("2xx") and/or exact codes (301) |
keyword | — | a string that must be present in the response body |
keyword_absent | false | true — the string must be absent instead |
follow_redirects | true | whether to follow redirects |
headers | — | up to 10 custom headers |
basic_auth | — | username + password |
ssl_days_before | 14 | 7 / 14 / 30 — how many days before certificate expiry to alert |
confirmations | 2 | K consecutive failed probes before down (1–5) |
An HTTP check's schedule is always a fixed interval
(30–3600 s); cron expressions are for heartbeat checks only.
Requests are sent with User-Agent: CronAlive-Probe/1.0.
The keyword check does not apply to HEAD — the body is empty.
| Free | Pro | Business |
|---|---|---|
| 5 min | 1 min | 30 s |
timeout_sec;expected_codes — the alert says "unexpected status 503";Every probe is recorded: response code, latency (ms), probe region, error text. Latency is shown on the duration chart of the check page.
The parameters above are three layers of checking; each one catches its own class of problems, and it pays to know what each layer covers:
timeout_sec —
the probe fails regardless of the other settings.
expected_codes) —
catches a live web server with a dead backend: nginx accepts
the connection and dutifully replies 502/504 while the
application is long gone. It also works in reverse: if the
correct answer of a page is 404 (a stub page) or 401 (a
protected admin area), set that code as expected — the
check goes down the moment the admin area suddenly starts
replying 200 without authentication.
keyword) —
catches a "successful" response with broken content: with
the database down an application often returns code 200 and
a page full of "Fatal error". Require a string that only a
healthy page contains, or enable
keyword_absent for a forbidden
string.
The most reliable target is not the home page but a dedicated
/health endpoint that touches the
critical dependencies itself (database, cache) and replies 200
with the body healthy only when
everything is alive. The check for it: expected code
200 + keyword healthy — all three layers at full
strength.
# check parameters
url: https://example.com/health
expected_codes: 200
keyword: healthy A /health example in PHP:
<?php // public/health.php try { $db = new PDO('pgsql:host=127.0.0.1;dbname=app', 'app', getenv('DB_PASSWORD')); $db->query('SELECT 1'); // the database responds (new Redis())->connect('127.0.0.1'); // the cache responds echo 'healthy'; } catch (Throwable) { http_response_code(500); echo 'unhealthy'; }
And the same in Python (Flask):
@app.get("/health")
def health():
try:
db.session.execute(text("SELECT 1")) # the database responds
cache.get("health-probe") # the cache responds
except Exception:
return "unhealthy", 500
return "healthy", 200
The primary probes run from the DE server (the main
monitoring server, Germany) — strictly at the check's interval.
Two external probes, RU and US, join in to confirm
outages and periodically poll healthy checks (baseline, below).
In your server logs the requests carry
User-Agent: CronAlive-Probe/1.0:
from DE — every check interval, from RU and US — roughly every
15 minutes plus during incidents.
One failed request is not an incident yet. The down status
is assigned only after confirmations
(2 by default) consecutive failed probes — an outage is
detected within at most K intervals. The first successful
response resets the counter and flips the check back to up.
A down additionally requires a quorum of two regions: after K failures from DE the probe job is immediately dispatched to the RU and US agents, and the flip happens only when at least two distinct regions see the failure within a 15-minute window. A local network issue of a single region does not cause a false alert.
To give every region a history, the external probes also poll healthy checks — roughly every 15 minutes (that is the baseline poll; it is why a URL owner sees occasional CronAlive-Probe/1.0 requests from RU/US and constant ones from DE).
If a site blocks some region (the typical case: geo-blocking Russian IPs), that region consistently fails its probes while the others see the site alive. Such a region is "chronic": its failures do not confirm down, a geo-block never causes false alerts, and the check status stays up. On the check page the availability-by-region block marks it with an Unreachable-from-RU badge and an explanation — the same block shows the latest result per region, updating live without a reload.
For https URLs the service watches the certificate expiry:
checked every 12 hours, from the main server (DE), alongside a
successful main probe. The result shows as the TLS: N d
badge on the check page and in the list: green — more than the
threshold remains, amber — below the threshold (the check's
ssl_days_before or 14 days), red —
expired, gray n/a — the certificate could not be fetched.
The alert is separate and opt-in: when ≤
ssl_days_before days remain, a
notification goes to all enabled integrations of the project
(webhooks receive the ssl_expiring
event). Leave the "SSL" field empty to disable the alert — the
badge keeps showing the expiry regardless.