Website Screenshot API
for Python
Need to capture website screenshots in Python? There are three main approaches: run a headless browser with Selenium or Playwright, or call an API like GrabShot. Here's working code for each, with the tradeoffs that matter.
1. Selenium + ChromeDriver
Selenium is the most popular browser automation library in Python. You need Chrome and ChromeDriver installed on your machine.
pip install selenium webdriver-manager
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
def screenshot(url: str, output: str = "screenshot.png"):
options = Options()
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--window-size=1440,900")
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options
)
try:
driver.get(url)
driver.save_screenshot(output)
print(f"Saved to {output}")
finally:
driver.quit()
screenshot("https://github.com")
Full-page screenshot (scrolls the entire page):
def full_page_screenshot(url: str, output: str = "full.png"):
options = Options()
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options
)
try:
driver.set_window_size(1440, 900)
driver.get(url)
# Get total page height
height = driver.execute_script(
"return Math.max(document.body.scrollHeight, "
"document.documentElement.scrollHeight)"
)
driver.set_window_size(1440, height)
driver.save_screenshot(output)
finally:
driver.quit()
Pros: Free, mature ecosystem, tons of Stack Overflow answers.
Cons: ChromeDriver version mismatches are constant pain. Uses 300-500MB RAM per instance. Slow startup (2-5 seconds). Hard to deploy on serverless.
2. Playwright for Python
Microsoft's Playwright has first-class Python support and handles browser management for you. No more ChromeDriver version hell.
pip install playwright
playwright install chromium
from playwright.sync_api import sync_playwright
def screenshot(url: str, output: str = "screenshot.png"):
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={"width": 1440, "height": 900})
page.goto(url, wait_until="networkidle")
page.screenshot(path=output)
browser.close()
screenshot("https://github.com")
# Full page? Just add full_page=True:
# page.screenshot(path="full.png", full_page=True)
Async version (for FastAPI, Django async views, etc.):
import asyncio
from playwright.async_api import async_playwright
async def screenshot(url: str, output: str = "screenshot.png"):
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page(viewport={"width": 1440, "height": 900})
await page.goto(url, wait_until="networkidle")
await page.screenshot(path=output)
await browser.close()
asyncio.run(screenshot("https://github.com"))
Pros: Better auto-waiting than Selenium, no driver mismatch issues, async support, multi-browser.
Cons: Still needs a browser installed (~400MB). Still uses significant RAM per instance. Still hard on serverless.
3. GrabShot API (No Browser Needed)
If you just need screenshots (not browser interaction), an API call is simpler than running Chrome. GrabShot handles the browser infrastructure so you don't have to.
# No special dependencies - just requests (or use urllib)
pip install requests
import requests
def screenshot(url: str, output: str = "screenshot.webp"):
response = requests.get(
"https://grabshot.dev/v1/screenshot",
params={
"url": url,
"format": "webp",
"width": "1440",
"apiKey": "YOUR_API_KEY" # Free at grabshot.dev
}
)
response.raise_for_status()
with open(output, "wb") as f:
f.write(response.content)
print(f"Saved {len(response.content)} bytes to {output}")
screenshot("https://github.com")
With device frames and AI cleanup:
def fancy_screenshot(url: str, output: str = "mockup.png"):
"""Screenshot with MacBook frame, cookie banners removed by AI"""
response = requests.get(
"https://grabshot.dev/v1/screenshot",
params={
"url": url,
"format": "png",
"width": "1440",
"deviceFrame": "macbook-air",
"aiCleanup": "true",
"apiKey": "YOUR_API_KEY"
}
)
response.raise_for_status()
with open(output, "wb") as f:
f.write(response.content)
fancy_screenshot("https://stripe.com")
Batch screenshots (async for speed):
import asyncio
import aiohttp
async def batch_screenshots(urls: list[str], api_key: str):
async with aiohttp.ClientSession() as session:
tasks = []
for url in urls:
task = session.get(
"https://grabshot.dev/v1/screenshot",
params={"url": url, "format": "webp", "apiKey": api_key}
)
tasks.append(task)
responses = await asyncio.gather(*tasks)
for i, resp in enumerate(responses):
data = await resp.read()
with open(f"screenshot_{i}.webp", "wb") as f:
f.write(data)
print(f"Saved {urls[i]}")
urls = [
"https://github.com",
"https://stripe.com",
"https://vercel.com",
]
asyncio.run(batch_screenshots(urls, "YOUR_API_KEY"))
Pros: No Chrome/browser to install. Works on any platform (AWS Lambda, Google Cloud Functions, Raspberry Pi). AI removes cookie popups. Device frame mockups built in. 25 free screenshots/month.
Cons: Paid plans start at $9/mo for 2,500 screenshots. Can't interact with the page (click, scroll, type).
Comparison
| Feature | Selenium | Playwright | GrabShot API |
|---|---|---|---|
| pip install + first screenshot | 5-10 min | 3-5 min | 30 seconds |
| Needs Chrome/browser | Yes | Yes | No |
| RAM per screenshot | 300-500MB | 200-400MB | ~1MB (HTTP call) |
| Serverless (Lambda, Cloud Functions) | Painful | Painful | Easy |
| Full-page screenshots | Manual resize | Built-in | Built-in |
| Device frame mockups | No | No | Yes |
| Cookie popup removal | Manual scripting | Manual scripting | AI-powered |
| Page interaction | Full | Full | No |
See it in action
Try GrabShot right now — paste any URL and get a screenshot instantly. No signup needed.
Try Free Screenshot Tool →