Cloudflare is a popular DNS provider precisely because of its reliability and speed. But "reliable DNS infrastructure" and "monitoring your DNS records for unexpected changes" are two different things. Cloudflare won't alert you when an A record changes, a CNAME gets pointed somewhere wrong, or an MX record disappears — whether that change was made by a team member, an API key, or a compromised account.
DNS record changes are among the highest-impact, lowest-visibility infrastructure events. An accidental change propagates globally within minutes. Detection by symptom — users reporting that the site is down, email bouncing, SPF checks failing — is slow and stressful.
Cloudflare's dashboard includes audit logs under Account Settings → Audit Log. These show changes made through the Cloudflare UI and API, including:
This is useful for incident investigation. It's not useful for real-time alerting — you'd have to poll the audit log continuously to detect changes as they happen.
Cloudflare's paid tiers add Notifications, which can alert on zone-level health events (DDoS, origin errors), but DNS record change notifications aren't available in the standard notification options.
You can build a DNS change detection script using the Cloudflare API. The approach: snapshot all DNS records for a zone at a baseline, then compare on a schedule.
# Get all DNS records for a zone
curl -s -X GET \
"https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records?per_page=100" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
| python3 -m json.tool
A minimal monitoring script:
#!/usr/bin/env python3
import json, hashlib, subprocess, sys, os
ZONE_ID = os.environ["CF_ZONE_ID"]
API_TOKEN = os.environ["CF_API_TOKEN"]
SNAPSHOT_FILE = "/var/lib/dns-monitor/cf-snapshot.json"
ALERT_EMAIL = "ops@yourcompany.com"
def get_records():
import urllib.request
req = urllib.request.Request(
f"https://api.cloudflare.com/client/v4/zones/{ZONE_ID}/dns_records?per_page=100",
headers={"Authorization": f"Bearer {API_TOKEN}", "Content-Type": "application/json"}
)
with urllib.request.urlopen(req) as r:
data = json.loads(r.read())
# Normalize: sort by name+type, drop volatile fields
records = sorted(data["result"], key=lambda r: (r["name"], r["type"]))
return [{k: r[k] for k in ("name","type","content","ttl","proxied")} for r in records]
current = get_records()
current_hash = hashlib.sha256(json.dumps(current).encode()).hexdigest()
if os.path.exists(SNAPSHOT_FILE):
with open(SNAPSHOT_FILE) as f:
saved = json.load(f)
if saved["hash"] != current_hash:
# Find what changed
old_set = {json.dumps(r) for r in saved["records"]}
new_set = {json.dumps(r) for r in current}
added = new_set - old_set
removed = old_set - new_set
print(f"DNS CHANGE DETECTED in zone {ZONE_ID}")
for r in removed: print(f" REMOVED: {r}")
for r in added: print(f" ADDED: {r}")
# Send alert via mail or your preferred method
# subprocess.run(["mail", "-s", "DNS Change Alert", ALERT_EMAIL], input=alert_body, ...)
sys.exit(2) # Non-zero exit for monitoring integration
else:
print("No changes detected")
with open(SNAPSHOT_FILE, "w") as f:
json.dump({"hash": current_hash, "records": current}, f)
Run this from cron every 5–15 minutes:
*/10 * * * * /usr/local/bin/cf-dns-monitor.py >> /var/log/cf-dns-monitor.log 2>&1
Zone:DNS:Read only. This script needs read access — not write. A read-only token limits the blast radius if the token is ever exposed.
Cloudflare API monitoring tells you what's in your Cloudflare DNS configuration. External DNS monitoring tells you what resolvers around the world are returning for your records. These can differ in ways that matter:
A complete setup uses both: Cloudflare API for change detection (immediate, no propagation delay) and external resolver monitoring for validation (confirms what end users are actually seeing).
MX and TXT record changes are particularly high-stakes and easy to miss:
Both record types should be explicitly included in any DNS monitoring setup — not just A and CNAME records.
Before setting up automated monitoring, get a baseline snapshot of your current DNS records:
Enter any domain to see all DNS records (A, AAAA, CNAME, MX, TXT, NS). Works for Cloudflare-managed domains and any other DNS provider.
Check DNS records → Get change alerts →The self-hosted API approach works for teams comfortable managing Python scripts and cron jobs. The maintenance overhead is real: the script needs to run reliably, alerts need to reach someone who can act, and the monitoring infrastructure itself needs to stay up.
For a lower-maintenance alternative, external DNS monitoring services check your records on a schedule, compare against a saved baseline, and alert you when anything changes — without requiring API tokens, local scripts, or infrastructure on your end.
DNSWatch monitors your DNS records and sends email alerts the moment an A, CNAME, MX, or TXT record changes. Works for Cloudflare-managed domains, Route53, Namecheap, and any other DNS provider.
Join the DNSWatch waitlist → Free DNS checker →