How to Solve Cloudflare With Go (chromedp + Scrapeless)
Lead Scraping Automation Engineer
TL;DR:
- Cloudflare scores the browser, not the visitor. It reads fingerprint consistency, behavioral signals, and the exit IP, then sets a
cf_clearancecookie for a browser it trusts — so clearing it in Go means being a trusted browser, not answering a puzzle. - A local Go browser stack fails that scoring on three axes: the
navigator.webdrivertell, a headless-default fingerprint, and a datacenter exit IP. Maintaining evasions by hand is a treadmill. - The Scrapeless Scraping Browser clears the challenge during render — real self-developed Chromium, a consistent per-session fingerprint, and residential egress in 195+ countries, reached over one WebSocket endpoint.
- Your Go stays standard chromedp. Point
chromedp.NewRemoteAllocatorat the Scrapeless endpoint, wait for the post-challenge content, and read the page — the only change is the connection URL. - Verified live: a Go chromedp session over the cloud browser cleared the Cloudflare challenge page, read the success marker
You bypassed the Cloudflare challenge! :D, and received acf_clearancecookie. - Free to start. New Scrapeless accounts include free Scraping Browser runtime — sign up at app.scrapeless.com.
Introduction: clearing Cloudflare in Go is a browser problem
A Cloudflare challenge is not an image CAPTCHA you decode. It runs in the background and grades the browser that loaded the page — whether the fingerprint is internally consistent, whether the interaction signals look human, and whether the exit IP has a clean reputation. When the score passes, Cloudflare sets a cf_clearance cookie and the real page loads. When it doesn't, you get an interstitial instead of content.
That reframes the Go task. There is no answer to submit — the work is presenting a browser Cloudflare already trusts. A local headless Chromium driven by chromedp can't: it announces automation through the navigator.webdriver property, ships headless-default fonts and canvas behavior, and exits from an IP reputation services already know. You can maintain your own evasions and then keep maintaining them as Chromium and the detectors move. This guide takes the shorter path: drive the Scrapeless Scraping Browser from standard chromedp, so the fingerprint, behavior, and exit IP are handled server-side and the challenge clears during a normal render.
What Cloudflare actually checks
Cloudflare's own documentation describes a verification step that runs without interrupting the visitor. In practice it grades three things and grants a cf_clearance cookie — a standard HTTP cookie — when they pass:
| What Cloudflare reads | Why a local Go browser fails it |
|---|---|
| Fingerprint consistency | headless defaults and the webdriver flag contradict a real Chrome |
| Behavioral signals | scripted timing without a coherent browser surface |
| Exit IP reputation | datacenter IPs score worse than residential ones |
A coherent, trusted browser matters more than any single evasion — which is why moving all three server-side is more durable than hand-rolled patches.
Why Scrapeless Scraping Browser
The Scrapeless Scraping Browser is a customizable, anti-detection cloud browser designed for web crawlers and AI agents. For Cloudflare specifically, it brings:
- Real self-developed Chromium that runs the challenge JavaScript exactly like Chrome, so it resolves instead of stalling.
- A consistent per-session fingerprint — no
navigator.webdrivertell, no headless defaults leaking through. - Residential egress in 195+ countries — Cloudflare scores the exit IP, and a residential region reads clean where a datacenter IP does not.
- Session persistence so a
cf_clearancegrant can be reused across requests in the same session. - One connection surface — every option is a query parameter on the same WebSocket endpoint.
Get your API key on the free plan at app.scrapeless.com.
Prerequisites
- A Go toolchain (Go 1.21 or newer)
github.com/chromedp/chromedpandgithub.com/chromedp/cdproto- A Scrapeless account and API key — sign up at app.scrapeless.com
Full connection details live in the Scraping Browser documentation.
Install
Pull chromedp into your module. You connect to a remote browser, so no local Chrome is required.
bash
go get github.com/chromedp/chromedp
go get github.com/chromedp/cdproto
export SCRAPELESS_API_KEY=your_api_token_here # free key at https://app.scrapeless.com
Connect and clear the challenge
chromedp attaches to a remote browser with NewRemoteAllocator. Pass the Scrapeless endpoint with chromedp.NoModifyURL so chromedp uses the WebSocket URL as-is, then wait for the post-challenge content. The challenge is solved during render — there is no separate solve call.
Note: running this needs a Go toolchain with the chromedp modules installed. This block was verified live against the Scrapeless cloud browser; add your API key and
go runit to reproduce.
go
package main
import (
"context"
"fmt"
"net/url"
"os"
"time"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
)
func main() {
q := url.Values{}
q.Set("token", os.Getenv("SCRAPELESS_API_KEY"))
q.Set("sessionTTL", "180")
q.Set("proxyCountry", "US")
endpoint := "wss://browser.scrapeless.com/api/v2/browser?" + q.Encode()
target := "https://www.scrapingcourse.com/cloudflare-challenge"
allocCtx, cancel := chromedp.NewRemoteAllocator(context.Background(), endpoint, chromedp.NoModifyURL)
defer cancel()
ctx, cancel2 := chromedp.NewContext(allocCtx)
defer cancel2()
ctx, cancel3 := context.WithTimeout(ctx, 120*time.Second)
defer cancel3()
var cleared string
var cookies []*network.Cookie
err := chromedp.Run(ctx,
chromedp.Navigate(target),
chromedp.WaitVisible("#challenge-title", chromedp.ByID),
chromedp.Text("#challenge-title", &cleared, chromedp.ByID),
chromedp.ActionFunc(func(ctx context.Context) error {
c, err := network.GetCookies().Do(ctx)
cookies = c
return err
}),
)
if err != nil {
fmt.Println("error:", err)
os.Exit(1)
}
hasClearance := false
for _, c := range cookies {
if c.Name == "cf_clearance" {
hasClearance = true
}
}
fmt.Println("cleared:", cleared)
fmt.Println("cf_clearance:", hasClearance)
}
A live run of this program printed cleared: You bypassed the Cloudflare challenge! :D and cf_clearance: true — standard chromedp, sourced through the cloud browser.
Get your API key on the free plan: app.scrapeless.com
Pin the region for a reliable clear
Cloudflare scores the exit IP, so pin proxyCountry to a residential region. Turn it to any ISO country code. The W3C WebDriver specification requires conforming automation to expose the webdriver flag; the cloud browser does not carry it, so a clean IP has a clean fingerprint beside it.
go
q := url.Values{}
q.Set("token", os.Getenv("SCRAPELESS_API_KEY"))
q.Set("sessionTTL", "180")
q.Set("proxyCountry", "US") // or "DE", "JP", "ANY"
Where local Go browsers stop
A local chromedp scraper is fine until Cloudflare starts scoring the browser. Then the headless fingerprint, the webdriver flag, and the datacenter IP each fail a different check, and the interstitial replaces the content. Those are fingerprint, behavior, and IP problems — the three the cloud browser handles server-side. Connecting to Scrapeless hands them to a managed session while your chromedp actions stay standard.
What you get back
The session behaves like any chromedp session — Navigate, WaitVisible, Text, and CDP network.GetCookies all work. A few honest observations from clearing Cloudflare over the cloud browser:
navigator.webdriveris absent, so the first check Cloudflare runs reads like a real Chrome.- The exit IP matches
proxyCountry— a residential region clears far more reliably than a datacenter IP. cf_clearanceis present after a pass — reuse the same session to carry the grant across follow-up requests.- Warm the session for stubborn pages — load the site's homepage first in the same session before the protected page, so the behavioral surface looks like a normal visit.
Conclusion: clear Cloudflare, keep your Go
Clearing Cloudflare in Go is not about decoding a challenge — it is about presenting a browser Cloudflare trusts. The Scrapeless Scraping Browser handles the three things it scores (fingerprint, behavior, exit IP) server-side, so your chromedp code changes only its connection URL. Pin proxyCountry to a residential region, wait for the post-challenge content, and read cf_clearance to confirm the pass. For running the same cloud browser from Python instead, see the Scrapling production-scraper guide, and compare plans on the Scrapeless pricing page.
Ready to Build Your Cloudflare-Clearing Pipeline?
Join our community to claim a free plan and connect with developers scraping Cloudflare-protected sites: Discord · Telegram.
Sign up at app.scrapeless.com for free Scraping Browser runtime and point chromedp at the cloud browser that clears Cloudflare during render.
FAQ
Q: Do I need a separate CAPTCHA-solving service?
Not on a passing browser. Cloudflare mostly scores fingerprint, behavior, and IP in the background and issues a cf_clearance cookie. The cloud browser is built to pass that scoring during a normal render, so there is no separate puzzle step to wire up.
Q: Why NewRemoteAllocator with NoModifyURL?
NewRemoteAllocator attaches chromedp to a browser it did not launch. NoModifyURL tells chromedp to use the Scrapeless WebSocket URL exactly as given, instead of rewriting it to discover a local DevTools endpoint.
Q: Do I need a proxy?
No. Residential egress is built in — set proxyCountry to a region or ANY. Cloudflare scores the exit IP, so a residential region clears more reliably than a datacenter address.
Q: The challenge still shows on some pages — what helps?
Pin proxyCountry to a residential region and warm the session by loading the site's homepage first in the same session before the protected page, so the behavioral surface reads like a normal visit.
Q: Is clearing Cloudflare legal?
Accessing publicly available data is generally permitted, but the rules vary by jurisdiction and site. Review the target's terms of service, respect robots directives, and consult counsel for anything sensitive.
At Scrapeless, we only access publicly available data while strictly complying with applicable laws, regulations, and website privacy policies. The content in this blog is for demonstration purposes only and does not involve any illegal or infringing activities. We make no guarantees and disclaim all liability for the use of information from this blog or third-party links. Before engaging in any scraping activities, consult your legal advisor and review the target website's terms of service or obtain the necessary permissions.



