Docs

PageVistly API

Screenshots, PDFs, and OG images — rendered in real Chrome, returned as agent-friendly content.

Base URL: https://api.pagevistly.com

Quick start

Grab an API key from the dashboard (Google sign-in), then call any endpoint.

cURL
# Screenshot a URL
curl -X POST https://api.pagevistly.com/v1/screenshot \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://stripe.com/pricing","full_page":true}' \
  --output page.png

# Agent mode — compact preview + text + signed URL
curl -X POST https://api.pagevistly.com/v1/screenshot \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://stripe.com/pricing","response":"agent","detail":"low"}'
Node.js
const res = await fetch("https://api.pagevistly.com/v1/screenshot", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_live_xxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ url: "https://example.com", response: "agent" }),
});
const data = await res.json();

Authentication

All /v1/* endpoints require an API key. Pass it as a Bearer token, or the api_key query/body parameter.

auth
Authorization: Bearer sk_live_xxx
# or
?api_key=sk_live_xxx

Keys are created in the dashboard. Each key has its own rate limit and monthly quota tied to your plan.

Screenshot POST /v1/screenshot

Capture a webpage as PNG/JPEG/WebP. Add response: "agent" to get context-friendly JSON instead of binary image data. Supports GET with query params too.

Parameters

ParameterTypeDefaultDescription
urlstringRequired. URL to capture (http/https only)
formatstringpngpng / jpeg / webp
full_pageboolfalseCapture full scrollable height
widthint1280Viewport width (320–3840)
heightint800Viewport height (240–2160)
device_scaleint1Retina factor (1–3)
wait_untilstringloadload / networkidle
wait_for_selectorstringCSS selector to wait for before capture
delay_msint0Extra wait after load (0–10000)
block_adsboolfalseStrip ads and trackers before capture
block_cookie_bannersboolfalseHide cookie consent walls
cache_ttlint0Cache response for N seconds (0–604800)
responsestringimageimage = binary; agent = JSON
detailstringlowlow = preview + text; high = text only, no image
max_tokensint4000Token budget for text (256–32000)
diffboolfalseCompare with last render, return changed + text diff
visualboolfalseDescribe screenshot with a vision model (charts/Canvas)

Agent mode

When response: "agent", the API returns JSON instead of binary. This is the core of PageVistly — output designed for agent context, not human eyeballs.

response=agent
{
  "ok": true,
  "title": "Stripe Pricing",
  "text": "Pricing. Starter $9...",
  "links": [{ "href": "...", "text": "..." }],
  "preview": "iVBOR...",
  "est_tokens": 1800,
  "full_res_url": "https://api.pagevistly.com/v1/file?key=..."
}
FieldDescription
titlePage title
textExtracted page text (DOM, not OCR — more accurate and free)
linksUp to 50 links with anchor text
previewDownscaled JPEG preview (~30KB), only when detail=low
est_tokensEstimated token cost of this response
full_res_urlSigned URL to fetch the full-res original on demand
Text-only models (DeepSeek, etc.) read text; multimodal models also get preview. Both skip the 500KB original unless they explicitly fetch full_res_url.

Visual diff

Add diff: true to detect what changed since the last render of the same URL — ideal for monitoring agents.

response=agent&diff=true
{
  "changed": true,
  "diff": {
    "added": ["Pro $39/mo"],
    "removed": ["Pro $29/mo"]
  }
}

The first call with diff: true establishes a baseline (no changed field). Subsequent calls compare against it. Baseline text is stored in R2 keyed by URL.

Visual description

Add visual: true to describe the screenshot with a vision model — useful for charts, tables, or Canvas content that DOM text extraction can't capture.

response=agent&visual=true
{
  "visual_description": "A pricing page with three tiers: Free, Starter ($5/mo), Pro ($15/mo)..."
}

PDF POST /v1/pdf

Convert a URL or raw HTML to a print-perfect PDF.

ParameterTypeDefaultDescription
urlstringURL to convert (use url or html, not both)
htmlstringRaw HTML (max 2MB)
formatstringA4A4 / Letter / Legal
landscapeboolfalseLandscape orientation
print_backgroundbooltruePrint CSS backgrounds
margin_mmint10Page margin in mm (0–50)
page_rangesstringe.g. "1-3"
cURL
curl -X POST https://api.pagevistly.com/v1/pdf \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com","format":"A4"}' \
  --output page.pdf

OG image POST /v1/og-image

Generate a 1200×630 social card from a template.

ParameterTypeDefaultDescription
templatestringdefaultblog / product / default
titlestringRequired. Card title (max 200)
subtitlestringCard subtitle (max 300)
authorstringAuthor / brand name (max 80)

Fetch full-res GET /v1/file

Retrieve the full-resolution original behind a full_res_url from agent mode.

cURL
curl "https://api.pagevistly.com/v1/file?key=screenshot/<hash>.png" \
  -H "Authorization: Bearer sk_live_xxx" --output full.png

MCP server

Drop PageVistly straight into Claude Desktop, Cursor, or any MCP client. Two tools: read_page and make_og_image.

claude_desktop_config.json
{
  "mcpServers": {
    "pagevistly": {
      "command": "npx",
      "args": ["-y", "@pagevistly/mcp"],
      "env": { "PAGEVISTLY_API_KEY": "sk_live_xxx" }
    }
  }
}
ToolDescription
read_pageRead a webpage as agent-friendly content (preview + text + signed URL). Args: url, detail, max_tokens
make_og_imageGenerate an OG social card. Args: template, title, subtitle, author

Caching

PageVistly uses a three-tier cache: edge Cache API → R2 persistent cache → live render.

HeaderMeaning
X-Cache: HIT-EDGEServed from edge cache (milliseconds)
X-Cache: HIT-R2Served from persistent storage
X-Cache: MISSFresh render

Enable caching with cache_ttl (seconds). Cached responses don't count against your quota.

Error codes

Errors are deterministic JSON — agents can parse them reliably. Format: {"error": "<code>"}.

CodeHTTPMeaning
missing_api_key401No API key provided
invalid_api_key401Key not found
api_key_disabled401Key is inactive
rate_limit_exceeded429Per-minute limit hit
quota_exceeded429Monthly quota exhausted
invalid_url400Malformed URL
url_protocol_not_allowed400Not http/https
url_host_not_allowed400Private/internal/reserved address (SSRF blocked)
invalid_json400Malformed request body
missing_input / ambiguous_input400PDF: need url or html, not both
html_too_large400PDF html exceeds 2MB
missing_title400OG image: title required
render_failed502Render error (page timeout, browser failure)
not_found404Full-res object not found

Rate limits & quota

Rate limit: 60 requests/minute per key. Monthly quota by plan:

PlanMonthly quota
Free500 renders
Starter2,000 renders
Pro10,000 renders

Usage resets on the 1st of each month (UTC). Track usage in the dashboard.