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.
- Create a free account — 1,000 renders/month, no credit card.
- Open the dashboard and click + New key. Copy the key — it is shown once.
- Hit the render endpoint with your key. That is it.
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.
curl -H "Authorization: Bearer YOUR_KEY" \
"https://pageflash.io/render?url=https://news.ycombinator.com" \
| head -40You 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.
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
renderType=htmlReturns the fully rendered DOM as a string. Ideal for Googlebot, Bingbot, social-link crawlers, and any system that does not run JavaScript.
GET /render?url=https://your-app.com
Authorization: Bearer YOUR_KEY<!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><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=pngPixel-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.
curl -H "Authorization: Bearer YOUR_KEY" \
"https://pageflash.io/render?url=https://your-app.com&renderType=png&width=1440&height=900" \
--output viewport.pngcurl -H "Authorization: Bearer YOUR_KEY" \
"https://pageflash.io/render?url=https://your-app.com&renderType=jpeg&fullpage=true" \
--output fullpage.jpgfullpage=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=pdfConvert any web page to a PDF with backgrounds preserved. Perfect for invoices, statements, weekly reports, contracts, or compliance archives.
curl -H "Authorization: Bearer YOUR_KEY" \
"https://pageflash.io/render?url=https://your-app.com/invoice/123&renderType=pdf" \
--output invoice-123.pdf@media print { ... }.Outputs
Markdown — for AI agents and RAG
Accept: text/markdownWe 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.
curl -H "Authorization: Bearer YOUR_KEY" \
-H "Accept: text/markdown" \
"https://pageflash.io/render?url=https://your-blog.com/post"# 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.
// In your app
window.prerenderReady = false
fetchData().then(() => {
window.prerenderReady = true // PageFlash takes the snapshot now
})GET /render?url=…&waitForSelector=.article-contentGET /render?url=…&waitForFunction=window.__APP_HYDRATED__===trueTotal 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.
GET /render?url=…&blockResources=false&blockAnalytics=falseBehavior
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.
GET /render?url=…&javascript=document.querySelector('.cookie-banner')?.remove()Set window.prerenderData inside your script to get custom JSON back alongside the rendered output.
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.
<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.
| Mode | What PageFlash does | Best for |
|---|---|---|
| Override existing tags | Replace 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 only | Keep 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
@typeand 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.
curl -X DELETE \
-H "Authorization: Bearer YOUR_KEY" \
"https://pageflash.io/cache?url=https://your-app.com/path"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.
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"]}'pathsmust 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.
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,
]);
});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.
| Plan | Renders/month | Requests/min |
|---|---|---|
| Free | 1,000 | 10 |
| Starter | 25,000 | 60 |
| Growth | 150,000 | 200 |
| Pro | 600,000 | 500 |
Response headers expose your live state: X-RateLimit-Limit, X-RateLimit-Remaining, X-Plan.
Integration
Two ways to integrate
PageFlash fits two distinct use patterns. Pick the one that matches your goal — you can mix both later.
SEO middleware
Auto-detect bot user-agents and route only those requests through PageFlash. Real users keep your fast SPA. Done in 8 lines.
Pick a stack →
Direct API call
Call /render from your backend whenever you need a screenshot, PDF, or Markdown extract. One HTTP call, any language.
Pick a language →
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
// 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.
# 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"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.
| Param | Default | Description |
|---|---|---|
| url | (required) | The page to render. Must be http:// or https://. |
| renderType | html | html · jpeg · png · pdf |
| userAgent | Chrome desktop | Override the User-Agent string sent to the target. |
| width | 1440 | Viewport width in pixels. |
| height | 718 | Viewport height in pixels. |
| fullpage | false | Screenshot only — capture the whole scroll height. |
| waitForSelector | — | CSS selector that must appear in the DOM before snapshot. |
| waitForFunction | — | JS expression that must return truthy. |
| waitForTimeout | — | Extra fixed wait in milliseconds. |
| pageLoadTimeout | 25000 | Max ms to wait for navigation. Returns whatever rendered if exceeded. |
| waitAfterLastRequest | 500 | Quiet network period (ms) used by networkidle detection. |
| blockResources | true | Block images, video, audio. Auto-false for screenshots. |
| blockAnalytics | true | Block GA, GTM, Hotjar, Mixpanel, Segment. |
| javascript | — | Inject JS to run before snapshot. Set window.prerenderData to return data. |
| removeScriptTags | true | Strip <script> tags from HTML output. |
| followRedirects | false | Follow HTTP redirects to the final URL. |
| ignoreHTTPSErrors | true | Render even if the cert is invalid (staging, self-signed). |
| ttl | 300 | Cache 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.