Screenshot API with Python and Django: A Complete Guide
Django powers some of the most complex web applications in the world. When you need to add screenshot, PDF generation, or page capture capabilities to a Django project, SnapAPI provides a clean REST API that integrates in minutes. This guide walks through every integration pattern from simple view helpers to async Celery tasks.
Installation and Setup
SnapAPI does not require a dedicated Python SDK, though one is available. For Django projects, the simplest integration uses the requests library which is almost certainly already in your requirements.txt. Install it if needed:
pip install requests
Add your SnapAPI key to your Django settings or environment:
SNAPAPI_KEY = os.environ.get("SNAPAPI_KEY", "")
Basic Screenshot Helper
Create a utility module at myapp/snapapi.py to centralize API calls:
import requests
from django.conf import settings
SNAPAPI_BASE = "https://snapapi.pics/api"
def screenshot(url, **kwargs):
params = {"access_key": settings.SNAPAPI_KEY, "url": url}
params.update(kwargs)
r = requests.get(SNAPAPI_BASE + "/screenshot", params=params, timeout=30)
r.raise_for_status()
return r.content # raw PNG bytes
def screenshot_url(url, **kwargs):
params = {"access_key": settings.SNAPAPI_KEY, "url": url, "response_type": "json"}
params.update(kwargs)
r = requests.get(SNAPAPI_BASE + "/screenshot", params=params, timeout=30)
r.raise_for_status()
return r.json()["url"]
Using Screenshots in Django Views
The helper makes it straightforward to add screenshot functionality to any view. Here is a view that accepts a URL parameter, captures a screenshot, and returns the image directly:
from django.http import HttpResponse, JsonResponse
from .snapapi import screenshot, screenshot_url
def capture_view(request):
url = request.GET.get("url")
if not url:
return JsonResponse({"error": "url parameter required"}, status=400)
try:
img_bytes = screenshot(url, width=1280, height=800, full_page=True)
return HttpResponse(img_bytes, content_type="image/png")
except Exception as e:
return JsonResponse({"error": str(e)}, status=500)
Async Screenshot Tasks with Celery
For production Django applications, screenshot generation should never block the request/response cycle. Screenshots can take 2 to 10 seconds depending on page complexity. Use Celery to offload captures to background workers:
from celery import shared_task
from .snapapi import screenshot_url
from .models import PageCapture
@shared_task(bind=True, max_retries=3)
def capture_page_task(self, page_capture_id):
capture = PageCapture.objects.get(id=page_capture_id)
try:
img_url = screenshot_url(capture.url, width=1280, full_page=True)
capture.screenshot_url = img_url
capture.status = "done"
capture.save()
except Exception as exc:
capture.status = "failed"
capture.save()
raise self.retry(exc=exc, countdown=10)
Dispatch the task from your view and return immediately:
def request_capture(request):
url = request.POST.get("url")
capture = PageCapture.objects.create(url=url, status="pending")
capture_page_task.delay(capture.id)
return JsonResponse({"id": capture.id, "status": "pending"})
Django Model for Screenshot Storage
Define a model to track screenshot jobs and their results:
from django.db import models
class PageCapture(models.Model):
STATUS = [("pending","Pending"),("done","Done"),("failed","Failed")]
url = models.URLField()
screenshot_url = models.URLField(blank=True)
status = models.CharField(max_length=10, choices=STATUS, default="pending")
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.url
PDF Generation in Django
SnapAPI can render any URL as a PDF, which is useful for generating invoices, reports, and print-ready documents from your Django templates. Render a Django view as PDF:
def invoice_pdf(request, invoice_id):
invoice = Invoice.objects.get(id=invoice_id, user=request.user)
invoice_url = request.build_absolute_uri(
reverse("invoice-render", args=[invoice_id])
)
params = {
"access_key": settings.SNAPAPI_KEY,
"url": invoice_url,
"format": "pdf",
"pdf_page_size": "A4",
}
r = requests.get("https://snapapi.pics/api/screenshot", params=params)
return HttpResponse(r.content,
content_type="application/pdf",
headers={"Content-Disposition": "attachment; filename=invoice.pdf"})
Scraping with Django and SnapAPI
Beyond screenshots, SnapAPI provides a scrape endpoint that returns clean HTML after full JavaScript rendering. This is ideal for building data pipelines in Django that consume JS-rendered content without managing a browser pool yourself:
def scrape(url, **kwargs):
params = {"access_key": settings.SNAPAPI_KEY, "url": url, "wait_until": "networkidle"}
params.update(kwargs)
r = requests.get("https://snapapi.pics/api/scrape", params=params, timeout=60)
r.raise_for_status()
return r.text # rendered HTML
Rate Limiting and Error Handling
Production Django apps should handle SnapAPI rate limits and transient errors gracefully. Wrap API calls with exponential backoff using the tenacity library:
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3), wait=wait_exponential(min=1, max=10))
def screenshot_with_retry(url, **kwargs):
return screenshot_url(url, **kwargs)
Caching Screenshots in Django
Screenshots of the same URL rarely change in short time windows. Use Django's cache framework to avoid redundant API calls for frequently requested pages:
from django.core.cache import cache
import hashlib
def screenshot_cached(url, ttl=3600, **kwargs):
key = "snap:" + hashlib.md5(url.encode()).hexdigest()
result = cache.get(key)
if result:
return result
result = screenshot_url(url, **kwargs)
cache.set(key, result, ttl)
return result
Django Admin Integration
Add a screenshot preview to the Django admin for any model that has a URL field. This is useful for content management systems where editors need a visual preview of the page they are managing:
from django.contrib import admin
from django.utils.html import format_html
from .snapapi import screenshot_url
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
readonly_fields = ("screenshot_preview",)
def screenshot_preview(self, obj):
if not obj.url:
return "No URL"
img_url = screenshot_url(obj.url, width=800, height=600)
return format_html('
', img_url)
screenshot_preview.short_description = "Page Preview"
Environment Configuration Best Practices
Never hardcode your SnapAPI key in Django settings files that are committed to version control. Use environment variables loaded via python-decouple or django-environ. Store the key in your deployment environment, CI/CD secrets manager, or a .env file excluded from git. Rotate keys periodically through your SnapAPI dashboard and update your deployment configuration.
Get Started with SnapAPI and Django
SnapAPI offers 200 free screenshot API calls per month with no credit card required. Sign up, grab your API key, and have your first Django screenshot working in under five minutes. Plans start at $19 per month for 5,000 captures and scale to custom enterprise tiers.
Get Free API Key