Language

Python Screenshot API

Integrate screenshot capture into Python applications using the requests library or httpx. Ideal for data pipelines, Django/Flask web apps, automation scripts, and web scraping projects. Includes examples for synchronous and async requests, saving images to files, and handling rate limits with exponential backoff.

Quick summaryPython capture via requests or httpx. Use requests for sync cron scripts and Django views. Use httpx + asyncio for anything concurrent. Always capture inside a background job, never inline in a request handler.

Quick Start

1

Install dependencies

Run pip install requests (or pip install httpx for async support). Works with Python 3.7+.

2

Get your API key

Sign up for Screenshotly and get your API key from the dashboard.

3

Copy the code example

Use our Python code example as a starting point.

4

Customize and integrate

Modify the code to fit your specific use case and requirements.

Code Example

# Python with requests
import requests

def capture_screenshot(url: str, output_path: str) -> None:
    response = requests.post(
        'https://api.screenshotly.app/screenshot',
        headers={
            'Authorization': f'Bearer {API_KEY}',
            'Content-Type': 'application/json',
        },
        json={
            'url': url,
            'device': 'desktop',
            'format': 'png',
        }
    )
    
    with open(output_path, 'wb') as f:
        f.write(response.content)

When to Use Python with Screenshotly

Use the Python integration for data pipelines, Django/Flask web applications, automation scripts, and machine learning preprocessing. Python is ideal when you need to combine screenshots with data analysis (Pandas), image processing (Pillow/OpenCV), or feed visual data into ML models.

Python Best Practices

Use httpx instead of requests for async support — critical for Django Channels, FastAPI, and high-concurrency data pipelines.

Implement exponential backoff with the tenacity library: @retry(stop=stop_after_attempt(3), wait=wait_exponential()).

Save screenshots to BytesIO for in-memory processing with Pillow before writing to disk or uploading to S3.

For Pandas batch workflows, use concurrent.futures.ThreadPoolExecutor to parallelize captures across a DataFrame of URLs.

Python: Production Notes

Python has two legitimate paths: `requests` for sync scripts and classic Flask/Django views, and `httpx` for FastAPI and anything async. `requests` remains fine for cron and batch scripts. `httpx` is the right call anywhere concurrency matters.

For Django, never call the API inline in a `save()` method — offload to Celery or django-q. An inline capture blocks the request thread for several seconds and destroys p99 response time.

Error Handling Recipes

Concrete strategies for each failure mode. Do not silently swallow errors — surface them to your monitoring so the pipeline is observable.

HTTP 429

For Celery tasks, raise self.retry(countdown=retry_after) instead of blocking. For sync scripts, parse Retry-After and sleep.

if response.status_code == 429:
    retry_after = int(response.headers.get('Retry-After', 1))
    raise self.retry(countdown=retry_after, max_retries=3)

HTTP 5xx

Tenacity-backed retry with exponential backoff, 3 attempts max. Do not retry 4xx other than 429.

Production Hardening Checklist

The difference between dev code and prod code. Work through these before putting Python captures on a critical path.

  • Reuse httpx.AsyncClient or requests.Session across calls — never per-request instances.
  • All captures run in a Celery/RQ task or asyncio worker — never inline in a web request.
  • Tenacity handles 5xx with jittered exponential backoff.
  • Bound concurrency with asyncio.Semaphore(5) for batch work.
  • Stream response bodies for captures >5 MB.

Rate-Limit Strategy

Use aiolimiter or limits to cap requests-per-second at ~half the published rate limit, leaving headroom for retry traffic. For multi-worker deployments, coordinate via Redis.

When Python isn't the right fit

Python works well for most capture workloads, but these patterns are legitimate reasons to pick a different stack:

  • You need GIL-free parallelism beyond what asyncio provides — consider Go or Rust for heavy concurrent capture workloads.
  • Your Django app has no background job infrastructure and you are not willing to add Celery or django-q. Inline capture in views is a reliability footgun; skip this stack until the queue layer exists.
  • You need browser-automation flows like login, form submission, or element interaction. Use Playwright for Python instead.

Want a step-by-step walkthrough?

Read the full Python tutorial →

API Reference

EndpointPOST /api/screenshot
AuthenticationBearer token
Content-Typeapplication/json
View full API docs

Frequently Asked Questions

How do I handle authentication in Python requests?

Include your API key in the Authorization header as 'Bearer YOUR_API_KEY'. Use environment variables to store your key securely: os.getenv('SCREENSHOTLY_API_KEY').

Can I use Screenshotly with Django or Flask?

Yes! Create views that accept URLs and return screenshots. You can serve images directly using HttpResponse with image content-type or save to media storage for later access.

What's the best way to handle errors in Python?

Use response.raise_for_status() to raise exceptions for HTTP errors. Wrap API calls in try-except blocks to handle RequestException, Timeout, and ConnectionError appropriately.

How do I process screenshots in Python data pipelines?

Use libraries like Pandas for batch processing URLs, concurrent.futures for parallel requests, and PIL/Pillow for image processing. Consider using asyncio with aiohttp for high-performance async processing.

Start building with Python

Get your API key and start capturing screenshots in minutes.

Other Languages