{"record":{"id":"b7bb4ab0f61f9ce7","repo":"can1357/oh-my-pi","slug":"ecosia-blocked-the-request-with-a-cloudflare-bot-c","errorCode":null,"errorMessage":"Ecosia blocked the request with a Cloudflare bot challenge. Ecosia's firewall throttles automated searches from datacenter/shared-egress IPs; try another web search provider such as DuckDuckGo, Brave, or Tavily.","messagePattern":"Ecosia blocked the request with a Cloudflare bot challenge\\. Ecosia's firewall throttles automated searches from datacenter/shared-egress IPs; try another web search provider such as DuckDuckGo, Brave, or Tavily\\.","errorType":"exception","errorClass":"SearchProviderError","httpStatus":429,"severity":"warning","filePath":"packages/coding-agent/src/web/search/providers/ecosia.ts","lineNumber":135,"sourceCode":"\t\t\t\thomeUrl: ECOSIA_HOME_URL,\n\t\t\t\tready: {\n\t\t\t\t\tselector: 'article[data-test-id=\"organic-result\"]',\n\t\t\t\t\ttimeoutMs: RESULT_RENDER_TIMEOUT_MS,\n\t\t\t\t},\n\t\t\t\tshouldFallback: isBlockedPage,\n\t\t\t},\n\t\t});\n\t} catch (error) {\n\t\tif (error instanceof SearchProviderError || params.signal?.aborted) throw error;\n\t\tif (signal.aborted) {\n\t\t\tthrow new SearchProviderError(\"ecosia\", \"Ecosia search timed out.\", 504);\n\t\t}\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new SearchProviderError(\"ecosia\", `Ecosia search failed: ${message}`, 503);\n\t}\n\n\tif (isBlockedPage(page)) {\n\t\tthrow new SearchProviderError(\n\t\t\t\"ecosia\",\n\t\t\t\"Ecosia blocked the request with a Cloudflare bot challenge. Ecosia's firewall throttles automated searches from datacenter/shared-egress IPs; try another web search provider such as DuckDuckGo, Brave, or Tavily.\",\n\t\t\t429,\n\t\t);\n\t}\n\tif (page.status < 200 || page.status >= 300) {\n\t\tconst classified = classifyProviderHttpError(\"ecosia\", page.status, page.html);\n\t\tif (classified) throw classified;\n\t\tthrow new SearchProviderError(\"ecosia\", `Ecosia HTML error (${page.status})`, page.status);\n\t}\n\treturn page.html;\n}\n\n/** Execute an Ecosia web search and parse the server-rendered result page. */\nexport async function searchEcosia(params: SearchParams): Promise<SearchResponse> {\n\tconst numResults = clampNumResults(params.numSearchResults ?? params.limit, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS);\n\tconst html = await callEcosiaHtml(params);\n\tconst parsed = parseHtmlResults(html);","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/ecosia.ts#L117-L153","documentation":"Ecosia served a page containing a Cloudflare bot challenge instead of search results. The provider detects this (isBlockedPage) and raises HTTP 429. Ecosia's firewall throttles automated searches coming from datacenter or shared-egress IPs, so requests from servers/VPNs/CI runners are frequently challenged.","triggerScenarios":"callEcosiaHtml fetched a 200-class HTML page but isBlockedPage(page) matched Cloudflare challenge markers in the markup. Typical when running from cloud VMs, containers, VPNs, or after many rapid automated queries from one IP.","commonSituations":"Running the coding agent on an AWS/GCP/Azure box; corporate shared NAT egress; scraping Ecosia at high volume; Ecosia tightening bot protection after a markup change.","solutions":["Configure a different web search provider (DuckDuckGo, Brave, or Tavily) via an API key — these are the explicitly recommended alternatives.","Run from a residential/different network IP if Ecosia must be used.","Reduce Ecosia query rate to avoid triggering throttling.","Check for an Ecosia API integration or paid search API instead of HTML scraping."],"exampleFix":"// before\nconst results = await search({ provider: \"ecosia\", query });\n// after\nconst results = await search({ provider: \"brave\", query }); // with BRAVE_API_KEY set","handlingStrategy":"fallback","validationCode":"const res = await fetch(\"https://www.ecosia.org/search?q=test\");\nconst html = await res.text();\nconst likelyBlocked = html.includes(\"cf-challenge\") || html.includes(\"Just a moment...\");\nif (likelyBlocked) console.warn(\"Ecosia will challenge this IP; use another provider\");","typeGuard":null,"tryCatchPattern":"try {\n  const res = await search({ provider: \"ecosia\", query });\n} catch (e) {\n  if (e instanceof SearchProviderError && e.status === 429) {\n    const res = await search({ provider: \"duckduckgo\", query }); // recommended fallback\n  } else throw e;\n}","preventionTips":["Configure an API-key provider (Brave, Tavily, DuckDuckGo) for datacenter/CI environments","Avoid running Ecosia scrapes from shared cloud egress IPs","Throttle query rate to stay below challenge thresholds","Treat 429 from this provider as permanent for the current IP, not retryable"],"tags":["bot-detection","cloudflare","rate-limit","ecosia","search-provider"],"backgroundTag":"cloudflare-bot-challenge","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}