Alert bridge: self-hosted Cloudflare Worker
What it is
Section titled “What it is”The alerts-bridge is an open-source Cloudflare Worker that translates Monitive webhook events into push notifications. Deploy it once to your own Cloudflare account and every monitor.down, monitor.up, and monitor.flapping event reaches your phone, Slack workspace, or Discord server — via Pushover, ntfy, Slack, Discord, or Telegram.
You own the Worker. Monitive sends the webhook; the bridge forwards it to your provider. No third-party relay, no vendor lock-in.
New to this? The Reliable alerts guide covers why Do Not Disturb makes browser push and email unreliable, and lets you pick a provider and runtime. This page is the full deploy reference.
Prerequisites
Section titled “Prerequisites”- A Cloudflare account (free tier is enough)
- Node 20 or newer
- A UptimeMonitoring.com account with at least one monitor
- A provider account — this walkthrough uses Pushover
Get the code
Section titled “Get the code”git clone https://github.com/uptimemonitoring/alerts-bridgecd alerts-bridgenpm installDeploy
Section titled “Deploy”Log in to Cloudflare, then deploy:
npx wrangler loginnpm run deployWrangler prints the Worker URL when the deploy succeeds:
Published alerts-bridge (0.00 sec) https://alerts-bridge.<your-subdomain>.workers.devNote that URL — you register it with your monitor next.
Wire to Monitive
Section titled “Wire to Monitive”- Go to Recipients in app.uptimemonitoring.com and click Create recipient.
- Choose Webhook, paste the
*.workers.devURL from the deploy step, and click Create recipient. - Copy Your recipient secret — shown once — you’ll paste it as
MONITOR_WEBHOOK_SECRETSin the next step. - Open your monitor’s Recipients section, check the new recipient, and save.
(API equivalent: POST /api/v1/recipients with type: "webhook" returns the secret once in the creation response; attach the recipient to a monitor with PUT /api/v1/monitors/<id>/recipients — see Choose who gets alerts.) The bridge verifies the X-UptimeMonitoring-Signature header against this secret on every request — see Webhooks for the signature contract.
Set secrets
Section titled “Set secrets”Configure the Worker secrets with npx wrangler secret put. Wrangler prompts you for each value; nothing is written to disk.
# Which provider to usenpx wrangler secret put PROVIDER# → pushover
# Pushover application token (from pushover.net → Your Applications)# Tip: name the Pushover application "UptimeMonitoring" — that name is what# shows as the source on each push notification.npx wrangler secret put PUSHOVER_TOKEN
# Pushover user key (from pushover.net → Your User Key)npx wrangler secret put PUSHOVER_USER
# The whs_live_… signing secret you copied from the recipient's creation response abovenpx wrangler secret put MONITOR_WEBHOOK_SECRETSWatch the Worker logs in one terminal:
npx wrangler tailThen trigger a real event: point the monitor at a URL that returns 5xx (or stop the service it watches) so Monitive fires a monitor.down webhook, then restore it to fire monitor.up. Confirm each notification arrives on your device, and watch wrangler tail for the incoming request and the provider’s response.
The webhook recipient’s Send test button (on its row in Recipients) is the fastest way to fire a sample delivery without affecting the monitor’s real state.
Provider reference
Section titled “Provider reference”Set PROVIDER to one of the values in the first column and supply the corresponding secrets:
PROVIDER value |
Required secrets | Notes |
|---|---|---|
pushover |
PUSHOVER_TOKEN, PUSHOVER_USER |
Pushover app token + user key |
ntfy |
NTFY_TOPIC (+ optional NTFY_URL, NTFY_TOKEN) |
NTFY_URL defaults to https://ntfy.sh; NTFY_TOKEN only for protected topics |
slack |
SLACK_WEBHOOK_URL |
Slack incoming webhook URL |
discord |
DISCORD_WEBHOOK_URL |
Discord webhook URL |
telegram |
TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID |
Bot token + target chat ID |
Troubleshooting
Section titled “Troubleshooting”401 from the Worker
The signature verification failed. Check that the MONITOR_WEBHOOK_SECRETS value in the Worker matches the recipient secret you copied at creation time exactly — trailing whitespace or a copy-paste error will cause every request to be rejected. UptimeMonitoring doesn’t show that secret again, and there’s no rotate endpoint — don’t just delete the recipient and create a new one: that leaves every monitor attached to it unalerted until you reattach them by hand, and deleting a recipient also discards whatever of its deliveries are still queued (pending/retrying) at that moment, outright. Instead, follow one of the two procedures on the Webhooks page, picking based on what the Worker can verify at once:
- Dual-secret overlap, if your deployed version of the bridge checks multiple candidate secrets: create the replacement, install its secret in the Worker alongside the still-valid original, attach it to every monitor the original was on with each monitor’s saved
down_delay_s, verify delivery with Send test or a controlled down/up transition, then wait out the original’s queued deliveries and delete it. - Downtime window, if the Worker can only hold one secret: create the replacement, take the Worker offline, swap old for new on every affected monitor (one
PUTper monitor), install the new secret and bring the Worker back online, verify delivery, then wait out and delete the original the same way.
Either path, a clean delivery-log scan only proves nothing was queued as of that read — it can’t prove nothing is queued the instant you call DELETE, since a transition firing in that gap still queues a delivery that deletion discards outright, not delivers late. The Webhooks page’s procedures show how to run that scan; for margin against that gap, keep the original recipient around for at least the longest retry delay (2 hours) past a clean scan before deleting it.
No push notification
Signature passed but the provider rejected the request. Double-check PUSHOVER_TOKEN and PUSHOVER_USER (or the equivalent for your provider). Run npx wrangler tail while triggering a test event to see the provider’s error response.
413 Request Entity Too Large The webhook payload exceeded the Worker’s request size limit. This should not happen with standard Monitive payloads — if it does, open an issue in the alerts-bridge repository.