Cloudflare blocks your scraper again. You've tried rotating user agents, adding delays, and switching IPs. Nothing works.
This is where FlareSolverr becomes your secret weapon. It's a proxy server that actually behaves like a real browser, solving Cloudflare challenges automatically while you focus on extracting data.
In this guide, I'll show you how to install FlareSolverr, integrate it with Python, manage sessions efficiently, and troubleshoot the most common issues developers face.
What is FlareSolverr?
FlareSolverr is an open-source proxy server built to bypass Cloudflare and DDoS-GUARD protection. It uses Selenium with undetected-chromedriver under the hood, which means it actually launches a real Chrome browser to solve challenges.
When a request comes in, FlareSolverr opens the target URL in a headless browser, waits for Cloudflare's JavaScript challenges to complete, then returns the HTML and cookies to your application.
Those cookies can then be reused with standard HTTP clients like Python's requests library, letting you scrape protected sites without spinning up a browser for every single request.
How FlareSolverr Works
The workflow is straightforward:
- Your scraper sends a POST request to the FlareSolverr API
- FlareSolverr launches a Chrome instance using undetected-chromedriver
- The browser loads the target URL and waits for Cloudflare challenges
- Once solved, FlareSolverr returns the HTML, cookies, and response headers
- You use those cookies for subsequent requests with any HTTP client
The beauty here is that FlareSolverr stays idle when not in use, consuming minimal resources. It only spins up browsers when you actually need them.
Step 1: Install FlareSolverr with Docker
Docker is the recommended installation method. The image includes everything—Chromium browser, Python dependencies, and proper configuration.
Pull and Run the Container
Open your terminal and run:
docker run -d \
--name=flaresolverr \
-p 8191:8191 \
-e LOG_LEVEL=info \
--restart unless-stopped \
ghcr.io/flaresolverr/flaresolverr:latest
Let me break down what each flag does.
The -d flag runs the container in detached mode, so it operates in the background. The --name flag assigns a friendly name you can reference later.
Port mapping with -p 8191:8191 exposes the FlareSolverr API on localhost. The environment variable LOG_LEVEL=info controls verbosity—switch to debug when troubleshooting.
Finally, --restart unless-stopped ensures the container restarts automatically after system reboots unless you explicitly stop it.
Verify the Installation
Check if FlareSolverr is running:
docker ps | grep flaresolverr
You should see the container listed with status "Up". The API now accepts requests at http://localhost:8191/v1.
Using Docker Compose
For more complex setups, create a docker-compose.yml file:
version: "3.8"
services:
flaresolverr:
image: ghcr.io/flaresolverr/flaresolverr:latest
container_name: flaresolverr
environment:
- LOG_LEVEL=info
- TZ=UTC
- HEADLESS=true
ports:
- "8191:8191"
restart: unless-stopped
Run it with:
docker compose up -d
This approach makes it easier to version control your configuration and integrate FlareSolverr into larger application stacks.
Step 2: Install FlareSolverr Without Docker
Not everyone wants to use Docker. Here's how to run FlareSolverr natively on Linux and Windows.
Linux Installation
Start by installing the required dependencies:
sudo apt update
sudo apt install python3.11 chromium xvfb
The xvfb package provides a virtual framebuffer, which is necessary for running headless Chrome on servers without a display.
Clone the repository and install Python packages:
git clone https://github.com/FlareSolverr/FlareSolverr.git
cd FlareSolverr
pip install -r requirements.txt
Start the server:
python src/flaresolverr.py
You'll see output confirming FlareSolverr is listening on port 8191.
Windows Installation
The easiest approach on Windows is using precompiled binaries.
Download the latest release from the FlareSolverr releases page. Extract the ZIP file and run FlareSolverr.exe.
Windows Firewall might ask for permission—allow it through, and you're good to go.
To configure environment variables on Windows, open Command Prompt and set them before running:
set LOG_LEVEL=debug
set BROWSER_TIMEOUT=120000
FlareSolverr.exe
Step 3: Make Your First Request with Python
Now for the fun part. Let's actually use FlareSolverr to bypass Cloudflare.
Basic GET Request
Install the requests library if you haven't already:
pip install requests
Here's a simple script that sends a URL through FlareSolverr:
import requests
# FlareSolverr API endpoint
flaresolverr_url = "http://localhost:8191/v1"
# Request headers
headers = {"Content-Type": "application/json"}
# Payload with the target URL
payload = {
"cmd": "request.get",
"url": "https://example-protected-site.com",
"maxTimeout": 60000
}
# Send request to FlareSolverr
response = requests.post(
flaresolverr_url,
headers=headers,
json=payload
)
# Parse the response
result = response.json()
The cmd field tells FlareSolverr what type of request to make. The maxTimeout value (in milliseconds) sets how long to wait for the challenge to solve.
Extracting the Data
Once FlareSolverr returns a response, you'll want to extract the HTML and cookies:
if result["status"] == "ok":
# Get the HTML content
html_content = result["solution"]["response"]
# Get cookies for reuse
cookies = result["solution"]["cookies"]
# Get the user agent used
user_agent = result["solution"]["userAgent"]
print("Challenge solved!")
print(f"Received {len(html_content)} bytes of HTML")
else:
print(f"Error: {result['message']}")
The solution object contains everything you need: the full HTML response, cookies as a list of dictionaries, and the user agent string FlareSolverr used.
Reusing Cookies with Requests
Here's where FlareSolverr really shines. Instead of routing every request through the proxy (which launches a browser each time), grab the cookies once and use them directly:
import requests
# Convert FlareSolverr cookies to requests format
session = requests.Session()
for cookie in cookies:
session.cookies.set(
cookie["name"],
cookie["value"],
domain=cookie["domain"],
path=cookie["path"]
)
# Set the same user agent
session.headers.update({"User-Agent": user_agent})
# Now make requests directly
response = session.get("https://example-protected-site.com/page2")
print(response.text)
This approach is significantly faster and uses far fewer resources. The cookies typically remain valid for 15-30 minutes, depending on the site's Cloudflare configuration.
Step 4: Use Sessions for Multiple Requests
If you're scraping multiple pages on the same domain, sessions prevent FlareSolverr from launching a new browser for each request.
Create a Session
import requests
flaresolverr_url = "http://localhost:8191/v1"
headers = {"Content-Type": "application/json"}
# Create a new session
create_session = {
"cmd": "sessions.create",
"session": "my-scraping-session"
}
response = requests.post(
flaresolverr_url,
headers=headers,
json=create_session
)
print(response.json())
The session parameter is your custom identifier. Use something meaningful like the domain you're scraping.
Make Requests with the Session
# Use the session for requests
payload = {
"cmd": "request.get",
"url": "https://example-protected-site.com",
"session": "my-scraping-session",
"maxTimeout": 60000
}
response = requests.post(
flaresolverr_url,
headers=headers,
json=payload
)
The browser instance persists between requests, keeping cookies and session state intact.
Destroy the Session When Done
Always clean up sessions to free resources:
destroy_session = {
"cmd": "sessions.destroy",
"session": "my-scraping-session"
}
response = requests.post(
flaresolverr_url,
headers=headers,
json=destroy_session
)
Leaving sessions open consumes memory. On machines with limited RAM, this becomes critical.
Step 5: Configure Proxies for IP Rotation
Cloudflare might still block you if too many requests come from the same IP. Combining FlareSolverr with residential or datacenter proxies solves this.
Add Proxy to Request
payload = {
"cmd": "request.get",
"url": "https://example-protected-site.com",
"maxTimeout": 60000,
"proxy": {
"url": "http://proxy-server:8080"
}
}
The proxy URL must include the protocol scheme: http://, socks4://, or socks5://.
Proxy Authentication
If your proxy requires credentials:
payload = {
"cmd": "request.get",
"url": "https://example-protected-site.com",
"maxTimeout": 60000,
"proxy": {
"url": "http://proxy-server:8080",
"username": "your_username",
"password": "your_password"
}
}
For high-volume scraping, consider services like Roundproxies.com that offer residential and mobile proxies specifically designed for web scraping. Rotating through different IP addresses prevents rate limiting and reduces the chance of detection.
Session-Level Proxy
You can also set proxies when creating a session:
create_session = {
"cmd": "sessions.create",
"session": "proxy-session",
"proxy": {
"url": "socks5://proxy-server:1080",
"username": "user",
"password": "pass"
}
}
All requests using that session will route through the specified proxy.
Step 6: Handle POST Requests
FlareSolverr supports POST requests for forms and APIs that require them.
payload = {
"cmd": "request.post",
"url": "https://example-protected-site.com/login",
"maxTimeout": 60000,
"postData": "username=test&password=secret"
}
The postData field must be URL-encoded (application/x-www-form-urlencoded). For JSON payloads, you'd need to handle that differently—typically by first getting cookies via GET, then making the POST with a regular HTTP client.
Step 7: Environment Variables and Configuration
Fine-tune FlareSolverr behavior with environment variables.
Common Configuration Options
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL |
info | Logging verbosity (debug, info, warn, error) |
HEADLESS |
true | Run browser in headless mode |
BROWSER_TIMEOUT |
60000 | Default timeout in milliseconds |
TZ |
UTC | Timezone for browser and logs |
LANG |
none | Browser language (e.g., en_US) |
PROXY_URL |
none | Default proxy for all requests |
PORT |
8191 | API listening port |
Docker Example with Custom Config
docker run -d \
--name=flaresolverr \
-p 8191:8191 \
-e LOG_LEVEL=debug \
-e HEADLESS=true \
-e TZ=America/New_York \
-e BROWSER_TIMEOUT=90000 \
--restart unless-stopped \
ghcr.io/flaresolverr/flaresolverr:latest
Setting HEADLESS=false can help with debugging—you'll see the browser window and watch it solve challenges in real time.
Troubleshooting Common FlareSolverr Issues
Even the best tools run into problems. Here's how to fix the most common ones.
Challenge Timeout
Symptom: FlareSolverr returns "Challenge not solved" after waiting.
Solution: Increase maxTimeout in your request. Some sites take longer to verify. Also check if the site requires additional interaction like CAPTCHA solving.
Memory Issues
Symptom: Container crashes or becomes unresponsive after multiple requests.
Solution: Reduce concurrent requests. Each browser instance consumes 100-200MB of RAM. Use sessions to reuse browser instances instead of creating new ones.
Version Mismatch
Symptom: FlareSolverr suddenly stops working on sites that previously worked.
Solution: Update to the latest version. Cloudflare frequently updates their challenges, and the FlareSolverr team releases patches to keep up.
docker pull ghcr.io/flaresolverr/flaresolverr:latest
docker stop flaresolverr
docker rm flaresolverr
# Run the container again with your config
CAPTCHA Detection
Symptom: FlareSolverr returns a page with a CAPTCHA instead of the actual content.
Solution: Currently, FlareSolverr cannot solve CAPTCHAs automatically. You'll need a third-party CAPTCHA solving service integrated into your workflow. The CAPTCHA_SOLVER environment variable exists but no working solvers are available at this time.
Connection Refused
Symptom: Python throws "Connection refused" when trying to reach FlareSolverr.
Solution: Verify the container is running (docker ps). Check if port 8191 is correctly mapped and not blocked by a firewall.
Building a Reusable FlareSolverr Client
Here's a production-ready Python class that handles retries, sessions, and error handling:
import requests
from time import sleep
class FlareSolverrClient:
def __init__(self, host="localhost", port=8191):
self.base_url = f"http://{host}:{port}/v1"
self.headers = {"Content-Type": "application/json"}
def solve(self, url, max_timeout=60000, retries=3):
"""Solve Cloudflare challenge and return HTML + cookies"""
payload = {
"cmd": "request.get",
"url": url,
"maxTimeout": max_timeout
}
for attempt in range(retries):
try:
response = requests.post(
self.base_url,
headers=self.headers,
json=payload,
timeout=max_timeout / 1000 + 10
)
result = response.json()
if result["status"] == "ok":
return {
"success": True,
"html": result["solution"]["response"],
"cookies": result["solution"]["cookies"],
"user_agent": result["solution"]["userAgent"]
}
print(f"Attempt {attempt + 1} failed: {result['message']}")
sleep(2)
except requests.exceptions.Timeout:
print(f"Attempt {attempt + 1} timed out")
sleep(5)
return {"success": False, "error": "Max retries exceeded"}
Use it like this:
client = FlareSolverrClient()
result = client.solve("https://protected-site.com")
if result["success"]:
print("Got the HTML!")
# Process result["html"]
When to Use FlareSolverr (And When Not To)
FlareSolverr works great for:
- Small to medium scraping projects
- Bypassing basic Cloudflare challenges
- Grabbing cookies for use with faster HTTP clients
- Testing and development environments
Consider alternatives when:
- Scraping millions of pages (browser overhead adds up)
- Dealing with advanced CAPTCHAs
- Needing real-time data with sub-second latency
- Running on memory-constrained servers
For high-volume production scraping, consider building a custom solution with Playwright or Puppeteer that gives you more control over browser behavior and resource management.
Final Thoughts
FlareSolverr removes one of the biggest headaches in web scraping—Cloudflare protection. The Docker installation takes five minutes, and the API is dead simple.
Start with the basic setup, solve your first challenge, then build up to sessions and proxy rotation as your needs grow. Remember to always respect robots.txt and terms of service when scraping.
The tool isn't magic. Cloudflare constantly updates their detection methods, and FlareSolverr might lag behind occasionally. Keep it updated, monitor your success rates, and have fallback strategies ready.
FAQ
Does FlareSolverr work with all Cloudflare-protected sites?
FlareSolverr handles most Cloudflare JavaScript challenges and browser verification checks. However, sites using Cloudflare's managed challenge or enterprise features with advanced CAPTCHAs may require additional solutions.
How much memory does FlareSolverr need?
Each browser instance consumes 100-200MB of RAM. A server with 4GB RAM can comfortably handle 5-10 concurrent requests. Use sessions to reduce memory usage by reusing browser instances.
Can I run FlareSolverr on a VPS?
Yes. Any Linux VPS with 2GB+ RAM can run FlareSolverr. Docker simplifies deployment significantly. Make sure your VPS provider allows web scraping activities.
How often should I update FlareSolverr?
Check for updates monthly or whenever you notice increased challenge failures. Cloudflare updates frequently, and the FlareSolverr team releases patches to keep up.
Is using FlareSolverr legal?
FlareSolverr itself is legal open-source software. However, bypassing security measures may violate a website's terms of service. Always review the legal implications and respect robots.txt directives before scraping.