How to Automate Screenshots with cURL
You don't need Node.js, Python, or any programming language to automate website screenshots. A screenshot API and cURL give you everything you need from the command line.
This is useful for:
- Capturing screenshots in shell scripts or cron jobs
- Integrating screenshots into CI/CD pipelines
- Quick one-off captures without writing code
- Batch processing a list of URLs from a file
Getting Started
You need two things: cURL (installed by default on macOS and most Linux distributions) and a screenshot API key.
Sign up for SnapRender to get a free API key. The free tier includes 500 screenshots per month, no credit card required.
Set your API key as an environment variable so you don't have to repeat it:
export SNAPRENDER_KEY="sk_live_your_key_here"
Basic Screenshot
Capture a website and save it as a PNG:
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o screenshot.png
The API returns the raw image binary. The -o flag saves it to a file. -s suppresses the progress bar.
Choosing Output Format
The API supports PNG, JPEG, WebP, and PDF:
# JPEG (smaller file size)
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&format=jpeg&quality=85" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o screenshot.jpg
# WebP (best compression)
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&format=webp&quality=80" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o screenshot.webp
# PDF
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&format=pdf" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o page.pdf
Full-Page Capture
Capture the entire scrollable page, not just the visible viewport:
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&fullPage=true" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o fullpage.png
Custom Viewport Size
Set the browser window dimensions:
# Desktop HD
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&width=1920&height=1080" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o desktop.png
# Narrow mobile width
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&width=375&height=812" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o mobile.png
Device Emulation
Capture screenshots as they would appear on specific devices:
# iPhone 15 Pro
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&device=iphone_15_pro" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o iphone.png
# iPad Pro
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&device=ipad_pro" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o ipad.png
# Pixel 7
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&device=pixel_7" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o pixel.png
Device presets set the correct viewport size, device scale factor, and user agent string automatically.
Dark Mode
Capture pages with dark color scheme:
curl -s "https://app.snap-render.com/v1/screenshot?url=https://developer.mozilla.org&darkMode=true" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o dark.png
Clean Screenshots (No Ads, No Cookie Banners)
Ad blocking and cookie banner removal are enabled by default. You can control them explicitly:
curl -s "https://app.snap-render.com/v1/screenshot?url=https://www.bbc.com&blockAds=true&blockCookieBanners=true" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o clean.png
Hide Specific Elements
Remove elements by CSS selector before capturing:
# Hide the navigation bar
curl -s "https://app.snap-render.com/v1/screenshot?url=https://en.wikipedia.org/wiki/Screenshot&hideSelectors=%23mw-navigation" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o no-nav.png
URL-encode the selectors. %23 is #, %2C is , for separating multiple selectors.
Batch Screenshots from a File
For large-scale batch jobs (up to 50 URLs in one call with automatic rate limit handling), see the Batch API optimization guide. The examples below use simple cURL loops, which work well for smaller lists.
Create a text file with one URL per line:
https://example.com
https://github.com
https://stripe.com
https://developer.mozilla.org
Then loop through it:
while IFS= read -r url; do
# Create filename from URL (strip protocol, replace / with -)
filename=$(echo "$url" | sed 's|https\?://||; s|/|-|g; s|-$||').png
echo "Capturing $url -> $filename"
curl -s "https://app.snap-render.com/v1/screenshot?url=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$url', safe=''))")&format=png" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o "$filename"
done < urls.txt
Parallel Batch Captures
Speed up batch processing by running captures in parallel with xargs:
cat urls.txt | xargs -P 5 -I {} bash -c '
url="{}"
filename=$(echo "$url" | sed "s|https\?://||; s|/|-|g; s|-$||").png
curl -s "https://app.snap-render.com/v1/screenshot?url=$url&format=png" \
-H "X-API-Key: '"$SNAPRENDER_KEY"'" \
-o "$filename"
echo "Done: $filename"
'
-P 5 runs 5 captures simultaneously. Adjust based on your plan's burst rate limit.
Scheduled Screenshots with Cron
Capture a website every hour and save timestamped files:
# Edit crontab
crontab -e
Add this line:
0 * * * * curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&format=png" -H "X-API-Key: sk_live_your_key" -o /home/user/screenshots/example-$(date +\%Y\%m\%d-\%H\%M).png
This captures example.com at the top of every hour and saves files like example-20260307-1400.png.
A More Robust Cron Script
For production use, create a script that handles errors:
#!/bin/bash
# screenshot-cron.sh
API_KEY="sk_live_your_key"
URL="https://example.com"
OUTPUT_DIR="/home/user/screenshots"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
mkdir -p "$OUTPUT_DIR"
HTTP_CODE=$(curl -s -w "%{http_code}" \
"https://app.snap-render.com/v1/screenshot?url=$URL&format=png" \
-H "X-API-Key: $API_KEY" \
-o "$OUTPUT_DIR/capture-$TIMESTAMP.png")
if [ "$HTTP_CODE" -ne 200 ]; then
echo "$(date): Failed to capture $URL (HTTP $HTTP_CODE)" >> "$OUTPUT_DIR/errors.log"
rm -f "$OUTPUT_DIR/capture-$TIMESTAMP.png"
fi
CI/CD Integration
GitHub Actions
Add screenshot captures to your CI pipeline:
- name: Capture screenshots
env:
SNAPRENDER_KEY: ${{ secrets.SNAPRENDER_KEY }}
run: |
curl -s "https://app.snap-render.com/v1/screenshot?url=https://staging.example.com&format=png&fullPage=true" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o screenshot.png
- name: Upload screenshot artifact
uses: actions/upload-artifact@v4
with:
name: screenshots
path: screenshot.png
Visual Diff in CI
Capture before and after screenshots to review visual changes:
#!/bin/bash
# visual-diff.sh - Run in CI after deploying to staging
PAGES=("/" "/pricing" "/docs" "/blog")
BASE_URL="https://staging.example.com"
for path in "${PAGES[@]}"; do
safe_name=$(echo "$path" | sed 's|/|-|g; s|^-||; s|-$||')
[ -z "$safe_name" ] && safe_name="home"
curl -s "https://app.snap-render.com/v1/screenshot?url=${BASE_URL}${path}&format=png&fullPage=true" \
-H "X-API-Key: $SNAPRENDER_KEY" \
-o "screenshots/${safe_name}.png"
echo "Captured: ${path} -> ${safe_name}.png"
done
Getting JSON Instead of Binary
If you need metadata along with the image (dimensions, file size, cache status), request a JSON response:
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&format=png&response_type=json" \
-H "X-API-Key: $SNAPRENDER_KEY" | python3 -m json.tool
This returns:
{
"url": "https://example.com",
"format": "png",
"width": 1280,
"height": 800,
"image": "data:image/png;base64,iVBOR...",
"size": 45231,
"cache": false,
"responseTime": 2134,
"remainingCredits": 487
}
The image is base64-encoded in the image field. Extract and decode it:
curl -s "https://app.snap-render.com/v1/screenshot?url=https://example.com&response_type=json" \
-H "X-API-Key: $SNAPRENDER_KEY" \
| python3 -c "import sys,json,base64; d=json.load(sys.stdin); open('out.png','wb').write(base64.b64decode(d['image'].split(',')[1]))"
Check Your Usage
Monitor how many screenshots you have left this month:
curl -s "https://app.snap-render.com/v1/screenshot/info?action=usage" \
-H "X-API-Key: $SNAPRENDER_KEY" | python3 -m json.tool
Error Handling in Scripts
The API returns JSON error responses with HTTP status codes. Check them in your scripts:
response=$(curl -s -w "\n%{http_code}" \
"https://app.snap-render.com/v1/screenshot?url=https://example.com" \
-H "X-API-Key: $SNAPRENDER_KEY")
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | sed '$d')
if [ "$http_code" -eq 200 ]; then
echo "$body" > screenshot.png
echo "Success"
elif [ "$http_code" -eq 429 ]; then
echo "Rate limited or quota exceeded"
elif [ "$http_code" -eq 401 ]; then
echo "Invalid API key"
else
echo "Error $http_code: $body"
fi
Common Parameters Reference
| Parameter | Values | Default | Description |
|---|---|---|---|
url |
Any URL | required | Target website |
format |
png, jpeg, webp, pdf |
png |
Output format |
width |
320-3840 | 1280 | Viewport width (px) |
height |
200-10000 | 800 | Viewport height (px) |
fullPage |
true/false |
false |
Capture full scrollable page |
quality |
1-100 | 90 | JPEG/WebP quality |
darkMode |
true/false |
false |
Dark color scheme |
device |
iphone_14, iphone_15_pro, pixel_7, ipad_pro, macbook_pro |
none | Device preset |
blockAds |
true/false |
true |
Block ads |
blockCookieBanners |
true/false |
true |
Remove cookie banners |
hideSelectors |
CSS selectors | none | Elements to hide |
delay |
0-10000 | 0 | Wait ms after page load |
cache |
true/false |
false |
Use cached result |
response_type |
json |
binary | Response format |
Summary
cURL and a screenshot API give you automated website captures without writing application code. This works for one-off captures, batch processing, cron jobs, and CI/CD pipelines.
Get a free API key (500 screenshots/month, no credit card) and start capturing in under a minute.