Skip to main content

Check Types

SolidPing supports 39 check types across multiple categories for monitoring your services. Each check type has specific configuration options and validation capabilities.

Network Checks

HTTP/HTTPS

Monitor web services, APIs, and websites.

URL Format:

http://example.com/path
https://api.example.com/health
OptionDescriptionExample
URLThe endpoint to checkhttps://api.example.com/health
MethodHTTP methodGET, POST, PUT, DELETE
TimeoutRequest timeout30s
Expected StatusStatus code to expect200, 2XX (wildcard)
HeadersCustom request headersAuthorization: Bearer token
BodyRequest body (for POST/PUT){"key": "value"}
Body MatchPattern to match in response"status": "ok"
SSH tunnelDial through an SSH check's bastionAn ssh check with expected_fingerprint set
Basic AuthUsername and password — stored encrypted at restuser:password
Custom User-AgentOverride the default user-agentSolidPing/1.0

Status Code Matching:

  • Exact match: 200, 201, 404
  • Wildcard: 2XX (any 2xx status), 5XX (any 5xx status)

Basic Auth storage: you still enter a username and a password in the form, but the pair is stored as a single encrypted credential (a reserved basicAuth config key) — both halves are protected, not just the password. The dashboard never gets the credential back: an existing one renders as •••• (encrypted — enter new values to replace), and editing anything else on the check leaves it (and any secret headers) untouched. To change it, retype both fields; to remove it, clear both and save. Checks written before this change keep working and fold into the new shape the next time they are saved.

Examples:

# Basic health check
url: https://api.example.com/health
method: GET
expected_status: 200
timeout: 10s

# API with authentication
url: https://api.example.com/v1/users
method: GET
headers:
Authorization: Bearer your-token
Accept: application/json
expected_status: 200
body_match: '"users":'

# POST request
url: https://api.example.com/webhook
method: POST
headers:
Content-Type: application/json
body: '{"test": true}'
expected_status: 200

TCP

Monitor TCP services like databases, message queues, and custom services.

URL Format:

tcp://hostname:port
tcps://hostname:port # With TLS
OptionDescriptionExample
HostTarget hostnamedb.example.com
PortTarget port5432
TLSEnable TLS/SSLtrue / false
TimeoutConnection timeout10s
SSH tunnelDial through an SSH check's bastion — the hostname is resolved by the bastionAn ssh check with expected_fingerprint set

UDP

Check UDP port reachability.

URL Format:

udp://hostname:port
OptionDescriptionExample
HostTarget hostnamedns.example.com
PortTarget port53
TimeoutConnection timeout10s

ICMP (Ping)

Check host availability using ICMP echo requests.

URL Format:

ping://hostname
icmp://hostname
OptionDescriptionDefault
HostTarget hostname or IP-
CountNumber of packets3
IntervalTime between packets1s
TimeoutTotal timeout10s
Permissions

ICMP checks may require elevated permissions on some systems. Docker containers typically need NET_RAW capability.

DNS

Verify DNS resolution and record values.

URL Format:

dns://resolver/domain?type=A
dns://8.8.8.8/example.com?type=MX
OptionDescriptionExample
ResolverDNS server to query8.8.8.8, 1.1.1.1
DomainDomain to resolveexample.com
TypeRecord typeA, AAAA, MX, TXT, CNAME, NS, SOA
ExpectedExpected values93.184.216.34

WebSocket

Monitor WebSocket endpoint availability.

URL Format:

ws://hostname/path
wss://hostname/path # With TLS
OptionDescriptionExample
URLWebSocket endpointwss://api.example.com/ws
TimeoutConnection timeout10s

RDP (Remote Desktop)

Monitor Remote Desktop Protocol servers. Unlike a plain TCP/3389 port probe, this checker performs the pre-auth RDP negotiation handshake (X.224 Connection Request/Confirm, MS-RDPBCGR): a valid answer proves the RDP listener (TermService, xrdp, …) actually parsed the request — not just that a firewall forwards the port. The handshake needs no credentials and stops before any authentication.

OptionDescriptionDefault
HostRDP server hostname or IP- (required)
PortTCP port3389
TimeoutCheck timeout (max 60s)5s
Require NLAMark down unless the server selects Network Level Authentication (CredSSP) — catches NLA silently disabled by policyoff
Cert warning (days)Mark warning when the server certificate expires in at most this many days. 0 = offoff
Cert critical (days)Mark down when the server certificate expires in at most this many days. Must be ≤ Cert warning. 0 = offoff
  • Default verdict = TCP connect + a valid X.224 Connection Confirm. A negotiation failure (RDP_NEG_FAILURE, e.g. HYBRID_REQUIRED_BY_SERVER) or a non-RDP answer yields down.
  • The negotiated security protocol (rdp, tls, nla, nla_ex, rdstls) and the server's negotiation flags are reported in the check output.
  • When a TLS-based protocol is selected, the checker completes one TLS handshake to read the server certificate (subject, issuer, expiry, self-signed flag). RDP certificates are routinely self-signed or from an internal CA, so only the leaf's expiry is inspected — the chain is deliberately not validated. An already-expired certificate is always down.
Network access

RDP hosts are typically reachable only from inside a network — run the check from a worker with network access to the host. The handshake is pre-auth and closes cleanly, so it generates connection events but no authentication-failure noise in Windows event logs.

Security & Certificates

SSL/TLS Certificate

Monitor SSL/TLS certificate expiration and validity.

OptionDescriptionExample
HostTarget hostnameexample.com
PortHTTPS port443
Warning DaysDays before expiry to warn30
Critical DaysDays before expiry to alert7

What gets checked:

  • Certificate validity
  • Expiration date
  • Chain validation
  • Hostname verification

Domain Expiration

Monitor domain name registration expiration. Lookups go through RDAP (RFC 7480–7484), the structured, HTTPS-based successor to WHOIS, with an automatic fallback to WHOIS when RDAP can't answer (no RDAP service for the TLD, a request error, or a response with no expiration date).

OptionDescriptionExample
DomainDomain name to checkexample.com
Warning DaysDays before expiry to warn30
Critical DaysDays before expiry to alert7
Lookup method (Advanced)auto (default, RDAP first with WHOIS fallback), rdap (RDAP only, no fallback), or whois (WHOIS only)auto

The check result reports which path answered via a method field ("rdap" or "whois") alongside the existing expiry_date, days_remaining, and registrar fields.

Expiry is graduated across two tiers, exactly like the SSL/TLS check: at or below Critical Days the check goes down (pages); between Critical and Warning Days it reports warning (amber, counts as up, no incident). Existing checks that only set the legacy single threshold keep working unchanged — it's treated as Critical Days, with Warning Days defaulting to the same value.

DNSBL (DNS Blocklist)

Check whether an IP address or hostname is listed on DNS-based blocklists (DNSBLs) such as Spamhaus, SpamCop, Barracuda, or UCEPROTECT. This is essential for monitoring the reputation of mail servers and public IPs.

OptionDescriptionDefault
TargetIPv4 address or hostname to check- (required)
BlocklistsList of DNSBL zones to queryzen.spamhaus.org, bl.spamcop.net, b.barracudacentral.org, dnsbl-1.uceprotect.net
NameserverCustom DNS resolver (host:port)system resolver
TimeoutQuery timeout (max 60s)10s

Hostnames are resolved to IPv4 before lookup. The check fails when the target is listed on at least one blocklist, and succeeds when it is clean. If every queried zone errors out, the result is inconclusive (timeout).

Error/status codes. DNSBLs reserve the 127.255.255.0/24 range for error and status replies rather than real listings — Spamhaus, for example, returns 127.255.255.254 when a query arrives via a public/open resolver (refused) and 127.255.255.255 when a rate limit is exceeded. SolidPing treats any 127.255.255.x answer as an error code, not a listing: the affected zone is reported as inconclusive and the raw code is surfaced under error_codes in the check output.

Spamhaus from cloud IPs. Because workers run on public cloud (and use the provider's shared resolvers), the public zen.spamhaus.org zone will typically be refused with 127.255.255.254. For reliable Spamhaus results, use the Spamhaus Data Query Service (DQS): configure the DQS account-key blocklist zones and a dedicated resolver via the Blocklists and Nameserver options rather than querying the public zen.spamhaus.org zone.

Database Checks

PostgreSQL

Monitor PostgreSQL database connectivity and query execution.

URL Format:

postgres://user:password@hostname:5432/database
OptionDescriptionExample
URLConnection stringpostgres://user:pass@db:5432/mydb
QueryOptional test querySELECT 1
TimeoutConnection timeout10s

MySQL / MariaDB

Monitor MySQL or MariaDB database connectivity and query execution.

URL Format:

mysql://user:password@hostname:3306/database
OptionDescriptionExample
URLConnection stringmysql://user:pass@db:3306/mydb
QueryOptional test querySELECT 1
TimeoutConnection timeout10s

MongoDB

Monitor MongoDB connectivity using the ping command.

URL Format:

mongodb://user:password@hostname:27017/database
OptionDescriptionExample
URLConnection stringmongodb://user:pass@db:27017/mydb
TimeoutConnection timeout10s

Redis

Monitor Redis server availability using the PING command.

URL Format:

redis://hostname:6379
redis://:password@hostname:6379
OptionDescriptionExample
URLConnection stringredis://redis:6379
TimeoutConnection timeout10s

Microsoft SQL Server

Monitor MSSQL database connectivity and query execution.

URL Format:

sqlserver://user:password@hostname:1433?database=mydb
OptionDescriptionExample
URLConnection stringsqlserver://sa:pass@db:1433?database=mydb
QueryOptional test querySELECT 1
TimeoutConnection timeout10s

Oracle Database

Monitor Oracle database connectivity and query execution.

URL Format:

oracle://user:password@hostname:1521/service
OptionDescriptionExample
URLConnection stringoracle://user:pass@db:1521/orcl
QueryOptional test querySELECT 1 FROM DUAL
TimeoutConnection timeout10s

ClickHouse

Monitor ClickHouse connectivity and query execution over the native (binary) protocol — not the HTTP interface — so the check exercises the same transport your analytics clients use.

OptionDescriptionExample
HostServer hostnameclickhouse.example.com
PortNative port. Defaults to 9000, or 9440 when TLS is on9000
UsernameOptional, defaults to ClickHouse's default usermonitor
PasswordOptional password
DatabaseOptional, defaults to defaultmetrics
Use TLSNative protocol over TLS (required by ClickHouse Cloud)false
Verify TLS certificateValidate the server certificate. Requires TLSfalse
QueryOptional test query, must start with SELECTSELECT 1
TimeoutConnection timeout (max 30s)10s

The check pings the server, then runs the query and reports its first cell. The server version is reported in the result output, and connection_time_ms / query_time_ms / total_time_ms are recorded as metrics.

Email Services

SMTP

Monitor SMTP server availability with optional authentication.

URL Format:

smtp://hostname:25
smtp://hostname:587
smtps://hostname:465 # With SSL
OptionDescriptionExample
HostSMTP serversmtp.example.com
PortSMTP port25, 587, 465
STARTTLSEnable STARTTLStrue / false
AuthTest authenticationuser:password
TimeoutConnection timeout10s

Send mode: a real probe email

By default the SMTP check stops at the handshake (EHLO/STARTTLS/AUTH) — it proves the server is reachable and, optionally, that credentials work, but not that mail submitted to it actually gets delivered. Send mode closes that gap: on every check execution, after the normal handshake, SolidPing submits a real, system-generated email through the monitored server and addresses it to a paired Email Reception check's tokenized address.

OptionDescription
Send a probe emailEnables send mode
Mail FromEnvelope sender for the probe email — the monitored server's outbound policy (SPF/DKIM alignment, relay ACLs) usually dictates it
Delivery checkPick a paired Email Reception check; the dashboard fills in the recipient address from it

The message itself is entirely system-generated — there is no subject or body field to fill in, by design: this keeps the feature from ever becoming a way to send arbitrary mail through a monitored server. It carries two headers the Email Reception check reads to attribute and time the delivery:

X-SolidPing-Check: <the sending SMTP check's UID>
X-SolidPing-Sent-At: <RFC3339 send time>

If an intermediate mail server strips these headers, the Email Reception check still ticks up as normal — only the attribution and latency are lost.

The two checks split responsibility cleanly:

  • The SMTP check's own result reflects submission only — a 250 after DATA is up (with submission_ms recorded), any rejection is down with the server's reply.
  • The paired Email Reception check reflects end-to-end delivery — it goes down (via its normal passive-overdue logic) if probes stop arriving within its period.

Submission failures and delivery failures are different problems with different fixes, so keeping them as two checks gives each its own incident lifecycle.

Sizing the paired check's period. The Email Reception check's period is the delivery deadline. Size it generously:

email check period ≥ SMTP check interval + worst acceptable delivery time

Greylisting in particular can legitimately delay a first-time sender by several minutes — a paired check sized too tightly will flap on nothing but normal greylisting behavior.

A 60-second floor applies to send-mode SMTP checks — every execution sends a real email, so an unbounded fast interval could flood the paired inbox.

Several SMTP checks may target the same Email Reception check — the headers keep each arrival attributable to its sender — but pairing one SMTP check to one dedicated Email Reception check is the recommended setup; a shared target's up/down state otherwise conflates multiple senders. Create the Email Reception check first, then select it from the SMTP check's delivery picker — SolidPing does not offer to create one on your behalf, to keep the two checks' lifecycles independent (delete/rename either one without surprising the other).

Requires a configured inbox

Send mode requires the instance to have an email inbox configured (the same one Email Reception checks use to receive mail) — see Email Reception. The recipient address must also be at that inbox's domain; SolidPing rejects anything else.

Under the hood, the recipient address is stored on the check, not resolved at send time. Picking a delivery check in the dashboard just fills in the address for you — the same probe works identically from any worker, including a private location / deported agent, with no extra setup. One consequence worth knowing: SolidPing does not verify that the delivery check you name belongs to your organization once it's just an address — anyone who already knows another check's tokenized address could in principle aim a probe at it too. The receiving inbox domain restriction still holds absolutely (a recipient outside the instance's own inbox is never possible), and the tokenized address itself is exactly as unguessable as it always was.

IMAP

Monitor IMAP server availability and authentication.

URL Format:

imap://hostname:143
imaps://hostname:993 # With SSL
OptionDescriptionExample
HostIMAP serverimap.example.com
PortIMAP port143, 993
TLSUse implicit TLStrue / false
STARTTLSEnable STARTTLStrue / false
TimeoutConnection timeout10s
Port 993 always means implicit TLS

When creating the check as a JSON config rather than a URL, set "tls": true explicitly alongside "port": 993 — SolidPing also derives implicit TLS automatically from port 993 if tls/starttls are both left unset, but spelling it out keeps a copy-pasted config unambiguous.

POP3

Monitor POP3 server availability and authentication.

URL Format:

pop3://hostname:110
pop3s://hostname:995 # With SSL
OptionDescriptionExample
HostPOP3 serverpop3.example.com
PortPOP3 port110, 995
TLSUse implicit TLStrue / false
STARTTLSEnable STARTTLStrue / false
TimeoutConnection timeout10s
Port 995 always means implicit TLS

When creating the check as a JSON config rather than a URL, set "tls": true explicitly alongside "port": 995 — SolidPing also derives implicit TLS automatically from port 995 if tls/starttls are both left unset, but spelling it out keeps a copy-pasted config unambiguous.

Email Reception (Passive Inbox)

Verify end-to-end email delivery rather than just server connectivity. SolidPing generates a unique address for the check; when a message arrives at that address, the check is marked up. This is ideal for monitoring a full sending pipeline (queue → relay → inbox).

OptionDescriptionDefault
TokenSecret part of the unique receiving addressauto-generated

The receiving domain is configured by your administrator. Point a periodic test email (or your application's "send a heartbeat" job) at the generated address, and SolidPing reports an incident if expected mail stops arriving.

Passive check

Email-reception checks are receive-only — SolidPing waits for mail instead of actively probing a server. Combine it with an SMTP check to also monitor outbound connectivity, or use SMTP send mode to have SolidPing generate and submit that probe email for you automatically.

Remote Access

SSH

Monitor SSH server availability.

URL Format:

ssh://hostname:22
OptionDescriptionExample
HostSSH serverserver.example.com
PortSSH port22
TimeoutConnection timeout10s

FTP

Monitor FTP server availability.

URL Format:

ftp://hostname:21
OptionDescriptionExample
HostFTP serverftp.example.com
PortFTP port21
TimeoutConnection timeout10s

SFTP

Monitor SFTP server availability.

URL Format:

sftp://hostname:22
OptionDescriptionExample
HostSFTP serversftp.example.com
PortSFTP port22
TimeoutConnection timeout10s

Messaging & Streaming

gRPC

Monitor gRPC services using the standard health check protocol (grpc.health.v1).

URL Format:

grpc://hostname:50051
OptionDescriptionExample
HostgRPC serverapi.example.com
PortgRPC port50051
ServiceService name to checkmy.service.v1
TLSEnable TLStrue / false
TimeoutConnection timeout10s

Kafka

Monitor Apache Kafka broker connectivity.

URL Format:

kafka://hostname:9092
OptionDescriptionExample
BrokerKafka broker addresskafka:9092
TimeoutConnection timeout10s

RabbitMQ

Monitor RabbitMQ message queue connectivity.

URL Format:

amqp://user:password@hostname:5672
OptionDescriptionExample
URLAMQP connection stringamqp://guest:guest@rabbitmq:5672
TimeoutConnection timeout10s

MQTT

Monitor MQTT broker connectivity via subscription.

URL Format:

mqtt://hostname:1883
mqtts://hostname:8883 # With TLS
OptionDescriptionExample
HostMQTT brokermqtt.example.com
PortMQTT port1883
TimeoutConnection timeout10s

Telephony

SIP (VoIP)

Monitor SIP servers used for voice/VoIP, either by checking reachability with an OPTIONS ping or by verifying that a user can register (REGISTER with digest authentication).

Address Format:

host:port
udp://host:5060
tcp://host:5060
tls://host:5061
OptionDescriptionDefault
HostSIP server hostname or IP- (required)
PortSIP port5060 (UDP/TCP), 5061 (TLS)
Transportudp, tcp, or tlsudp
Modeoptions (ping) or register (auth)options
DomainSIP domain for From/To headerssame as Host
UsernameSIP username (required for register)-
PasswordSIP password for digest auth (register)-
Expect StatusAccepted SIP status codes for OPTIONS (e.g. 200,405)-
TLS VerifyVerify the server certificate (TLS transport)false
TimeoutRequest timeout (max 60s)5s
  • OPTIONS mode succeeds when the server returns a valid SIP status code (matching expect_status if set).
  • REGISTER mode performs the standard two-step challenge/response and succeeds only on a final 200 OK.

NTP (Time Server)

Monitor an NTP time server. Unlike a plain UDP/123 reachability probe, this checker sends a real NTP request and judges the server as a clock: it confirms the server returns a valid response and reports itself healthy (stratum, leap indicator, and root distance, via the server's own self-report — no trust in the worker's clock). Two optional, opt-in thresholds let you also alert on the measured clock offset and on the server's stratum depth.

OptionDescriptionDefault
HostNTP server hostname or IP- (required)
PortNTP UDP port123
VersionNTP protocol version (3 or 4)4
TimeoutQuery timeout (max 60s)5s
Offset warn (ms)Mark warning when the absolute clock offset exceeds this. 0 = offoff
Offset critical (ms)Mark down when the absolute clock offset exceeds this. Must be ≥ Offset warn. 0 = offoff
Max stratumMark down when the server's stratum exceeds this (115). 0 = offoff
  • Default verdict = reachable and the server reports a usable clock. A Kiss-o'-Death (stratum 0), an unsynchronized server (stratum 16), a LeapNotInSync leap indicator, or an out-of-range root distance all yield down.
  • Clock offset is measured relative to the worker's own clock. A worker whose clock is itself skewed will report a misleading offset, so the offset thresholds are opt-in rather than the default verdict — keep this in mind when running across a distributed worker fleet.
  • Metrics exposed: clock offset, RTT, stratum, root delay, root dispersion, root distance, poll interval, and precision.
Egress

NTP uses outbound UDP port 123, which is frequently blocked by egress firewalls. A blocked path surfaces deterministically as down/timeout.

Infrastructure

SNMP

Monitor devices via SNMP protocol.

OptionDescriptionExample
HostTarget deviceswitch.example.com
CommunitySNMP community stringpublic
OIDObject identifier1.3.6.1.2.1.1.1.0
VersionSNMP version2c
TimeoutConnection timeout10s

Docker

Monitor remote Docker daemon connectivity.

URL Format:

docker://hostname:2375
OptionDescriptionExample
HostDocker daemondocker.example.com
PortDocker API port2375, 2376 (TLS)
TLSEnable TLStrue / false
TimeoutConnection timeout10s

A2S Game Server (Source / Steam)

Query Source-engine and Steam game servers using the Valve A2S protocol (A2S_INFO).

OptionDescriptionExample
HostGame server addressgame.example.com
PortQuery port27015
TimeoutConnection timeout10s

Minecraft

Monitor Minecraft servers (both Java and Bedrock editions), with optional player-count thresholds.

OptionDescriptionDefault
HostServer hostname or IP- (required)
PortServer port25565 (Java), 19132 (Bedrock)
Editionjava or bedrockjava
Min PlayersAlert if fewer players are online (0 = off)0
Max PlayersAlert if more players are online (0 = off)0
TimeoutQuery timeout (max 30s)10s

The check reports online players, max players, MOTD, and version. It fails if the query fails or the player count falls outside the configured bounds.

Freebox Line (xDSL / FTTH)

Monitor the quality of a Freebox broadband line (xDSL or FTTH) through the Freebox OS API. The check connects via a stored Freebox integration connection rather than a direct address.

OptionDescriptionDefault
ConnectionReference to a freebox integration connection- (required)
Link Typexdsl or ftth- (required)
Min Sync Rate (down)Minimum downstream sync rate, kbps (xDSL)0 (off)
Min SNR Margin (down)Minimum downstream SNR margin, dB (xDSL)0 (off)
Max AttenuationMaximum downstream attenuation, dB (xDSL)0 (off)
Max CRC ErrorsMaximum CRC errors per run (xDSL)0 (off)
Min / Max RX PowerOptical receive power bounds, mW (FTTH)0 (off)

The check reports sync rates, SNR, attenuation, CRC counts (xDSL) or optical power and SFP details (FTTH), and fails when the WAN is down, the link is not trained, or any configured threshold is violated.

Kubernetes (Workload Replica Health)

Monitor a Kubernetes workload's replica health — the structural analog of how the Docker check mirrors a container's HEALTHCHECK. The check connects via a stored Kubernetes cluster connection (an integration of type kubernetes) referenced by UID, never an inline credential.

OptionDescriptionDefault
ClusterReference to a kubernetes integration connection- (required)
NamespaceWorkload namespace- (required)
KindDeployment or ReplicaSet- (required)
NameWorkload name- (required)
TimeoutPer-execution API timeout (max 60s)10s

Status semantics (ready vs. desired replicas):

  • UpreadyReplicas == desiredReplicas and desiredReplicas > 0.
  • Warning0 < readyReplicas < desiredReplicas (mid-rollout or partially degraded), or desiredReplicas == 0 (intentionally scaled to zero — surfaced, not paged).
  • DownreadyReplicas == 0 with desiredReplicas > 0, a stuck rollout (Deployment Progressing=False / ProgressDeadlineExceeded), or the workload no longer exists.

Outputs include the namespace, kind, name, container images, and workload conditions; metrics include desiredReplicas, readyReplicas, availableReplicas, updatedReplicas, and unavailableReplicas.

Cluster connection

Register a cluster once under Integrations → Kubernetes (it is a data source, not a notification channel). Three authentication modes:

  • API server + token — an API server URL plus a bearer token (typically a service-account token), optionally a CA certificate (or skip TLS verification).
  • Kubeconfig — paste a full kubeconfig that resolves to an API server and credentials.
  • In-cluster — when SolidPing itself runs as a pod in the target cluster, it uses the mounted service-account token; no credentials are stored.

The token / kubeconfig is stored encrypted (AES-256-GCM) in the connection's private settings and is never returned to the dashboard. Use Test connection to confirm the credentials work — it calls the cluster's /version endpoint.

Required RBAC

The connection only needs read access to the monitored workloads. Bind a read-only ClusterRole to the service account whose token you register:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: solidping-readonly
rules:
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: solidping-readonly
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: solidping-readonly
subjects:
- kind: ServiceAccount
name: solidping
namespace: solidping

Kubernetes discovery (enumerating workloads automatically) builds on this same connection and additionally needs get/list on services, endpoints, and ingresses (and nodes); grant those too if you plan to use it.

Metrics

Prometheus Metric

Alert on a number a target reports about itself rather than on whether it answers. Every other check type answers "is it up?"; this one answers "is the value still acceptable?" — a queue depth, a free-disk gauge, an open-file-descriptor count, an error rate. It works against any endpoint that speaks the Prometheus text exposition format (most Go, Java, Python and Rust services expose one at /metrics), and against a Prometheus server itself via PromQL. No Prometheus + Alertmanager stack is required.

OptionDescriptionDefault
URLMetrics endpoint (scrape) or Prometheus server base URL (promql)- (required)
Modescrape or promqlscrape
MetricSeries name to select (scrape mode)- (required in scrape)
LabelsLabel/value pairs the series must carry (subset match, scrape mode)none
QueryPromQL instant query (promql mode)- (required in promql)
Operator>, >=, <, <=, ==, !=>
Warning ValueThreshold that yields Warning (amber, counts as up, never pages)unset
Critical ValueThreshold that yields Down (pages)unset
MatchWhat to do when several series match: single, min, max, sum, avgsingle
On MissingStatus when nothing matches: down, warning, updown
HeadersExtra request headers (bearer / basic auth)none
TimeoutPer-execution request timeout (max 60s)15s

At least one of Warning Value / Critical Value must be set. 0 is a perfectly legal threshold — "alert when free slots reach 0" is written as warningValue: 0, and it is honoured as a real threshold, not read as "unset".

Modes

scrape fetches the URL, parses the exposition format, and picks the series named by Metric whose labels contain every configured label/value pair (extra labels on the series are fine). Histograms and summaries need no special handling: address them through the flattened series names Prometheus itself exposes — <name>_sum, <name>_count, <name>_bucket (with an le label), or <name> with a quantile label.

{
"url": "https://app.example.com/metrics",
"mode": "scrape",
"metric": "process_open_fds",
"labels": { "instance": "app-1" },
"operator": ">",
"warningValue": 800,
"criticalValue": 1000
}

promql treats the URL as a Prometheus server base URL and runs an instant query against {url}/api/v1/query. Scalar and instant-vector results are accepted; a matrix (range) result is rejected — a range returns a series of points over time, not one current value, so use an instant query.

{
"url": "https://prometheus.example.com",
"mode": "promql",
"query": "sum(rate(http_requests_total{code=~\"5..\"}[5m]))",
"operator": ">",
"warningValue": 1,
"criticalValue": 10
}

Threshold semantics

The check fires when value <operator> threshold is true:

  • Critical breached → Down (pages, opens an incident).
  • Otherwise warning breached → Warning (amber; counts as up for availability, aggregates to Degraded, does not open an incident).
  • Otherwise Up.

A check with only a Warning Value is valid and can never page — the same contract as warningDays on the Domain and SSL checks. Use it for "I want to see this, not be woken by it".

The operator points the thresholds. For > / >= (something growing too big), Critical must be greater than or equal to Warning. For < / <= (something shrinking too far) the ordering reverses — this is the free-disk shape:

{
"url": "https://app.example.com/metrics",
"mode": "scrape",
"metric": "node_filesystem_avail_bytes",
"labels": { "mountpoint": "/" },
"operator": "<",
"warningValue": 10737418240,
"criticalValue": 2147483648
}

That check warns below 10 GiB free and pages below 2 GiB. == and != accept a Critical Value only — there is no ordering between two equality targets, so a warning tier would be meaningless and is rejected at validation time.

Multiple matching series

By default (match: single) a selector that matches more than one series is an error result, not a silent pick — an ambiguous selector is a configuration bug, and guessing would grade an arbitrary series. Either narrow the selector with labels, or choose an explicit aggregation: min, max, sum or avg.

Missing metrics

onMissing decides what an absent metric (or an empty PromQL vector) means. The default is down: a metric that vanished usually means the target is broken, not healthy. Use warning when the metric is expected to be absent occasionally, or up when its absence is genuinely fine.

Counters and rates

This check reads whatever value is exposed, right now. It performs no client-side rate computation — a rate needs state between executions, which is explicitly out of scope. A raw counter (http_requests_total) only ever grows, so thresholding it directly is rarely what you want. For rates, use promql mode and let Prometheus do the work: rate(http_requests_total[5m]).

Graphing

Every execution records the resolved value as a value metric, so the check page graphs the monitored number over time and rolls it up like any latency metric — that history is half the point of the check type.

Limits

Scrape responses are capped at 5 MB. A larger body is refused with an explicit error naming the cap — never truncated: a half-read exposition body still parses, and would then be graded as a wrong-but-plausible value. If your /metrics output is that big, narrow the endpoint or switch to promql mode, where the query bounds the response.

Special Check Types

Heartbeat

Passive monitoring that expects incoming pings at regular intervals. Instead of SolidPing checking a service, the service pings SolidPing to report it's alive.

OptionDescriptionDefault
PeriodExpected ping interval60s
GraceGrace period before incident30s

Use cases:

  • Cron job monitoring
  • Backup completion verification
  • Batch process health checks
  • IoT device connectivity

Each ping's caller metadata (User-Agent header, source IP, and HTTP method) is recorded and shown on that ping's result detail page — useful for confirming which script or host is actually pinging the check.

Sending the token. The dashboard generates a ?token= URL that works everywhere, but the token can also travel as an Authorization: Bearer header instead — useful when you'd rather not put a secret in a URL (proxy and CDN access logs, shell history, Referer headers). Both forms are accepted forever; if a request supplies both, the header wins.

# Query string (works everywhere, including a bare browser tab)
curl "https://your-solidping.example.com/api/v1/heartbeat/default/my-cron-job?token=<TOKEN>"

# Authorization header (keeps the token out of logs and URLs)
curl -H "Authorization: Bearer <TOKEN>" \
"https://your-solidping.example.com/api/v1/heartbeat/default/my-cron-job"

Structured body. A JSON body's message key still becomes the ping's message exactly as before. A durationMs key — a number of milliseconds, between 0 and 604 800 000 (7 days) — becomes the result's response time, feeding the check's response-time chart just like an active probe's measured duration; an invalid value (wrong type, negative, or over the cap) is ignored for that purpose but still shown in the "Data" card below, so you can see exactly what was sent. Any other keys in the body are stored alongside it and shown in that "Data" card on the result detail page — handy for a CI run URL, commit SHA, record count, or batch ID. The body is capped at 8 KiB; malformed JSON is tolerated (the ping is still recorded with an empty message), but an over-cap body is rejected with 400.

curl -X POST -H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{"message":"backup completed","durationMs":42000,"recordCount":18234,"runUrl":"https://ci.example.com/runs/512"}' \
"https://your-solidping.example.com/api/v1/heartbeat/default/my-cron-job"

Monitoring GitHub Actions

Your nightly workflow can stop running and nobody notices. GitHub already emails you when a workflow fails, but it has no way to tell you a scheduled workflow never ran at all — and GitHub auto-disables scheduled workflows after 60 days of repository inactivity, silently. A broken cron expression, a renamed default branch, or a deleted secret can just as easily stop a schedule from firing, with zero notifications either way. This is exactly the gap a heartbeat check closes: period + grace is an assertion about absence — "if no ping arrives in time, open an incident" — which no notify-on-failure system can make.

fclairamb/solidping-action wraps the ping in one step, mapping the job's outcome to the right heartbeat status and building an actionable message (run URL, workflow name, run number, commit SHA, actor) from the github context:

- uses: fclairamb/solidping-action@v1
if: always()
with:
org: acme
check: nightly-backup
token: ${{ secrets.SOLIDPING_HEARTBEAT_TOKEN }}
status: ${{ job.status }}

status should always be ${{ job.status }}; the action maps it to SolidPing's vocabulary:

job.statusHeartbeat status
successup
failuredown
cancelledno ping sent
anything elseerror

This is for on: schedule workflows only — not push-triggered CI. A heartbeat's period is meaningful for a cron job that's expected to run every N minutes; a push-triggered job has no period, so a quiet repo with no pushes for a few days would trip the grace window and page someone for nothing. Reporting push-triggered CI failures is a different, useful feature, but it isn't this one.

JavaScript

Custom monitoring scripts with arbitrary logic. Write JavaScript code that runs on each check cycle.

Minimum period: 30s (default 1m) — see Check Intervals.

Use cases:

  • Complex multi-step API workflows
  • Custom business logic validation
  • Conditional checks based on time or state
  • Aggregating multiple checks into one

Browser

Headless browser-based monitoring using a real browser engine.

Minimum period: 60s (default 5m) — a headless-browser run costs several seconds, so faster periods would occupy a monitoring slot continuously. See Check Intervals.

Use cases:

  • Single-page application monitoring
  • Login flow verification
  • Visual regression detection
  • JavaScript-rendered content checks

Where Chrome comes from

The SolidPing image is distroless and deliberately ships no browser — a browser check drives a Chrome that lives outside the SolidPing process. There are two ways to give it one, and nothing is ever downloaded at runtime.

1. Remote Chrome over CDP (recommended, and the only option in containers). Point the worker at a long-lived headless Chrome speaking the Chrome DevTools Protocol:

SettingEnvironment variableMeaning
checkers.browser.cdp_urlSP_CHECKERS_BROWSER_CDP_URLWebsocket/HTTP address of the CDP endpoint, e.g. ws://browser:9222
checkers.browser.chrome_pathSP_CHECKERS_BROWSER_CHROME_PATHLocal Chrome binary for the fallback below

Each execution opens a fresh isolated (incognito) browser context and tab, torn down afterwards, so consecutive checks never share cookies, storage or a service worker. Because the browser process is already running, the measured duration no longer includes Chrome's ~1s cold start.

The expected deployment shape is a sidecar next to each checks workerchromedp/headless-shell, pinned to a tag so every region runs the same Chrome version, reached over localhost. In Docker Compose that is an extra service; see Docker Compose installation. In Kubernetes it is a second container in the worker Pod with SP_CHECKERS_BROWSER_CDP_URL=ws://127.0.0.1:9222.

If the endpoint is unreachable, the check reports an error — never "down". Your monitored site is not implicated by your browser sidecar being down, and SolidPing will not raise a false incident for it. The browser capability (below) also drops on the next worker heartbeat.

2. Local Chrome binary (fallback). With no cdp_url configured, SolidPing executes a locally installed Chrome/Chromium: chrome_path if set, otherwise the usual binary names (google-chrome, chromium, chromium-browser, …). This is the zero-config path on a developer laptop and an opt-in for agents installed on a host that already has Chrome. SolidPing never downloads a browser.

Concurrency

At most 4 browser checks run at a time per worker — a browser execution costs orders of magnitude more than a network probe, and an unbounded pool of tabs would starve the sidecar. A fifth execution waits for a slot inside its own timeout budget and reports a timeout if none frees up. Space browser checks out, or add workers, rather than lowering their period.

Region capability

Workers self-report a browser capability (a reachable CDP endpoint, or a local binary), aggregated per region alongside ipv4/ipv6. Creating or editing a browser check in a region whose live workers report no browser produces a warning naming a region that does have one — the check is still saved and still runs. A region with no live worker, or served by an agent predating the probe, reports unknown and never warns.

Common Options

All check types support these common options:

OptionDescriptionDefault
nameDisplay name-
descriptionDescription-
enabledEnable/disable checktrue
periodCheck interval60s
timeoutRequest timeout30s
regionsWorker regions to run fromall
incident_thresholdFailures before incident1
escalation_thresholdFailures before escalation3
recovery_thresholdSuccesses before recovery1
ipVersionAddress family to probe over (auto, ipv4, ipv6)auto

IP version

An IPv4 check does not verify IPv6 reachability. By default a check resolves its target and probes exactly one address — whichever family it lands on first. So a dual-stack host whose IPv6 path is broken (a missing AAAA record, a firewall rule that was never added for v6, a dead v6 route, a load balancer listening on v4 only) keeps reporting up while every IPv6 user is down.

Set ipVersion to pin the check to a family, or pick it under Advanced → IP version in the dashboard:

ValueMeaning
auto (default)No constraint — probe one address, exactly as before this option existed. Unchanged behaviour for every check that does not set it.
ipv4Probe over IPv4 only. Fails if the target publishes no A record.
ipv6Probe over IPv6 only. Fails if the target publishes no AAAA record.

The family a probe actually used is reported back as the ip_version field of the result output, and shown on the check detail page — so an ipVersion: ipv6 check that reports ip_version: ipv6 is real, verified IPv6 coverage.

One check covers one family. auto means "pick one", not "probe both" — this is a deliberate difference from Better Stack, where an unset value monitors both. To cover both families, create two checks on the same target, one pinned to each; the Better Stack importer warns when a monitor relied on that default.

Supported on http, tcp, udp, icmp, ssl, ssh, smtp, imap, pop3 and dnsbl (where only auto/ipv4 are accepted — DNS blocklists are indexed by IPv4 address). The dashboard only shows the option on types that support it, driven by supportsIpVersion on /api/v1/orgs/{org}/check-types.

dns checks do not take ipVersion and reject it. For a DNS check the option could mean either "which record types to assert on" or "which transport to reach the nameserver over" — two different features. Use the dns check's own record_type (A / AAAA) to assert on records.

Tunneled checks do not take ipVersion either and reject the pair. A tunneled check is resolved and dialed on the far side of the bastion, so the address family is the tunnel's to choose — pinning it here could only ever be a claim the worker cannot honor.

When a worker has no IPv6. A check pinned to a family the worker itself cannot originate fails with an explicit error saying so — it names the worker's missing egress rather than blaming the target. If you see it, change the check's region rather than investigating your service.

SSH tunnel

Every TCP-based check type can dial its target through an SSH check's bastion — set tunnelCheckUid to a reference to an ssh check that has expected_fingerprint set, or pick it under Advanced → Run through SSH tunnel in the dashboard. This covers the classic bastion use cases (a database or broker on a private network): http, tcp, ssl, websocket, grpc, postgresql, mysql, mssql, oracle, clickhouse, redis, mongodb, rabbitmq, kafka, mqtt, smtp, imap, pop3, and ftp.

UDP- and ICMP-based types (icmp, udp, ntp, snmp, dns, dnsbl, sip, a2s) cannot tunnel — an SSH direct-tcpip forward is TCP only. The dashboard only shows the option on types that support it, driven by supportsTunnel on /api/v1/orgs/{org}/check-types.

Check Intervals

Supported interval formats:

  • Seconds: 10s, 30s, 60s
  • Minutes: 1m, 5m, 15m
  • Hours: 1h, 6h, 24h, 168h (1 week), 336h (2 weeks), 720h (30 days)

The dashboard's interval picker offers 1 week / 2 weeks / 30 days for any check type whose MaxPeriod allows it (uncapped by default — see the table below), useful for slow-moving checks like domain expiration. Every region you select still runs the check at the full interval — see Multiple regions.

Minimum intervals

The API enforces a minimum period per check type — both in the dashboard and on direct API calls (400 VALIDATION_ERROR naming the floor):

Check typeMinimum periodDefault period
browser60s5m
js30s1m
ssl1h6h
domain6h24h
dnsbl15m1h
All other types10s1m

Heavy check types (headless browser, custom scripts) carry higher floors because each run can occupy a monitoring slot for several seconds — a fast period would keep a runner busy full-time. Existing checks are grandfathered: a period created before a floor was raised keeps working, and the limit applies on the next edit. The check detail page shows a warning when a check occupies 50% or more of a runner slot (its duty cycle).

Recommended minimum: 30s for production.

Multiple regions

The period applies per region: each region you select runs the check at the full interval, and SolidPing staggers the regions across the period so they don't all fire at once. A 60s check on 3 regions runs every 60 seconds in each region (roughly 20 seconds apart), for a combined detection interval of about 20 seconds — selecting more regions multiplies coverage, it does not divide the frequency.

By default the inter-region offset ("spread") is period ÷ region count. Set regionSpread (a duration, API-first) to override it — e.g. 1s to sample all regions almost simultaneously for comparative cross-region latency, or 0s to fire them together. It must satisfy 0 ≤ regionSpread < period.

Because every region executes independently, a multi-region check consumes regions × 60s ÷ period checks per minute against your plan's checks-per-minute limit (a 60s check on 3 regions counts as 3/min). The Usage page reflects this multiplier.

Best Practices

  1. Use appropriate timeouts - Set timeouts based on expected response times
  2. Avoid excessive frequency - Sub-minute checks increase load on both SolidPing and targets
  3. Use meaningful names - Make check names descriptive for quick identification
  4. Set appropriate thresholds - Balance between noise and missing real issues
  5. Monitor from multiple regions - Use distributed workers for global services
  6. Use database checks for actual connectivity - Prefer native database checks (PostgreSQL, MySQL, Redis) over generic TCP checks for database monitoring
  7. Leverage heartbeat checks - Use heartbeat mode for monitoring cron jobs and batch processes