How to Take Website Screenshots with Crawl4AI
Capture and save website screenshots with Crawl4AI: configure rendering, decode the PNG, handle dynamic and long pages, and fix common errors.
To take a website screenshot with Crawl4AI, set screenshot=True in a CrawlerRunConfig, call AsyncWebCrawler.arun(), base64-decode result.screenshot, and write the bytes to a file. The returned screenshot is an optional base64-encoded PNG string, not a path or ready-to-write image byte sequence.
Minimal runnable example
Install Crawl4AI in your Python environment using its official installation instructions, then save this as capture.py and run it. The current documented workflow puts per-run settings in CrawlerRunConfig.
import asyncio
import base64
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
async def main():
config = CrawlerRunConfig(screenshot=True)
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(
"https://example.com",
config=config,
)
if not result.success:
raise RuntimeError(f"Crawl failed: {result.error_message}")
if not result.screenshot:
raise RuntimeError("Crawl succeeded but no screenshot was returned")
image_bytes = base64.b64decode(result.screenshot)
with open("page.png", "wb") as image_file:
image_file.write(image_bytes)
asyncio.run(main())
This example captures the page using Crawl4AI’s default screenshot scope. For the exact behavior and available options in your installed version, check the Crawl4AI documentation.
What the code does
CrawlerRunConfig(screenshot=True)requests screenshot capture for this crawl.crawler.arun(url, config=config)opens and processes the page asynchronously.result.successindicates whether the crawl succeeded;result.error_messageprovides error context.result.screenshotholds the optional base64-encoded PNG.base64.b64decode()converts the encoded string into image bytes. Open the output file in binary mode (wb) so those bytes are preserved.
Do not save the base64 text directly with a .png extension. It will not be a valid PNG file.
Choose viewport or full-page capture
A viewport screenshot contains the currently visible browser area. A full-page screenshot aims to include the document beyond the initial viewport. Use force_viewport_screenshot=True when you specifically need only the viewport. The parameter reference also lists screenshot_height_threshold for handling unusually tall pages and scroll_delay for delays between scrolling steps when scanning or capturing long pages.
config = CrawlerRunConfig(
screenshot=True,
force_viewport_screenshot=True,
)
For a page that reveals images or content as you scroll, allow time between scrolling steps with scroll_delay. Set a suitable height threshold for very tall documents. These controls address capture scope and page behavior; no fixed delay guarantees that every page has finished rendering. See the Crawl4AI configuration reference for the parameter details supported by your version.
Wait for dynamic content
Pages that render client-side or load content asynchronously may need a readiness condition before capture. Crawl4AI documents wait_for for a CSS selector or JavaScript expression, and screenshot_wait_for for adding a delay before taking the screenshot.
config = CrawlerRunConfig(
screenshot=True,
wait_for="css:main",
screenshot_wait_for=2.0,
)
Choose a selector that appears when the part of the page you need is ready. The delay is an additional wait, not a substitute for a meaningful readiness condition. Adjust the values to the target page; avoid assuming that one fixed wait works for every site.
Save the screenshot safely
For scripts that process many URLs, validate the result and handle decoding or file errors explicitly. A small helper keeps the checks in one place:
import base64
from pathlib import Path
def save_screenshot(result, output_path: str) -> None:
if not result.success:
raise RuntimeError(f"Crawl failed: {result.error_message}")
if not result.screenshot:
raise RuntimeError("No screenshot was returned")
try:
image_bytes = base64.b64decode(result.screenshot, validate=True)
except (ValueError, TypeError) as exc:
raise RuntimeError("Screenshot data was not valid base64") from exc
Path(output_path).write_bytes(image_bytes)
Use unique output names when capturing multiple URLs; otherwise each run can overwrite the previous image. If you build names from URLs, sanitize them and avoid using an untrusted URL as a filesystem path.
Long pages and other output formats
Very tall or complex pages can make full-page screenshots slow or error-prone. Crawl4AI’s advanced guide suggests PDF export as a more reliable option for very long pages. PDF bytes are returned separately as result.pdf. The guide also describes requesting both PDF and screenshot, which converts the first PDF page into an image.
MHTML capture is available for preserving a page together with its resources for archival or offline viewing. MHTML is not a screenshot image. Use it when you need a saved web-page package rather than a visual PNG.
Consult the Crawl4AI advanced features guide for the documented PDF and MHTML behavior and configuration for your version.
Configuration choices at a glance
| Need | Relevant setting or result | Notes |
|---|---|---|
| Capture an image | screenshot=True |
Set in CrawlerRunConfig; read the optional base64 PNG from result.screenshot. |
| Capture only what is visible | force_viewport_screenshot=True |
Use when viewport-only output is intended. |
| Wait for page content | wait_for |
Can use a CSS selector or JavaScript expression. |
| Add time before screenshot | screenshot_wait_for |
A delay can help with asynchronous rendering, but is not a universal readiness guarantee. |
| Handle tall pages | screenshot_height_threshold, scroll_delay |
Relevant to tall-page handling and delays between scrolling steps; tune for the page. |
| Export a long page | pdf=True, inspect result.pdf |
The advanced guide recommends considering PDF for very long or complex pages. |
| Archive page with resources | capture_mhtml=True |
MHTML is for preservation and offline viewing, not a screenshot image. |
Screenshot-related settings belong in CrawlerRunConfig in the current documented workflow. Older direct arguments to arun() remain accepted for backward compatibility, but the documentation advises moving run-specific settings into the config object.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
result.screenshot is empty or None |
The crawl failed, screenshot capture was not enabled, or no screenshot was returned. | Check result.success and result.error_message; confirm screenshot=True is in the config and handle the optional value. |
| The saved file is not a valid image | The base64 text was written as text, or the returned value was not decoded. | Decode with base64.b64decode() and write bytes using binary mode. |
| The screenshot is blank or missing expected content | The page may not have rendered the target content before capture. | Wait for a meaningful selector or JavaScript condition with wait_for; if needed, add screenshot_wait_for. |
| Content near the bottom is absent | The capture was limited to the viewport, or content only loads during scrolling. | Do not force viewport-only capture if you need the full page; consider scroll_delay and the height threshold for tall pages. |
| Full-page capture is slow or fails on a very long document | The page may be too tall or complex for reliable full-page image capture. | Try PDF output and inspect result.pdf, as recommended in the advanced guide for long or complex pages. |
| Config options appear ignored or deprecated | Settings may be passed through older direct arun() arguments or may differ by installed version. |
Put run-specific options in CrawlerRunConfig and compare against the documentation for the version in use. |
Performance, reliability, and cost considerations
- Wait only for what you need. A selector tied to the desired content can avoid arbitrary long delays. Use additional screenshot delay only when the page behavior calls for it.
- Full-page work grows with page size. Tall pages and scroll-triggered loading take more capture work; PDF can be a better fit for very long documents.
- Check each result. Treat both crawl success and screenshot presence as separate conditions, and surface the returned error message in logs.
- Plan storage and naming. Screenshot files consume space, and repeated output paths overwrite earlier captures. Use deliberate retention and unique names in batch jobs.
- Cost depends on your setup. This Crawl4AI workflow is software you run in your own environment; the research materials provide no pricing or resource benchmark. Account for the compute and storage used by your deployment rather than assuming a universal per-shot cost.
Or skip the browser setup
If you want a single request instead of managing browser capture, ScreenshotNeo is a website screenshot API and MCP server for developers. It returns a PNG, JPEG, WebP, or PDF from one GET request. See the API documentation for options and response details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', new Uint8Array(await res.arrayBuffer()));
- Cookie banners are accepted and removed before the shot; newsletter popups and chat widgets are removed too. Each cleanup step can be turned off.
- Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed; response headers identify the page verdict and billing status.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdffor Claude, Cursor, and other MCP clients. - The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan.
Sign up free for 1,000 screenshots a month, with no card required.
FAQ
Is result.screenshot already a PNG file?
No. It is an optional base64-encoded PNG string. Decode it to bytes before writing the image file.
Can I use Crawl4AI for a viewport-only screenshot?
Yes. The parameter reference documents force_viewport_screenshot=True for viewport-only capture.
Should I use MHTML instead of a screenshot?
Use MHTML when you need the page and its resources preserved for offline viewing. It is not an image format for screenshot output.
What if I need a very long page as a visual record?
Consider PDF output for very long or complex pages. If you need an image, the advanced guide describes requesting both PDF and screenshot to convert the first PDF page into an image.


