# Cloudflare notification notifications on your phone > Get a push notification for any Cloudflare notification, loudest for DDoS attacks and origin errors and quiet for informational updates and resolved alerts. - Company: Cloudflare (https://www.justpush.io/recipes/cloudflare) - Event: `notification` (Notification) - Tags: Hosting & deployment, Security, Uptime & downtime - Install: https://studio.justpush.io/recipes/cloudflare/notification - Web page: https://www.justpush.io/recipes/cloudflare/notification ## Setup 1. Click Install in Studio and sign in. The recipe is added to your account and you get a personal webhook URL. 2. In the Cloudflare dashboard, go to Notifications > Destinations and select Create in the Webhooks card (needs at least one Pro zone). 3. Name it, paste your webhook URL (shown in Studio after install) as the URL and select Save and Test. 4. Under Notifications, add or edit the notifications you want and pick this webhook as a destination. 5. In the Cloudflare dashboard, go to **Notifications → Destinations** and select **Create** in the **Webhooks** card. Webhook destinations need at least one zone on a Pro plan or higher. 6. Name it, paste the URL above and select **Save and Test**. The test gives a quiet **🔔 Cloudflare connected** push. 7. Under **Notifications**, add the notifications you care about (DDoS attacks, origin error rate, health checks, SSL certificates, tunnel health, Workers usage â€Ļ) and choose this webhook as their destination. 8. The push shows Cloudflare's own text. The alert type sets how loud it is: **Highest** for DDoS attacks, origin errors and BGP hijacks, **High** for health checks, tunnels, error rates and security findings, **Normal** for certificates, usage and anything the recipe doesn't know, **Low** for maintenance, digests and resolved alerts. 9. Cloudflare can send a secret in the `cf-webhook-auth` header, but JustPush doesn't check it yet, so keep your endpoint URL private. ## Code Studio calls `handleRequest(request)` with the incoming webhook (`{ method, headers, body, query, raw }`) and sends the message object it returns. Returning `null` sends nothing. ```js // Cloudflare → any notification sent to a generic webhook destination // Fires for every Cloudflare notification policy that uses this webhook. The push uses // Cloudflare's own text; the alert type sets the label and how loud it is. // Docs: https://developers.cloudflare.com/notifications/reference/webhook-payload-schema/ // alert_type → label and priority. // 2: under attack or the site is down right now. // 1: needs you soon (errors, failing health checks, security findings). // 0: worth knowing (certificates, usage, deploys). // -1: informational digests and maintenance. const TYPES = { advanced_ddos_attack_l4_alert: { emoji: "đŸ›Ąī¸", label: "DDoS attack", priority: 2 }, advanced_ddos_attack_l7_alert: { emoji: "đŸ›Ąī¸", label: "HTTP DDoS attack", priority: 2 }, dos_attack_l4: { emoji: "đŸ›Ąī¸", label: "DDoS attack", priority: 2 }, dos_attack_l7: { emoji: "đŸ›Ąī¸", label: "HTTP DDoS attack", priority: 2 }, fbm_dosd_attack: { emoji: "đŸ›Ąī¸", label: "DDoS attack on your network", priority: 2 }, fbm_volumetric_attack: { emoji: "đŸ›Ąī¸", label: "Volumetric attack on your network", priority: 2 }, bgp_hijack_notification: { emoji: "🚨", label: "BGP hijack detected", priority: 2 }, http_alert_origin_error: { emoji: "đŸ”Ĩ", label: "Origin error rate high", priority: 2 }, real_origin_monitoring: { emoji: "đŸ”Ĩ", label: "Origin unreachable", priority: 2 }, load_balancing_health_alert: { emoji: "âš ī¸", label: "Load balancer pool health changed", priority: 1 }, health_check_status_notification: { emoji: "âš ī¸", label: "Health check status changed", priority: 1 }, tunnel_health_event: { emoji: "âš ī¸", label: "Tunnel health changed", priority: 1 }, magic_tunnel_health_check_event: { emoji: "âš ī¸", label: "Magic tunnel health changed", priority: 1 }, magic_wan_tunnel_health: { emoji: "âš ī¸", label: "Magic WAN tunnel health changed", priority: 1 }, http_alert_edge_error: { emoji: "âš ī¸", label: "Edge error rate high", priority: 1 }, advanced_http_alert_error: { emoji: "âš ī¸", label: "HTTP error rate high", priority: 1 }, traffic_anomalies_alert: { emoji: "âš ī¸", label: "Traffic anomaly", priority: 1 }, clickhouse_alert_fw_anomaly: { emoji: "âš ī¸", label: "Security events spike", priority: 1 }, clickhouse_alert_fw_ent_anomaly: { emoji: "âš ī¸", label: "Security events spike", priority: 1 }, bot_traffic_basic_alert: { emoji: "🤖", label: "Bot traffic spike", priority: 1 }, custom_bot_detection_alert: { emoji: "🤖", label: "Bot detection alert", priority: 1 }, scriptmonitor_alert_new_malicious_scripts: { emoji: "🚨", label: "Malicious script detected", priority: 1 }, scriptmonitor_alert_new_malicious_hosts: { emoji: "🚨", label: "Malicious script host detected", priority: 1 }, scriptmonitor_alert_new_malicious_url: { emoji: "🚨", label: "Malicious URL detected", priority: 1 }, abuse_report_alert: { emoji: "âš ī¸", label: "Abuse report", priority: 1 }, block_notification_new_block: { emoji: "⛔", label: "Content blocked", priority: 1 }, secondary_dns_all_primaries_failing: { emoji: "đŸ”Ĩ", label: "All DNS primaries failing", priority: 1 }, secondary_dns_primaries_failing: { emoji: "âš ī¸", label: "DNS primaries failing", priority: 1 }, failing_logpush_job_disabled_alert: { emoji: "âš ī¸", label: "Logpush job disabled", priority: 1 }, workers_observability_alert: { emoji: "âš ī¸", label: "Workers alert", priority: 1 }, synthetic_test_low_availability_alert: { emoji: "âš ī¸", label: "Low availability", priority: 1 }, device_connectivity_anomaly_alert: { emoji: "âš ī¸", label: "Device connectivity anomaly", priority: 1 }, sentinel_alert: { emoji: "âš ī¸", label: "Sentinel alert", priority: 1 }, universal_ssl_event_type: { emoji: "🔒", label: "Universal SSL certificate", priority: 0 }, dedicated_ssl_certificate_event_type: { emoji: "🔒", label: "SSL certificate", priority: 0 }, custom_ssl_certificate_event_type: { emoji: "🔒", label: "Custom SSL certificate", priority: 0 }, access_custom_certificate_expiration_type: { emoji: "🔒", label: "Access certificate expiring", priority: 0 }, hostname_aop_custom_certificate_expiration_type: { emoji: "🔒", label: "Origin pull certificate expiring", priority: 0 }, zone_aop_custom_certificate_expiration_type: { emoji: "🔒", label: "Origin pull certificate expiring", priority: 0 }, mtls_certificate_store_certificate_expiration_type: { emoji: "🔒", label: "mTLS certificate expiring", priority: 0 }, expiring_service_token_alert: { emoji: "🔑", label: "Service token expiring", priority: 0 }, workers_alert: { emoji: "📈", label: "Workers usage", priority: 0 }, billing_usage_alert: { emoji: "đŸ’ŗ", label: "Usage alert", priority: 0 }, pages_event_alert: { emoji: "📄", label: "Pages deployment", priority: 0 }, incident_alert: { emoji: "đŸ“ĸ", label: "Cloudflare incident", priority: 0 }, synthetic_test_latency_alert: { emoji: "đŸĸ", label: "High latency", priority: 0 }, secondary_dns_warning: { emoji: "âš ī¸", label: "Secondary DNS warning", priority: 0 }, secondary_dns_zone_validation_warning: { emoji: "âš ī¸", label: "Secondary DNS warning", priority: 0 }, load_balancing_pool_enablement_alert: { emoji: "âš–ī¸", label: "Load balancer pool toggled", priority: 0 }, scriptmonitor_alert_new_hosts: { emoji: "📜", label: "New script host", priority: 0 }, scriptmonitor_alert_new_resources: { emoji: "📜", label: "New script", priority: 0 }, scriptmonitor_alert_new_code_change_detections: { emoji: "📜", label: "Script changed", priority: 0 }, scriptmonitor_alert_new_max_length_resource_url: { emoji: "📜", label: "Long script URL", priority: 0 }, fbm_auto_advertisement: { emoji: "đŸ›Ąī¸", label: "Prefix auto-advertised", priority: 1 }, maintenance_event_notification: { emoji: "🔧", label: "Scheduled maintenance", priority: -1 }, cni_maintenance_notification: { emoji: "🔧", label: "Interconnect maintenance", priority: -1 }, secondary_dns_zone_successfully_updated: { emoji: "â„šī¸", label: "Secondary DNS zone updated", priority: -1 }, block_notification_block_removed: { emoji: "â„šī¸", label: "Block removed", priority: -1 }, web_analytics_metrics_update: { emoji: "📊", label: "Web Analytics update", priority: -1 }, radar_notification: { emoji: "📡", label: "Radar notification", priority: -1 }, brand_protection_digest: { emoji: "â„šī¸", label: "Brand protection digest", priority: -1 }, } // Look a key up in one of the tables above, ignoring inherited names like "toString". function pick(table, key, fallback) { return Object.prototype.hasOwnProperty.call(table, key) ? table[key] : fallback } // Only link to real http(s) URLs. function link(url, cta) { return typeof url === "string" && /^https?:\/\//.test(url) ? [{ cta, url }] : [] } // A plain, non-empty string or null. function text(value) { return typeof value === "string" && value.trim() ? value.trim() : null } function handleRequest(request) { const body = request.body && typeof request.body === "object" ? request.body : {} const data = body.data && typeof body.data === "object" ? body.data : {} const message = text(body.text) const alertType = text(body.alert_type) const policy = text(body.name) ?? text(body.policy_name) // "Save and Test" sends only a text field; confirm the connection quietly. if (message && !alertType && !policy && /test message/i.test(message)) { return { title: "🔔 Cloudflare connected", message: "Your Cloudflare webhook destination is working", topic: "Cloudflare", priority: -1, } } // Guard: a Cloudflare notification has text plus an alert type or policy name. if (!message || (!alertType && !policy)) { console.log("Not a Cloudflare notification — skipping") return null } const type = pick(TYPES, alertType, null) // An alert that ended, or a health check that turned healthy, is good news. const healthy = /^healthy$/i.test(text(data.new_health_status) ?? text(data.new_status) ?? "") const resolved = body.alert_event === "ALERT_STATE_EVENT_END" || healthy const label = type?.label ?? policy ?? "Cloudflare notification" // Name the zone or host when Cloudflare's text doesn't already. const where = text(data.target_hostname) ?? text(data.zone_name) const title = resolved ? `✅ Resolved: ${label}` : `${type?.emoji ?? "🔔"} ${label}${where && !message.includes(where) ? ` on ${where}` : ""}` // Dashboard links: the alert's own link when it has one, otherwise the account. const account = text(body.account_id) const dashboard = text(data.dashboard_link) ?? text(data.rule_link) ?? (account && /^[0-9a-f]{32}$/i.test(account) ? `https://dash.cloudflare.com/${account}` : null) return { title, message: message.length > 500 ? `${message.slice(0, 497)}â€Ļ` : message, topic: "Cloudflare", // Resolved alerts are good news; unknown alert types default to Normal. priority: resolved ? -1 : type?.priority ?? 0, buttons: link(dashboard, "Open dashboard"), } } ``` ## Cloudflare notification webhook payload (sample) ```json { "ts": 1790671200, "data": { "action": "block", "rule_id": "fdfdac75430c4c47a959592f0aa5e68a", "max_rate": "184000", "zone_tag": "023e105f4ecef8ad9ca31a8372d0c353", "attack_id": "a1b2c3d4e5f6", "zone_name": "example.com", "mitigation": "block", "ruleset_id": "4d21379b4f9f4bb088e0729962c8b3cf", "start_time": "2026-09-29T08:40:00Z", "account_tag": "9035f53656c247e895c5a6939ae8a0e0", "attack_type": "HTTP flood", "account_name": "Acme", "dashboard_link": "https://dash.cloudflare.com/9035f53656c247e895c5a6939ae8a0e0/example.com/security/events", "target_hostname": "shop.example.com", "rule_description": "HTTP requests from known botnet signatures", "requests_per_second": 184000 }, "name": "DDoS alerts", "text": "Cloudflare is mitigating an HTTP DDoS attack against shop.example.com, peaking at 184,000 requests per second.", "policy_id": "749b911ea5d04344a58e45edd099b328", "account_id": "9035f53656c247e895c5a6939ae8a0e0", "alert_type": "advanced_ddos_attack_l7_alert", "alert_event": "ALERT_STATE_EVENT_START", "policy_name": "DDoS alerts", "alert_correlation_id": "000eaa907ed24e78946d3a93adb2ae57" } ``` ## FAQ ### Does this work on iPhone and Android? Yes. Install the JustPush app from the App Store or Google Play and sign in. Every phone signed in to your account gets the notification. ### Do I need to write code? No. Install the recipe in Studio, paste your webhook URL into Cloudflare and you are done. The code is there if you want to change the text, the sound or the buttons. ### Can I change what the notification says? Yes. After install the recipe's code is yours. Edit it in Studio and test it against the sample payload before you save. ### What does it cost? JustPush is free for 30 days. After that it's $19.99 a year, or $39.99 once. There is no extra charge for recipes.