API Reference
Complete reference for every PageBolt endpoint, parameter, and integration.
Quick Start
Get your first screenshot in under 5 minutes. Three steps:
Sign up free
Create an account at pagebolt.dev/signup. No credit card required — you get 100 requests/month on all 7 APIs.
Get your API key
Your API key is generated automatically when you verify your email. Find it in the Dashboard.
Make your first API call
Copy this cURL command, replace YOUR_API_KEY, and run it:
curl -X POST https://pagebolt.dev/api/v1/screenshot \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "format": "webp"}' \
-o screenshot.webp
What's next?
Screenshot API →
30+ parameters, device presets, dark mode, ad blocking, style themes
Video Recording →
Record demo videos with cursor effects, click highlighting, and voice narration
PDF Generation →
Convert URLs or HTML to production-grade PDFs
MCP Server →
Use PageBolt from Claude Desktop, Cursor, or Windsurf
Authentication
All API requests require an API key. Pass it via the x-api-key header. For security, query parameter authentication is not supported — API keys should never appear in URLs, logs, or browser history.
curl -H "x-api-key: pf_live_your_key_here" \
https://pagebolt.dev/api/v1/screenshot
Base URL
https://pagebolt.dev/api/v1
All endpoint paths in this documentation are relative to this base URL.
Error Responses
All errors return JSON with an error field.
| Status | Meaning |
|---|---|
| 400 | Bad request — check your parameters |
| 401 | Invalid or missing API key |
| 402 | Quota exceeded (subscription) or insufficient balance (PAYG) — upgrade or top up |
| 429 | Rate limit exceeded — slow down |
| 500 | Server error — try again or contact support |
{
"error": "Either \"url\", \"html\", or \"markdown\" is required"
}
Rate Limits
Rate limits are per-user, based on your plan. Check response headers:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Requests per minute allowed |
| X-RateLimit-Remaining | Requests remaining this window |
| X-Usage-Current | Requests used this month |
| X-Usage-Limit | Monthly request limit |
/v1/screenshot
Capture a screenshot of a URL, raw HTML, or Markdown content. Returns the image as binary data (or base64 JSON with metadata).
Input
| Parameter | Type | Default | Description |
|---|---|---|---|
| url | string | — | URL to capture (required if no html or markdown) |
| html | string | — | Raw HTML to render |
| markdown | string | — | Markdown to render NEW |
Viewport
| Parameter | Type | Default | Description |
|---|---|---|---|
| width | integer | 1280 | Viewport width in pixels (max 3840) |
| height | integer | 720 | Viewport height in pixels (max 2160) |
| deviceScaleFactor | number | 1 | Device pixel ratio, use 2 for retina (max 3) |
| viewportDevice | string | — | Device preset, e.g. "iphone_14_pro". Overrides width/height/DPR. NEW |
| viewportMobile | boolean | false | Enable mobile meta viewport NEW |
| viewportHasTouch | boolean | false | Enable touch events NEW |
| viewportLandscape | boolean | false | Enable landscape mode NEW |
Output
| Parameter | Type | Default | Description |
|---|---|---|---|
| format | string | png | png, jpeg, or webp |
| quality | integer | 80 | JPEG/WebP quality 1–100 |
| fullPage | boolean | false | Capture the full scrollable page |
| selector | string | — | CSS selector for element capture |
| omitBackground | boolean | false | Transparent background (PNG/WebP only) NEW |
| clip | object | — | Crop region {x, y, width, height} in pixels NEW |
Full Page Controls NEW
| Parameter | Type | Default | Description |
|---|---|---|---|
| fullPageScroll | boolean | auto | Auto-scroll to trigger lazy-loaded images before capture |
| fullPageScrollDelay | integer | 400 | Milliseconds to wait between scroll steps |
| fullPageScrollBy | integer | viewport height | Pixels per scroll step |
| fullPageMaxHeight | integer | — | Maximum screenshot height cap in pixels |
Timing
| Parameter | Type | Default | Description |
|---|---|---|---|
| delay | integer | 0 | Wait ms before capture (max 10000) |
| waitUntil | string | networkidle2 | load, domcontentloaded, networkidle0, networkidle2 NEW |
| waitForSelector | string | — | Wait for a CSS selector to appear before capturing NEW |
| navigationTimeout | integer | 25000 | Navigation timeout in milliseconds NEW |
Emulation NEW
| Parameter | Type | Default | Description |
|---|---|---|---|
| darkMode | boolean | false | Emulate dark color scheme (prefers-color-scheme: dark) |
| reducedMotion | boolean | false | Reduce animations (prefers-reduced-motion) |
| mediaType | string | — | "screen" or "print" |
| timeZone | string | — | Timezone ID, e.g. "America/New_York" |
| geolocation | object | — | {latitude, longitude, accuracy?} |
Customization
| Parameter | Type | Default | Description |
|---|---|---|---|
| userAgent | string | — | Custom User-Agent string NEW |
| cookies | array | — | Array of "name=value" strings or {name, value, domain?} objects NEW |
| headers | object | — | Extra HTTP headers to send with the page request NEW |
| authorization | string | — | Authorization header value, e.g. "Bearer <token>" NEW |
| authState | object | — | Full browser auth state — injects cookies and localStorage before navigation. Use the Auth State Extractor to capture this from your browser. NEW |
| bypassCSP | boolean | false | Bypass Content-Security-Policy on the page NEW |
| hideSelectors | array | — | CSS selectors to hide before capture NEW |
| click | string | — | Click a CSS selector before capture NEW |
| injectCss | string | — | Custom CSS to inject into the page |
| injectJs | string | — | Custom JavaScript to execute before capture |
Blocking
| Parameter | Type | Default | Description |
|---|---|---|---|
| blockBanners | boolean | false | Hide cookie consent banners (GDPR popups, OneTrust, CookieBot, etc.) |
| blockAds | boolean | false | Block advertisements NEW |
| blockChats | boolean | false | Block live chat widgets (Intercom, Crisp, Drift, etc.) NEW |
| blockTrackers | boolean | false | Block analytics trackers (GA, Hotjar, Segment, etc.) NEW |
| blockRequests | array | — | URL patterns to block (substring match) NEW |
| blockResources | array | — | Resource types to block: document, stylesheet, image, media, font, script, xhr, fetch, etc. NEW |
Anti-Detection & Proxy NEW
| Parameter | Type | Default | Description |
|---|---|---|---|
| stealth | boolean | false | Mask browser fingerprints to bypass bot detection walls. Uses an ephemeral browser instance per request. |
| proxy | string | — | Route requests through your proxy. Format: "http://user:pass@host:port". Supports http, https, socks4, socks5. |
Both parameters are supported on Screenshot, PDF, Sequence, and Video endpoints.
Metadata NEW
| Parameter | Type | Default | Description |
|---|---|---|---|
| extractMetadata | boolean | false | Extract page metadata (title, description, OG tags, favicon, HTTP status, canonical, lang) |
Response Format
| Parameter | Type | Default | Description |
|---|---|---|---|
| response_type | string | binary | Set to "json" for base64-encoded response with metadata |
When response_type is "json" and extractMetadata is true, the response includes:
{
"data": "iVBORw0KGgo...",
"format": "png",
"content_type": "image/png",
"size_bytes": 284512,
"duration_ms": 1243,
"metadata": {
"title": "Page Title",
"description": "Meta description",
"ogTitle": "OG Title",
"ogDescription": "OG Description",
"ogImage": "https://example.com/og.png",
"ogType": "website",
"favicon": "/favicon.ico",
"httpStatusCode": 200,
"canonical": "https://example.com",
"lang": "en"
}
}
Content-Type header (image/png, image/jpeg, or image/webp). Status 200 on success.
Styling (Post-Processing)
Add presentation-ready styling to your screenshots — curated theme presets, gradient backgrounds, glassmorphism, neon glows, noise textures, and more. Pass a style object to apply post-capture beautification.
Theme Presets NEW
Use style.theme for a one-param curated style. Themes set frame, background, shadow, padding, and border radius automatically. You can override any individual property alongside the theme.
| Theme | Frame | Background | Tier |
|---|---|---|---|
| notion | macOS light | Solid warm white | Free |
| paper | None | Solid white | Free |
| vercel | None | Solid black | Free |
| glass | Minimal | Frosted glass | Free |
| ocean | macOS | Ocean gradient | Free |
| sunset | macOS | Sunset gradient | Free |
| linear | Minimal | Midnight gradient | Starter+ |
| arc | macOS | Aurora gradient | Starter+ |
| glassDark | None | Dark frosted glass | Starter+ |
| glassWarm | None | Warm frosted glass | Starter+ |
| spotlight | None | Radial spotlight | Starter+ |
| neonBlue | Minimal | Midnight + blue glow | Starter+ |
| neonPurple | Minimal | Midnight + purple glow | Starter+ |
| neonGreen | Minimal | Slate + green glow | Starter+ |
| lavender | macOS | Lavender gradient | Starter+ |
| ember | Minimal | Ember gradient | Starter+ |
| dots | Minimal | Dot grid pattern | Starter+ |
| grid | Minimal | Grid line pattern | Starter+ |
Manual Style Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| style.theme | string | — | Theme preset name (see table above). Sets all style properties at once. Individual overrides still apply. NEW |
| style.frame | string | none | macos, windows, minimal, or none. Adds a browser chrome bar above the screenshot. |
| style.frameTheme | string | dark | light, dark, or auto. Controls the frame bar color scheme. |
| style.background | string | none | Gradient preset: ocean, sunset, forest, midnight, aurora, lavender, peach, arctic, ember, slate, neon. Special: glass (frosted), spotlight, dots, grid, noise, solid, or none. |
| style.bgColor | string | #1e3a5f | Hex color for solid background, e.g. "#1e3a5f". |
| style.bgColors | array | — | Custom gradient: array of exactly 2 hex colors, e.g. ["#667eea","#764ba2"]. Overrides preset. |
| style.padding | integer | 40 | Padding around the screenshot in pixels (0–120). |
| style.borderRadius | integer | 12 | Corner radius in pixels (0–40). |
| style.shadow | string | md | none, xs, sm, md, lg, xl, or 2xl. Drop shadow intensity. |
{ "style": { "theme": "linear" } } for instant polished results. The glass background creates a frosted glassmorphism effect using a blurred version of the screenshot itself as the backdrop. The neon* themes add a colored glow border and shadow — great for dark-mode hero images.
Styled screenshot example
curl -X POST https://pagebolt.dev/api/v1/screenshot \
-H "x-api-key: pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://my-saas.com",
"format": "png",
"style": {
"frame": "macos",
"background": "ocean",
"shadow": "lg",
"padding": 60,
"borderRadius": 16
}
}' \
-o styled-screenshot.png
Example 1: Basic screenshot
curl -X POST https://pagebolt.dev/api/v1/screenshot \
-H "x-api-key: pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://my-saas.com",
"width": 1280,
"height": 720,
"format": "png",
"fullPage": false
}' \
-o screenshot.png
Example 2: Device preset + dark mode
curl -X POST https://pagebolt.dev/api/v1/screenshot \
-H "x-api-key: pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://my-saas.com",
"viewportDevice": "iphone_15_pro_max",
"darkMode": true,
"format": "webp",
"quality": 90
}' \
-o linear-mobile-dark.webp
Example 3: Metadata extraction
const res = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': process.env.PAGEBOLT_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://my-saas.com',
extractMetadata: true,
response_type: 'json',
format: 'webp',
}),
});
const { data, metadata } = await res.json();
console.log(metadata.title); // "My SaaS — Dashboard"
console.log(metadata.ogImage); // "https://my-saas.com/og.png"
console.log(metadata.httpStatusCode); // 200
// Save the screenshot
const buf = Buffer.from(data, 'base64');
fs.writeFileSync('my-saas.webp', buf);
Example 4: Ad blocking + transparent background
import requests, os
resp = requests.post(
"https://pagebolt.dev/api/v1/screenshot",
headers={
"x-api-key": os.environ["PAGEBOLT_KEY"],
"Content-Type": "application/json",
},
json={
"url": "https://my-blog.com",
"blockAds": True,
"blockBanners": True,
"blockChats": True,
"blockTrackers": True,
"omitBackground": True,
"format": "png",
},
)
with open("clean-screenshot.png", "wb") as f:
f.write(resp.content)
Example 5: Full page with lazy image scroll
curl -X POST https://pagebolt.dev/api/v1/screenshot \
-H "x-api-key: pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.apple.com/iphone",
"fullPage": true,
"fullPageScroll": true,
"fullPageScrollDelay": 500,
"fullPageMaxHeight": 15000,
"format": "jpeg",
"quality": 85
}' \
-o apple-fullpage.jpg
Example 6: Geolocation and timezone
curl -X POST https://pagebolt.dev/api/v1/screenshot \
-H "x-api-key: pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://weather.com",
"timeZone": "Asia/Tokyo",
"geolocation": {
"latitude": 35.6762,
"longitude": 139.6503,
"accuracy": 100
},
"width": 1440,
"height": 900,
"darkMode": true
}' \
-o weather-tokyo.png
Example 7: Authenticated page with cookies & headers
const res = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': process.env.PAGEBOLT_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://myapp.com/dashboard',
cookies: [
{ name: 'session', value: 'abc123xyz', domain: 'myapp.com' },
{ name: 'theme', value: 'dark', domain: 'myapp.com' },
],
headers: {
'Accept-Language': 'en-US',
},
authorization: 'Bearer eyJhbGciOiJIUzI1NiIs...',
waitForSelector: '.dashboard-loaded',
darkMode: true,
}),
});
const screenshot = Buffer.from(await res.arrayBuffer());
fs.writeFileSync('dashboard.png', screenshot);
Authenticated Recording
Recording pages behind OAuth, SSO, or session-based auth requires injecting your existing browser session into Pagebolt. The authState parameter handles this for all endpoints — /screenshot, /video, /sequence, and /inspect.
authState parameter lets you hand that session to Pagebolt so it starts already authenticated.
The authState format
{
"authState": {
"cookies": [
{
"name": "session_id",
"value": "abc123xyz",
"domain": "myapp.com",
"path": "/",
"secure": true,
"httpOnly": true
}
],
"localStorage": [
{
"origin": "https://myapp.com",
"items": [
{ "name": "access_token", "value": "eyJhbGciOiJIUzI1NiIs..." },
{ "name": "user_id", "value": "usr_abc123" }
]
}
]
}
}
Step 1 — Extract your session
Log into your app in Chrome, then open DevTools (F12) and paste this snippet into the Console tab. It extracts your cookies and localStorage into the exact authState format and copies it to your clipboard.
(function() {
var origin = location.origin;
var cookies = document.cookie.split(';').filter(Boolean).map(function(c) {
var parts = c.trim().split('=');
var name = parts[0].trim();
var value = parts.slice(1).join('=').trim();
return { name: name, value: value, domain: location.hostname };
});
var lsItems = Object.keys(localStorage).map(function(k) {
return { name: k, value: localStorage.getItem(k) };
});
var authState = {
cookies: cookies,
localStorage: [{ origin: origin, items: lsItems }]
};
var json = JSON.stringify({ authState: authState }, null, 2);
console.log(json);
try { copy(json); console.log('%c✓ Copied to clipboard', 'color: #4ade80'); }
catch(e) { console.log('%c↑ Copy the JSON above', 'color: #facc15'); }
})();
HttpOnly cookies by design. If your app uses only HttpOnly session cookies, use the Pagebolt Chrome extension instead — it has access to all cookies including HttpOnly ones.
Step 2 — Pass it to the API
const res = await fetch('https://pagebolt.dev/api/v1/video', {
method: 'POST',
headers: {
'x-api-key': process.env.PAGEBOLT_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
steps: [
{ action: 'navigate', url: 'https://myapp.com/dashboard' },
{ action: 'click', selector: '.sidebar-nav-reports', note: 'Open reports' },
{ action: 'scroll', y: 400 },
],
authState: {
cookies: [
{ name: 'session_id', value: 'abc123xyz', domain: 'myapp.com' }
],
localStorage: [
{
origin: 'https://myapp.com',
items: [
{ name: 'access_token', value: 'eyJhbGciOiJIUzI1NiIs...' }
]
}
]
},
format: 'mp4',
pace: 'slow',
cursor: { style: 'highlight' },
}),
});
const result = await res.json();
// result.data is base64-encoded MP4
Using the Chrome extension
The Pagebolt Chrome extension has a Capture Auth button in its side panel. Click it while on your logged-in app and your full session state — including HttpOnly cookies — is captured automatically and included in every recording you make from the extension.
/v1/screenshot
Convenience endpoint — pass all parameters as query strings. Ideal for embedding in <img> tags or opening directly in a browser.
url parameter is required. Booleans are "true" / "false" strings. Array params like hideSelectors can be repeated (e.g. hideSelectors=.ad&hideSelectors=.banner).
curl -H "x-api-key: pf_live_your_key" \
"https://pagebolt.dev/api/v1/screenshot?\
url=https://my-saas.com&\
viewportDevice=iphone_14_pro&\
blockBanners=true&\
blockAds=true&\
format=webp" \
-o my-saas-mobile.webp
Signed Embed Screenshot URLs
Generate HMAC-signed URLs that render a screenshot and can be placed directly in an <img> tag — no backend proxy required. Starter plan and above.
The signature binds all parameters — changing any part of the URL invalidates it. Expiry is enforced server-side (max 7 days).
POST /dashboard/sign-screenshot from your backend to get a signed URL. Embed that URL in your HTML. When the browser loads the image, PageBolt verifies the signature and serves the screenshot — your API key is never exposed to the browser.
Step 1 — Generate the signed URL (server-side)
curl -X POST https://pagebolt.dev/dashboard/sign-screenshot \
-H "Authorization: Bearer YOUR_JWT_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"params": {
"url": "https://example.com",
"fullPage": "true",
"blockBanners": "true",
"format": "png"
},
"expiry_hours": 24
}'
Response
{
"url": "https://pagebolt.dev/api/v1/embed/screenshot?url=https%3A%2F%2Fexample.com&fullPage=true&blockBanners=true&format=png&_key=pf_live_abc123&_exp=1740528000&_sig=a3f9e2...",
"expires_at": "2026-02-26T12:00:00.000Z",
"key_prefix": "pf_live_abc123"
}
Step 2 — Embed in HTML
<img src="https://pagebolt.dev/api/v1/embed/screenshot?url=...&_key=...&_exp=...&_sig=..." alt="Screenshot" />
Parameters
| Field | Type | Description |
|---|---|---|
| params | object | Screenshot parameters. url is required. Same options as POST /screenshot (all values as strings). |
| expiry_hours | number | How long the URL is valid. Default: 24. Max: 168 (7 days). |
/v1/style
NEWApply styling (frame, background, shadow, theme) to an existing screenshot image. Accepts a base64-encoded image and returns the styled result. Does not count toward your monthly quota — this endpoint performs image processing only, no browser rendering.
curl -X POST https://pagebolt.dev/api/v1/style \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image": "iVBORw0KGgo...base64-encoded-screenshot...",
"format": "png",
"style": {
"theme": "ocean"
}
}'
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
image | string | Yes | Base64-encoded image data (PNG, JPEG, or WebP). Max 10MB. |
format | string | No | Output format: png, jpeg, webp. Default: png |
style | object | Yes | Style configuration. Use theme for presets, or set individual properties. |
style.theme | string | No | Theme preset name: notion, ocean, sunset, linear, arc, etc. See Screenshot API for full list. |
style.frame | string | No | macos, windows, minimal, or none |
style.background | string | No | Background preset: ocean, sunset, glass, solid, dots, grid, etc. |
style.shadow | string | No | none, xs, sm, md, lg, xl, 2xl |
style.padding | integer | No | Padding in pixels (0–120). Default: 40 |
style.borderRadius | integer | No | Corner radius in pixels (0–40). Default: 12 |
style.bgColor | string | No | Hex color for solid background, e.g. #1e3a5f |
response_type | string | No | json returns base64 JSON. Default: binary image. |
Response
Binary image by default. If response_type: "json":
{
"data": "iVBORw0KGgo...base64...",
"format": "png",
"content_type": "image/png",
"size_bytes": 245120,
"duration_ms": 340
}
/v1/pdf
Generate a PDF from a URL or HTML content. Returns the PDF as binary data.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| url | string | — | URL to render (required if no html) |
| html | string | — | Raw HTML to render (required if no url) |
| format | string | A4 | Paper format: A4, Letter, Legal, Tabloid |
| landscape | boolean | false | Landscape orientation |
| printBackground | boolean | true | Include CSS backgrounds |
| margin | string | — | CSS margin for all sides (e.g. "1cm") |
| margins | object | — | {top, right, bottom, left} in CSS units |
| displayHeaderFooter | boolean | false | Show header and footer |
| headerTemplate | string | — | HTML template for header |
| footerTemplate | string | — | HTML template for footer |
| scale | number | 1 | Rendering scale (0.1–2) |
| pageRanges | string | — | e.g. "1-5, 8" |
| width | integer | — | Viewport width for rendering |
| delay | integer | 0 | Wait ms before rendering (max 10000) |
| response_type | string | binary | Set to "json" for base64 response |
Example 8: Generate an invoice PDF
curl -X POST https://pagebolt.dev/api/v1/pdf \
-H "x-api-key: pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"html": "<h1>Invoice #1234</h1><p>Amount: $99.00</p>",
"format": "A4",
"margin": "2cm",
"printBackground": true,
"displayHeaderFooter": true,
"footerTemplate": "<div style=\"font-size:10px;text-align:center;width:100%\">Page <span class=\"pageNumber\"></span> of <span class=\"totalPages\"></span></div>"
}' \
-o invoice.pdf
/v1/og-image
Generate dynamic Open Graph / social card images. Use built-in templates or provide custom HTML.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| template | string | default | default, minimal, or gradient |
| html | string | — | Custom HTML template (overrides template) |
| title | string | — | Main title text |
| subtitle | string | — | Subtitle text |
| logo | string | — | Logo image URL |
| bgColor | string | #0f172a | Background color (hex) |
| textColor | string | #f8fafc | Text color (hex) |
| accentColor | string | #6366f1 | Accent color (hex) |
| bgImage | string | — | Background image URL |
| width | integer | 1200 | Image width (max 2400) |
| height | integer | 630 | Image height (max 1260) |
| format | string | png | png, jpeg, or webp |
| response_type | string | binary | Set to "json" for base64 response |
Example 9: Create a social card
curl -X POST https://pagebolt.dev/api/v1/og-image \
-H "x-api-key: pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"template": "gradient",
"title": "How to Build a SaaS in 2026",
"subtitle": "A practical guide for solo founders",
"accentColor": "#8b5cf6",
"bgColor": "#1e1b4b",
"logo": "https://mysite.com/logo.png"
}' \
-o social-card.png
/v1/sequence
NewExecute a multi-step browser automation sequence. Navigate pages, interact with elements (click, fill forms, scroll), and capture multiple screenshots and PDFs in a single browser session. Local URLs are not supported — Puppeteer runs on our servers, not yours. To record a local dev server, expose it first with ngrok http 3000 and use the public ngrok URL.
Top-Level Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| steps | array | — | Required. Array of step objects (max 20) |
| viewport | object | — | {width, height} — default 1280×720 |
| darkMode | boolean | false | Emulate dark color scheme |
| blockBanners | boolean | false | Auto-hide cookie consent banners |
| deviceScaleFactor | number | 1 | Pixel ratio (max 3, use 2 for retina) |
Available Actions
| Action | Required Fields | Description |
|---|---|---|
| navigate | url | Go to a URL (http/https only) |
| click | selector | Click an element by CSS selector |
| fill | selector, value | Clear and type into an input field |
| select | selector, value | Select a dropdown option by value |
| hover | selector | Hover over an element (reveals tooltips, dropdowns) |
| scroll | selector or x, y | Scroll to element or absolute position |
| wait | ms | Wait fixed milliseconds (max 10000) |
| wait_for | selector | Wait for element to appear and become visible (optional timeout, max 15s) |
| evaluate | script | Run JavaScript in page context (max 5000 chars, max 2 per sequence) |
| screenshot | name | Capture current state. Optional: format, fullPage, quality, selector, style |
| name | Generate PDF. Optional: format (A4, Letter, Legal, Tabloid, A3, A5), landscape, margin, scale |
style object to any screenshot step to apply post-capture styling (frames, backgrounds, shadows, themes). Uses the same options as the Screenshot API style parameter. Example: { "action": "screenshot", "name": "hero", "style": { "theme": "ocean" } }
Example 10: Capture a login flow
curl -X POST https://pagebolt.dev/api/v1/sequence \
-H "x-api-key: pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"steps": [
{"action": "navigate", "url": "https://example.com/login"},
{"action": "screenshot", "name": "login-page"},
{"action": "fill", "selector": "#email", "value": "user@example.com"},
{"action": "fill", "selector": "#password", "value": "demo123"},
{"action": "click", "selector": "button[type=submit]"},
{"action": "wait_for", "selector": ".dashboard", "timeout": 5000},
{"action": "screenshot", "name": "dashboard", "fullPage": true}
],
"viewport": {"width": 1440, "height": 900},
"blockBanners": true
}'
Response
{
"outputs": [
{
"name": "login-page",
"type": "screenshot",
"format": "png",
"content_type": "image/png",
"data": "iVBORw0KGgo...",
"size_bytes": 145832,
"step_index": 1,
"duration_ms": 342
},
{
"name": "dashboard",
"type": "screenshot",
"format": "png",
"content_type": "image/png",
"data": "iVBORw0KGgo...",
"size_bytes": 287654,
"step_index": 6,
"duration_ms": 521
}
],
"step_results": [
{"step_index": 0, "action": "navigate", "status": "ok", "duration_ms": 2341},
{"step_index": 1, "action": "screenshot", "status": "ok", "name": "login-page", "duration_ms": 342},
{"step_index": 2, "action": "fill", "status": "ok", "duration_ms": 87},
{"step_index": 3, "action": "fill", "status": "ok", "duration_ms": 92},
{"step_index": 4, "action": "click", "status": "ok", "duration_ms": 45},
{"step_index": 5, "action": "wait_for", "status": "ok", "duration_ms": 1823},
{"step_index": 6, "action": "screenshot", "status": "ok", "name": "dashboard", "duration_ms": 521}
],
"steps_completed": 7,
"total_steps": 7,
"total_duration_ms": 5251,
"usage": {
"outputs_charged": 2,
"remaining": 4998
}
}
/v1/video
NewRecord a professional demo video of multi-step browser automation with cursor highlighting and click effects. Each video costs 3 API requests. Local URLs are not supported — Puppeteer runs on our servers, not yours. To record a local dev server, expose it first with ngrok http 3000 and use the public ngrok URL.
Top-Level Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| steps | array | — | Required. Array of step objects (same actions as sequence, except no screenshot/pdf) |
| viewport | object | — | {width, height} — default 1280×720 |
| format | string | mp4 | mp4, webm, or gif |
| framerate | number | 30 | Frames per second: 24, 30, or 60 |
| darkMode | boolean | false | Emulate dark color scheme |
| blockBanners | boolean | true | Auto-hide cookie consent banners |
| deviceScaleFactor | number | 1 | Pixel ratio 1–3 (use 2 for retina) |
| pace | number | string | 1.0 | Controls video speed. Number 0.25–6.0 (higher = slower/more deliberate) or preset: "fast" (0.5×), "normal" (1×), "slow" (2×), "dramatic" (3×), "cinematic" (4.5×). Scales cursor movement, pauses between steps, typing speed, and all cosmetic delays. |
| response_type | string | binary | Set to "json" for base64-encoded response with metadata |
Cursor Options
| Parameter | Type | Default | Description |
|---|---|---|---|
| cursor.visible | boolean | true | Show animated cursor in the recording |
| cursor.style | string | highlight | highlight, circle, spotlight, dot, or classic NEW |
| cursor.color | string | #3B82F6 | Cursor color (hex) |
| cursor.size | number | 20 | Cursor size in pixels (8–60) |
| cursor.smoothing | boolean | true | Smooth cursor movement between actions |
| cursor.opacity | number | 1.0 | Cursor opacity (0.1–1.0) |
| cursor.persist | boolean | false | Keep cursor visible between actions instead of fading out NEW |
Zoom Options
| Parameter | Type | Default | Description |
|---|---|---|---|
Per-step zoom — Add a zoom object to individual click/dblclick steps to zoom into that specific action.
{ "action": "click", "selector": "#btn", "zoom": { "enabled": true, "level": 1.5 } }
| |||
Click Effect Options
| Parameter | Type | Default | Description |
|---|---|---|---|
| clickEffect.enabled | boolean | true | Show visual feedback on clicks |
| clickEffect.style | string | ripple | ripple, pulse, or ring |
| clickEffect.color | string | cursor color | Click effect color (hex) — defaults to cursor.color |
Frame Options NEW
| Parameter | Type | Default | Description |
|---|---|---|---|
| frame.enabled | boolean | false | Add browser window frame chrome overlay |
| frame.style | string | macos | macos, windows, or minimal |
| frame.theme | string | auto | light, dark, or auto (matches darkMode) |
| frame.showUrl | boolean | true | Show the current URL in the frame’s address bar |
Background Options NEW
| Parameter | Type | Default | Description |
|---|---|---|---|
| background.enabled | boolean | false | Add a decorative background behind the browser viewport |
| background.type | string | gradient | gradient or solid |
| background.gradient | string | ocean | Preset: ocean, sunset, forest, midnight, aurora, or custom |
| background.color | string | #1e3a5f | Background color for solid type (hex) |
| background.colors | array | — | Array of 2 hex colors for custom gradient |
| background.padding | number | 40 | Padding around viewport in pixels (0–120) |
| background.borderRadius | number | 12 | Border radius of viewport in pixels (0–40) |
Audio Guide Options NEW
Add AI-generated narration to your demo videos. Two modes are available:
Per-step mode (default) — Add narration text to individual steps. Each clip is spoken before the action executes.
Script mode — Provide a single audioGuide.script with {{N}} step markers for continuous narration. Steps execute when the narration reaches each marker, creating a natural flow. Example: "Welcome to our app. {{1}} Here are the features. {{2}} Click to get started."
| Parameter | Type | Default | Description |
|---|---|---|---|
| audioGuide.enabled | boolean | false | Enable Audio Guide narration |
| audioGuide.provider | string | azure | TTS provider: azure or openai |
| audioGuide.voice | string | ava | Voice preset name (see list below) |
| audioGuide.speed | number | 1.0 | Speech rate (0.5–2.0) |
| audioGuide.pitch | string | default | Voice pitch (Azure only) |
| audioGuide.volume | string | default | Audio volume (Azure only) |
| audioGuide.style | string | — | Speaking style (Azure only): narration-professional, cheerful, etc. |
| audioGuide.styleDegree | number | 1.0 | Style intensity (Azure only, 0.01–2.0) |
| audioGuide.model | string | tts-1 | OpenAI model (OpenAI only) |
| audioGuide.script | string | — | Script mode narration. A single text with {{N}} step markers (0-indexed). When provided, per-step narration fields are ignored. Max 5000 chars. |
Available Voices
| Provider | Voice | Gender |
|---|---|---|
| Azure | ava | Female |
| andrew | Male | |
| emma | Female | |
| brian | Male | |
| aria | Female | |
| guy | Male | |
| jenny | Female | |
| davis | Male | |
| christopher | Male | |
| michelle | Female | |
| OpenAI | alloy | Neutral |
| echo | Male | |
| fable | Neutral | |
| nova | Female | |
| onyx | Male | |
| shimmer | Female |
Available Actions
| Action | Required Fields | Description |
|---|---|---|
| navigate | url | Go to a URL (http/https only) |
| click | selector | Click an element by CSS selector |
| dblclick | selector | Double-click an element by CSS selector |
| fill | selector, value | Clear and type into an input field |
| select | selector, value | Select a dropdown option by value |
| hover | selector | Hover over an element (reveals tooltips, dropdowns) |
| scroll | selector or x, y | Scroll to element or absolute position |
| wait | ms | Wait fixed milliseconds (max 10000). Add live: true to capture animated content. |
| wait_for | selector | Wait for element to appear and become visible (optional timeout, max 15s) |
| evaluate | script | Run JavaScript in page context (max 5000 chars, max 2 per sequence) |
Step Notes and Narration NEW
Add a note string to any step to display a text overlay in the video — perfect for guided product tours, onboarding walkthroughs, and tutorial videos. The note appears as a styled callout near the target element before the action executes. Use narration with audioGuide.enabled for spoken voice-over on each step.
| Parameter | Type | Max Length | Description |
|---|---|---|---|
| note | string | 500 chars | Optional. Text overlay displayed before the action executes. Available on navigate, click, dblclick, fill, hover, and scroll actions. |
| narration | string | 500 chars | Optional. TTS narration spoken before the action when audioGuide.enabled is true. Available on same actions as note. |
Plan Limits
| Plan | Base + Per-Step Budget | Max Steps | Formats |
|---|---|---|---|
| Free | 20s + 5s/step | 10 | mp4 |
| Starter | 30s + 5s/step | 20 | mp4, webm |
| Growth | 45s + 6s/step | 30 | mp4, webm, gif |
| Scale | 60s + 6s/step | 50 | mp4, webm, gif |
base + (steps × per-step budget × pace). Using pace: "slow", pace: "dramatic", or pace: "cinematic" automatically extends the allowed recording time so your video doesn't time out.
Example: Record a guided demo video
curl -X POST https://pagebolt.dev/api/v1/video \
-H "x-api-key: pf_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"steps": [
{ "action": "navigate", "url": "https://pagebolt.dev" },
{ "action": "scroll", "selector": "#pricing" },
{ "action": "wait", "ms": 3000 },
{ "action": "click", "selector": "#get-started",
"note": "Click here to sign up for PageBolt" }
],
"viewport": { "width": 1280, "height": 800 },
"format": "mp4",
"blockBanners": true,
"pace": "normal",
"cursor": { "style": "highlight", "color": "#3B82F6", "persist": true },
"clickEffect": { "enabled": true, "style": "ripple" },
"frame": { "enabled": true, "style": "macos", "showUrl": true },
"background": {
"enabled": true, "type": "gradient", "padding": 120,
"borderRadius": 12, "gradient": "sunset"
}
}' \
-o demo.mp4
Example: Record a demo video with Audio Guide
curl -X POST https://pagebolt.dev/api/v1/video \
-H "x-api-key: pf_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"steps": [
{ "action": "navigate", "url": "https://pagebolt.dev",
"narration": "Welcome to PageBolt, the screenshot and automation API." },
{ "action": "scroll", "selector": "#pricing",
"narration": "Let me show you our pricing plans." },
{ "action": "click", "selector": "#get-started",
"note": "Click here to sign up",
"narration": "Click Get Started to create your free account." }
],
"viewport": { "width": 1280, "height": 800 },
"format": "mp4",
"blockBanners": true,
"pace": "normal",
"audioGuide": {
"enabled": true,
"provider": "azure",
"voice": "ava",
"speed": 1.0
}
}' \
-o demo-with-narration.mp4
Example: Script Mode — continuous narration with step markers
curl -X POST https://pagebolt.dev/api/v1/video \
-H "x-api-key: pf_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"steps": [
{ "action": "navigate", "url": "https://pagebolt.dev" },
{ "action": "scroll", "selector": "#features" },
{ "action": "click", "selector": "#tab-python" },
{ "action": "scroll", "selector": "#pricing" },
{ "action": "click", "selector": "#get-started" }
],
"viewport": { "width": 1280, "height": 800 },
"format": "mp4",
"blockBanners": true,
"audioGuide": {
"enabled": true,
"provider": "azure",
"voice": "ava",
"script": "Welcome to PageBolt — the web capture API. {{1}} Here are the core features — screenshots, PDFs, video recording, and more. {{2}} And it works in any language — here is the Python example. {{3}} Pricing is simple and transparent — start free. {{4}} Click here to get your free API key."
}
}' \
-o demo-script-mode.mp4
In script mode, the narration is synthesized as a single continuous audio track. Step markers {{N}} (0-indexed) tell the video engine when to execute each step, synchronized to the narration timing. Steps not referenced by a marker still execute at their natural position.
JSON Response (when response_type=json)
{
"data": "base64...",
"format": "mp4",
"content_type": "video/mp4",
"size_bytes": 2457600,
"duration_ms": 12400,
"frames": 372,
"steps_completed": 5,
"total_steps": 5,
"step_results": [
{"step_index": 0, "action": "navigate", "status": "ok", "duration_ms": 2341},
{"step_index": 1, "action": "click", "status": "ok", "duration_ms": 512},
{"step_index": 2, "action": "fill", "status": "ok", "duration_ms": 1087},
{"step_index": 3, "action": "click", "status": "ok", "duration_ms": 445},
{"step_index": 4, "action": "wait", "status": "ok", "duration_ms": 2000}
],
"usage": {
"video_cost": 3,
"remaining": 4847
}
}
Content-Type header (video/mp4, video/webm, or image/gif). Status 200 on success.
/v1/inspect
NewInspect a web page and get a structured map of all interactive elements, headings, forms, links, and images — each with a unique CSS selector ready for use with /v1/sequence. Returns compact JSON optimized for AI agents.
/v1/sequence to discover what elements exist on a page and get reliable CSS selectors. Returns text (2-15 KB) instead of an image, saving tokens and improving accuracy.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| url | string | — | Required (if no html). URL to inspect. |
| html | string | — | Raw HTML to inspect (alternative to url). |
| width | integer | 1280 | Viewport width in pixels (1–3840). |
| height | integer | 720 | Viewport height in pixels (1–2160). |
| viewportDevice | string | — | Device preset (e.g. "iphone_14_pro"). See /devices. |
| darkMode | boolean | false | Emulate dark color scheme. |
| waitUntil | string | networkidle2 | load, domcontentloaded, networkidle0, networkidle2. |
| waitForSelector | string | — | Wait for this CSS selector before inspecting. |
| cookies | array | — | Array of "name=value" strings or {name, value, domain?} objects. |
| headers | object | — | Extra HTTP headers. |
| authorization | string | — | Authorization header value. |
| authState | object | — | Full browser auth state (cookies + localStorage). See Authenticated Recording. |
| userAgent | string | — | Override the browser User-Agent. |
| blockBanners | boolean | false | Hide cookie consent banners. |
| blockAds | boolean | false | Block advertisements. |
| blockChats | boolean | false | Block live chat widgets. |
| blockTrackers | boolean | false | Block tracking scripts. |
| bypassCSP | boolean | false | Bypass Content-Security-Policy. |
| hideSelectors | array | — | CSS selectors to hide before inspecting. |
| injectCss | string | — | Custom CSS to inject. |
| injectJs | string | — | Custom JavaScript to execute before inspecting. |
Response
Always returns JSON with the following structure:
{
"url": "https://example.com",
"title": "Example Page",
"metadata": {
"description": "Page description",
"ogTitle": "OG Title",
"lang": "en",
"httpStatusCode": 200
},
"elements": [
{
"tag": "button",
"role": "button",
"text": "Sign Up",
"selector": "#signup-btn",
"attributes": { "id": "signup-btn", "type": "submit" },
"rect": { "x": 120, "y": 340, "width": 160, "height": 40 }
},
{
"tag": "input",
"role": "input",
"text": "",
"selector": "input[name='email']",
"attributes": { "type": "email", "name": "email", "placeholder": "Enter email" },
"rect": { "x": 20, "y": 280, "width": 300, "height": 36 }
}
],
"headings": [
{ "level": 1, "text": "Welcome", "selector": "h1" }
],
"forms": [
{ "selector": "form#signup", "action": "/signup", "method": "POST",
"fields": ["input[name='email']", "input[name='password']"] }
],
"links": [
{ "text": "About", "href": "/about", "selector": "nav a[href='/about']" }
],
"images": [
{ "alt": "Logo", "src": "/logo.png", "selector": "img[alt='Logo']",
"rect": { "x": 10, "y": 10, "width": 120, "height": 40 } }
],
"duration_ms": 1234
}
cURL Example
curl -X POST https://pagebolt.dev/api/v1/inspect \
-H "x-api-key: pf_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"blockBanners": true
}'
/v1/sequence for reliable browser automation — inspect first, then interact using the returned selectors.
Persistent Browser Sessions NEW
Sessions let you keep a browser page alive across multiple API calls. Cookies, localStorage, and authentication state persist between requests — useful for multi-step agent workflows that need to log in once and then interact with authenticated pages repeatedly.
403.Important: Sessions are in-memory only. They do not survive server restarts. Build your workflows to handle a missing session gracefully (catch the
404 and re-authenticate).
Limits
| Limit | Value | Notes |
|---|---|---|
| Max concurrent sessions (global) | 3 | Shared across all users. Returns 503 if full. |
| Max sessions per API key | 2 | Returns 429 if exceeded. |
| Inactivity timeout | 10 minutes | Resets on each request that uses the session. |
| Hard cap | 30 minutes | Absolute maximum regardless of activity. |
Example: Log in once, screenshot multiple pages
# 1. Create a session
SESSION=$(curl -s -X POST https://pagebolt.dev/api/v1/sessions \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{}' | jq -r .session_id)
# 2. Log in (auth cookies are now stored in the session)
curl -s -X POST https://pagebolt.dev/api/v1/sequence \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"session_id\": \"$SESSION\",
\"steps\": [
{\"action\": \"navigate\", \"url\": \"https://app.example.com/login\"},
{\"action\": \"fill\", \"selector\": \"#email\", \"value\": \"user@example.com\"},
{\"action\": \"fill\", \"selector\": \"#password\", \"value\": \"hunter2\"},
{\"action\": \"click\", \"selector\": \"button[type=submit]\"},
{\"action\": \"screenshot\", \"name\": \"logged-in\"}
]
}" > /dev/null
# 3. Take screenshots of authenticated pages (session still alive)
curl -X POST https://pagebolt.dev/api/v1/screenshot \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"session_id\": \"$SESSION\", \"url\": \"https://app.example.com/dashboard\"}" \
-o dashboard.png
# 4. Clean up when done
curl -X DELETE https://pagebolt.dev/api/v1/sessions/$SESSION \
-H "x-api-key: YOUR_API_KEY"
/v1/sessions
NewCreate a new persistent browser session. Returns a session_id you can pass to /screenshot and /sequence requests.
Request body
| Parameter | Type | Default | Description |
|---|---|---|---|
| cookies | array | — | Optional. Array of cookie objects to pre-set on the session page before any navigation. |
| viewport | object | 1280×720 | Optional. { "width": 1280, "height": 720 } |
| stealth | boolean | false | Optional. Use puppeteer-extra stealth plugin for this session. Stealth sessions get their own isolated browser instance. |
Response
{
"session_id": "sess_a1b2c3d4e5f6g7h8i9j0k1l2",
"expires_at": "2026-02-23T10:30:00.000Z",
"expires_in_seconds": 600,
"note": "Sessions expire after 10 minutes of inactivity. They do not persist across server restarts."
}
/v1/sessions
List all active sessions owned by the current API key, with idle time and remaining TTL for each.
Response
{
"sessions": [
{
"session_id": "sess_a1b2c3d4e5f6g7h8i9j0k1l2",
"created_at": "2026-02-23T10:20:00.000Z",
"expires_at": "2026-02-23T10:32:15.000Z",
"idle_seconds": 45,
"expires_in_seconds": 555
}
],
"count": 1
}
/v1/sessions/:id
Destroy a session immediately, releasing the browser page. Returns 204 No Content on success, or 404 if the session has already expired or belongs to a different key.
Always destroy sessions when your workflow is complete rather than waiting for the inactivity timeout to free the slot.
/v1/usage
Check your current usage and plan limits programmatically. No parameters needed.
curl https://pagebolt.dev/api/v1/usage \
-H "x-api-key: pf_live_your_key"
Response
{
"plan": "starter",
"usage": {
"current": 1247,
"limit": 5000,
"remaining": 3753
}
}
/v1/devices
NewReturns the list of available device presets for the viewportDevice parameter. No parameters needed.
curl https://pagebolt.dev/api/v1/devices \
-H "x-api-key: pf_live_your_key"
Response (excerpt)
{
"devices": [
{"id": "iphone_se", "name": "iPhone SE", "width": 375, "height": 667, "deviceScaleFactor": 2, "mobile": true},
{"id": "iphone_14_pro", "name": "iPhone 14 Pro", "width": 393, "height": 852, "deviceScaleFactor": 3, "mobile": true},
{"id": "iphone_15_pro_max", "name": "iPhone 15 Pro Max", "width": 430, "height": 932, "deviceScaleFactor": 3, "mobile": true},
{"id": "ipad_pro_12", "name": "iPad Pro 12.9\"", "width": 1024, "height": 1366, "deviceScaleFactor": 2, "mobile": true},
{"id": "pixel_8_pro", "name": "Google Pixel 8 Pro", "width": 412, "height": 915, "deviceScaleFactor": 3.5, "mobile": true},
{"id": "galaxy_s24_ultra", "name": "Galaxy S24 Ultra", "width": 412, "height": 915, "deviceScaleFactor": 3.5, "mobile": true},
{"id": "macbook_pro_14", "name": "MacBook Pro 14\"", "width": 1512, "height": 982, "deviceScaleFactor": 2, "mobile": false},
{"id": "desktop_4k", "name": "Desktop 4K", "width": 3840, "height": 2160, "deviceScaleFactor": 1, "mobile": false}
]
}
id value as the viewportDevice parameter.
MCP Server (AI Agent Integration)
PageBolt includes a built-in Model Context Protocol (MCP) server that lets AI coding assistants call the PageBolt API directly. Say "take a screenshot of example.com" in your IDE and get the result inline.
Available Tools
| Tool | Description |
|---|---|
| take_screenshot | Capture a screenshot of a URL, HTML, or Markdown. Returns an inline image. Supports all 50+ screenshot parameters. |
| generate_pdf | Generate a PDF from a URL or HTML. Saves to disk and returns the file path. |
| create_og_image | Create an OG/social card image from templates or custom HTML. Returns an inline image. |
| run_sequence | Execute a multi-step browser automation sequence with multiple outputs. |
| record_video | Record a demo video of browser automation with cursor effects, click highlighting, step notes, and Audio Guide narration. Saves to disk. Costs 3 requests. NEW |
| inspect_page | Inspect a page and get a structured map of interactive elements with CSS selectors. Use before run_sequence. |
| list_devices | List all available device presets for viewport emulation. |
| check_usage | Check your current API usage and plan limits. |
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
| PAGEBOLT_API_KEY | Yes | — | Your PageBolt API key (from the Dashboard) |
| PAGEBOLT_BASE_URL | No | https://pagebolt.dev | PageBolt API URL. Override for self-hosted instances. |
Example 11: Claude Desktop / Cursor config
Add this to your Claude Desktop config (~/.claude/claude_desktop_config.json) or Cursor MCP config (.cursor/mcp.json):
{
"mcpServers": {
"pagebolt": {
"command": "npx",
"args": ["-y", "pagebolt-mcp"],
"env": {
"PAGEBOLT_API_KEY": "pf_live_your_key_here"
}
}
}
}
Example Prompts
Once configured, you can ask your AI agent things like:
CI / CD Integration
NEWAutomatically generate polished demo videos from pull requests. An AI agent reads your PR diff, inspects the deployed preview, and records a video showing the feature in action — then posts it as a PR comment. No config files or scripts required.
Requirements
| Requirement | Details |
|---|---|
| PageBolt API key | Get one free at pagebolt.dev/dashboard |
| AI provider API key | Anthropic (Claude) or OpenAI (GPT-4o). The agent uses tool-calling to inspect and record. |
| Preview deployment | A publicly accessible URL for the PR (e.g. Vercel preview, Netlify deploy preview, or any staging URL). |
GitHub Action
The simplest way to add demo videos to your PRs. Add this workflow file to your repository:
Basic Setup (Vercel)
name: PageBolt Demo Video
on:
pull_request:
types: [opened, synchronize]
jobs:
demo-video:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Wait for Vercel preview
uses: patrickedqvist/wait-for-vercel-preview@v1.3.2
id: preview
with:
token: ${{ secrets.GITHUB_TOKEN }}
max_timeout: 300
- name: Record demo video
uses: Custodia-Admin/pagebolt/ci/action@main
with:
api-key: ${{ secrets.PAGEBOLT_API_KEY }}
ai-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
preview-url: ${{ steps.preview.outputs.url }}
Action Inputs
| Input | Required | Default | Description |
|---|---|---|---|
| api-key | Yes | — | Your PageBolt API key |
| ai-api-key | Yes | — | Anthropic or OpenAI API key for the AI agent |
| preview-url | Yes | — | Preview deployment URL for this PR |
| ai-provider | No | anthropic | AI provider: anthropic or openai |
| ai-model | No | auto | Override the AI model (e.g. claude-sonnet-4-20250514) |
| spec-dir | No | .pagebolt/demos | Path to YAML demo spec files (optional, for non-agent mode) |
| output-dir | No | ./pagebolt-artifacts | Directory to save video artifacts |
| github-token | No | github.token | GitHub token for posting PR comments |
| verbose | No | false | Enable verbose logging |
Action Outputs
| Output | Description |
|---|---|
| results-json | JSON string of all recording results |
| artifact-dir | Path to directory containing video artifacts |
| videos-recorded | Number of videos successfully recorded |
Netlify Example
name: PageBolt Demo Video
on:
deployment_status:
jobs:
demo-video:
if: github.event.deployment_status.state == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Record demo video
uses: Custodia-Admin/pagebolt/ci/action@main
with:
api-key: ${{ secrets.PAGEBOLT_API_KEY }}
ai-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
preview-url: ${{ github.event.deployment_status.target_url }}
CLI Reference
Use pagebolt-ci directly for local testing or non-GitHub CI systems.
Installation
npm install -g pagebolt-ci
# Or use npx without installing:
npx pagebolt-ci run --api-key pf_live_... --preview-url https://preview.example.com
Commands
pagebolt-ci run
Record demo videos. Automatically chooses between spec-based mode (if .pagebolt/demos/*.yml files exist) and autonomous agent mode.
| Flag | Description |
|---|---|
| --api-key | PageBolt API key (or set PAGEBOLT_API_KEY) |
| --preview-url | URL of the preview deployment to record |
| --ai-provider | anthropic or openai |
| --ai-api-key | API key for the AI provider |
| --ai-model | Override AI model (e.g. claude-sonnet-4-20250514) |
| --pr-title | PR title (passed to the agent for context) |
| --pr-description | PR description / body (helps the agent understand the feature) |
| --output-dir | Directory for video output (default: ./pagebolt-artifacts) |
| --base-url | PageBolt API base URL (default: https://pagebolt.dev) |
| --verbose | Enable verbose logging |
Example: Agent Mode
pagebolt-ci run \
--api-key pf_live_your_key \
--ai-provider anthropic \
--ai-api-key sk-ant-your_key \
--preview-url https://preview-abc123.vercel.app \
--pr-title "feat: Add user onboarding flow" \
--output-dir ./demo-videos \
--verbose
pagebolt-ci comment
Post or update a PR comment with recording results. Usually called automatically by the GitHub Action after run completes.
| Flag | Description |
|---|---|
| --github-token | GitHub token with PR comment permissions |
| --repo | Repository in owner/repo format |
| --pr-number | PR number to comment on |
| --results-file | Path to _results.json from the run command |
Agent Mode (Zero-Config)
When no spec files are found in .pagebolt/demos/, the CLI automatically enters Agent Mode. An AI agent (Claude or GPT-4o) autonomously:
- Reads the PR title, description, and diff to understand the feature
- Calls
inspect_pageon the preview URL to discover interactive elements - Plans a demo flow — which buttons to click, which inputs to fill, what sequence tells the best story
- Calls
record_videowith the planned steps, producing a polished MP4
inspect_page (discover page elements) and record_video (record a demo). It uses up to 15 turns of reasoning to plan and execute the recording.
Video Settings
Agent-recorded videos automatically include polished defaults:
| Setting | Default |
|---|---|
| Cursor | Classic pointer, always visible, smooth movement |
| Frame | macOS dark window chrome |
| Background | Gradient with 120px padding and 40px border radius |
| Click effects | Ripple effect on every click |
| Pace | Normal (1x) |
| Step notes | Tooltip annotations on every meaningful step |
| Blocking | Ads, banners, chat widgets, and trackers blocked |
Supported AI Providers
| Provider | Recommended Model | Notes |
|---|---|---|
| anthropic | claude-sonnet-4-20250514 | Best results. Excellent tool-calling and planning. |
| openai | gpt-4o | Good alternative. Supports function calling. |
Spec-Based Mode (Optional)
For deterministic recordings (no AI), create YAML spec files in .pagebolt/demos/:
name: Onboarding Flow
description: Demo of the new user onboarding experience
triggers:
paths:
- src/components/onboarding/**
- src/pages/welcome.*
viewport:
width: 1280
height: 720
steps:
- action: navigate
url: "{{preview_url}}/welcome"
note: Opening the welcome page
- action: wait
ms: 1500
- action: click
selector: "#get-started-btn"
note: Click Get Started
- action: fill
selector: "#company-name"
value: Acme Corp
note: Enter company name
- action: click
selector: "#continue-btn"
note: Continue to next step
When spec files exist and match changed files in the PR, spec-based mode takes priority over agent mode. Use {{preview_url}} as a variable placeholder that resolves to the PR's preview deployment URL.
FAQ
Common questions about PageBolt's API behaviour.
Can I capture a local dev server (localhost)?
Not directly. Puppeteer runs on PageBolt's servers — not on your machine — so URLs like
http://localhost:3000 or
http://127.0.0.1:8080 resolve to
our server's loopback, not yours. Private IP ranges are also blocked as an SSRF safeguard.
The fix is to expose your local server with a tunnel, then pass the public URL to PageBolt:
# ngrok (most common)
ngrok http 3000
# → Forwarding: https://abc123.ngrok-free.app → localhost:3000
# Cloudflare Tunnel (no account required for quick tests)
cloudflared tunnel --url http://localhost:3000
# → https://random-name.trycloudflare.com
Then use the public tunnel URL in your API call:
{
"url": "https://abc123.ngrok-free.app",
"fullPage": true
}
This works for all endpoints — /screenshot,
/sequence,
/video, and
/pdf.
ngrok's free tier is sufficient for development and CI use; Cloudflare Tunnel requires no account at all.
Questions? Email support@pagebolt.dev
© 2026 PageBolt. All rights reserved.