A customer says Cloudflare blocked them: how to find the rule and stop losing orders

A customer says Cloudflare blocked them: how to find the rule and stop losing orders

Updated: October 24, 2026
16 min read
Guide
Security auditor

A customer emails to say your shop "won't let them in". They saw a Cloudflare page with a four-digit code, gave up, and bought somewhere else. Your server logs show nothing, because the request never got past Cloudflare. This happens on WooCommerce stores, WordPress lead-gen sites, headless frontends on Astro or Next.js and any custom app proxied through Cloudflare. The cause is almost always a rule on your own zone, and Cloudflare records which one.

This guide walks through the order that works: get the Ray ID, look it up, read which feature acted, then narrow that feature so it stops catching buyers and payment callbacks. Every behaviour described below comes from Cloudflare’s developer documentation as of October 2026.

#What Cloudflare error 1015, 1020 and 1009 mean

The code tells you where to look. A post in r/CloudFlare on 21 October 2026 summed up the codes, and each one matches Cloudflare’s own troubleshooting pages:

  • 1015 (HTTP 429): a rate limiting rule matched. Cloudflare’s advice is to review thresholds and, if a rule counts over a very short period such as one second, try 10 seconds.
  • 1020 (HTTP 403): a security rule with a Block action and no custom response. The 1020 page names API Shield schema validation and JWT validation as examples, and states that WAF custom rules and managed rules no longer return 1020. They serve the WAF block page instead.
  • 1009 (HTTP 403): a country or region ban set in IP Access rules. Country blocks there are Enterprise-only; on other plans a country block is a custom rule, and that shows the WAF block page.
  • 1010 (HTTP 403): Browser Integrity Check rejected the browser signature.
  • “Just a moment…” or a challenge page: a Managed Challenge from a custom rule, a rate limiting rule, Bot Fight Mode or Under Attack Mode.

The 1020 detail saves hours. If you are combing through custom rules looking for the one that returned 1020, you are in the wrong list.

#How to find the Cloudflare Ray ID

Ask the customer for a screenshot of the whole error page. It carries the code, the Ray ID and a UTC timestamp. The OP of the same thread added this in a reply:

the code’s the easy part, the bit people miss is the ray id on the same screen. paste it into security events and it shows which of your own rules fired.

(u/Hot_Bee_5451, r/CloudFlare, 22 October 2026)

A Ray ID is attached to every request through Cloudflare and sent to your origin in the cf-ray header. Cloudflare warns that Ray IDs are not guaranteed unique, so match the timestamp and IP as well. If the customer cannot send a screenshot, ask for their public IP address and the approximate time and country. For challenge failures there is a second route, suggested in another thread:

Well you can provide the RayID that is created when it runs that test to the website admin and they can look up the exact reason you failed.

(u/Logvin, r/CloudFlare, 21 October 2026)

#How to reproduce a Cloudflare block with curl

A screenshot tells you what happened once. Reproducing the request tells you whether it still happens after your fix. From a terminal, request the page the customer could not open and read the headers:

curl -sI https://example.com/checkout/
curl -sI "https://example.com/?wc-api=wc_stripe"

Three headers matter. server: cloudflare confirms the answer came from the edge. cf-ray gives you a fresh Ray ID to look up in Security Events. And a cf-mitigated: challenge header means the response is a challenge page: Cloudflare’s challenge detection guide says the header is set for every challenge page type, challenge is its only value, and the body is always text/html, whatever resource was requested.

That last detail explains a common headless failure. An Astro or Next.js frontend that calls its own API with fetch expects JSON, receives an HTML challenge, and fails with a parse error that looks like a code bug. Check response.headers.get("cf-mitigated") before parsing, log it, and you will know within one deploy whether Cloudflare is the cause. Your own IP and browser may not trip the same rule as the customer’s, so a clean result from your desk proves less than a clean result in Security Events.

#How to search a Ray ID in Cloudflare Security Events

In the dashboard, open Security > Analytics and the Events tab. Add a filter for Ray ID, or for the client IP, and set the time range to cover the complaint. Convert the UTC time from the error page to your own timezone first; Cloudflare’s 1020 page points this out explicitly.

Two limits from the Security Events documentation matter here. Data is kept for up to 31 days. And the list uses sampled logs, so on a busy zone a single request may not appear. If the Ray ID search returns nothing, narrow the time window to a few minutes and filter by IP; a smaller window shows more events. One request can also produce several events if several features acted on it.

#Which Cloudflare rule blocked the visitor

Expand the event. The Service field names the feature, and for rules you also get the rule name or ID. What each one usually means:

  • Custom rules: your own expression. Common culprits are country blocks, ASN blocks aimed at hosting providers (which also catch VPN users) and over-broad path rules on /wp-login.php or /checkout.
  • Managed rules: a Cloudflare or OWASP signature matched something in the request. Long search queries, form fields containing code snippets and some page-builder payloads trip these.
  • Rate limiting rules: the 1015 case. Shoppers behind one office or mobile carrier IP share a counter when the rule counts by IP.
  • Bot Fight Mode or Super Bot Fight Mode: the bot products. Cloudflare’s bot documentation says both may challenge API or mobile app traffic.
  • Security Level or Under Attack Mode: the zone-wide interstitial.

A deleted rule shows as “Rule unavailable”. Check the audit log to see who removed or changed it.

#How to create a Cloudflare skip rule without opening the whole site

The fix is a custom rule with the Skip action, placed above the rule that blocked, matching only the traffic you trust. Cloudflare’s skip options let you skip all remaining custom rules, all rate limiting rules, all managed rules and all Super Bot Fight Mode rules. Through the API you can also skip Browser Integrity Check, Security Level, User Agent Blocking, Zone Lockdown and Hotlink Protection. Custom rules run in order, so position matters.

Keep the expression narrow. For the WooCommerce Stripe extension, which uses only /?wc-api=wc_stripe as its webhook endpoint:

(http.request.uri.query contains "wc-api=wc_stripe" and ip.src in $stripe_webhooks)

Here $stripe_webhooks is an IP list you create from Stripe’s published webhook IP addresses. For a store integration calling the WooCommerce REST API from a fixed server:

(starts_with(http.request.uri.path, "/wp-json/wc/") and ip.src in $erp_servers)

For a false positive that hit real shoppers, often the better fix is to change the original rule instead of adding an exception: raise the rate limit period, scope a country block to /wp-login.php, or switch a Block to a Managed Challenge. Leave Log matching requests on for the skip rule so you can see it working.

#How to exclude one Cloudflare managed rule instead of the whole WAF

When the event shows a managed rule, do not skip all managed rules for the checkout. Cloudflare’s managed rules exceptions can skip all remaining managed rules, one or more managed rulesets, or one or more individual rules, and the exception has its own expression. Copy the rule ID from the event, create an exception for that rule only, and limit it to the path and method that triggered it, for example POST requests to the form endpoint that carried the payload.

Scope matters. An exception defined at zone level does not stop a match from a managed ruleset deployed at account level, because account-level rulesets run first in each phase. If you manage several shops under one Cloudflare account, check where the managed rules are deployed before writing the exception.

#Cloudflare rate limiting settings that stop catching shoppers

The rate limiting rules page lists what each plan can set, and those numbers decide how fine your fix can be:

PlanFields in the rule expressionCounting periodMitigation timeoutCounting by
FreePath, Verified Bot10 s10 sIP
Proadds Host, URI, Full URI, Queryup to 1 minup to 1 hIP
Businessadds Method, Source IP, User Agentup to 10 minup to 1 dayIP, IP with NAT support
Enterprise with Advanced Rate Limitinggeneral request and header fieldsup to 65,535 sup to 1 dayadds headers, cookies, ASN, country and more

Counting by IP is the reason an office or a mobile carrier can trip a rule built for a single bot. Three changes from Cloudflare’s rate limiting best practices reduce that:

  • Exclude known partners. Cloudflare’s example allows 10 requests per minute per IP to /status unless the address is in an IP list named partner_ips, using not ip.src in $partner_ips in the expression. Source IP is available in rate limiting expressions only from Business upward; on Free and Pro, put the partner list in a custom skip rule that skips all rate limiting rules, since custom rules can match on the source IP.
  • Count only failures. From Business upward a custom counting expression is available, so a login rule can count only POST requests that returned 401 or 403. A customer who logs in on the first try never adds to the counter.
  • Match the exact path. The same page warns that a rule for /validate/otp will not match /api/otp/validate. Check the real path in analytics before writing the rule, and keep /wp-json/ and checkout AJAX endpoints out of rules meant for login pages.

On Enterprise, the Request rate analysis tab in Security Analytics shows the request rate distribution for the top 50 clients and can pre-fill a rate limiting rule from the selected rate. Cloudflare recommends deploying such a rule with the Log action first.

#Can a WAF rule bypass Bot Fight Mode

No. The Bot Fight Mode page says you cannot bypass or skip it with WAF custom rules or Page Rules, because it does not run on the Ruleset Engine, so Skip, Bypass and Allow have no effect. The skip options page repeats that only Super Bot Fight Mode can be skipped. One exception is documented: Bot Fight Mode does not trigger if an IP Access rule matches the request first.

So on the Free plan, if Bot Fight Mode challenges your payment provider, your ERP or your uptime monitor, you have three choices: an IP Access allow rule for that provider’s addresses, turning Bot Fight Mode off, or moving to a paid plan where Super Bot Fight Mode accepts skip rules. Super Bot Fight Mode also has an Optimize for WordPress setting that lets WordPress loopback requests through, which fixes Site Health errors without a custom rule.

#Why Cloudflare blocks Stripe webhooks and WooCommerce REST API calls

Server-to-server calls have no browser, so they cannot solve a JavaScript challenge. Any feature that challenges instead of blocking still breaks them. A store owner described exactly this in r/CloudFlare:

When I turn on Under Attack Mode, the Singapore traffic stops in GA4. But Under Attack Mode makes my site slow, and my server-to-server API calls (WooCommerce REST API) get the Cloudflare “Just a moment…” challenge, so they fail.

(u/lastoneinbatumi, r/CloudFlare, 19 October 2026)

The cost differs by provider. Stripe retries a failed webhook with exponential backoff for up to three days in live mode, so orders stuck as “pending payment” usually recover once you fix the rule. Shopify retries up to eight times over four hours and then removes the subscription, which matters if your app or headless backend receives Shopify webhooks behind your Cloudflare zone. Check each provider’s dashboard for failed deliveries after any security change.

Under Attack Mode is meant as a last resort during an attack. Cloudflare’s Security Level page says to use a configuration rule to turn it on or off for your API or any other part of the domain. Keep it off for /wp-json/, webhook paths and your API host.

The same thread had a second lesson. When blocked traffic keeps appearing in analytics, ask whether it goes through Cloudflare at all:

Is your host configured to only allow traffic to and from Cloudflare? Otherwise it could be reached directly by ip

(u/Wilbo007, r/CloudFlare, 19 October 2026)

Cloudflare’s IP address documentation recommends blocking traffic at the origin that does not come from Cloudflare or your trusted partners. Allow your payment providers’ addresses in that origin firewall too.

Update, . Letting a payment provider’s webhooks through Cloudflare does not mean the endpoint should trust whoever calls it. The Wordfence weekly vulnerability report for 12 to 18 October 2026 listed WooCommerce payment plugins whose webhook handlers accepted forged calls: Asaas Gateway before 2.7.8 matched an empty configured token against an empty request token, and Cardinity 3.2.6 to 3.4.1 checked the HMAC signature against an empty project secret, so anyone could mark orders as paid. Visma Pay before 1.2.2 and iPOSpays up to 1.4.6 had unauthenticated payment bypasses in the same week. Cloudflare cannot tell a forged webhook from a real one, so the check belongs in the application: set the webhook secret in the gateway settings, keep the plugin updated, and confirm that paid orders match transactions in the provider dashboard.

#How to test a Cloudflare rule without blocking customers

Cloudflare’s custom rule guide offers the Log action for validating a rule before enforcing it, on Enterprise plans only. On other plans it suggests starting with Managed Challenge, reviewing the matched requests in Security Events, and switching to Block once the matches look right. A real customer can pass a Managed Challenge; a Block gives them nothing to do.

A challenged visitor who passes gets a cf_clearance cookie. The Challenge Passage setting controls how long it stays valid: 30 minutes by default, with Cloudflare recommending 15 to 45 minutes. Two consequences for support tickets. A customer who blocks cookies is challenged again on every page, which reads as “the site keeps checking me”. And Challenge Passage does not apply to rate limiting rules, so passing a challenge does not reset a 1015.

#How to show blocked customers what to do next

The default block page tells the visitor nothing about your shop. Two options exist on paid plans. Custom Errors are available on Pro, Business and Enterprise, not on Free, and an Error Page of type WAF block replaces the page shown for WAF blocks across the zone. From Pro upward, a single custom rule with the Block action can also return its own response, with a status code between 400 and 499 and an HTML, JSON or plain text body.

Use that page to ask for what you need: a screenshot with the Ray ID, the time, and an email address or phone number that is not behind the same zone. For an API path, return JSON so integrations log a readable error instead of an HTML page. Cloudflare’s custom error rule examples include one for 1020 errors that matches cf.response.1xxx_code eq 1020.

#Cloudflare block troubleshooting table

What the customer or log showsLikely ruleFix
Error 1015, HTTP 429Rate limiting ruleLonger counting period, higher threshold, or skip rate limiting for trusted IPs
WAF block page, HTTP 403, no 1xxx codeWAF custom rule or managed ruleFind the rule by Ray ID; narrow the expression or add a skip rule above it
Error 1020, HTTP 403Another Block without custom response (for example API Shield)Look in Security Events, not in custom rules
Error 1009Country block in IP Access rulesAllow the visitor’s IP or move geoblocking to a scoped custom rule
Error 1010Browser Integrity CheckSkip it for the affected path via API, or turn it off
Challenge loop on every pageUnder Attack Mode or Security LevelTurn it off, or limit it with a configuration rule
Webhook or REST API failing, no human involvedBot Fight Mode, Under Attack Mode or a challenge ruleIP Access allow or Super Bot Fight Mode skip rule; keep UAM off API paths
Nothing in Security EventsSampling, wrong time zone, or the request never reached CloudflareSmaller time window, filter by IP; check DNS and the origin firewall

#How to monitor Cloudflare blocks after the fix

Do not stop at one customer. In Security Events, filter by Action equal to Block or Managed Challenge and group by path. Requests to /checkout, /cart, /my-account, /wp-json/ or your contact form endpoint are the ones costing money. The filtered URL can be shared, so a colleague sees the same view. Up to 500 sampled events can be exported as JSON.

Then check the other side: failed deliveries in Stripe, PayPal or Shopify, WooCommerce orders stuck in pending, and contact form submissions per day. A drop the day after a security change points straight at the rule you added. My Cloudflare edge service covers rule audits of this kind, and the store reliability plan includes this monitoring for WooCommerce shops.

Related reading: whether Cloudflare’s AI bot settings also stop search crawlers is covered in does Cloudflare block Googlebot. How much of a small site’s traffic is automated, and why that tempts owners into aggressive bot rules, is in 72% of my traffic is not a browser. For moving logic to the edge, see Cloudflare Workers and WooCommerce.

Next step

Turn the article into an actual implementation

This block strengthens internal linking and gives readers the most relevant next move instead of leaving them at a dead end.

Explore other WordPress services and knowledge base

Frequently asked questions

Practical answers to apply the topic in real execution.

Why do I not see error 1020 in my server logs#
Because the request never reached your server. Cloudflare answered it at the edge, so your origin logs and most analytics tools show nothing. The 1xxx code appears only on the error page the visitor saw, which is why you need their screenshot with the Ray ID.
Can I whitelist an IP so Bot Fight Mode stops challenging it#
Not with a skip rule. Cloudflare documents that Bot Fight Mode runs outside the Ruleset Engine, so Skip, Bypass and Allow have no effect. An IP Access rule that matches first prevents it from triggering. For path-level exceptions you need Super Bot Fight Mode on a paid plan, or Bot Fight Mode switched off.
Is it safe to skip the WAF for Stripe or PayPal webhooks#
Skip only the features that break the call, only on the webhook path, and keep signature verification in your application. Stripe signs every event and publishes its webhook IP addresses, so a rule matching both the path and the IP list is much narrower than turning protection off.
How long can I look back for a blocked customer#
Security Events keeps up to 31 days of history on every plan, with a 30-day query window on most. A complaint from last week is still searchable; one from two months ago is not.
Why does a customer get the challenge page again and again#
Passing a challenge sets a cf_clearance cookie that lasts 30 minutes by default. A browser that blocks or clears cookies loses it and is challenged on the next page. Rate limiting is separate: passing a challenge does not lift a 1015.

Related Articles

WordPress supply chain attacks in 2026

A single week in June 2026 saw the Awesome Motive CDN breach, the ShapedPlugin build pipeline compromise, and a 13-year backdoor campaign exposed. The common thread: the official update channel was the attack vector. What store owners should actually change.