You have a few dozen domains on Cloudflare’s Free plan, and most of them only redirect. You want to hear about a broken one before a customer does. Cloudflare can tell you some of that by email, for free, once you switch it on. It will not tell you that a redirect sends people to the wrong place, that someone changed a DNS record, or that a domain at another registrar is about to lapse. That holds on every plan, Enterprise included.
This article lists what the Free plan watches, what paying adds and for how much, and gives you a Worker that checks the redirects themselves. If you are still choosing how to redirect, start with every way to redirect on Cloudflare.
What Cloudflare watches, by plan
Checked on 23 September 2026 against Cloudflare’s documentation and against the notification API of our own account.
| What breaks | Free plan | What lifts it | Left uncovered |
|---|---|---|---|
| Origin unreachable | Passive Origin Monitoring, email; stayed silent in our test | low traffic domains, and 522 |
|
Origin errors, 522 included |
nothing | Origin Error Rate Alert, Enterprise only | everything below Enterprise |
| Active checks of a URL | nothing | Health Checks: 10 on Pro ($20 a month billed yearly), 50 on Business ($200) | anything past 10 or 50 URLs |
| Edge certificate (Universal SSL) | Universal SSL Alert, email | ||
| Origin CA certificate expiry | nothing | nothing | every plan |
| Domain at Cloudflare Registrar expiring | monthly email to the Super Administrator | ||
| Domain at another registrar expiring | nothing | nothing | every plan |
| DNS record or nameserver change | Audit Logs, no alert | nothing | every plan |
| Redirect sends people to the wrong place | nothing | nothing | every plan |
| Where alerts can go | webhooks with a paid subscription, PagerDuty from Business |
Two rows need a note.
Passive Origin Monitoring is missing from the current list of available notifications, last
updated 24 April 2026. The API still offers it: on our account it is listed as
real_origin_monitoring, “Cloudflare is unable to reach your origin”. Cloudflare’s announcement
from 2019 says it “is available to customers on all Cloudflare plans”.
The webhook page says the feature “is only available if your account has at least one zone with a pro plan or above.” Our account has two Free zones and a Workers Paid subscription, which starts at $5 a month, and the API reports webhooks as eligible. The getting started page has the rule that matches what we see: “Accounts with a paid service will additionally have access to webhooks.”
Nothing is switched on until you add it
On 23 September our account had been serving this site since July. It held one notification policy: a billing budget alert that Cloudflare created by itself. Neither of the two free alerts above was there.
Add them under Notifications, then Add:
- Passive Origin Monitoring. One policy covers every zone in the account.
- Universal SSL Alert. Validation, issuance, renewal and expiration of the certificate visitors get.
Both go to an email address you type in. Pick one that somebody reads. A notification sent to a former colleague’s inbox is the same failure as the renewal email in auto-renew was on and the domain expired anyway.
We broke a hostname twice and the free alert said nothing
Cloudflare describes the trigger of Passive Origin Monitoring in one place only, its post of July 2021. The notification:
tells you if every request to your origin is returning a 521 error (web server down) for a full five minutes
A 521 means the server refused the connection. A domain set up the way the
portfolio runbook recommends has no server to refuse anything: a
proxied A record points at 192.0.2.1, an address nobody answers on, and the redirect runs at
the edge. When someone deletes or narrows the redirect rule, Cloudflare forwards the request to
192.0.2.1, waits, and gives the visitor a 522, a timeout.
So we tested both on 23 September, with the notification switched on in our account.
- A proxied hostname pointing at
192.0.2.1with no redirect rule. From 08:24 to 08:44 UTC we requested it every 15 seconds. All 35 responses were522. - The same hostname pointing at a server that refuses connections on port 443, the port
Cloudflare uses in our Full SSL mode. From 08:46 to 09:06 UTC, the same schedule. All 78
responses were
521.
The account’s notification history stayed empty through both runs and until 09:24 UTC, when we stopped looking. No email arrived at the address on the policy. The second run is the case the 2021 post describes, and it did not fire either. The documentation names no minimum amount of traffic, but a request every 15 seconds was not enough.
A parked domain that only redirects gets less than that. Turn Passive Origin Monitoring on, since
it costs nothing, and do not read its silence as proof that anything works. The one notification
documented to count 522 is the Origin Error Rate Alert, sold on Enterprise only.
Check the redirects yourself on a cron Worker
What no plan offers is a request to your domain and a look at where the answer points. A Worker
on a schedule can do that, and a Worker with no route of its own runs on workers.dev, so it
needs no domain.
// Each row: the URL, the status you expect, the Location you expect.
const CHECKS = [
['https://old-brand.com/', 301, 'https://brand.com/'],
['https://www.old-brand.com/', 301, 'https://brand.com/'],
['https://promo-brand.net/', 302, 'https://brand.com/spring/'],
];
async function probe() {
const failures = [];
for (const [url, status, location] of CHECKS) {
try {
const res = await fetch(url, { redirect: 'manual' });
const got = res.headers.get('location');
if (res.status !== status || got !== location) {
failures.push(`${url} → ${res.status} ${got ?? '(no Location)'}`);
}
} catch (err) {
failures.push(`${url} → ${err.message}`);
}
}
return failures;
}
export default {
async scheduled(event, env) {
const failures = await probe();
if (failures.length === 0) return;
const text = failures.join('\n');
await fetch(env.ALERT_WEBHOOK, {
method: 'POST',
headers: { 'content-type': 'application/json' },
// Slack reads `text`, Discord reads `content`.
body: JSON.stringify({ text, content: text }),
});
},
};
name = "redirect-check"
main = "index.js"
compatibility_date = "2026-09-01"
[triggers]
crons = ["*/30 * * * *"]
Store the webhook address as a secret with wrangler secret put ALERT_WEBHOOK, so it stays out
of the code. redirect: 'manual' is the important part: the Worker gets the first answer and
does not follow it, so you compare exactly what a visitor’s browser receives.
We ran the probe() function from workers.dev on 23 September against our own domains, which
sit on the same Cloudflare account as the Worker. The correct redirects passed without a
message. A row where we deliberately expected the wrong target was reported. A domain that does not exist came
back as a 530 response rather than an error, and the status check caught it just the same.
On the Free plan two limits decide how far this goes. A Worker invocation may make 50 subrequests, so one run checks 49 URLs and keeps one request for the alert. An account may have 5 cron triggers in total. Our account runs nine, seven of them for the workers that distribute this blog, so we were past the Free limit before monitoring came up. Workers Paid raises the numbers to 10,000 subrequests and 250 cron triggers, from $5 a month.
Where this breaks
The checker lives inside Cloudflare. When Cloudflare has a bad day, the Worker and the
notifications have it too. From 19 June 11:35 to 23 June 02:50 UTC this year, some security and
DDoS alerts were not delivered, as a
community thread and the status page recorded. A
monitor outside Cloudflare, such as UptimeRobot, sees what visitors see, a 522 included.
Notifications belong to the account, not the domain. You cannot mute one zone in an account wide policy, and a question asking how to do that has sat without a reply since June.
DNS changes leave a record and nothing else. Audit Logs are available on every plan and kept for 18 months, but no notification reads them. In January someone found their nameservers changed after the zone was added to a second account, and learned about it when the site went down. Polling the Audit Logs API, or resolving each domain’s NS records on a schedule, is the only way to hear about it sooner.
Origin CA certificates expire in silence. Cloudflare says so directly:
Cloudflare does not currently send expiration notifications for origin CA certificates.
Certificates now expire in 200 days has a command that reads the one on your server.
Domains at other registrars are invisible. Cloudflare Registrar sends a monthly email listing domains “expiring in the next 60-90 days”. A domain registered anywhere else gets nothing from Cloudflare.
When 301.st is worth it
For a handful of domains you do not need us. Switch on the two alerts, deploy the Worker with your list, and read the email.
With hundreds of domains, the gap that hurts most is the one nothing on Cloudflare covers: domains whose nameservers no longer point where the redirect rules live. 301.st resolves the NS records of the domains it manages on a loop, each domain at least twice a day, and compares them with the ones Cloudflare assigned. It rereads each zone’s status from Cloudflare on a rolling schedule. When a domain with active rules stops getting traffic through them, because the nameservers moved or the zone left the account, it emails you the list.
The rest shows on one screen for the whole portfolio rather than as alerts: the VirusTotal verdict for each domain, using your own API key; Cloudflare’s phishing block; a daily count of redirect responses per host that flags a drop of half, nine tenths, or to zero; and the registration expiry read from RDAP, whichever registrar holds the domain.
It does not request each redirect and compare the target with what you expected. That is the Worker above, and it is worth running next to 301.st.