🚀 We are hiring! See open positions

How to Screenshot Cloudflare-Protected Websites

How to Screenshot Cloudflare-Protected Websites

You want to grab a screenshot of your competitor's pricing page to track their changes, but Cloudflare keeps blocking you. Every screenshot tool you try either times out, returns a blank image, or worse - captures the challenge page instead of the actual content.

If standard screenshot tools like Puppeteer or Selenium are failing on Cloudflare-protected sites, you're dealing with sophisticated anti-bot detection. In this guide, we'll show you exactly how to capture screenshots from these protected pages using three different approaches, from fully automated APIs to DIY browser solutions.

Key Takeaways

Master screenshotting Cloudflare-protected websites with automated bypass tools, stealth browser configurations, and proper troubleshooting techniques.

  • Use Screenshot API with built-in Cloudflare bypass for 99.99% success rate on protected sites
  • Configure Puppeteer and Playwright with stealth plugins to avoid headless browser detection
  • Implement Selenium with undetected ChromeDriver for legacy automation workflows
  • Handle common screenshot errors: timeouts, blank captures, and challenge page interception
  • Configure viewport, resolution, and geo-targeting for accurate screenshot captures
  • Use wait conditions and rendering delays to capture dynamic content correctly

Why Cloudflare Blocks Screenshot Attempts

When you try to screenshot a Cloudflare-protected website, you're not just loading a page - you're triggering multiple detection systems designed to identify and block automated tools.

How Detection Works

Cloudflare uses several methods to detect and block screenshot automation:

Headless Browser Detection: Your browser leaves fingerprints. Cloudflare checks for properties like navigator.webdriver (which is true in Selenium by default) and looks for Chrome DevTools Protocol signatures. These are dead giveaways that you're using automation.

TLS Fingerprinting: Before you even load the page, Cloudflare analyzes how your browser performs the TLS handshake. Automated tools create different JA3/JA4 signatures than real browsers, making them easy to spot. Learn more about TLS fingerprinting detection.

JavaScript Challenges: Cloudflare's Turnstile challenge and waiting rooms actively test your browser. They look for things like WebGL capabilities, canvas fingerprinting, and how quickly you solve computational challenges. Most screenshot tools fail these tests. See our guide on JavaScript challenge bypass.

IP Reputation: Cloudflare tracks where requests come from. If you're using datacenter proxies or IPs associated with cloud providers, they'll often block you outright. They maintain lists of known datacenter IP ranges and treat them differently than residential IPs. Read more about IP blocking avoidance.

Browser Integrity Checks: These are subtle tests checking for inconsistencies. Does your User-Agent match your actual browser capabilities? Are timezone and language settings consistent? Do you have the expected fonts and APIs? Any mismatch can trigger blocking.

What Happens When Blocked

When Cloudflare blocks your screenshot attempt, you'll run into specific problems:

Black or blank screenshots: You captured the challenge page before it resolved. The solution is to wait for the challenge to complete using wait_for_selector to ensure the actual content loads.

Timeout errors: The page never finishes loading. This happens when Cloudflare completely blocks the request or when you're using the wrong IP country. Increase your timeout and consider using residential proxies - Cloudflare actively detects and blocks datacenter proxy pools.

Captcha in your screenshot: Your tool hit Cloudflare's Turnstile captcha. You need a solution with built-in captcha solving capabilities that can handle these challenges automatically.

Wrong page captured: The page redirected but your tool didn't follow it. Use wait_for network idle events and ensure redirect following is enabled.

Low quality or wrong viewport: You didn't set explicit dimensions. Always specify viewport size and device scale factor for consistent results.

Let's look at what a failed attempt looks like:

# import selenium and undetected chromedriver
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import os

# Initialize Chrome driver
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))

# Attempt to navigate to a protected page without any stealth configuration
driver.get("https://www.redfin.com/")

# Create a directory for the screenshots
os.makedirs("posts/how-to-screenshot-cloudflare-protected-websites", exist_ok=True)
path = os.path.join("posts/how-to-screenshot-cloudflare-protected-websites", "failed.png")

# This will likely capture the Cloudflare challenge page
driver.save_screenshot(path)
driver.quit()

This basic code will capture Cloudflare's challenge page, not the actual content:

Failed Selenium screenshot showing Cloudflare challenge
Failed Selenium screenshot showing Cloudflare challenge

Now that we understand why screenshots fail, let's look at solutions that actually work.

Method 1: Using Scrapfly Screenshot API

The Screenshot API handles Cloudflare protection automatically. No need to manage browser drivers, configure stealth plugins, or rotate proxies - it's built to bypass anti-bot systems out of the box.

How It Works

Scrapfly Screenshot API uses real browser rendering with automatic challenge solving. It maintains a 99.99% success rate across protected sites and processes over 1PB of data monthly. The API handles detection avoidance at every level, from TLS fingerprinting to JavaScript challenge solving.

Screenshot API Key Capabilities

Bypass Anti-Bot Measures

The API automatically solves JavaScript challenges and optimizes requests to look like real browser traffic. The asp=True parameter enables Anti-Scraping Protection mode, which is essential for Cloudflare bypass. It includes built-in stealth mode that removes all headless browser fingerprints.

Automatic Proxy Rotation

Access over 130M+ proxies across 120+ countries. Use the country parameter for geo-targeting and get residential proxies automatically to avoid datacenter detection - Cloudflare flags datacenter IPs aggressively.

Capture Clean Screenshots

Remove visual clutter automatically with options=block_banners. This blocks ads, cookie pop-ups, and page distractions so you capture clean content without consent dialogs covering your screenshot.

Target Full Page or Specific Areas

Use capture parameter to grab the full page, just the viewport, or target specific elements with CSS selectors or XPath. Perfect when you only need a pricing table or product grid instead of the entire page.

Change Viewport Resolution

Set custom resolutions like desktop 1920x1080, mobile 375x812, or tablet 1024x768 using the resolution parameter. This ensures accurate responsive design captures across different device types.

Control Screenshot Flow

Use wait_for_selector to ensure content loads before capturing. Set rendering_wait for time-based delays in milliseconds. Enable auto_scroll to force lazy-loaded content to appear by scrolling the entire page.

Server-Side Caching

Enable caching with cache=True to store screenshots and reuse them. Set cache_ttl to control how long cached versions are valid. This reduces redundant requests and cuts costs for frequently captured pages.

Export Multiple Formats

Choose between JPG, PNG, WebP, or GIF using the format parameter. Control quality and compression to balance file size with image clarity.

Python Example

Here's a complete example capturing a Cloudflare-protected page:

import requests

key = 'YOUR_SCRAPFLY_KEY'
params = {
    'url': 'https://www.redfin.com/',
    'key': key,
    'country': 'US',  # Use US residential proxy
    'wait_for_selector': 'body',  # Wait for main content to load
    'rendering_wait': 2000,  # Wait extra 2 seconds for dynamic content
    'resolution': '1920x1080',  # Set explicit viewport size
    'options': 'block_banners',  # Block ads and cookie consent banners
    'capture': 'viewport',  # Capture visible area only
    'format': 'png'
}

# Call the Screenshot API
response = requests.get('https://api.scrapfly.io/screenshot', params=params)

# Save the successful screenshot
with open('screenshot.png', 'wb') as f:
    f.write(response.content)

print("Screenshot captured successfully")
Screenshot using requests and Screenshot API
Screenshot using requests and Screenshot API

This captures the actual page content, not the Cloudflare challenge. The API handles:

  • Solving JavaScript challenges automatically
  • Using residential proxies to avoid IP blocks
  • Removing the webdriver property and other detection signals
  • Managing cookies and sessions properly
  • Following redirects and waiting for content to load

The Screenshot API is the fastest path to reliable screenshots of protected sites. Try it free at Scrapfly Screenshot API.

Method 2: Puppeteer/Playwright with Stealth Plugins

If you need to run your own headless browser, Puppeteer and Playwright can work with stealth plugins. This approach gives you control but requires maintenance and doesn't work on all protected sites.

Setup and Configuration

For Puppeteer, install the stealth plugin:

npm install puppeteer puppeteer-extra puppeteer-extra-plugin-stealth

For Playwright, use playwright-stealth:

npm install playwright playwright-stealth

Puppeteer Example with Stealth

const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');

// Enable stealth plugin
puppeteer.use(StealthPlugin());

(async () => {
  const browser = await puppeteer.launch({
    headless: 'new',
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-blink-features=AutomationControlled' // Remove automation flags
    ]
  });

  const page = await browser.newPage();

  // Set realistic viewport to look like a real screen
  await page.setViewport({ width: 1920, height: 1080 });

  // Set a standard user agent
  await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');

  try {
    // Navigate to protected site
    await page.goto('https://nowsecure.nl/', {
      waitUntil: 'networkidle2', // Wait for network to settle
      timeout: 30000
    });

    // Wait for the body to ensure content loaded
    await page.waitForSelector('body', { timeout: 15000 });

    // Take the screenshot
    await page.screenshot({
      path: 'screenshot.png',
      fullPage: true
    });

    console.log('Screenshot captured successfully');
  } catch (error) {
    console.error('Failed:', error.message);
  } finally {
    await browser.close();
  }
})();

Playwright Example with Stealth

const { chromium } = require('playwright');
const { addExtra } = require('playwright-extra');
const stealth = require('playwright-extra-plugin-stealth')();

const browser = addExtra(chromium);
// Apply stealth to browser context
browser.use(stealth);

(async () => {
  const browserInstance = await browser.launch({
    headless: true
  });

  // Create context with specific viewport and user agent
  const context = await browserInstance.newContext({
    viewport: { width: 1920, height: 1080 },
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
  });

  const page = await context.newPage();

  // Navigate and wait for network idle to ensure redirects complete
  await page.goto('https://nowsecure.nl/', {
    waitUntil: 'networkidle'
  });

  // Additional wait for potential challenges
  await page.waitForTimeout(3000);

  // Capture full page screenshot
  await page.screenshot({
    path: 'screenshot.png',
    fullPage: true
  });

  await browserInstance.close();
})();

Limitations

This approach has several challenges:

High resource consumption: Running full browsers uses significant CPU and memory. You'll need powerful servers for parallel captures.

Maintenance burden: Cloudflare constantly updates detection. Stealth plugins need regular updates to stay effective.

Inconsistent results: Works on sites with basic Cloudflare protection but fails on advanced Turnstile challenges.

Proxy management: You need to handle proxy rotation yourself to avoid IP blocks.

When this method fails on tougher protection, the Screenshot API handles the complexity for you - it's built specifically to bypass modern anti-bot systems.

For more details on these tools, see:

Method 3: Selenium with Undetected ChromeDriver

If you're already using Selenium, undetected-chromedriver can help bypass basic detection. It's less sophisticated than stealth plugins but works for teams committed to the Selenium ecosystem. For details on how it works, see our Undetected ChromeDriver guide.

When to Use Selenium

Use this approach if:

  • Your team already has Selenium infrastructure
  • You're automating other tasks beyond screenshots
  • You're dealing with older or simpler Cloudflare implementations

Setup

Install undetected-chromedriver:

pip install undetected-chromedriver

Code Example

import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import os

# Configure options for stealth
options = uc.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_argument('--window-size=1920,1080')

# Initialize undetected chromedriver
# use_subprocess=True is often safer for avoiding detection
driver = uc.Chrome(options=options, use_subprocess=True)

try:
    # Navigate to protected page
    driver.get('https://nowsecure.nl/')

    # Wait for page to load and challenge to resolve
    wait = WebDriverWait(driver, 20)
    wait.until(EC.presence_of_element_located((By.TAG_NAME, 'body')))

    # Additional wait for JavaScript execution/challenge completion
    time.sleep(5)

    # Take screenshot after challenge is passed
    driver.save_screenshot('screenshot.png')

    print('Screenshot saved successfully')

except Exception as e:
    print(f'Error: {e}')

finally:
    driver.quit()

Using SeleniumBase UC Mode

SeleniumBase offers a UC (undetected) mode that's easier to configure:
from seleniumbase import Driver

# Initialize with UC (undetected) mode enabled
driver = Driver(uc=True)

driver.get('https://nowsecure.nl/')
driver.sleep(3)  # Wait for challenge resolution
driver.save_screenshot('screenshot.png')
driver.quit()

Selenium with undetected-chromedriver works for basic scenarios but struggles with advanced protection. For production use with high success rates, consider using specialized tools.

Learn more: Taking Screenshots with Selenium

Troubleshooting Common Errors

Even with the right tools, you might encounter issues. Here's how to fix the most common screenshot problems with Cloudflare-protected sites.

Black or Blank Screenshots

Problem: Your screenshot is completely black or blank.

Cause: You captured the Cloudflare challenge page before it finished loading.

Solution:

# Wait for specific element indicating page is loaded
params = {
    'url': 'https://example.com',
    'key': key,
    # ASP handles the anti-bot bypass
    'asp': 'true',
    # Ensure the content you need is loaded before capturing
    'wait_for_selector': '#content',
    'rendering_wait': 3000
}
result = requests.get('https://api.scrapfly.io/screenshot', params=params)

Don't rely on page load events alone - wait for actual content to appear.

Timeout Errors

Problem: Screenshot request times out completely.

Cause: Either the page genuinely takes too long to load, or Cloudflare is blocking your IP.

Solution:

# Increase timeout and use residential proxy
params = {
    'url': 'https://example.com',
    'key': key,
    'country': 'US',  # Use residential proxy from specific country
    'asp': 'true',
    'timeout': 120000  # Increase to 120 seconds if using a client that supports it
}
result = requests.get('https://api.scrapfly.io/screenshot', params=params)

Important: Timeout errors often occur when using datacenter IPs. Cloudflare actively detects and blocks datacenter proxy pools. Switch to residential proxies to solve this.

Captcha in Screenshot

Problem: Your screenshot shows a Turnstile captcha challenge.

Cause: Cloudflare's captcha wasn't solved automatically.

Solution: Use an API with built-in captcha solving. The Screenshot API handles Turnstile challenges automatically:

# ASP automatically solves captchas
params = {
    'url': 'https://example.com',
    'key': key,
    'asp': 'true',  # Enables automatic captcha solving
    # Give the solver enough time
    'rendering_wait': 5000 
}
result = requests.get('https://api.scrapfly.io/screenshot', params=params)

Manual tools like Puppeteer or Selenium require external captcha solving services. Learn more about captcha bypass methods.

Wrong Page Captured

Problem: You got a redirect page or intermediate state instead of final content.

Cause: Screenshot was taken before redirects completed.

Solution:

# Wait for network to settle
params = {
    'url': 'https://example.com',
    'key': key,
    'asp': 'true',
    # Wait for the body or a specific element to be present
    'wait_for_selector': 'body',
    'rendering_wait': 3000  # Let redirects complete
}
result = requests.get('https://api.scrapfly.io/screenshot', params=params)

Always wait for networkidle events when dealing with redirects.

Low Quality or Wrong Viewport

Problem: Screenshot has wrong dimensions or looks pixelated.

Cause: Viewport wasn't explicitly set.

Solution:

# Set explicit viewport and quality
params = {
    'url': 'https://example.com',
    'key': key,
    'asp': 'true',
    'resolution': '1920x1080',  # Explicit dimensions
    'format': 'png'  # Use PNG for better quality
}
result = requests.get('https://api.scrapfly.io/screenshot', params=params)

Always specify resolution for consistent results across captures.

Advanced Use Cases

Once you've mastered basic screenshot capture, you can handle more complex scenarios. Here are practical applications with code examples.

For comprehensive coverage of all screenshot techniques in Python, see our Python Screenshots Guide.

Full-Page Screenshots

Capture entire scrollable pages, not just the viewport:

import requests

key = 'YOUR_SCRAPFLY_KEY'
params = {
    'url': 'https://www.redfin.com/',
    'key': key,
    'capture': 'fullpage',  # Enable full page capture
    'auto_scroll': 'true',  # Scroll to bottom to trigger lazy loading
    'resolution': '1920x1080',
    'format': 'png'
}

response = requests.get('https://api.scrapfly.io/screenshot', params=params)

with open('fullpage.png', 'wb') as f:
    f.write(response.content)
Full page screenshot including scrollable content
Full page screenshot including scrollable content

The auto_scroll parameter scrolls to the bottom before capturing, which loads images and content that only appear when scrolled into view.

Element-Specific Screenshots

import requests

key = 'YOUR_SCRAPFLY_KEY'
params = {
    'url': 'https://scrapfly.io/pricing',
    'key': key,
    'capture': '.pricing-card-box',  # Capture specific CSS selector
    'wait_for_selector': '.pricing-card-box',  # Ensure it exists before capturing
    'options': 'block_banners',  # Remove clutter
    'format': 'png'
}

response = requests.get('https://api.scrapfly.io/screenshot', params=params)

with open('pricing-table.png', 'wb') as f:
    f.write(response.content)
Element specific screenshot of pricing table
Element specific screenshot of pricing table

Mobile Device Screenshots

Capture mobile versions of Cloudflare-protected sites:

Use common device resolutions:

  • iPhone: 375x812
  • Android: 360x800
  • iPad: 768x1024
  • Desktop: 1920x1080

Geo-Targeted Screenshots

See how content appears from different countries. This is crucial since many sites show different content based on location.

import requests
import base64

key = 'YOUR_SCRAPFLY_KEY'

# UK Version configuration
params_uk = {
    'url': 'https://www.netflix.com/',
    'key': key,
    'country': 'GB',  # Great Britain proxy
    'resolution': '1920x1080'
}
response_uk = requests.get('https://api.scrapfly.io/screenshot', params=params_uk)
with open('uk-version.png', 'wb') as f:
    f.write(response_uk.content)
UK version of Netflix
UK version of Netflix

For sites that check browser locale and currency:

# FR Version with JS to simulate browser language
# JS parameter must be base64 encoded as per API spec
js_code = 'window.navigator.language = "fr-FR"'
js_b64 = base64.b64encode(js_code.encode()).decode()

params_fr = {
    'url': 'https://www.netflix.com/',
    'key': key,
    'country': 'FR',  # France proxy
    'js': js_b64  # Execute JS to set language
}
response_fr = requests.get('https://api.scrapfly.io/screenshot', params=params_fr)
with open('fr-version.png', 'wb') as f:
    f.write(response_fr.content)
French version of Netflix
French version of Netflix

Learn more about proper geo-targeting configuration:

For automated screenshot-to-PDF workflows, see our dedicated Screenshot to PDF Guide.

This creates timestamped screenshots you can compare to detect pricing changes or layout updates. For scraping pricing data directly, see our guide on competitor price tracking.

Best Practices for Production

When running screenshot automation in production, follow these practices to ensure reliability and efficiency.

  • Rate Limiting and Respectful Crawling: Don't hammer protected sites with rapid-fire requests. Use built-in rate limiting when available. Most APIs offer throttling configuration to stay within acceptable limits.
  • Caching Screenshots: Avoid redundant captures of unchanged pages. This reduces costs and load on target servers. Adjust TTL based on how frequently content changes.
  • Error Handling and Retry Logic: Always implement proper error handling. Use exponential backoff for retries to handle temporary failures gracefully.
  • Storing and Organizing Screenshots: Keep your captures organized. This makes it easy to track changes over time and locate specific captures.
  • Visual Comparison Tools: Use image comparison to detect changes. This helps automate detection of pricing changes, layout updates, or content modifications.

FAQs

How to take a screenshot from a protected website?

Use a screenshot API with built-in bypass capabilities like Scrapfly Screenshot API. It handles Cloudflare challenges automatically with asp=True and uses residential proxies to avoid IP blocks. For DIY solutions, try Puppeteer with stealth plugins or Selenium with undetected-chromedriver, but these require more configuration and have lower success rates.

How to capture a restricted screenshot?

Screenshots are "restricted" when sites use anti-bot protection. The key is bypassing detection: use tools that avoid headless browser fingerprints, solve JavaScript challenges automatically, and rotate residential IPs. The Screenshot API handles all of this, or configure stealth plugins if you're running your own browsers. See our Cloudflare bypass guide for detection avoidance techniques.

Can a website prevent screenshots?

Only in specific scenarios. Apps and DRM-protected content (like Netflix or Disney+ video players) can show black frames due to DRM protection. Regular web pages can't truly prevent screenshots, but they can make automated screenshot capture harder through anti-bot measures like Cloudflare. They detect headless browsers, block datacenter IPs, and use JavaScript challenges - but these can be bypassed with the right tools.

How to access a website blocked by Cloudflare?

Use residential proxies from the target country, ensure your browser has proper fingerprints (no webdriver property), solve JavaScript challenges, and maintain consistent cookies/sessions. For screenshots specifically, use an API that handles this automatically. For web scraping, see our detailed guides:

Why can't I screenshot some sites?

Three common reasons: (1) JavaScript challenges like Cloudflare Turnstile that your tool can't solve, (2) Anti-bot detection identifying your headless browser through fingerprints like navigator.webdriver, (3) IP blocking when you're using datacenter proxies that Cloudflare flags. For video streaming sites specifically, DRM protection prevents capturing video frames. Regular web content can be captured with proper bypass techniques.

Summary

Screenshotting Cloudflare-protected websites doesn't have to be complicated. While these sites use sophisticated detection to block automation, the right tools make bypass straightforward.

We covered three approaches:

Screenshot API handles everything automatically, Cloudflare challenges, IP rotation, browser fingerprinting. Use this for production with 99.99% success rates and no maintenance.

Puppeteer/Playwright with stealth plugins works for DIY solutions on sites with basic protection. Requires ongoing maintenance as detection evolves.

Selenium with undetected-chromedriver helps teams already invested in Selenium infrastructure. Less sophisticated than stealth plugins but easier to integrate into existing workflows.

For reliable screenshot capture without the complexity of managing browsers, proxies, and detection bypass, try the Screenshot API free today. It's built specifically to handle protected sites with automatic Cloudflare bypass and residential proxy rotation.

Explore this Article with AI

Related Knowledgebase

Related Articles