Screenshot Happy

Screenshot Happy

One request, one screenshot. Send a URL, get back a PNG.

Try it

curl "https://screenshot-api-production-ffd7.up.railway.app/screenshot?url=https://example.com" \
  -H "x-api-key: YOUR_API_KEY" \
  --output screenshot.png
// JavaScript
const res = await fetch("https://screenshot-api-production-ffd7.up.railway.app/screenshot?url=" + encodeURIComponent("https://example.com"), {
  headers: { "x-api-key": "YOUR_API_KEY" }
});
const buffer = await res.arrayBuffer();
# Python
import requests
r = requests.get("https://screenshot-api-production-ffd7.up.railway.app/screenshot",
    params={"url": "https://example.com"},
    headers={"x-api-key": "YOUR_API_KEY"})
open("screenshot.png", "wb").write(r.content)

Parameters

15s timeout. Not available yet: WebP, custom headers/cookies, ad-block or cookie-banner removal.

Limits

Over any limit you get 429 with a reintenta_en_segundos field and a Retry-After header — never a silent hang.

Errors

Monitoring

Same engine as /screenshot, running on a schedule: it captures a URL periodically, compares each capture against the previous one, and calls your webhook when the difference crosses a threshold. Not available on the demo key — needs a real API key (see Pricing for how many pages and how often per plan).

curl -X POST "https://screenshot-api-production-ffd7.up.railway.app/monitors" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "webhook_url": "https://your-server.com/webhook",
    "frecuencia_minutos": 60,
    "umbral_diferencia": 5
  }'
// JavaScript
const res = await fetch("https://screenshot-api-production-ffd7.up.railway.app/monitors", {
  method: "POST",
  headers: { "x-api-key": "YOUR_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    url: "https://example.com",
    webhook_url: "https://your-server.com/webhook",
    frecuencia_minutos: 60,
    umbral_diferencia: 5
  })
});
const monitor = await res.json();
# Python
import requests
r = requests.post("https://screenshot-api-production-ffd7.up.railway.app/monitors",
    headers={"x-api-key": "YOUR_API_KEY"},
    json={
        "url": "https://example.com",
        "webhook_url": "https://your-server.com/webhook",
        "frecuencia_minutos": 60,
        "umbral_diferencia": 5,
    })
monitor = r.json()

frecuencia_minutos — minimum check interval in minutes; your plan sets the floor (see Pricing), 15 min is the hard minimum for everyone. umbral_diferencia — % of changed pixels that counts as a real change (default 5).

When a change is detected, we POST this to your webhook_url. Up to 3 attempts if your endpoint doesn't return a 2xx (immediately, then after 5s, then after 30s) — after that we give up on that delivery, no queue or dead-letter yet:

{
  "monitor_id": 4,
  "url": "https://example.com",
  "comprobado_en": "2026-09-18T17:00:00.000Z",
  "cambio_detectado": true,
  "diferencia_porcentaje": 12.4
}

One monitor check runs at a time across the whole service (simple by design for now) — with very few customers this is invisible, but it means the check frequency your plan promises is a target, not a real-time guarantee, until this scales. Being upfront about it here rather than after you notice.

Pricing

Every plan combines screenshots and change-monitoring in one payment — no separate products, no usage billing to track. Hit your monthly screenshot limit or your plan's page limit for monitors? You get a clear 429 response telling you so — never silent throttling or a surprise charge. Upgrade any time; it takes effect immediately, no waiting for a renewal date. No contracts, cancel whenever (see billing terms).

Free

€0 /month

  • 200 screenshots/month
  • 3 monitored pages, checked every 6h

Starter

€9 /month

  • 2,000 screenshots/month
  • 20 monitored pages, checked every 1h, webhook alerts on change

Growth

€29 /month

  • 10,000 screenshots/month
  • 100 monitored pages, checked every 15–30 min, webhook alerts on change

Need more than Growth? Contact us directly.

Already subscribed?

Manage your subscription, update your card, see invoices, or cancel — enter your API key.

Something broken?

Tell us what happened. We read every message.

Privacy · Terms