Explainer
Cloudflare Waiting Room vs a Challenge Page: What Crawlers See
A Cloudflare Waiting Room is a queue, not a bot check. How to tell it from a challenge page, how its cookie and JSON mode work, and how to wait your turn.
By ZeroCaptcha Engineering5 min readPublished
A Cloudflare Waiting Room is a queue, not a bot check. It holds visitors when traffic to a
page passes limits the site owner set (“total active users” and “new users per minute”), shows
them a waiting page that refreshes itself every 20 seconds, and keeps their place in an encrypted
cookie named __cfwaitingroom. A challenge page is different: it answers HTTP 403 with the
header cf-mitigated: challenge, and waiting does not help, while a waiting room answers 200 by
default and waiting is the whole point. An automated client should keep its cookie, ask again at
the room’s interval, and never open new sessions to jump the line.
This explainer compares the two, shows the JSON mode Cloudflare offers for non-browser clients, and gives a polite client that waits its turn. Facts are from Cloudflare’s documentation as checked on 1 October 2026.
Waiting room or challenge page?
| Waiting room | Challenge page | |
|---|---|---|
| Why you see it | Traffic passed the owner’s limits | A rule, Bot Management or Under Attack mode challenged your request |
| Status | 200 by default; the owner can pick another code |
403 |
| Marker | The __cfwaitingroom cookie; with JSON mode, a cfWaitingRoom object |
Header cf-mitigated: challenge |
| What passes it | Time: the queue lets you in when there is room | Passing the challenge, which sets cf_clearance |
| What a client should do | Wait, with its cookie, at the room’s interval | Back off, or pass it where allowed |
A waiting room can also include a Cloudflare Turnstile widget. Its settings offer the modes off,
invisible, visible_non_interactive and visible_managed (default invisible), and two actions
for a failed check, log (the default) and infinite_queue. In Cloudflare’s analytics for that
widget, an infinite queue shows up as “the number of refresh requests from bots in the infinite
queue”: a client judged a bot keeps waiting and never gets in.
How the queue works
- Limits: the owner sets the number of active users the site can take at once and how many new users may enter per minute; the room queues everyone beyond them.
- Order: “First In First Out (FIFO)” by default. Some plans can use Random, Passthrough (let everyone through) or Reject (let nobody through).
- Refresh: in a browser, “the user’s browser automatically refreshes every 20 seconds”.
- Cookie:
__cfwaitingroomholds “a unique group ID corresponding to when the visitor entered the waiting room” and anacceptedAtvalue. While queued, its “expiration is always set to five minutes, but renews every 20 seconds”; once in, it lasts for the room’s session duration, 5 minutes by default and up to 30. - Cookies are required: “When a waiting room is actively queueing, users cannot visit that host and path combination without enabling cookies.”
JSON mode for non-browser clients
A site owner can turn on JSON responses for “mobile and other non-browser traffic” (the
json_response_enabled setting, off by default). The client must send exactly
Accept: application/json: “If it is anything else or has any additional content such as
Accept: application/json, text/html the response will not return in the JSON format.” The reply
while queued looks like this, in Cloudflare’s example:
{ "cfWaitingRoom": { "inWaitingRoom": true, "waitTime": 5, "waitTimeKnown": true, "waitTimeFormatted": "5 minutes", "queueIsFull": false, "queueAll": false, "lastUpdated": "2021-08-03T23:46:00.000Z", "refreshIntervalSeconds": 20 }}The client must “retry the request every refreshIntervalSeconds in order for users to advance in
the queue”, sending the cookie and keeping it updated from each response. Without the cookie, the
room treats the client as new, at the back of the queue.
A client that waits its turn
This Python function waits in a room with one session, at the interval the room asks for, and gives up after a limit you choose. It returns the first response that is not a queue reply; ask for the page again with your usual headers once it returns.
import time
import requests
def wait_in_queue(session, url, max_wait_seconds=1800): deadline = time.monotonic() + max_wait_seconds while time.monotonic() < deadline: response = session.get(url, headers={"Accept": "application/json"}, timeout=30) try: state = response.json().get("cfWaitingRoom") except (ValueError, AttributeError): state = None if not state or not state.get("inWaitingRoom"): return response print("queued, estimated wait:", state.get("waitTimeFormatted", "unknown")) time.sleep(state.get("refreshIntervalSeconds", 20)) raise TimeoutError(f"still queued after {max_wait_seconds} seconds")
with requests.Session() as session: wait_in_queue(session, "https://tickets.example.com/event/42") page = session.get("https://tickets.example.com/event/42", timeout=30) print(page.status_code)If the owner has not turned on JSON mode, the queue page is HTML: wait 20 seconds between requests, keep the same session, and look for the page you asked for.
Three rules keep a crawler from hurting the queue it is in:
- One session per place in line. Opening many sessions puts many places in the queue, which pushes real visitors back. Don’t.
- Honour the interval. Asking faster than
refreshIntervalSecondsdoes not move you up. - Set a limit. A queue can be long, and a client judged a bot may be put in an infinite queue. Give up after a time that fits your job.
Where ZeroCaptcha fits, and where it doesn’t
A waiting room has nothing to solve, and ZeroCaptcha does not move anyone up a queue. What it covers are the checks that sit in front of pages: Cloudflare Turnstile widgets in forms, through the Cloudflare Turnstile solver, and Cloudflare challenge pages, through the Cloudflare WAF and 5-second challenge solver. If a site answers with a challenge rather than a queue, see Cloudflare challenge types; if it answers 429 with error 1015, you are being rate limited, which Cloudflare error 1015 covers.
Sources
- Cloudflare Waiting Room: about (checked 1 October 2026).
- Cloudflare Waiting Room: get JSON response for mobile and other non-browser traffic (checked 1 October 2026).
- Cloudflare Waiting Room: cookies (checked 1 October 2026).
- Cloudflare Waiting Room: configuration settings and queueing methods (checked 1 October 2026).
- Cloudflare Waiting Room: analytics, for Cloudflare Turnstile widget traffic (checked 1 October 2026).
- Cloudflare challenges: detect a challenge response (checked 1 October 2026).
- Cloudflare: Error 403 (checked 1 October 2026).
The team that builds and runs the ZeroCaptcha API. Articles are drafted with AI tools, then checked against the API's code and the primary sources each one cites.