Back to Blog
Comparison February 24, 2026 · 3 min read

Selenium Alternative for Screenshots and PDF Generation: Skip the WebDriver

Selenium is the standard for browser automation testing. But if what you actually need is a screenshot or a PDF — not assertions, not element interactions — Selenium is a lot of machinery for a simple output.

The setup alone: install selenium, download a WebDriver binary, match the browser version, configure the driver, handle platform differences between local and CI. Then manage the browser lifecycle in code.

Here's what the same job looks like without any of that.

Screenshot: Selenium vs API

Selenium (Python):

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')

driver = webdriver.Chrome(options=options)
driver.set_window_size(1280, 800)
driver.get('https://example.com')
driver.save_screenshot('screenshot.png')
driver.quit()

Requires: selenium, chromedriver, matching Chrome version, webdriver-manager in CI.

API (Python):

import requests

res = requests.post(
    'https://api.pagebolt.dev/v1/screenshot',
    headers={'x-api-key': 'YOUR_API_KEY'},
    json={'url': 'https://example.com', 'fullPage': True, 'blockBanners': True}
)
with open('screenshot.png', 'wb') as f:
    f.write(res.content)

Requires: requests. That's it.

PDF generation

Selenium has no native PDF export for arbitrary pages. The common workaround is Chrome DevTools Protocol (execute_cdp_cmd) — which works, but adds complexity and is Chrome-specific.

import base64
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('--headless=new')
driver = webdriver.Chrome(options=options)
driver.get('https://example.com')
pdf = driver.execute_cdp_cmd('Page.printToPDF', {'printBackground': True})
with open('page.pdf', 'wb') as f:
    f.write(base64.b64decode(pdf['data']))
driver.quit()

With an API:

res = requests.post(
    'https://api.pagebolt.dev/v1/pdf',
    headers={'x-api-key': 'YOUR_API_KEY'},
    json={'url': 'https://example.com', 'format': 'A4', 'printBackground': True}
)
with open('page.pdf', 'wb') as f:
    f.write(res.content)

Same result. No ChromeDriver, no CDP, no base64 decode.

When to keep Selenium

Selenium is the right choice when you need:

  • Cross-browser testing (Chrome + Firefox + Safari)
  • Complex element interactions with assertions (assert element.text == 'Expected')
  • Page object models and test frameworks (pytest-selenium, etc.)
  • Fine-grained control over browser state between test steps

If your code ends with driver.save_screenshot() or a CDP PDF call and no assertions, that's the sign you're using Selenium as a file generator, not a test runner.

Batch screenshots in parallel

import asyncio, aiohttp

async def screenshot(session, url, filename):
    async with session.post(
        'https://api.pagebolt.dev/v1/screenshot',
        headers={'x-api-key': 'YOUR_API_KEY'},
        json={'url': url, 'fullPage': True, 'blockBanners': True}
    ) as resp:
        with open(filename, 'wb') as f:
            f.write(await resp.read())

async def main():
    urls = [('https://site-a.com', 'a.png'), ('https://site-b.com', 'b.png')]
    async with aiohttp.ClientSession() as session:
        await asyncio.gather(*[screenshot(session, u, f) for u, f in urls])

asyncio.run(main())

Selenium with parallel sessions requires multiple driver instances, which multiplies memory usage. With an API, you fire concurrent requests and the browser infrastructure scales on the other end.

Get Started Free

100 requests/month, no credit card

Screenshots, PDFs, and batch parallel captures via API — no WebDriver, no browser binary, no lifecycle management.

Get Your Free API Key →