# StatusTick docs > StatusTick checks your websites, APIs and cron jobs from several regions, confirms a failure before it alerts you, and keeps your users informed with a status page. Every page below is also at its URL, and as Markdown at its URL with .md added. --- # How StatusTick works URL: https://statustick.com/docs/how-statustick-works > The core ideas in StatusTick: monitors, regions, checks, incidents, alert channels and status pages, and how they connect. StatusTick watches your websites, APIs, servers and scheduled jobs, opens an incident when one of them really fails, and tells the right people. This page explains the building blocks. ## Organizations and members Everything in StatusTick belongs to an **organization**. People join an organization by invite and have one of three roles: | Role | Can do | | --- | --- | | Owner | Everything, including member management and deleting the organization | | Admin | Create and change monitors, alert channels, incident settings and status pages | | Member | See monitors, incidents and reports, and work on incidents | Changes to monitors, channels and members are recorded in the organization's audit log. ## Monitors A **monitor** is one thing StatusTick checks: a URL, a host and port, a DNS name, or a scheduled job that reports in. Each monitor has a type, a target, an interval (every 30 seconds to every 24 hours) and the regions to check from. See [Monitor types](https://statustick.com/docs/monitor-types). ## Regions, private agents and checks On every interval, StatusTick runs a **check** from each region you chose, at the same time. Regions are public StatusTick locations or **private locations**: agents you run inside your own network to check internal services. Each region reports its own result: up, degraded, blocked or down, with the response time and the error if there was one. The regions are combined into one monitor status. By default, a monitor is only **down** when at least two regions fail. A single failing region is re-checked at once. See [Avoiding false alarms](https://statustick.com/docs/avoiding-false-alarms). Every check result is kept for 14 days. Each hour, StatusTick rolls the results up into hourly uptime and average, p95 and p99 response times, and keeps that history for 13 months. ## Incidents When a monitor goes down and stays down for the number of failed checks you set, StatusTick opens an **incident**. When the monitor recovers for the number of good checks you set, the incident resolves on its own. On an incident, your team can acknowledge it, assign it, change its severity (Critical, High, Medium, Low) and add comments. You can also open an incident by hand for problems a monitor cannot see. ## Alert channels An **alert channel** is where StatusTick sends incident alerts: email, SMS, Slack, Microsoft Teams, Discord, Telegram, PagerDuty or your own webhook. See [Alert channels](https://statustick.com/docs/alert-channels). ## Status pages A **status page** shows your users the state of your services. It is made of components, and each component is linked to one or more monitors. When the monitors disagree with a component, StatusTick suggests the change and a person publishes it. Visitors see the overall status, 90 days of uptime per component and your incident posts. StatusTick drafts each post from the incident, and pages can use your own domain and email subscribers. --- # Set up with an AI agent URL: https://statustick.com/docs/set-up-with-an-ai-agent > Copy-paste prompts for Claude Code and Cursor that add monitoring to your app: through the StatusTick MCP server, or as a statustick.yml file you sync with the CLI. Your coding agent already knows your app: its URL, its health route and its scheduled jobs. Give it access to StatusTick and one prompt, and it sets up the monitors for you. There are two ways: | Way | Best when | | --- | --- | | [MCP server](#set-up-through-the-mcp-server) | You want monitors now, without new files in your repository. The agent creates them in StatusTick for you. | | [statustick.yml and the CLI](#set-up-with-statustick-yml-and-the-cli) | You want your monitors in code, reviewed in pull requests and synced from CI. | Both prompts ask the agent to show you the plan first and wait for your OK before it creates anything. ## Set up through the MCP server The StatusTick MCP server is at `https://mcp.statustick.com`. It lets an agent list, create, pause and resume monitors, and read incidents and status pages. It cannot delete anything. ### 1. Add the server **Claude Code:** run this in your project folder: ```bash claude mcp add --transport http statustick https://mcp.statustick.com ``` **Cursor:** add the server to `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` for all projects): ```json { "mcpServers": { "statustick": { "url": "https://mcp.statustick.com" } } } ``` ### 2. Sign in **Claude Code:** start `claude`, run `/mcp`, pick `statustick` and choose to authenticate. **Cursor:** open Cursor Settings, find `statustick` in the MCP list and sign in when Cursor asks. Your browser opens the StatusTick sign-in page. Sign in, pick the organization, and choose **read and write** so the agent can create monitors. Only owners and admins can give write access; read only is enough to ask about monitors and incidents. No account yet? Choose **Continue with your email** on the sign-in page. StatusTick creates an account for you and emails a link to finish it. Open the link within 14 days to keep the account and to start receiving alerts. If your MCP client cannot sign in through the browser, use an organization API key (Settings → API keys, read and write) instead: ```bash claude mcp add --transport http statustick https://mcp.statustick.com \ --header "Authorization: Bearer $STATUSTICK_API_KEY" ``` In Cursor, add `"headers": { "Authorization": "Bearer stk_live_…" }` next to `url`, and keep that file out of git. ### 3. Ask the agent to add monitoring Paste this prompt into Claude Code or Cursor (agent mode): ```text Use the StatusTick MCP server to add monitoring to this app. 1. Find the production URL of the app (check the README, environment files, vercel.json and deploy config; ask me if you cannot find it). 2. Find a health route, for example app/api/health/route.ts in a Next.js app. If there is none, propose a small one that returns 200 when the app and its database work, and wait for my OK before adding it. 3. Find every scheduled job: crons in vercel.json, scheduled GitHub Actions workflows, node-cron or similar schedulers, and background workers. Then show me a table of the monitors you plan to create and wait for my OK: - an HTTP monitor for the home page, every 60 seconds - an HTTP monitor for the health route, every 60 seconds - a HEARTBEAT monitor for each scheduled job, with an interval that matches its schedule After I agree, create them with create_monitor. Each heartbeat answer has a ping URL. For each job, add code that calls its ping URL when the job ends successfully, reading the URL from an environment variable such as STATUSTICK_PING_URL_NIGHTLY_REPORT. Never write a ping URL into the code. At the end, list the monitors you created and the environment variables I need to set, with their values. ``` New monitors use your organization's default regions. Choose where alerts go and which status pages show the monitors in the dashboard; see [Alert channels](https://statustick.com/docs/alert-channels) and [Heartbeat monitors](https://statustick.com/docs/heartbeat-monitors). ### More things to ask The same server answers questions about what you monitor: ```text Is anything down in StatusTick right now? If there is an open incident, show me its timeline and the last failed checks. ``` ```text Start a 30-minute StatusTick maintenance window for the API monitors while I deploy, and end it when the deploy is done. ``` ## Set up with statustick.yml and the CLI With the `statustick` CLI, your monitors live in a `statustick.yml` file next to your code. A sync makes StatusTick match the file: it creates new monitors, changes the ones that differ and deletes the ones you removed from the file. Monitors made in the dashboard are never touched. The `statustick` command comes with the launch. Until then, use the [MCP server](#set-up-through-the-mcp-server). A `statustick.yml` your agent writes today works with the CLI as it is. ### 1. Give the CLI an API key Create an organization API key in Settings → API keys and set it in your shell, not in a file in the repository: ```bash export STATUSTICK_API_KEY=stk_live_… # read and write to sync; read is enough for a dry run ``` ### 2. Ask the agent to write the file Paste this prompt into Claude Code or Cursor (agent mode): ```text Add StatusTick monitoring to this app as code. Read https://statustick.com/docs/set-up-with-an-ai-agent.md for the statustick.yml format. 1. Find the production URL, the health route and every scheduled job (crons in vercel.json, scheduled GitHub Actions workflows, node-cron or similar). Ask me if you cannot find the production URL. 2. Write statustick.yml in the repository root with version: 1 and: - an http monitor for the home page and one for the health route, interval 1m - a heartbeat monitor for each scheduled job, with a cron and timeZone that match its schedule Use short, stable keys; renaming a key later deletes the monitor and creates a new one. Put secret header values in ${ENV_VAR} references. 3. Run `statustick validate` and fix every problem it reports. 4. Run `statustick sync --dry-run` and show me the plan. Run `statustick sync` only after I agree. 5. The sync prints a ping URL for each new heartbeat. For each job, add code that calls its ping URL when the job ends successfully, reading it from an environment variable such as STATUSTICK_PING_URL_NIGHTLY_REPORT, and tell me which variables to set. ``` ### The file format A `statustick.yml` for a Next.js app with one Vercel cron job: ```yaml version: 1 defaults: interval: 1m timeout: 10s tags: [web] monitors: - key: home name: Home page type: http target: https://app.example.com - key: health name: Health route type: http target: https://app.example.com/api/health http: expectedStatusCodes: [200] keyword: '"status":"ok"' degradedThresholdMs: 1500 - key: nightly-report name: Nightly report type: heartbeat heartbeat: cron: "0 3 * * *" timeZone: UTC grace: 10m ``` The fields: | Field | What it sets | | --- | --- | | `version` | Always `1`. Required. | | `defaults` | Values for every monitor that leaves the field out: `interval`, `timeout`, `locations`, `alertPolicy`, `tags`, `group`. | | `key` | Required. 1 to 64 of `a-z`, `0-9`, `-` and `_`, unique in the file. StatusTick tracks the monitor by its key. | | `name` | The name in StatusTick, at most 64 characters. Default: the key. | | `type` | `http`, `tcp`, `ping`, `dns` or `heartbeat`. | | `target` | A URL for `http`, `host:port` for `tcp`, a host for `ping` and `dns`. Heartbeats have no target. | | `interval` | Seconds, or `30s`, `5m`, `1h`, `1d`. From 30 seconds to 1 day. Default `5m`. | | `timeout` | 1 to 60 seconds. Default `10s`. | | `locations` | Region codes, region names or private location names. Left out, the monitor keeps its locations. | | `http` | `method`, `headers`, `expectedStatusCodes` (default 200 to 206) and `keyword`, text the response must contain. | | `dns` | `recordType`: `A`, `AAAA`, `CNAME`, `MX`, `TXT`, `NS` or `SOA`. Default `A`. | | `heartbeat` | `grace` (default `5m`), and `cron` with `timeZone` (an IANA name, default UTC) instead of an interval. | | `degradedThresholdMs` | Checks slower than this count as degraded. | | `tags`, `group` | Up to 10 tags of at most 32 characters, and a group name. | | `paused` | `true` to stop checks and alerts. | | `alertPolicy` | An alert policy by name, or `Default`. Left out, set it in the dashboard. | | `statusPageComponents` | A list of `page` and `component` names the monitor shows on. Left out, set it in the dashboard. | `${NAME}` in a value is read from the environment when the CLI runs, and values never show in plans. A field you remove goes back to the default on the next sync. ### The commands | Command | What it does | | --- | --- | | `statustick validate` | Checks the file without calling StatusTick. Each problem names the line and the field. | | `statustick sync --dry-run` | Shows what a sync would create, change and delete, field by field. | | `statustick sync` | Makes StatusTick match the file. If StatusTick refuses one monitor, nothing is saved. | | `statustick export -o statustick.yml` | Writes the monitors you already have as a file, to start from. | | `statustick adopt` | Takes over monitors made in the dashboard that the file names by `id`. | Monitors the file manages refuse edits in the dashboard and the API, except alert settings, muting and deleting, so the file stays the source of truth. A monitor deleted by hand comes back on the next sync. ## Other agents and tools - **Any MCP client** (ChatGPT, Windsurf, VS Code and others): add `https://mcp.statustick.com` as a remote MCP server over Streamable HTTP, and sign in or send an API key as `Authorization: Bearer`. - **REST API:** the same monitors, incidents and status pages, with organization API keys. The reference is at [api.statustick.com/docs](https://api.statustick.com/docs) and the OpenAPI file at `https://api.statustick.com/docs/openapi.yaml`. - **These docs for agents:** [statustick.com/llms.txt](https://statustick.com/llms.txt) lists every docs page, [llms-full.txt](https://statustick.com/llms-full.txt) has all of them in one Markdown file, and every page is also Markdown when you add `.md` to its URL. --- # Monitor types URL: https://statustick.com/docs/monitor-types > What StatusTick can check: HTTP(S), TCP, ping, DNS, browser checks, heartbeats, SSL certificates, domain expiry and page assets, with the settings for each. Every monitor has a type. The type decides what a check does and which settings you can set. ## HTTP(S) Sends an HTTP request to a URL and checks the answer. Use it for websites, APIs and health endpoints. | Setting | What it does | | --- | --- | | Method, headers, body | The request StatusTick sends. Bodies can be JSON, form data or raw text. | | Expected status codes | Which codes count as up. Anything else counts as down. | | Response must contain / must not contain | A text check on the response body, with an option to ignore case. | | Response headers | Headers the response must include, with optional values. | | Follow redirects | Turn off to treat a redirect as the answer instead of following it. | | Timeout | How long to wait before the check fails. | | Slow-response threshold | Responses slower than this show as **Degraded**, not down. | ### SSL certificate check For HTTPS monitors, StatusTick also reads the TLS certificate once a day. It alerts before the certificate expires, and at once if the certificate is invalid, expired or does not match the host name. The warning times scale with the certificate's lifetime, so short-lived certificates do not alert too early or too late. It also warns when a certificate was not renewed at its usual time. ### Page assets check Optional. After loading the page, StatusTick checks up to 30 images, scripts and stylesheets on it. If any fail to load, the check is **Degraded** and lists the broken URLs. You can ignore assets from other domains. This check runs at most every 10 minutes. ## TCP Opens a connection to a host and port, for example a database, mail server or game server. The SSL certificate check also works on TLS ports such as 465 or 993. ## Ping Sends ICMP ping to a host and records the round-trip time. ## DNS Resolves a host name for one record type (A, AAAA, CNAME, MX, TXT, NS or SOA) and can check that the answer matches the value you expect. ## Playwright checks (browser) Runs a Playwright script in a real Chromium browser to test a full user journey, such as log in and check out. See [Playwright checks](https://statustick.com/docs/browser-checks). ## Heartbeat For jobs that run on a schedule, such as backups, cron jobs and queue workers. There is nothing to call from outside, so the job calls StatusTick instead. See [Heartbeat monitors](https://statustick.com/docs/heartbeat-monitors). ## Domain expiry For HTTP, TCP, ping and DNS monitors, StatusTick finds the registered domain, reads its expiry date from the registry (RDAP) and alerts before it expires. ## IPv4 and IPv6 A host can work over IPv4 and fail over IPv6, or the other way round. You can check both address families separately, so you see which one fails. ## Limits - **Private and internal addresses from public regions.** Public regions refuse targets such as `localhost`, `10.0.0.0/8` or `192.168.0.0/16`. To check internal services, use a private agent in your network. --- # Heartbeat monitors URL: https://statustick.com/docs/heartbeat-monitors > Watch cron jobs, backups and workers: your job calls a secret StatusTick URL, and StatusTick alerts when the call does not arrive in time. A heartbeat monitor watches something that runs on a schedule: a backup, a cron job, a queue worker. Instead of StatusTick calling your service, your job calls StatusTick each time it runs. ## How it works 1. Create a heartbeat monitor and set how often the job runs. You can set a simple interval (for example every 24 hours) or a cron expression. 2. Set a **grace period**: how late the job may be before it counts as missing. 3. Copy the monitor's unique ping URL and call it from your job when it finishes. If no call arrives within the interval plus the grace period, the monitor goes **down** and the normal incident and alert flow runs. ## Calling the ping URL Ping URLs look like `https://webhook.statustick.com/v1/ping/`. A `GET` or a `POST` to the URL counts as a ping. For example, at the end of a shell script: ```bash # Replace the URL with the ping URL from your monitor page curl -fsS --retry 3 "$STATUSTICK_PING_URL" > /dev/null ``` The URL also has two extra endpoints: | Endpoint | Use it to | | --- | --- | | `/start` | Mark the start of the job, so StatusTick can measure how long it runs. | | `/fail` | Report a failure at once, without waiting for the grace period. | For example: ```bash curl -fsS "$STATUSTICK_PING_URL/start" > /dev/null if ./backup.sh; then curl -fsS "$STATUSTICK_PING_URL" > /dev/null else curl -fsS "$STATUSTICK_PING_URL/fail" > /dev/null fi ``` ## Keep the URL secret Anyone with the ping URL can report pings for the monitor. Store it like a password, for example in an environment variable. If it leaks, regenerate it from the monitor page; the old URL stops working. --- # Playwright checks URL: https://statustick.com/docs/browser-checks > Monitor full user journeys with Playwright: write a script, run it in real Chromium on a schedule from several regions, and debug failures with screenshots and traces. A browser check runs a Playwright script in a real Chromium browser on a schedule. Use it for journeys that a single HTTP request cannot prove: log in, sign up, search, check out. ## Write a script Browser checks use the Playwright test API. Each check is one test file. ```ts import { test, expect } from '@playwright/test'; test('customer can log in', async ({ page }) => { await page.goto('https://app.example.com/login'); await page.getByLabel('Email').fill(process.env.TEST_USER_EMAIL!); await page.getByLabel('Password').fill(process.env.TEST_USER_PASSWORD!); await page.getByRole('button', { name: 'Log in' }).click(); await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible(); }); ``` Use **Run now** in the editor to try the script before you save it. ## Secrets Store test accounts and keys as encrypted **variables** on the check. They are available as `process.env.NAME` in the script and are never shown in results or logs. Use a dedicated test account with the least rights it needs. ## Schedule and locations - Schedules from every 5 minutes to once a day. - Run from one or more public regions, or from a private agent to test internal apps. - The same false-alarm controls apply as for every monitor: confirmation from more than one region, failures in a row and maintenance windows. ## Results Every run records: | Result | What you get | | --- | --- | | Status | Passed or failed, with the failing step and the error | | Step timings | Duration of each test step | | Screenshot | The page at the moment of failure | | Trace | A Playwright trace to replay actions, network requests and console messages | | Web Vitals | LCP, CLS and total blocking time | ## Limits - One test file per check, with a run time of up to 2 minutes. - Each run starts in a fresh, isolated browser; nothing is kept between runs. - Files on your computer cannot be imported; keep helpers inside the test file. --- # Private agents URL: https://statustick.com/docs/private-agents > Run a StatusTick agent inside your network to monitor internal services: install, network requirements, what leaves your network, and the security model. A private agent is a small StatusTick process that runs inside your network. It checks services that are not on the internet, such as internal APIs, admin tools, databases and intranets, and sends the results to StatusTick. ## Private locations and agents - A **private location** is a named place in your organization, for example "Frankfurt office" or "prod-vpc". Monitors choose it like a public region. - An **agent** is one running process in a private location. You can run more than one with the same token: each check goes to one of them, and when one stops, the others pick up its checks. ## Install 1. In StatusTick, open **Settings → Private locations** and add a location. 2. Copy the token. It is shown once. 3. Start the agent on any host with Docker: ```bash docker run -d --name statustick-agent --restart unless-stopped \ -e STATUSTICK_URL="https://agent.statustick.com" \ -e STATUSTICK_TOKEN="" \ ghcr.io/statustick/agent:1 ``` The location shows **Online** within a minute. Add monitors and choose the private location. With Docker Compose: ```yaml services: statustick-agent: image: ghcr.io/statustick/agent:1 restart: unless-stopped environment: STATUSTICK_URL: https://agent.statustick.com STATUSTICK_TOKEN: ${STATUSTICK_TOKEN} ``` The image runs on amd64 and arm64, so a Raspberry Pi works too. ### Kubernetes (Helm) The Helm chart runs 2 agent replicas for one location, as a non-root user with a read-only root file system, with health probes and a PodDisruptionBudget. Put the token in a Secret first; the chart never takes the token itself. ```bash kubectl create namespace statustick kubectl create secret generic statustick-agent -n statustick --from-literal=token='' helm install statustick-agent oci://ghcr.io/statustick/charts/statustick-agent --version 0.1.0 \ -n statustick --set existingSecret.name=statustick-agent ``` Each pod is its own agent in the location. The chart's values cover the replica count, `STATUSTICK_ALLOW`, a proxy, an extra CA and ping; see the chart's README for the full list. Without ICMP in the pod, ping checks connect to TCP port 443 instead and say so in the result. ### Settings | Variable | Default | What it does | | --- | --- | --- | | `STATUSTICK_TOKEN` | required | The location token. | | `STATUSTICK_URL` | `https://agent.statustick.com` | Where the agent connects. Must be `https`. | | `STATUSTICK_CONCURRENCY` | `5` | How many checks run at the same time, 1 to 20. | | `STATUSTICK_ALLOW` | none | Optional allowlist of address ranges, addresses, host names and `*.` wildcards, for example `10.0.0.0/8,*.corp.example`. See "Security model". | | `STATUSTICK_HOSTNAME` | the container's host name | The name the agent reports. Set it (or `docker run --hostname`) to keep the same agent when the container is recreated. | | `HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY` | none | Proxy for the connection to StatusTick and for HTTP(S) checks. | | `NODE_EXTRA_CA_CERTS` | none | A PEM file with extra CA certificates, for a TLS-inspecting proxy or your internal CA. | | `STATUSTICK_BUFFER_SIZE` | `10000` | Results kept while StatusTick is unreachable, uploaded in order when it is back. When full, the oldest are dropped. | | `STATUSTICK_BUFFER_DIR` | none | A writable folder (for example a volume at `/var/lib/statustick`) that keeps the buffer across restarts. Passwords are never written to it. | | `STATUSTICK_HEALTH_PORT` | none | Serves `/healthz` and `/readyz` on this port for container health checks. | The image runs as a non-root user and works with a read-only root file system (`--read-only`). Browser checks need the separate `ghcr.io/statustick/agent:1-browser` image, with up to 2 GB of memory per browser check running at the same time (`BROWSER_CONCURRENCY`, default 1). ### Uninstall Stop and remove the container (`docker rm -f statustick-agent`, or `docker compose down`), then remove the image (`docker image rm ghcr.io/statustick/agent:1`). The agent keeps nothing on disk unless you set `STATUSTICK_BUFFER_DIR`; remove that volume too. For Helm, run `helm uninstall statustick-agent -n statustick`. In StatusTick, revoke the location's token or delete the location in **Settings → Private locations**. ## Updates `ghcr.io/statustick/agent:1` follows every 1.x release. To stay on one version, use the full tag, for example `ghcr.io/statustick/agent:1.0.0`. The changelog lists every release. Update with Docker: ```bash docker pull ghcr.io/statustick/agent:1 && docker rm -f statustick-agent && docker run -d --name statustick-agent --restart unless-stopped -e STATUSTICK_URL="https://agent.statustick.com" -e STATUSTICK_TOKEN="" ghcr.io/statustick/agent:1 ``` Update with Docker Compose: ```bash docker compose pull statustick-agent && docker compose up -d statustick-agent ``` When a newer version is recommended, the location shows **Update available**. StatusTick also keeps a minimum version: older agents are refused and stop with "Update required". We email the owners and admins of every organization with an older agent at least 30 days before a new minimum applies. Only a security fix can raise it sooner. ## Verify the image Every image is signed with cosign (keyless, by our release workflow) and comes with an SBOM and build provenance: ```bash cosign verify ghcr.io/statustick/agent:1.0.0 \ --certificate-identity-regexp '^https://github.com/[^/]+/statustick-drone/.github/workflows/agent-image.yml@refs/tags/agent-v' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com ``` Releases with a critical vulnerability in the image are not published. ## Database checks A private location can also check PostgreSQL, MySQL and MariaDB, Redis and MongoDB. The agent connects, logs in and runs one read-only command: `SELECT 1`, `PING` or the MongoDB `ping` command. For PostgreSQL and MySQL you can give your own query and the value you expect, for example a replication lag check. The query runs in a read-only transaction with a time limit and is rolled back. Only private locations run database checks. Keep the password on the agent and give StatusTick only the name of the variable. The agent reads only variables that start with `STATUSTICK_SECRET_`. We recommend binding each one to the hosts it belongs to with a second variable, the same name plus `_HOSTS`: ```bash docker run -d --name statustick-agent --restart unless-stopped \ -e STATUSTICK_TOKEN="" \ -e STATUSTICK_SECRET_PG_PASSWORD="" \ -e STATUSTICK_SECRET_PG_PASSWORD_HOSTS="db1.corp.example,10.0.0.5" \ -e STATUSTICK_REQUIRE_SECRET_HOSTS=true \ ghcr.io/statustick/agent:1 ``` Then choose "Keep them on the agent" in the monitor and enter `STATUSTICK_SECRET_PG_PASSWORD`. The `_HOSTS` list takes host names (as written in the monitor, `*.` for subdomains), addresses and ranges such as `10.0.0.0/24`. A check that would send the secret to any other host fails with `SECRET_NOT_ALLOWED` and the agent does not connect, so a changed monitor cannot hand the password to another server. This matters most for Redis and for PostgreSQL with plain password authentication, which send the password itself. `STATUSTICK_REQUIRE_SECRET_HOSTS=true` refuses every secret without a list. For PostgreSQL the agent never uses `PGUSER`, `PGPASSWORD` or `~/.pgpass` from its own environment; the monitor names the user. `STATUSTICK_ALLOW` still limits what the agent checks at all. You can also store the user and password in StatusTick: they are encrypted, shown masked and sent to the agent only inside a check. These are not bound to hosts. Give the agent a user with the least rights the check needs: ```sql -- PostgreSQL CREATE ROLE statustick_monitor LOGIN PASSWORD ''; GRANT CONNECT ON DATABASE app TO statustick_monitor; GRANT pg_monitor TO statustick_monitor; -- only for replication lag and other statistics -- MySQL and MariaDB CREATE USER 'statustick'@'%' IDENTIFIED BY ''; GRANT USAGE ON *.* TO 'statustick'@'%'; ``` ```text # Redis 6 and later (add +select when you set a database number) ACL SETUSER statustick on > -@all +ping ``` ```js // MongoDB: ping needs no role db.getSiblingDB('admin').createUser({ user: 'statustick', pwd: '', roles: [] }) ``` If your own query reads tables, grant `SELECT` on those tables only. ## Network requirements | Direction | What | Port | | --- | --- | --- | | Outbound | HTTPS to `agent.statustick.com` | 443 | | Inbound | Nothing | — | No VPN, no inbound port and no IP allowlisting are needed; a firewall only has to allow `agent.statustick.com` on port 443. If your network uses an HTTP proxy, set `HTTPS_PROXY`. If it inspects TLS with its own CA, mount the CA file and set `NODE_EXTRA_CA_CERTS`. ## What leaves your network Only check results, with these fields: | Check | Fields sent | | --- | --- | | HTTP(S) | status (up, down, blocked or error), response time, HTTP status code, error text and type, whether the keyword matched, the name of an expected header that is missing or different, and for page asset checks the number checked and the status code of each failed asset | | TCP | status, response time, error text and code | | Ping | status, response time, packet loss, round-trip times (min, max, average, deviation) | | DNS | status, response time, the records found and their number, error text and code | | PostgreSQL, MySQL, Redis, MongoDB | status, response time, connect, login and query times, error code and a short error text, and the one compared value when you set an expected value | Response bodies, header values, cookies, the addresses of a page's assets and query results never leave your network. The agent drops any other field before sending. ## Security model The full summary is on [Agent security](https://statustick.com/docs/agent-security). - **Outbound only.** StatusTick never connects to the agent. - **Tokens.** Each location has its own token, shown once. StatusTick stores only a hash and shows its first characters (the prefix) so you can tell tokens apart. Making a new token keeps the old one working for 24 hours while you update your agents; revoking stops every agent of the location on its next call. - **Isolation.** An agent only receives checks for its own organization and location. - **Internal targets, two layers.** StatusTick lets a monitor use an internal target (`10.x`, `192.168.x`, `.internal` host names and similar) only when all of its locations are private locations of your organization; public locations keep refusing internal targets. On your side, the agent checks internal targets but always refuses cloud metadata addresses (`169.254.169.254`, `fd00:ec2::254`) unless you list them yourself. - **Your limits.** Set `STATUSTICK_ALLOW` (for example `10.0.0.0/8,*.corp.example`) and the agent refuses any target outside the list, without contacting it, and reports "target not allowed by agent policy". The list lives on your side, so nobody with StatusTick access can widen it. - **Agent down is not service down.** If no agent of a location called StatusTick for 3 minutes, the location shows **Offline**, your alert channels (except paging ones) get one notice, and monitors that run only from that location show **Location offline** instead of opening outage incidents. ## Troubleshooting Run the built-in check first: ```bash docker run --rm -e STATUSTICK_TOKEN="" ghcr.io/statustick/agent:1 doctor ``` It tests the token format, DNS for StatusTick, the connection on port 443, TLS, the proxy, whether StatusTick answers, whether it accepts the token, and the clock, and says how to fix each failed step. Add `--target https://intranet.example/health` to test one of your targets from the agent. - **Token rejected.** The log says `Token rejected`. The token is wrong, was revoked, or a rotated token's 24 hours are over. Make a new token for the location and restart the agent with it. - **Cannot reach StatusTick.** The log says `Disconnected` and the agent keeps retrying. Allow outbound HTTPS to `agent.statustick.com` on port 443; behind a proxy set `HTTPS_PROXY`, and if the proxy inspects TLS, set `NODE_EXTRA_CA_CERTS` to its CA file. - **Internal names do not resolve.** The agent uses the container's DNS. If your internal names resolve on the host but not in Docker, start the container with `--dns ` (or `dns:` in Compose), or with `--network host`. With `STATUSTICK_ALLOW` set, a name must also match the list. - **Update required.** The log says `Update required` and the agent stops polling: StatusTick no longer accepts this version. Pull the new image and restart the container (see "Updates"). --- # Agent security URL: https://statustick.com/docs/agent-security > How the StatusTick private agent is kept safe inside your network: what it does, what never leaves, and what stops misuse of StatusTick or of a stolen token. The [private agent](https://statustick.com/docs/private-agents) runs inside your network and takes check definitions from StatusTick. This page sums up how it stays safe; your security team can ask us for the full threat model. ## What the agent does - **Outbound only.** It calls one host, `agent.statustick.com`, over HTTPS, and the targets of its checks. It opens no port; StatusTick never connects to it. - **Checks are data, not code.** A check is a fixed set of fields (URL, method, timeout, expected text and similar). Unknown fields are dropped, a field of the wrong type refuses the check, and nothing is ever run as code or as a shell command. The browser image is the one exception you choose on purpose: it runs your own Playwright scripts. - **Results only.** What leaves your network is the status, response time, HTTP status code, error text, keyword match, which expected header did not match (compared on the agent), DNS records and ping statistics. Never a response body, header values, cookies or the addresses of a page's assets. ## What stops misuse | If… | Then… | | -- | -- | | a location token is stolen | it works only for that location's checks and results. Rotate or revoke it in the dashboard; a revoked token stops on its next call. | | StatusTick itself were compromised | `STATUSTICK_ALLOW` keeps the agent to the targets you list, and StatusTick cannot change it. Cloud metadata addresses are always refused unless you list them. Only result fields come back, never page content. | | someone in your organization points a monitor at an internal host | only owners and admins change monitors, every change is in the audit log, and internal targets work only on monitors that use private locations alone. | | someone intercepts the connection | the agent talks to StatusTick only over HTTPS and checks the certificate; extra CA files you mount only add trust for your own proxy. | | a target misbehaves | the agent reads at most 5 MB of a response, stops at the check's timeout even while the body is still arriving, follows at most 5 redirects and checks every hop against your rules. | ## Your controls - `STATUSTICK_ALLOW`: the only targets the agent may check, for example `10.0.0.0/8,*.corp.example`. - Run the agent with a read-only file system and no extra privileges; it runs as an unprivileged user. - `statustick-agent doctor` shows what the agent can reach, without sending data anywhere but StatusTick. --- # Avoiding false alarms URL: https://statustick.com/docs/avoiding-false-alarms > The settings that decide when StatusTick opens an incident: confirmation from several regions, failed checks in a row, degraded and blocked states, and maintenance windows. A monitoring tool is only useful if people trust its alerts. StatusTick has five controls that decide whether a failed check becomes an incident. The defaults are safe; change them per monitor when you need to. ## 1. Confirmation from more than one region Every check runs from all the regions you chose, at the same time. A network problem between one region and your site should not wake anyone up, so: - By default, a monitor is **down** only when at least **2 regions** fail. - When one region fails but not enough to confirm, StatusTick re-checks that region at once. - You can set the number of failing regions from 1 up to the number of regions on the monitor. The check result keeps each region's result, so you can see, for example, "down from EU West only". ## 2. Failed checks in a row Short blips during a deploy can fail one check. In the incident settings you choose: - **Failures to open:** how many failed checks in a row open an incident (1 to 10, default 2). - **Successes to resolve:** how many good checks in a row resolve it. The incident start time is the time of the first failed check, so your downtime numbers stay honest. ## 3. Slow is not down Set a slow-response threshold on a monitor. A check that answers correctly but slower than the threshold is **Degraded**, not down. Degraded shows on dashboards and status pages as "Degraded performance". ## 4. Blocked is not down Firewalls, WAFs and bot protection (for example a Cloudflare challenge) sometimes block monitoring requests while real users are fine. When StatusTick sees a typical block response, the check is **Blocked**, not down: - You get one notice with steps to allow StatusTick, at most once a day. - Blocked does not open an incident unless you turn that on for the monitor. - A real `403` from your application still counts as down when `403` is not an expected status code. See [Allowlisting StatusTick](https://statustick.com/docs/allowlisting-statustick). ## 5. Maintenance windows During a maintenance window, failures do not open incidents or send alerts. Windows can be one-off or repeat daily, weekly on chosen days, or monthly, with a start time, a length and a time zone. ## Delays and escalation - **Notification delay:** wait a few minutes after an incident opens before alerting, in case it resolves on its own. - **Auto-resolve delay:** wait before resolving, so a flapping monitor does not open and close incidents again and again. - **Escalation:** if nobody acknowledges an incident within the delay you set, StatusTick alerts a second set of channels, up to 3 times. Acknowledging or resolving the incident stops it. --- # Alert channels URL: https://statustick.com/docs/alert-channels > Where StatusTick sends incident alerts: email, SMS, Slack, Microsoft Teams, Discord, Telegram, PagerDuty and webhooks, and how delivery, retries and acknowledging work. An alert channel is a destination for incident alerts. Admins add channels in the organization settings, send a test message, and choose which channels each incident setting uses. ## Channels | Channel | What you need | | --- | --- | | Email | Verified email addresses | | SMS | A verified phone number in each person's profile | | Slack | An incoming webhook URL for the channel | | Microsoft Teams | A webhook URL for the Teams channel | | Discord | A channel webhook | | Telegram | A private or group chat to connect | | PagerDuty | An Events API v2 integration | | Webhook | Any HTTPS URL you control | SMS is built in: alert policies text the person on call, paid with your plan's SMS credits. For phone calls, connect PagerDuty. ## What an alert contains Alerts are sent when an incident opens and when it resolves. Each alert says which monitor failed, the target, the failing regions, the error and when it started, with links to the incident and to **acknowledge** it. Acknowledging from the link stops escalation. ## Webhooks StatusTick sends a JSON `POST` to your URL when an incident opens or resolves. You can protect the endpoint with one of these: - no authentication, - a bearer token, - HTTP basic authentication, - an API key in a header you choose. Webhook URLs must be public. StatusTick refuses private and internal addresses. ## Delivery and retries If a channel answers with a network error or a `5xx` status, StatusTick retries up to 3 times with a growing delay. A `4xx` answer (except `429`) is not retried, because it usually means the channel is set up wrong. Every attempt is stored for 30 days, so you can see whether an alert was delivered. --- # Alerts from other tools URL: https://statustick.com/docs/alerts-from-other-tools > Open StatusTick incidents from the alerts your other tools already send: a webhook URL per alert source that reads generic JSON or the webhook format of Prometheus Alertmanager, Grafana, Datadog, Sentry or AWS CloudWatch. An alert source turns alerts from another tool into StatusTick incidents. Admins add alert sources in **Settings → Alert sources**. Each source has a secret webhook URL, a default severity and a **format**: how StatusTick reads what the tool sends. An alert opens an incident, or updates the open incident with the same key. A resolved alert resolves it. Incidents from alerts go through the same acknowledge, escalation and notification steps as monitor incidents. Keep the webhook URL secret: anyone with it can open incidents. If it leaks, make a new one on the alert source. ## Generic JSON Choose **Generic JSON** for scripts and tools that let you shape the body. `POST` a JSON object to the URL: ```json { "title": "CPU above 90% on web-1", "status": "firing", "severity": "high", "dedup_key": "cpu-web-1", "description": "5-minute average is 94%.", "links": ["https://grafana.example.com/d/abc"] } ``` `status` is `firing` or `resolved`. Alerts with the same `dedup_key` (or, without one, the same title) update one open incident. ## Prometheus Alertmanager Set the format to **Prometheus Alertmanager**. In `alertmanager.yml`, add a receiver with the webhook URL and route alerts to it: ```yaml receivers: - name: statustick webhook_configs: - url: "https://webhook.statustick.com/v1/alerts/" send_resolved: true ``` Each alert in a group opens or updates its own incident, keyed by its fingerprint. The `severity` label sets the severity, and `summary`, `description` and `runbook_url` annotations are used when present. ## Grafana Set the format to **Grafana**. In Grafana, go to **Alerting → Contact points**, add a contact point of type **Webhook** with the webhook URL, and use it in a notification policy. Each alert in a notification opens or updates its own incident, with links to the alert rule, dashboard, panel and silence page. ## Datadog Set the format to **Datadog**. In Datadog, go to **Integrations → Webhooks**, add a webhook with the webhook URL and this payload: ```json { "title": "$EVENT_TITLE", "transition": "$ALERT_TRANSITION", "alert_type": "$ALERT_TYPE", "priority": "$ALERT_PRIORITY", "aggregate": "$AGGREG_KEY", "alert_id": "$ALERT_ID", "body": "$EVENT_MSG", "link": "$LINK", "hostname": "$HOSTNAME", "tags": "$TAGS" } ``` Then add `@webhook-` to the message of each monitor that should open incidents. A recovered monitor resolves the incident. The monitor priority (P1 to P5) sets the severity. ## Sentry Set the format to **Sentry**. In Sentry, add an internal integration (**Settings → Custom Integrations**) with the webhook URL, turn on **Alert Rule Action** and the **issue** webhook, and choose the integration as an action in your issue and metric alert rules. - Issue alerts open an incident per Sentry issue; resolving the issue in Sentry resolves it. - Metric alerts open an incident at warning or critical and resolve it when Sentry resolves the alert. The legacy WebHooks plugin works too: paste the webhook URL as a callback URL. ## AWS CloudWatch Set the format to **AWS CloudWatch (SNS)**. In Amazon SNS, add a subscription with protocol **HTTPS** and the webhook URL as the endpoint, on the topic your CloudWatch alarms notify. StatusTick confirms the subscription on its own. Use the topic for both the **In alarm** and **OK** actions of the alarm. `ALARM` opens an incident, `OK` resolves it, and `INSUFFICIENT_DATA` is skipped. ## Answers and limits The URL answers `204` when it takes an alert, `400` when the body is not a JSON object, and `429` when one source sends more than 120 alerts a minute. The raw body is kept for 14 days, so you can check what a tool sent. --- # Allowlisting StatusTick URL: https://statustick.com/docs/allowlisting-statustick > How to let StatusTick checks through your firewall, WAF or bot protection, so blocked checks do not hide the real status of your site. If your site uses a firewall, a WAF or bot protection (for example Cloudflare), it may block or challenge StatusTick's checks. StatusTick then shows the monitor as **Blocked** instead of guessing that the site is down. To see the real status, let StatusTick through. ## Option 1: allow our IP addresses StatusTick publishes the IPv4 and IPv6 addresses its checks come from, as a machine-readable list at a stable URL shown in your dashboard. Changes to the list are announced 7 days ahead. ## Option 2: a custom header or User-Agent On each HTTP monitor you can set a custom `User-Agent` or an extra request header, for example a secret token. Then add a rule in your firewall that allows requests with that header. Use a long random value and treat it like a password. ## What Blocked means A check is Blocked when the answer looks like a firewall or a bot challenge, for example a `403` or `429` with WAF headers, or a challenge page. It does not mean your site is down. Blocked monitors: - send one notice with these steps, at most once a day, - do not open incidents unless you turn that on, - show as operational on public status pages, because the real status is unknown. --- # Status page feeds, badge and widget URL: https://statustick.com/docs/status-page-feeds-and-embeds > Show your status page's state in your app, docs or README: JSON, RSS and Atom feeds, an SVG badge and a one-line widget. Every public status page can be read from outside StatusTick. Replace `` with your page's address (the part after `/status/`). Hidden pages return 404 everywhere. ## JSON ``` https://api.statustick.com/v1/pages/ ``` The overall status, each component with its status and uptime, and open and recent incidents. No login is needed, any website may read it (CORS is open), and answers are cached for a short time. ## RSS and Atom ``` https://api.statustick.com/v1/pages//feed.rss https://api.statustick.com/v1/pages//feed.atom ``` One entry per incident post, with its latest update. Add either URL to a feed reader or a chat tool that follows feeds. ## Badge ```markdown ![Status](https://api.statustick.com/v1/pages//badge.svg) ``` An SVG badge with the page's status. For one component use `https://api.statustick.com/v1/pages//components//badge.svg`. Add `?label=api` to change the left text. ## Widget ```html ``` Shows a small notice such as "All systems operational" where you put the tag, linked to your status page. Add `data-theme="dark"` to the tag for dark backgrounds. The script sets no cookies and sends no credentials.