Repository navigation
YAML Reference
Arian Omrani edited this page Oct 11, 2026
·
2 revisions
Language: English · فارسی
Every key of pulsecheck.yml, its type, default and rules. For explanations and recipes see Configuration. Unknown keys anywhere are errors (pulsecheck validate names the key and where it is).
| Rule | Detail |
|---|---|
| Where |
-c FILE, else ./pulsecheck.yml, else ~/.config/pulsecheck/pulsecheck.yml
|
| Format | YAML. JSON is accepted too (the Cloudflare Worker ships JSON) |
${NAME} |
Replaced in every string value (also inside lists and mappings; not in keys) with the environment variable NAME. A variable that is not set is an error (an empty KEY= line in .env counts as not set). There is no default syntax (${X:-y} is not supported) |
.env |
<folder of the config>/.env is loaded first (KEY=value; # comments; quotes allowed; export allowed). Real environment variables win. Empty values count as not set |
| Types |
int accepts 5 or "5", not true. str accepts text or a number. A list must be a list, a mapping must be a mapping |
| Inline mappings | Quote values containing ${VAR} inside { ... }: {url: "https://x/${T}"}
|
| Key | Type | Default | Meaning |
|---|---|---|---|
sites |
list of site | required | The checks. name must be unique |
defaults |
mapping | {} |
Any site key; merged under every site. The site's own value replaces it (no deep merge: a site headers replaces the default headers completely) |
notify |
notify | no urls | Global alert targets |
messages |
mapping | built-in | Alert texts, see messages |
maintenance |
list of maintenance | [] |
Windows that suppress alerts |
otel |
otel | off | OpenTelemetry export |
state_file |
str | pulsecheck.db |
SQLite file (CLI only). ~ is expanded; a relative path is relative to the config file's folder, so cron finds the same file. Ignored on Vercel/Cloudflare |
shoutrrr_bin |
str | auto |
auto = Docker image if docker info works, else the shoutrrr binary; docker = always the image; any other value = path to a binary. Ignored on Cloudflare |
shoutrrr_image |
str | nickfedor/shoutrrr:0.21.2 |
Image used in auto/docker mode |
| Key | Type | Default | Meaning |
|---|---|---|---|
urls |
list of str | [] |
shoutrrr URLs (see Notifications) |
events |
list of str | all four | Which alerts to send: down, up, degraded, ssl_warn. A repeated "still down" reminder counts as down
|
A site-level notify replaces the global one completely, including events.
Common keys (every type):
| Key | Type | Default | Meaning |
|---|---|---|---|
name |
str | required | Unique; used in alerts, status and reports |
type |
http | tcp | ping
|
http |
What to check |
timeout |
int (seconds) | 10 |
Per check (connect / request / ping wait) |
down_after |
int | 2 |
Consecutive failures before the site is down and the first alert is sent |
interval |
int (minutes) | 5 |
Minimum time between checks of this site. A run skips the site if its last check was less than interval minutes minus 1 minute ago (the minute absorbs scheduler jitter) |
max_response_ms |
int | null | off | A successful check slower than this counts as a failure |
slow_ms |
int | null | off | A successful check at least this slow is degraded (sends a degraded alert on change) |
remind_every |
int (minutes) |
0 (off) |
While down, repeat the alert (message key reminder) every N minutes. Also the minimum gap between certificate warnings (default once a day) |
ip_version |
4 | 6 | null |
system default | Connect only over IPv4 or IPv6, for http, tcp, ping and the certificate check. A host with no address of that family is reported down (for example Address family for hostname not supported); there is no silent fallback. IPv6 literals work without this key: url: http://[2001:db8::1]/, host: 2001:db8::1. Skipped on Cloudflare |
tags |
list of str | [] |
Labels for --tag, and {tags} in messages and metrics |
notify |
notify | null | global | Per-site alert targets |
messages |
mapping | {} |
Per-site alert texts (beat the global messages) |
| Key | Type | Default | Meaning |
|---|---|---|---|
url |
str | required |
http:// or https:// URL |
method |
str | GET |
HTTP method |
headers |
mapping str→str | {} |
Request headers |
body |
str | null | none | Request body (ignored for GET/HEAD on Cloudflare) |
expected_status |
list of int | [] |
Status codes that count as up. Empty = any 2xx. Redirects are followed first, so this is the final status |
max_redirects |
int | 5 |
Redirects to follow (CLI/Vercel; ignored on Cloudflare) |
ssl_warn_days |
int | null | off | https only. Warn when the certificate expires in fewer days than this (at most once a day, or per remind_every); a certificate that has expired fails the check with TLS certificate has expired. Not available on Cloudflare |
| Key | Type | Default | Meaning |
|---|---|---|---|
host |
str | required | Name or IP |
port |
int | required | Port. Up = the connection opened. Not available on Cloudflare |
| Key | Type | Default | Meaning |
|---|---|---|---|
host |
str | required | Name or IP. Runs ping -c 1 -W <timeout> <host> (Linux iputils). Not available on Vercel or Cloudflare |
Keys you may set (anything else is an error). Unset keys keep the built-in text.
| Key | Sent when | Built-in |
|---|---|---|
down |
the site went down | 🔴 {site} is DOWN: {error} |
reminder |
still down after remind_every
|
🔴 {site} is still DOWN after {minutes}m: {error} |
degraded |
up but slow (slow_ms) |
🟡 {site} is slow ({ms}ms) |
up |
recovered | 🟢 {site} is UP ({ms}ms) after {minutes}m |
ssl_warn |
certificate expires soon | 🔒 {site}: TLS certificate expires in {days} days |
test |
pulsecheck test-notify |
pulsecheck test notification |
Placeholders (others are errors): {site} {event} {error} {ms} {minutes} {status} {tags} {days}. Use {{ and }} for literal braces. Order: site messages > global messages > built-in.
| Key | Type | Default | Meaning |
|---|---|---|---|
start |
str | required |
"HH:MM" (every day) or "DAY HH:MM" with MON TUE WED THU FRI SAT SUN. UTC
|
duration |
int (minutes) | required | May cross midnight |
name |
str | maintenance |
Label only |
sites |
list of str |
[] (all) |
Site names the window applies to |
Checks keep running and are stored; the alerts (and OpenTelemetry log records) raised inside the window are dropped, not delivered later. Metrics are still exported.
| Key | Type | Default | Meaning |
|---|---|---|---|
endpoint |
str | required | Base URL, for example https://collector:4318. /v1/metrics and /v1/logs are appended |
headers |
mapping str→str | {} |
Extra headers, for example Authorization
|
service_name |
str | pulsecheck |
service.name resource attribute |
resource |
mapping str→str | {} |
More resource attributes |
metrics |
bool | true |
pulsecheck.up, .response_time, .http.status_code, .ssl.days_remaining
|
logs |
bool | true |
One record per alert |
- A check result is ok if the transport worked, the status is expected, and it was not slower than
max_response_ms. - ok and slower than
slow_ms→degraded; ok otherwise →up; not ok → counts a failure, and the site becomesdownafterdown_afterfailures in a row. - An alert goes out only when the status changes (or a reminder / certificate warning is due), is not inside a maintenance window, and its event is listed in
events.
state_file: pulsecheck.db
shoutrrr_bin: auto
shoutrrr_image: nickfedor/shoutrrr:0.21.2
notify:
urls: ["telegram://${TG_TOKEN}@telegram?chats=${TG_CHAT}", "ntfy://ntfy.sh/${NTFY_TOPIC}"]
events: [down, up, degraded, ssl_warn]
messages:
down: "🔴 {site} is DOWN: {error}"
up: "🟢 {site} recovered after {minutes} min"
otel:
endpoint: https://otel-collector.example.com:4318
headers: {Authorization: "Bearer ${OTEL_TOKEN}"}
resource: {env: prod}
maintenance:
- {name: weekly, start: "SUN 02:00", duration: 60, sites: [api]}
defaults: {timeout: 10, down_after: 2, interval: 5, slow_ms: 3000, remind_every: 60}
sites:
- name: web
url: https://example.com
expected_status: [200, 301]
max_response_ms: 10000
ssl_warn_days: 14
tags: [prod, web]
- name: api
url: https://api.example.com/health
method: POST
headers: {Authorization: "Bearer ${API_TOKEN}"}
body: '{"ping": true}'
max_redirects: 3
notify: {urls: ["discord://${DISCORD_TOKEN}@${DISCORD_ID}"], events: [down, up]}
messages: {down: "💳 api DOWN, page on-call: {error}"}
- {name: db, type: tcp, host: db.internal, port: 5432, interval: 1}
- {name: gateway, type: ping, host: 10.0.0.1}| Key / feature | CLI, CI, cron | Vercel | Cloudflare |
|---|---|---|---|
type: http |
yes | yes | yes (max_redirects ignored) |
type: tcp |
yes | yes | skipped |
type: ping |
yes | skipped | skipped |
ssl_warn_days |
yes | yes | ignored |
ip_version |
yes | yes, if the platform has that connectivity (not tested) | site skipped |
state_file, shoutrrr_bin, shoutrrr_image
|
yes | ignored | ignored |
notify.urls |
any shoutrrr URL | built-in 12 services, others via downloaded shoutrrr | built-in 12 services |
| everything else | yes | yes | yes |
| Name | Used by |
|---|---|
XDG_CONFIG_HOME, XDG_STATE_HOME
|
where init puts the config / state and log |
VISUAL, EDITOR
|
pulsecheck env |
CRON_SECRET |
Vercel: bearer token for /api/cron and /api/status
|
STATUS_TOKEN |
Cloudflare: bearer token for /status and /run
|
KV_REST_API_URL, KV_REST_API_TOKEN (or UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN) |
Vercel state store |
PULSECHECK_SOURCE |
install.sh: what uv tool install installs |
| Command | 0 | 1 |
|---|---|---|
run |
finished | with --fail-on-down: at least one site is down |
validate |
valid | an alert URL was rejected by shoutrrr (a config error stops with a message) |
test-notify |
every channel worked | at least one failed, or none configured |
update |
done / up to date | the upgrade command failed |