Screenshot API for Django: Complete Integration Guide

Published April 2026 • 11 min read • Python, Django, Integration

Django is one of the most widely deployed Python web frameworks, powering SaaS platforms, analytics dashboards, content management systems, and API backends across every industry. If your Django application needs screenshot, scraping, or PDF generation capabilities, SnapAPI provides a clean REST API that integrates with any Django project in minutes. This guide covers everything from a basic requests integration to a production-ready service class with Celery task offloading, Redis caching, and webhook support.

Basic Integration with requests

The simplest SnapAPI integration in Django uses the requests library:

import requests

SNAPAPI_KEY = "your_api_key_here"  # or use settings.SNAPAPI_KEY

def capture_screenshot(url, full_page=False, format="png"):
    response = requests.post(
        "https://snapapi.pics/api/screenshot",
        headers={"X-API-Key": SNAPAPI_KEY},
        json={"url": url, "full_page": full_page, "format": format},
        timeout=30
    )
    response.raise_for_status()
    return response.json()["url"]

Django Settings Configuration

Store credentials in settings.py using environment variables:

# settings.py
import os

SNAPAPI_KEY = os.environ.get("SNAPAPI_KEY", "")

# Usage in views:
from django.conf import settings
import requests

def my_view(request):
    screenshot_url = capture_screenshot(
        settings.SNAPAPI_KEY, "https://example.com"
    )

Service Class Pattern

For clean architecture, wrap SnapAPI in a reusable service class:

# services/snapapi.py
import requests
from django.conf import settings
from django.core.cache import cache
import hashlib

class SnapApiService:
    BASE_URL = "https://snapapi.pics"

    def __init__(self):
        self.api_key = settings.SNAPAPI_KEY

    def _headers(self):
        return {"X-API-Key": self.api_key, "Content-Type": "application/json"}

    def screenshot(self, url, **kwargs):
        cache_key = "snap:" + hashlib.md5(url.encode()).hexdigest()
        cached = cache.get(cache_key)
        if cached:
            return cached

        resp = requests.post(
            self.BASE_URL + "/api/screenshot",
            headers=self._headers(),
            json={"url": url, "full_page": kwargs.get("full_page", False),
                  "format": kwargs.get("format", "png")},
            timeout=30
        )
        resp.raise_for_status()
        result = resp.json()["url"]
        cache.set(cache_key, result, 900)  # 15-minute cache
        return result

    def extract(self, url, fields):
        resp = requests.post(
            self.BASE_URL + "/api/extract",
            headers=self._headers(),
            json={"url": url, "fields": fields},
            timeout=30
        )
        resp.raise_for_status()
        return resp.json().get("data", {})

    def pdf(self, url):
        resp = requests.post(
            self.BASE_URL + "/api/screenshot",
            headers=self._headers(),
            json={"url": url, "format": "pdf", "full_page": True},
            timeout=60
        )
        resp.raise_for_status()
        return resp.json()["url"]

Celery Background Tasks

For async screenshot processing, offload to Celery:

# tasks.py
from celery import shared_task
from .services.snapapi import SnapApiService
from .models import ScreenshotRecord

@shared_task(bind=True, max_retries=3)
def capture_screenshot_async(self, record_id, url):
    try:
        service = SnapApiService()
        screenshot_url = service.screenshot(url, full_page=True)
        ScreenshotRecord.objects.filter(pk=record_id).update(
            screenshot_url=screenshot_url,
            status="complete"
        )
    except Exception as exc:
        raise self.retry(exc=exc, countdown=10)

# In your view:
def request_screenshot(request):
    record = ScreenshotRecord.objects.create(url=url, status="pending")
    capture_screenshot_async.delay(record.id, url)
    return JsonResponse({"record_id": record.id})

PDF Export View

from django.http import StreamingHttpResponse
import requests

def export_report_pdf(request, report_id):
    report_url = request.build_absolute_uri(f"/reports/{report_id}/")
    service = SnapApiService()
    pdf_url = service.pdf(report_url)

    pdf_response = requests.get(pdf_url, stream=True)
    response = StreamingHttpResponse(
        pdf_response.iter_content(chunk_size=8192),
        content_type="application/pdf"
    )
    response["Content-Disposition"] = f"attachment; filename=report-{report_id}.pdf"
    return response

Testing with unittest.mock

from unittest.mock import patch, MagicMock
from django.test import TestCase

class SnapApiServiceTest(TestCase):
    @patch("myapp.services.snapapi.requests.post")
    def test_screenshot_returns_url(self, mock_post):
        mock_resp = MagicMock()
        mock_resp.json.return_value = {
            "url": "https://cdn.snapapi.pics/test.png",
            "captured_at": "2026-04-04T10:00:00Z"
        }
        mock_post.return_value = mock_resp

        service = SnapApiService()
        url = service.screenshot("https://example.com")
        self.assertEqual(url, "https://cdn.snapapi.pics/test.png")
        mock_post.assert_called_once()

Getting Started

Create your free account at snapapi.pics/dashboard. The free plan gives you 200 monthly screenshots to build and validate your Django integration. For production use, the Starter plan ($19/month) provides 5,000 captures, and the Growth plan ($79/month) scales to 50,000 with full extract and scrape endpoint access. The Python SDK is available via pip: pip install snapapi-python.

Django-Specific Patterns and Production Considerations

Django applications going to production with SnapAPI integration benefit from several framework-specific patterns that improve reliability, testability, and operational observability. These patterns build on the service class foundation established earlier in this guide and add the production hardening that high-traffic Django applications require.

Django signals provide a clean integration point for triggering screenshot captures at domain event boundaries without coupling your domain models to the SnapAPI service directly. Define a post_save signal on your content models that dispatches a Celery task when a new item is published. The Celery task calls SnapAPI, stores the screenshot URL on the model instance, and updates a screenshot_generated_at timestamp field. This event-driven pattern keeps your model save methods clean and makes the screenshot generation behavior easy to test in isolation by patching the signal handler.

Django REST Framework applications exposing screenshot functionality to frontend clients benefit from a dedicated ViewSet that wraps the SnapAPI service. The ViewSet accepts a URL parameter, validates it against your allowed origins list to prevent SSRF abuse, checks the per-user screenshot quota, calls the service class, and returns the screenshot URL in a standardized response envelope. Rate limiting the ViewSet with DRF throttle classes prevents individual API consumers from exhausting your SnapAPI monthly quota.

Observability is straightforward to add using Django signals and your existing metrics infrastructure. Emit a custom metric event after each SnapAPI call recording the response time, status code, and screenshot URL size. This data feeds your dashboard monitoring for SnapAPI usage patterns, allowing you to spot unusual consumption spikes, track quota burn rate relative to billing period boundaries, and identify individual users or workflows consuming disproportionate capture volume.

Database storage of screenshot metadata deserves careful schema design. Store the screenshot URL, capture timestamp, source URL, requesting user ID, response time in milliseconds, and a status field on a dedicated ScreenshotCapture model. Index on user ID and created_at for efficient per-user usage queries. A monthly aggregation view gives you the per-user capture counts needed for quota enforcement and usage-based billing calculations.

The SnapAPI Python SDK is available via pip at pip install snapapi-python and provides typed method signatures for all endpoints. Django applications using the SDK can configure credentials through the standard settings module and benefit from built-in retry logic and response validation. Free tier: 200 captures/month. Starter: $19/month for 5,000. Growth: $79/month for 50,000. Sign up at snapapi.pics/dashboard.

Integration Checklist for Production Deployments

When moving a SnapAPI integration from development to production, a few configuration steps ensure reliable operation at scale. Store your API key in environment variables, never in version control. Implement request timeout handling — set a 30-second timeout on screenshot requests and 60 seconds for full-page PDF renders. Add retry logic with exponential backoff for transient network failures. Cache successful screenshot responses for at least 15 minutes to avoid redundant API calls for the same URL. Monitor your monthly capture count against your plan limit and set up an alert at 80% consumption to avoid unexpected limit hits. Log all API calls with response times and status codes to your application monitoring system. These six steps cover the majority of production reliability concerns for screenshot API integrations at any scale. Visit snapapi.pics/docs for the complete API reference and SDK documentation.

Getting Started with SnapAPI

SnapAPI is the fastest way to add screenshot, scraping, and PDF generation to any web application. The REST API accepts a URL and optional configuration parameters, renders the page in a real Chromium browser, and returns either a hosted image URL or raw binary output. Every API response includes a capture timestamp, the rendered page URL, and optional DOM extraction data if you use the extract endpoint. Authentication uses a per-account API key passed in the X-API-Key request header. Response times average under three seconds for standard viewport screenshots and under eight seconds for full-page captures of complex JavaScript-heavy pages. The free plan requires no credit card and provides 200 monthly captures, making it easy to prototype and validate an integration before committing to a paid plan. Paid plans start at nineteen dollars per month for five thousand captures on the Starter tier, scaling to seventy-nine dollars per month for fifty thousand captures on the Growth tier, with custom enterprise agreements available for platforms requiring higher volumes or dedicated SLA commitments. Every paid plan includes access to all three endpoint types: screenshot for image and PDF captures, scrape for raw page content retrieval, and extract for structured DOM data extraction. The scrape endpoint returns the fully-rendered HTML source after all JavaScript has executed, making it ideal for downstream parsing pipelines that need accurate HTML rather than visual captures. The extract endpoint accepts a list of CSS selectors or natural-language field descriptions and returns matched content as key-value JSON, eliminating the need to write custom parsing logic for each new data source. Visit snapapi.pics to create your account and access the full API documentation and SDK repositories for JavaScript, Python, PHP, Ruby, Go, Swift, and Kotlin.

Django and SnapAPI: Frequently Asked Questions

Can SnapAPI capture authenticated Django admin pages? Yes. Pass your Django session cookie in the headers parameter of the screenshot request. The easiest way to get a valid session cookie is to log into your admin interface in a browser, copy the sessionid cookie value from developer tools, and pass it as Cookie: sessionid=your_value in the headers dictionary of your API request. This allows SnapAPI to render authenticated views that would otherwise redirect to the login page. Is SnapAPI suitable for generating PDF reports from Django templates? Absolutely. Render your report template to a public or authenticated URL, pass that URL to the screenshot endpoint with format set to pdf, and SnapAPI returns a fully-rendered PDF using Chromium print rendering. The output matches what a user would get printing the page from Chrome. How does SnapAPI handle Django pages that load data via AJAX after page load? The API waits for network activity to settle before capturing, which means dynamically loaded chart data, table rows fetched from API endpoints, and lazy-loaded images all render correctly in the screenshot output. You can additionally specify an explicit delay parameter to wait an extra number of milliseconds after network idle if your page has animations or deferred rendering steps that fire after network requests complete. What is the rate limit? The Starter plan supports 5,000 monthly captures with no per-minute hard limit under normal usage patterns. High-burst workloads spiking above 50 requests per second should implement client-side rate limiting to stay within fair-use guidelines. Contact SnapAPI support for dedicated rate limit tiers on enterprise plans.