API reference

Base URL: https://shotlane.dev. All endpoints accept GET with query parameters or POST with a JSON (or form) body. Successful responses return the raw file bytes with the matching Content-Type.

Authentication

Send your API key in any of these ways (header recommended for server-side code):

X-API-Key: sl_your_key
Authorization: Bearer sl_your_key
?access_key=sl_your_key        # handy for <img src> embeds

Don't have a key? Get one free — 100 renders included.

GET|POST /v1/screenshot

Capture a web page or an HTML snippet. Costs 1 credit per successful render.

ParameterDefaultDescription
url—Page to capture. https:// is assumed if omitted. Either url or html is required.
html—Raw HTML to render instead of a URL (POST recommended, max 2 MB).
formatpngpng, jpeg, webp or pdf.
width / height1280 / 800Viewport size in CSS pixels (240–3840 × 240–2160).
full_pagefalseCapture the entire scrollable page.
scale1Device scale factor, 1–3. Use 2 for retina-quality images.
selector—CSS selector; captures only the first matching element.
dark_modefalseEmulate prefers-color-scheme: dark.
hide_cookie_bannersfalseHide common cookie consent popups (OneTrust, Cookiebot, Didomi, Quantcast, …).
block_adsfalseBlock requests to common ad & tracking networks.
delay0Extra wait after load, in ms (0–10000).
wait_untilloadload, domcontentloaded or networkidle.
quality80JPEG/WebP quality, 1–100.
user_agent—Override the browser user agent.
downloadfalseAdd a Content-Disposition: attachment header.
device—Preset viewport + scale: desktop, desktop_hd, laptop, ipad, iphone, iphone_se, pixel, galaxy. Widths ≤ 480px automatically get a mobile user agent and touch emulation.
omit_backgroundfalseTransparent background for PNG (the page must not set its own background).
css—Custom CSS injected before capture.
js—JavaScript run in the page before capture (async/await allowed). Errors are returned as 422.
hide_selectors—Comma-separated CSS selectors (or JSON array) to hide, e.g. .chat-widget,#promo.
click—CSS selector to click before capture (e.g. open a tab or dismiss a modal).
wait_for_selector—Wait (up to 10s) until this element is visible.
headers—Extra HTTP headers as a JSON object, e.g. {"Authorization":"Bearer …"}. Sent only to the target host, never to third-party resources.
cookies—Cookies for the target URL: session=abc; theme=dark. Useful for pages behind a login.
cache_ttl0 (86400 for signed URLs)Seconds to cache the result (max 30 days). Identical requests within the TTL are served from cache for free — no credit used.
curl "https://shotlane.dev/v1/screenshot?url=example.com&width=1440&scale=2&format=jpeg" \
  -H "X-API-Key: $SHOTLANE_KEY" -o example.jpg

GET|POST /v1/pdf

Same parameters as /v1/screenshot (format defaults to pdf), plus:

ParameterDefaultDescription
paperA4A3, A4, A5, Letter, Legal, Tabloid.
landscapefalseLandscape orientation.
print_backgroundtrueInclude background colors/images and use screen styles. Set false to use your @media print CSS.

Tip: control margins and page breaks with CSS — @page { margin: 18mm } and break-before: page.

curl -X POST https://shotlane.dev/v1/pdf \
  -H "X-API-Key: $SHOTLANE_KEY" -H "Content-Type: application/json" \
  -d '{"html":"<h1>Hello PDF</h1>","paper":"Letter"}' -o hello.pdf

GET|POST /v1/extract  ·  /v1/markdown

Load a page in the browser (JavaScript executed, so SPAs work) and get its content as clean Markdown — ready for LLMs, RAG pipelines, search indexing or archiving. 1 credit per page. /v1/extract returns JSON; /v1/markdown returns the Markdown as text/markdown.

ParameterDefaultDescription
url / html—Page to load, or raw HTML.
main_contenttrueExtract just the main article/content (drops navigation, footers, ads). false converts the whole page.
selector—Convert only the first element matching this CSS selector.
include_linkstrueKeep hyperlinks (made absolute).
include_imagesfalseKeep images as ![alt](src).
formatjsonjson or markdown.

All page options above also work here: wait_until, wait_for_selector, delay, click, js, headers, cookies, block_ads, hide_cookie_banners, cache_ttl…

curl "https://shotlane.dev/v1/extract?url=https://en.wikipedia.org/wiki/Headless_browser" -H "X-API-Key: $SHOTLANE_KEY"

{
  "url": "https://en.wikipedia.org/wiki/Headless_browser",
  "title": "Headless browser - Wikipedia",
  "description": "",
  "author": null,
  "published": "2014-09-24",
  "markdown": "# Headless browser\n\nA **headless browser** is a [web browser](https://…) without a …",
  "word_count": 1077
}

GET /v1/account

Returns your remaining credits: {"email": "...", "credits": 1234}. Free — doesn't consume a credit.

MCP server for AI agents

Let Claude, Cursor, Windsurf or any MCP client look at web pages. Shotlane runs a remote MCP server (Streamable HTTP) with four tools: screenshot (returns the image directly to the model), read_page (page → clean Markdown, JavaScript rendered), html_to_pdf and credits.

https://shotlane.dev/mcp

Clients that support OAuth (ChatGPT, Claude, Cursor, VS Code, Claude Code) just need that URL — they'll open a sign-in window. Everything else can send your API key as X-API-Key / Authorization: Bearer, or append ?key=sl_your_key. Step-by-step setup for each app: Integrations.

Claude Code:

claude mcp add --transport http shotlane https://shotlane.dev/mcp

Cursor (mcp.json):

{
  "mcpServers": {
    "shotlane": { "url": "https://shotlane.dev/mcp" }
  }
}

Prefer headers? Send Authorization: Bearer sl_your_key instead of the key parameter. Each screenshot or PDF costs 1 credit, same as the REST API. Machine-readable docs: /llms.txt · /openapi.json

Response headers

X-Credits-RemainingCredits left after this request.
X-Render-Time-MsServer-side render time.

Errors

Errors return JSON: {"error": "message"}. Failed renders are never charged.

400Invalid parameter, or the host is unreachable / not allowed (private networks are blocked).
401Missing or invalid API key.
402Out of credits — top up.
413HTML payload too large.
422The page could not be loaded, or the selector wasn't found.
500Unexpected rendering error. Retry once; contact us if it persists.

Signed URLs for <img> embeds

The response is the image itself, so a Shotlane URL can go straight into an <img src> — ideal for link previews, directories and dashboards. Never put your secret key in public HTML; use a signed URL instead. It carries your public key (pub_…, on your dashboard) and an HMAC signature, so nobody can change the parameters or reuse your account for other pages.

Signed requests are cached for 24 hours by default (override with cache_ttl), and cache hits are free — a popular page costs you one credit per day, not one per visitor.

How to sign: take every parameter except key and signature, sort by name, URL-encode as a query string, and compute HMAC-SHA256 with your secret API key. Append key and signature (hex).

# Python
import hmac, hashlib
from urllib.parse import urlencode

def shotlane_url(params, public_key, secret_key):
    qs = urlencode(sorted((k, str(v)) for k, v in params.items()))
    sig = hmac.new(secret_key.encode(), qs.encode(), hashlib.sha256).hexdigest()
    return f"https://shotlane.dev/v1/screenshot?{qs}&key={public_key}&signature={sig}"

shotlane_url({"url": "https://example.com", "format": "webp"}, "pub_…", "sl_…")
// Node.js
import crypto from "node:crypto";

function shotlaneUrl(params, publicKey, secretKey) {
  const qs = new URLSearchParams(Object.entries(params).map(([k, v]) => [k, String(v)])
    .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))).toString();
  const sig = crypto.createHmac("sha256", secretKey).update(qs).digest("hex");
  return `https://shotlane.dev/v1/screenshot?${qs}&key=${publicKey}&signature=${sig}`;
}

Note: Python's urlencode encodes spaces as +, like URLSearchParams — both produce identical signatures.