Start

Getting started

PageFlash gives you one endpoint that turns any URL into HTML, a screenshot, a PDF, or clean Markdown. Here is the shortest path from signup to your first render.

  1. Create a free account — 1,000 renders/month, no credit card.
  2. Open the dashboard and click + New key. Copy the key — it is shown once.
  3. Hit the render endpoint with your key. That is it.
Your first render — clean HTML
curl -H "Authorization: Bearer YOUR_KEY" \
  "https://pageflash.io/render?url=https://example.com"

Need a screenshot, PDF, or Markdown instead? Skip ahead to the output sections.

Start

Quick test — 30 seconds, no setup

Paste this in your terminal to render any URL right now. No code, no framework, just curl. Replace YOUR_KEY after you sign up.

terminal
curl -H "Authorization: Bearer YOUR_KEY" \
  "https://pageflash.io/render?url=https://news.ycombinator.com" \
  | head -40

You should see fully rendered HTML come back. Now do the same for your own URL — that is the entire integration.

Start

Authentication

Every render request must include your API key in the Authorization header. Keys are tied to your account and count against your monthly render quota.

HTTP
Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • Create up to 1 / 3 / 10 / unlimited keys per plan (Free / Starter / Growth / Pro).
  • Revoke compromised keys instantly from the dashboard.
  • Never expose keys in browser code — call PageFlash from your backend.

Outputs

HTML — for crawlers and SEO

Default renderType=html

Returns the fully rendered DOM as a string. Ideal for Googlebot, Bingbot, social-link crawlers, and any system that does not run JavaScript.

Request
GET /render?url=https://your-app.com
Authorization: Bearer YOUR_KEY
Response (text/html)
<!doctype html>
<html lang="en">
  <head>
    <title>Your app</title>
    <meta name="description" content="..." />
    ...
  </head>
  <body>
    <!-- fully hydrated DOM, scripts stripped by default -->
  </body>
</html>
By default we strip <script> tags from the output to keep bots from running JS again. Set removeScriptTags=false to keep them.

Outputs

Screenshot — JPEG and PNG

renderType=jpeg or renderType=png

Pixel-perfect captures of any URL. Use for Open Graph images, visual monitoring, status dashboards, or generated previews. Resource blocking is automatically disabled for screenshots so fonts and images render correctly.

Viewport screenshot (1440×900)
curl -H "Authorization: Bearer YOUR_KEY" \
  "https://pageflash.io/render?url=https://your-app.com&renderType=png&width=1440&height=900" \
  --output viewport.png
Full-page JPEG
curl -H "Authorization: Bearer YOUR_KEY" \
  "https://pageflash.io/render?url=https://your-app.com&renderType=jpeg&fullpage=true" \
  --output fullpage.jpg
  • fullpage=true — captures the whole scroll height, not just viewport.
  • width / height — viewport size in pixels (default 1440×718).
  • userAgent — render with a custom UA (mobile, tablet, etc.).

Outputs

PDF — print-ready export

renderType=pdf

Convert any web page to a PDF with backgrounds preserved. Perfect for invoices, statements, weekly reports, contracts, or compliance archives.

Generate PDF
curl -H "Authorization: Bearer YOUR_KEY" \
  "https://pageflash.io/render?url=https://your-app.com/invoice/123&renderType=pdf" \
  --output invoice-123.pdf
For PDF-specific styling (page breaks, headers, hide nav), use CSS media queries: @media print { ... }.

Outputs

Markdown — for AI agents and RAG

Set Accept: text/markdown

We strip the page chrome — nav, footer, ads, scripts — and return clean Markdown that LLMs and search-RAG pipelines actually want. Headings, lists, links, and code blocks are preserved.

Markdown extraction
curl -H "Authorization: Bearer YOUR_KEY" \
     -H "Accept: text/markdown" \
  "https://pageflash.io/render?url=https://your-blog.com/post"
Sample response
# Why we switched to Playwright

Our prerender stack used to fall over twice a week. After we
rewrote it on Playwright we have not paged anyone in months.

## What changed

- Removed CDP-based renderer
- Added 4-signal page-ready detection
- Switched cache to Redis with stale-while-revalidate
...

Behavior

Wait strategies — when is the page ready?

SPAs do not have a single "loaded" event. PageFlash supports four signals so you can pick the most reliable one for your app.

networkidle

Default. Waits until no network activity for 500ms.

window.prerenderReady

Auto-detected. Set the flag in your app when data is ready.

waitForSelector

Wait until a CSS selector exists in the DOM.

waitForFunction

Wait until a JS expression returns truthy.

prerenderReady — recommended for SPAs
// In your app
window.prerenderReady = false
fetchData().then(() => {
  window.prerenderReady = true   // PageFlash takes the snapshot now
})
Wait for a selector
GET /render?url=…&waitForSelector=.article-content
Wait for a JS condition
GET /render?url=…&waitForFunction=window.__APP_HYDRATED__===true

Total page-load timeout defaults to 25 seconds. Override per-request with pageLoadTimeout=15000.

Behavior

Resource & analytics blocking

For HTML and Markdown renders, PageFlash blocks images, media, and common analytics by default. This makes pages reach networkidlefaster and keeps render times low.

  • blockResources=true (default) — drop images, video, audio.
  • blockAnalytics=true (default) — drop Google Analytics, GTM, Hotjar, Mixpanel, Segment.
  • Both auto-disabled for screenshot renders so visuals come out correctly.
Keep everything
GET /render?url=…&blockResources=false&blockAnalytics=false

Behavior

Custom JS injection

Run arbitrary JavaScript inside the page right before we snapshot. Use it to extract structured data, modify the DOM, or trigger app actions.

Inject JS via query param
GET /render?url=…&javascript=document.querySelector('.cookie-banner')?.remove()

Set window.prerenderData inside your script to get custom JSON back alongside the rendered output.

Capture data with prerenderData
POST /render
Content-Type: application/json
Authorization: Bearer YOUR_KEY

{
  "url": "https://your-app.com",
  "javascript": "window.prerenderData = { price: document.querySelector('.price').textContent }"
}

Behavior

Status code & response headers

Tell PageFlash to set HTTP status codes and headers from inside your page using <meta> tags. Useful for 404s, redirects, and cache-control on a per-route basis.

In your HTML
<meta name="prerender-status-code" content="404">
<meta name="prerender-header" content="Cache-Control: no-cache">
<meta name="prerender-header" content="X-Robots-Tag: noindex">

Behavior

SEO tag injection modes

SEO configs in the dashboard can replace tags that already exist on your rendered page, or only fill tags that are missing.

ModeWhat PageFlash doesBest for
Override existing tagsReplace matching title, meta, canonical, and JSON-LD tags with your saved values.Landing pages where PageFlash should be the source of truth.
Fill missing tags onlyKeep non-empty page tags and add your saved values only when the page has no tag yet.CMS pages that already publish some SEO tags.
  • Global, pattern, and URL-specific configs each have their own mode.
  • For JSON-LD, override replaces nodes with matching @type and keeps unrelated schema.
  • Blank fields are never injected, so you can fill only the tags you want PageFlash to manage.

Saving an SEO config refreshes affected cached pages in the background and replaces each cached render only after the fresh HTML is ready.

Performance

Caching

Every cacheable render is stored in PageFlash's edge cache (Redis- backed). Bots get cache hits in under 50 ms, and your origin barely sees traffic.

  • Cache hits do not count against your render quota.
  • Default TTL: 5 minutes. Override with ?ttl=3600 (seconds) per request.
  • Stale-while-revalidate is on by default — bots never wait for cold renders.
  • Inspect headers: X-Prerender-Cache: HIT | MISS.
Invalidate a single URL
curl -X DELETE \
  -H "Authorization: Bearer YOUR_KEY" \
  "https://pageflash.io/cache?url=https://your-app.com/path"
Renders that hit JavaScript injection ( javascript=…) are never cached — they are dynamic by definition.

Performance

Push refresh for fresh CMS publishes

Pro and Enterprise teams can tell PageFlash exactly which pages changed. PageFlash refreshes the cached render in the background and replaces it when the fresh version is ready.

The old cached HTML stays live during the refresh, so bots keep getting cache hits instead of a temporary miss.

Use an API key from your dashboard. A domain-scoped key can only refresh that domain, while an all-domain key can refresh any registered domain in your account.
Refresh one or more paths
curl -X POST "https://pageflash.io/api/domains/YOUR_DOMAIN_ID/invalidate" \
  -H "Authorization: Bearer YOUR_PAGEFLASH_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"paths":["/blog/your-post","/pricing"]}'
  • paths must be site paths that start with /, not full URLs.
  • PageFlash refreshes matching pages without creating a cache-miss window.
  • The endpoint accepts up to 100 paths per request and is limited to 100 requests per minute.
WordPress publish hook
add_action('save_post', function ($post_id) {
  if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
    return;
  }

  $domain_id = getenv('PAGEFLASH_DOMAIN_ID');
  $api_key = getenv('PAGEFLASH_API_KEY');
  $path = wp_parse_url(get_permalink($post_id), PHP_URL_PATH);

  wp_remote_post("https://pageflash.io/api/domains/{$domain_id}/invalidate", [
    'headers' => [
      'Authorization' => "Bearer {$api_key}",
      'Content-Type' => 'application/json',
    ],
    'body' => wp_json_encode([
      'paths' => [$path],
    ]),
    'timeout' => 5,
  ]);
});
Strapi lifecycle
const pageflashEndpoint =
  `https://pageflash.io/api/domains/${process.env.PAGEFLASH_DOMAIN_ID}/invalidate`

async function refreshPage(slug) {
  await fetch(pageflashEndpoint, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.PAGEFLASH_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      paths: [`/blog/${slug}`],
    }),
  })
}

export default {
  async afterCreate(event) {
    await refreshPage(event.result.slug)
  },
  async afterUpdate(event) {
    await refreshPage(event.result.slug)
  },
}

Need the domain ID? It is returned by GET /api/domains and when you add a domain from the dashboard. Store it in your CMS environment variables with your PageFlash API key.

Performance

Rate limits

Each plan has a per-minute rate limit. Exceeding it returns429 Too Many Requests. Quota and rate are independent — you can have plenty of monthly quota left and still get rate-limited.

PlanRenders/monthRequests/min
Free1,00010
Starter25,00060
Growth150,000200
Pro600,000500

Response headers expose your live state: X-RateLimit-Limit, X-RateLimit-Remaining, X-Plan.

Integration

Two ways to integrate

Integration · Path A

SEO middleware recipes

Pick the layer closest to your traffic. Cloudflare Worker is the simplest — drop one Worker in front of your site and you are done, no app code touched.

Edge / CDN — no app code change

Reverse proxy — drop into web server

Framework — add middleware in your app

src/worker.ts · Cloudflare Worker
// wrangler.toml: bind PAGEFLASH_KEY as a secret
// Then deploy with: wrangler deploy

const BOT_REGEX = /(googlebot|google-inspectiontool|googleother|bingbot|bingpreview|slurp|duckduckbot|duckassistbot|baiduspider|yandex|sogou|applebot|facebookexternalhit|facebot|facebookbot|meta-externalagent|twitterbot|linkedinbot|pinterestbot|pinterest|discordbot|slackbot|telegrambot|whatsapp|vkshare|zalobot|zalo\/|zaloapp|zaloweb|linespider|embedly|quora|outbrain|showyoubot|w3c_validator|chrome-lighthouse|rogerbot|petalbot|redditbot|semrushbot|ahrefsbot|mj12bot|gptbot|chatgpt-user|oai-searchbot|perplexitybot|perplexity-user|claudebot|claude-user|anthropic-ai|ccbot|bytespider|phindbot|dotbot)/i;

export default {
  async fetch(request, env) {
    const ua = request.headers.get('user-agent') || '';
    if (!BOT_REGEX.test(ua)) return fetch(request);

    const target = request.url;
    return fetch(
      `https://pageflash.io/render?url=${encodeURIComponent(target)}`,
      { headers: { Authorization: `Bearer ${env.PAGEFLASH_KEY}` } },
    );
  },
};

Integration · Path B

Direct API call from your backend

For screenshots, PDFs, and Markdown extraction you call PageFlash directly. Same endpoint, different output. Below is a working snippet in six languages.

terminal
# 1. HTML for SEO bots
curl -H "Authorization: Bearer YOUR_KEY" \
  "https://pageflash.io/render?url=https://your-app.com"

# 2. Full-page PNG screenshot
curl -H "Authorization: Bearer YOUR_KEY" \
  "https://pageflash.io/render?url=https://your-app.com&renderType=png&fullpage=true" \
  --output snap.png

# 3. PDF
curl -H "Authorization: Bearer YOUR_KEY" \
  "https://pageflash.io/render?url=https://your-app.com&renderType=pdf" \
  --output report.pdf

# 4. Markdown for AI agents
curl -H "Authorization: Bearer YOUR_KEY" \
     -H "Accept: text/markdown" \
  "https://pageflash.io/render?url=https://your-app.com"
Set renderType=jpeg, renderType=png, or renderType=pdf to get binary back. Add Accept: text/markdown for clean Markdown.

Reference

All parameters

Pass any of these as query params (GET) or JSON body (POST). Body wins, query is fallback.

ParamDefaultDescription
url(required)The page to render. Must be http:// or https://.
renderTypehtmlhtml · jpeg · png · pdf
userAgentChrome desktopOverride the User-Agent string sent to the target.
width1440Viewport width in pixels.
height718Viewport height in pixels.
fullpagefalseScreenshot only — capture the whole scroll height.
waitForSelectorCSS selector that must appear in the DOM before snapshot.
waitForFunctionJS expression that must return truthy.
waitForTimeoutExtra fixed wait in milliseconds.
pageLoadTimeout25000Max ms to wait for navigation. Returns whatever rendered if exceeded.
waitAfterLastRequest500Quiet network period (ms) used by networkidle detection.
blockResourcestrueBlock images, video, audio. Auto-false for screenshots.
blockAnalyticstrueBlock GA, GTM, Hotjar, Mixpanel, Segment.
javascriptInject JS to run before snapshot. Set window.prerenderData to return data.
removeScriptTagstrueStrip <script> tags from HTML output.
followRedirectsfalseFollow HTTP redirects to the final URL.
ignoreHTTPSErrorstrueRender even if the cert is invalid (staging, self-signed).
ttl300Cache TTL in seconds for this render.

Need a parameter that is not here? Email us — we ship custom flags within a week for paid plans.

Stuck or have a question? Email [email protected] — we read every message.