DEV Community

Vhub Systems
Vhub Systems

Posted on

curl_cffi Stopped Working for Scraping? Here's What to Try Next

curl_cffi Stopped Working for Scraping? Here's What to Try Next

You had a working scraper using curl_cffi to impersonate Chrome. It bypassed Cloudflare and everything was great — until one day it started returning 403s or challenge pages again. This is frustrating, but common. Here's exactly what to check and what to try next.

Why curl_cffi Stops Working

curl_cffi works by replicating the TLS fingerprint and HTTP/2 frame ordering of real browsers. When sites update their bot detection, they add new fingerprint checks that the current curl_cffi version may not match. The fix is usually one of these:

  1. Your curl_cffi version is outdated — the fingerprint it sends no longer matches current Chrome
  2. The site added JA3/JA4 checking — they now check deeper TLS parameters
  3. Behavioral signals are missing — the site needs cookies/session state beyond just the fingerprint
  4. The specific impersonation profile changed — e.g., chrome120 doesn't match Chrome's current TLS
  5. IP reputation — your IP got flagged regardless of fingerprint

Step 1: Update curl_cffi and Change the Profile

pip install -U curl-cffi
Enter fullscreen mode Exit fullscreen mode

Then try different impersonation profiles:

from curl_cffi import requests

# Try each of these:
for profile in ["chrome124", "chrome123", "chrome120", "chrome110", "edge101", "safari17_0"]:
    try:
        session = requests.Session()
        r = session.get("https://target-site.com/", impersonate=profile, timeout=10)
        print(f"{profile}: {r.status_code}")
        if r.status_code == 200:
            print(f"{profile} works!")
            break
    except Exception as e:
        print(f"{profile}: Error - {e}")
Enter fullscreen mode Exit fullscreen mode

Run this test against the actual target URL. Often just upgrading and switching from chrome120 to chrome124 fixes it.

Step 2: Check What curl_cffi Profiles Are Available

from curl_cffi.requests import BrowserType
print(dir(BrowserType))
# ['CHROME', 'CHROME100', 'CHROME101', ...]

# Or just:
import curl_cffi
print(curl_cffi.__version__)
Enter fullscreen mode Exit fullscreen mode

Use the newest Chrome profile available in your installed version.

Step 3: Add Proper Headers

curl_cffi handles the TLS layer, but you still need realistic headers:

from curl_cffi import requests

session = requests.Session()
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Cache-Control": "max-age=0",
    "Sec-Ch-Ua": '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
    "Sec-Ch-Ua-Mobile": "?0",
    "Sec-Ch-Ua-Platform": '"macOS"',
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
})

r = session.get("https://target-site.com/", impersonate="chrome124")
Enter fullscreen mode Exit fullscreen mode

The Sec-Ch-Ua header must match the Chrome version in your User-Agent string.

Step 4: Build a Session (Don't Skip the Homepage)

Many detections fail because scrapers jump directly to the target URL without visiting the homepage first. Real users always have cookies from the root domain.

from curl_cffi import requests
import time

session = requests.Session()

# Step 1: Visit homepage to pick up cookies
r1 = session.get("https://target-site.com/", impersonate="chrome124")
time.sleep(2)  # Human-like pause

# Step 2: Maybe visit a category page
r2 = session.get("https://target-site.com/products/", impersonate="chrome124",
                  headers={"Referer": "https://target-site.com/"})
time.sleep(1.5)

# Step 3: Now fetch the target
r3 = session.get("https://target-site.com/products/specific-item",
                  impersonate="chrome124",
                  headers={"Referer": "https://target-site.com/products/"})
print(r3.status_code)
Enter fullscreen mode Exit fullscreen mode

The key: reuse the same session object across all requests. It preserves cookies automatically.

Step 5: Try camoufox or nodriver Instead

If curl_cffi still fails after updating, the site may be doing JavaScript-based detection that requires a real browser engine.

camoufox (Firefox-based, hardened)

pip install camoufox
python -m camoufox fetch  # downloads Firefox
Enter fullscreen mode Exit fullscreen mode
from camoufox.sync_api import Camoufox

with Camoufox(headless=True) as browser:
    page = browser.new_page()
    page.goto("https://target-site.com/")
    content = page.content()
    print(content[:500])
Enter fullscreen mode Exit fullscreen mode

camoufox patches Firefox at the C++ level to remove automation fingerprints. It's harder to detect than Playwright or Selenium.

nodriver (undetected Chrome)

pip install nodriver
Enter fullscreen mode Exit fullscreen mode
import nodriver as uc
import asyncio

async def main():
    browser = await uc.start()
    page = await browser.get("https://target-site.com/")
    content = await page.get_content()
    print(content[:500])
    await browser.stop()

asyncio.run(main())
Enter fullscreen mode Exit fullscreen mode

Step 6: Debug What's Actually Detecting You

Before switching tools, understand what's failing. Check the response for clues:

from curl_cffi import requests

session = requests.Session()
r = session.get("https://target-site.com/", impersonate="chrome124")

print(f"Status: {r.status_code}")
print(f"URL (after redirects): {r.url}")
print(f"Response size: {len(r.content)} bytes")

# Check for bot detection markers
content = r.text
if "cf-chl-bypass" in content or "cf_clearance" in content:
    print("→ Cloudflare challenge page")
elif "Blocked" in content[:500]:
    print("→ IP block or WAF")
elif "captcha" in content.lower():
    print("→ CAPTCHA required")
elif r.status_code == 403:
    print("→ Forbidden - likely fingerprint or IP")
elif r.status_code == 200:
    print("→ Passed! Check if content is correct")

# Print Cloudflare headers if present
cf_headers = {k: v for k, v in r.headers.items() if k.lower().startswith('cf-')}
print("CF headers:", cf_headers)
Enter fullscreen mode Exit fullscreen mode

Decision Tree When curl_cffi Fails

Status 403 with "network policy" message?
  → IP blocked, not fingerprint. Switch proxy first.

Status 200 but getting challenge HTML?
  → Fingerprint issue. Update curl_cffi + try chrome124

Status 200 but content looks wrong?
  → Getting bot response. Need session warm-up + cookies.

Status 200, content correct on first request but fails after N requests?
  → Rate limiting. Add delays + proxy rotation.

Still failing after all of the above?
  → Site is doing JS behavioral analysis. Switch to camoufox or nodriver.
Enter fullscreen mode Exit fullscreen mode

Quick Reference: curl_cffi vs Alternatives

Situation Best Tool
TLS fingerprint only curl_cffi (fastest, lowest overhead)
TLS + behavioral signals camoufox (Firefox-based, stealthy)
Need Chrome APIs (canvas, WebGL) nodriver or playwright-stealth
High volume + many sites curl_cffi with proxy rotation
Interactive pages (login, forms) nodriver or camoufox

Summary

When curl_cffi stops working:

  1. pip install -U curl-cffi — update first
  2. Try chrome124 or chrome123 instead of chrome120
  3. Add Sec-Ch-Ua headers that match the Chrome version
  4. Visit the homepage first to build cookie session
  5. If still failing: check whether it's IP-based (switch proxy) or JS-based (switch to camoufox)

The most common fix is just updating and switching to a newer Chrome profile. TLS fingerprints change with each Chrome release, and curl_cffi releases matching profiles — but you need to keep it current.


Related Articles

If you found this helpful, these cover complementary topics:


Take the next step

Skip the setup. Production-ready tools for curl_cffi alternatives:

Apify Scrapers Bundle — $29 one-time

Instant download. Documented. Ready to deploy.

Top comments (0)