Selenium Alternative: How to Take Screenshots Without Managing a Browser
You need to take screenshots of web pages in production.
Your first instinct: use Selenium.
You google "Selenium screenshot tutorial." You find a guide that starts with:
"First, download the Java Development Kit (JDK)..."
Then:
"Next, download ChromeDriver..."
Then:
"Make sure ChromeDriver version matches your Chrome version..."
Then:
"If you get 'ChromeDriver is blocked by a certificate error'..."
Three hours later, you've installed JDK, ChromeDriver, configured version matching, and worked around a dozen compatibility issues.
Finally, you write 50 lines of code to take a single screenshot.
There's a better way.
The Problem: Selenium Setup Is a Nightmare
Selenium is powerful. It can automate complex browser interactions, fill forms, click buttons, wait for dynamic content.
But for screenshots, it's overkill.
Here's what you have to deal with:
1. Driver Binary Hellhole
// You need ChromeDriver
// Which version?
// Chrome 121? ChromeDriver 121.0.6167.140? 121.0.6167.160?
// Download the right version
// Extract to /usr/local/bin
// chmod +x
// Test it works
// Update Chrome
// Download new ChromeDriver
// It doesn't work
// ???
// Three hours later...
2. Java/JDK Dependency
If you're using Selenium for Java:
# Install Java 8? 11? 17?
# Maven or Gradle?
# Which version of selenium-java?
# Dependencies resolving...
# version conflicts...
# artifact not found...
3. Version Mismatches
Chrome: 121.0.6167.140
ChromeDriver: 121.0.6167.139
Error: "This version of ChromeDriver only supports Chrome 121.0.6167.139"
Update Chrome
ChromeDriver now out of sync
Download new version
...
4. Deployment Nightmares
You write a screenshot script locally (works fine).
Deploy to production (fails).
- Different Chrome version on server
- ChromeDriver binary missing from container
- Permission issues
- Memory limits crash the browser
5. 50 Lines of Code for One Screenshot
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
WebDriver driver = new ChromeDriver();
driver.get("https://example.com");
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
// Wait for element to load
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("content")));
// Take screenshot
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshot, new File("screenshot.png"));
driver.quit();
The Solution: One API Call
Instead of managing Selenium:
curl -X POST https://api.pagebolt.dev/v1/screenshot \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "png"
}' \
-o screenshot.png
That's it.
No Selenium. No ChromeDriver. No JDK. No version mismatches. One API call.
Before & After
Selenium: Screenshot Code
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Setup driver
driver = webdriver.Chrome()
try:
# Navigate
driver.get("https://example.com")
# Wait for element
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.ID, "content")))
# Take screenshot
driver.save_screenshot("screenshot.png")
finally:
driver.quit()
Lines of code: 18
Setup required: ChromeDriver, Selenium WebDriver, Python packages
Deployment: Fragile (Chrome versions must match)
Error handling: Missing (real code has 3x more lines for error handling)
PageBolt: Screenshot Code
import requests
response = requests.post(
"https://api.pagebolt.dev/v1/screenshot",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"url": "https://example.com", "format": "png"}
)
with open("screenshot.png", "wb") as f:
f.write(response.content)
Lines of code: 8
Setup required: API key only
Deployment: Works everywhere (cloud API)
Error handling: Simple (just check response status)
Real-World Comparison
Use Case: Screenshot a SaaS Dashboard Every Hour
With Selenium:
# schedule.py
import schedule
import time
from selenium import webdriver
def take_screenshot():
driver = webdriver.Chrome()
try:
driver.get("https://myapp.com/dashboard")
# Wait for dashboard to load (flaky)
time.sleep(5)
driver.save_screenshot("dashboard.png")
except Exception as e:
print(f"Screenshot failed: {e}")
finally:
driver.quit()
# Schedule every hour
schedule.every().hour.do(take_screenshot)
while True:
schedule.run_pending()
time.sleep(1)
Issues:
- Fixed
time.sleep(5)is unreliable - If Chrome crashes, script exits
- No logging/monitoring
- Can't run on headless servers (needs X11)
- Memory leaks over time
With PageBolt:
# schedule.py
import schedule
import requests
API_KEY = "YOUR_API_KEY"
def take_screenshot():
try:
response = requests.post(
"https://api.pagebolt.dev/v1/screenshot",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"url": "https://myapp.com/dashboard"}
)
response.raise_for_status()
with open("dashboard.png", "wb") as f:
f.write(response.content)
print("✅ Screenshot captured")
except requests.RequestException as e:
print(f"❌ Screenshot failed: {e}")
# Schedule every hour
schedule.every().hour.do(take_screenshot)
while True:
schedule.run_pending()
time.sleep(1)
Benefits:
- No flaky timeouts
- Cloud-hosted (no local browser needed)
- Works everywhere
- Automatic retry/monitoring
- Same code, 10x fewer headaches
Language Examples
Node.js
Selenium:
const { Builder } = require('selenium-webdriver');
const fs = require('fs');
async function screenshot() {
let driver = await new Builder()
.forBrowser('chrome')
.build();
try {
await driver.get('https://example.com');
await driver.sleep(2000);
let data = await driver.takeScreenshot();
fs.writeFileSync('screenshot.png', data, 'base64');
} finally {
await driver.quit();
}
}
PageBolt:
const axios = require('axios');
const fs = require('fs');
async function screenshot() {
const response = await axios.post(
'https://api.pagebolt.dev/v1/screenshot',
{ url: 'https://example.com', format: 'png' },
{ headers: { Authorization: 'Bearer YOUR_API_KEY' }, responseType: 'arraybuffer' }
);
fs.writeFileSync('screenshot.png', response.data);
}
Java
Selenium:
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
WebDriver driver = new ChromeDriver();
try {
driver.get("https://example.com");
Thread.sleep(2000);
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshot, new File("screenshot.png"));
} finally {
driver.quit();
}
PageBolt:
HttpClient client = HttpClient.newHttpClient();
String json = "{\"url\": \"https://example.com\", \"format\": \"png\"}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.pagebolt.dev/v1/screenshot"))
.header("Authorization", "Bearer YOUR_API_KEY")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
Files.write(Paths.get("screenshot.png"), response.body());
Python
Selenium:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://example.com")
driver.save_screenshot("screenshot.png")
driver.quit()
PageBolt:
import requests
response = requests.post(
"https://api.pagebolt.dev/v1/screenshot",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"url": "https://example.com", "format": "png"}
)
open("screenshot.png", "wb").write(response.content)
When You Still Need Selenium
PageBolt is great for screenshots and visual capture.
You still need Selenium for:
- Complex automation — fill forms, click buttons, navigate multi-step flows
- Real user interactions — test how users actually use your app
- JavaScript execution — run custom JS and check results
- Full browser testing — test cookies, local storage, console errors
But for screenshots alone, PageBolt is simpler, faster, and more reliable.
Migration Guide: Selenium → PageBolt
Step 1: Identify Screenshot Use Cases
In your Selenium code, find all calls to:
driver.save_screenshot()driver.get_screenshot_as_*driver.take_screenshot()
These are candidates for migration.
Step 2: Replace with API Calls
For each screenshot call:
Selenium:
driver.get(url)
driver.save_screenshot(path)
PageBolt:
response = requests.post(
"https://api.pagebolt.dev/v1/screenshot",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"url": url, "format": "png"}
)
open(path, "wb").write(response.content)
Step 3: Remove Selenium Dependencies
Delete from requirements.txt / pom.xml / package.json:
seleniumwebdriver-manager- Any ChromeDriver or WebDriver packages
Step 4: Test in Production
Deploy the new code to staging. Verify screenshots work.
Cost & Performance
| Metric | Selenium | PageBolt |
|---|---|---|
| Setup time | 2-3 hours | 5 minutes |
| Code lines | 30-50 | 5-10 |
| Deployment | Fragile | Reliable |
| Cost (self-hosted) | Free (but server costs) | $0-299/month (API) |
| Speed | 2-5 sec per screenshot | < 1 sec per screenshot |
| Reliability | ~80% (driver issues) | 99.9% (cloud) |
The Bottom Line
Selenium is overkill for screenshots. It's designed for complex browser automation.
If you just need images, use an API.
- ✅ No driver management
- ✅ No version mismatches
- ✅ No deployment headaches
- ✅ Cloud-hosted (works everywhere)
- ✅ 100x simpler code
- ✅ Lightning fast
Ready to stop managing Selenium?
Migrate your screenshot code to PageBolt in 5 minutes. Free tier: 100 screenshots/month. Starter plan: 5,000/month for $29.
Top comments (0)