# Advanced options ## Generating links with custom options [#generating-links-with-custom-options] We can add several additional paramaters to the request to customise the screenshot or PDF result. All the available parameters for screenshot and PDF are listed in next sections. We can go through few example on how to use these parameters: ### Capture a full page screenshot [#capture-a-full-page-screenshot] If you want to capture a full page screenshot of `http://www.apple.com/`, our request url will be: ``` https://cdn.capture.page/api_key/generated_hash/image?url=http://www.apple.com/&full=true ``` To generate the hash all we need to do is to create an `MD5` hash of the API secret and URL including our parameters. ```javascript md5(api_secret + 'url=http://www.apple.com/&full=true') ``` ### Capture a screenshot with custom dimensions [#capture-a-screenshot-with-custom-dimensions] If you want to capture a screenshot `http://www.apple.com/` with custom dimensions, we can make use of viewport width and height parameters, our request url will be: ``` https://cdn.capture.page/sample_key/generated_hash/image?url=http://www.apple.com/&vw=1920&vh=1080 ``` To generate the hash all we need to do is to create an `MD5` hash of the API secret and URL including our parameters. ```javascript md5(sample_secret + 'url=http://www.apple.com/&vw=1920&vh=1080') ``` ## Sample JavaScript Code [#sample-javascript-code] ```javascript // Include https://github.com/blueimp/JavaScript-MD5 var API_URL = 'https://cdn.capture.page/'; var your_api_key = 'API_KEY_FROM_CONSOLE'; var your_api_secret = 'API_SECRET_FROM_CONSOLE' // Target URL var input_url = encodeURIComponent('http://techulus.in/'); var options = 'full=true&scaleFactor=2' var full_url = input_url + '&' + options; var hash = md5(your_api_secret + 'url=' + full_url); // Image URL var result_img_url = API_URL + your_api_key + '/' + hash + '/image?url=' + full_url; // PDF URL var result_pdf_url = API_URL + your_api_key + '/' + hash + '/pdf?url=' + full_url; console.log(result_img_url, result_pdf_url); ``` # AI Agent Skill Add Capture as an Agent Skill to give Claude the ability to capture screenshots, generate PDFs, and extract content from any URL. ## Prerequisites [#prerequisites] 1. Install the [Capture CLI](/docs/capture-cli) 2. Set environment variables `CAPTURE_KEY` and `CAPTURE_SECRET` ## Installation [#installation] ```bash npx skills add techulus/capture-skills ``` For manual installation, see the [capture-skills repository](https://github.com/techulus/capture-skills). ## Usage [#usage] Once installed, Claude will automatically use the Capture skill when you ask it to: * Take a screenshot of a website * Generate a PDF from a URL * Extract content from a page * Get metadata from a URL * Create an animated recording of a page **Example prompts:** ``` "Take a screenshot of https://example.com" "Create a full-page screenshot of news.ycombinator.com in dark mode" "Screenshot this page as it would appear on an iPhone" "Generate an A4 PDF of this article with backgrounds" "Create a landscape PDF of this page" "Extract the content from this blog post as markdown" "Get the metadata from https://example.com" "Record a 10 second GIF of this page" ``` ## Available Commands [#available-commands] The skill provides access to all Capture CLI commands: | Command | Description | | ----------------------------------------- | ------------------- | | `capture screenshot -o ` | Capture screenshot | | `capture pdf -o ` | Generate PDF | | `capture content --format markdown` | Extract content | | `capture metadata --pretty` | Get metadata | | `capture animated -o ` | Record animated GIF | For the full list of options, see the [capture-skills repository](https://github.com/techulus/capture-skills) or the individual option pages: * [Screenshot Options](/docs/screenshot-options) * [PDF Options](/docs/pdf-options) * [Content Options](/docs/content-options) * [Metadata Options](/docs/metadata-options) * [Animated Screenshot Options](/docs/animated-screenshot-options) ## Related [#related] * [Capture CLI](/docs/capture-cli) - Installation and setup * [MCP Integration](/docs/mcp-integration) - Use Capture with Claude Desktop # Batch Image This API endpoint is for requesting batch processing of multiple image capture requests. Batch requests require an S3 bucket or S3-compatible storage (e.g., Cloudflare R2, MinIO) to be configured in your project settings. The generated files will be uploaded to this storage. ## Endpoint [#endpoint] POST `https://cdn.capture.page/batch-image/[your-api-key]` ## Authentication [#authentication] All requests have to be authenticated using a signature header (x-req-signature) x-req-signature is calculated as `HMAC-SHA256` of JSON request body with api secret as the key. ## Body (application/json) [#body-applicationjson] Request body should contain an array data having details of the url to captured and any additional options if required. It can also include an optional `notification_uri` (webhook) to receive notification when the requests is completely processed. Options can include any of the request queries mentioned in our documentation ([https://docs.capture.page](https://docs.capture.page)). Any errors in the request will be mentioned in the notification send to notification\_uri. ## Example [#example] ```json { "notification_uri": "https://hookb.in/KxQ9ROjo", "data": [ { "url": "https://news.ycombinator.com", "options": { "file_name": "news" } }, { "url": "https://news.ycombinator.com", "options": { "full": true } } ] } ``` # Batch PDF This API endpoint is for requesting batch processing of multiple PDF capture requests. Batch requests require an S3 bucket or S3-compatible storage (e.g., Cloudflare R2, MinIO) to be configured in your project settings. The generated files will be uploaded to this storage. ## Endpoint [#endpoint] POST `https://cdn.capture.page/batch-pdf/[your-api-key]` ## Authentication [#authentication] All requests have to be authenticated using a signature header (x-req-signature) x-req-signature is calculated as `HMAC-SHA256` of JSON request body with api secret as the key ## Body (application/json) [#body-applicationjson] Request body should contain an array data having details of the url to captured and any additional options if required. It can also include an optional `notification_uri` (webhook) to receive notification when the requests is completely processed. Options can include any of the request queries mentioned in our documentation ([https://docs.capture.page](https://docs.capture.page)). Any errors in the request will be mentioned in the notification send to notification\_uri. ## Example [#example] ```json { "notification_uri": "https://hookb.in/KxQ9ROjo", "data": [ { "url": "https://news.ycombinator.com", "options": { "file_name": "news", "format": "A3" } }, { "url": "https://news.ycombinator.com", "options": { "format": "A3" } } ] } ``` # Overview Browser sessions give you a stateful cloud browser that stays alive across multiple API calls. Instead of asking Capture to take one screenshot, PDF, or content extraction in a single request, you create a session, run actions against the same browser page, and close it when the workflow is finished. Use sessions when a capture needs interaction or shared state: signing in, navigating through a multi-step flow, waiting for an application to update, querying page content after a click, or taking a screenshot after several browser actions. ## How it works [#how-it-works] 1. Create a browser session with `POST /v1/sessions`. 2. Use the returned `sessionId` to execute actions with `POST /v1/sessions/{sessionId}/actions`. 3. Read session metadata when you need current state. 4. Close the session with `DELETE /v1/sessions/{sessionId}` when you are done. Sessions automatically close when their TTL expires, but you should close them explicitly once your workflow is complete. Sessions are billed by duration: 1 credit per minute the session stays open (rounded up), charged when the session closes or expires — not per action. A session can stay open for up to 15 minutes, and you can run up to 5 at once. Each action response for an existing session includes `expiresInSeconds` so clients can renew or close proactively before the TTL is reached. ## Authentication [#authentication] Session endpoints use Bearer authentication: ```text Authorization: Bearer ``` The `secret` can be your primary Capture secret or one of your API secrets. ## Example workflow [#example-workflow] Create a session: ```bash curl -X POST "https://api.capture.page/v1/sessions" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"maxTtlSeconds":300}' ``` Navigate the browser: ```bash curl -X POST "https://api.capture.page/v1/sessions/{sessionId}/actions" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "type": "goto", "payload": { "url": "https://example.com", "viewport": { "width": 1440, "height": 900 } } }' ``` Take a screenshot from the same session: ```bash curl -X POST "https://api.capture.page/v1/sessions/{sessionId}/actions" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "type": "screenshot", "payload": { "fullPage": true, "vw": 1440, "vh": 900 } }' ``` ## Batch multi-step workflows [#batch-multi-step-workflows] For multi-step workflows, prefer the `batch` action instead of sending each step as a separate HTTP request. Batched actions run sequentially inside the same session, keep the same browser state, and reduce repeated request, authentication, routing, and network overhead. ```bash curl -X POST "https://api.capture.page/v1/sessions/{sessionId}/actions" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "type": "batch", "payload": { "actions": [ { "type": "goto", "payload": { "url": "https://example.com", "waitUntil": "domcontentloaded" } }, { "type": "wait_for_selector", "payload": { "selector": "body", "visible": true } }, { "type": "scroll", "payload": { "direction": "down", "amount": 500 } }, { "type": "title" }, { "type": "screenshot", "payload": { "fullPage": false } } ] } }' ``` Use separate action requests when you need to inspect an intermediate result before deciding the next step. Otherwise, batching is the recommended pattern for predictable multi-action automations. ## Viewport and device emulation [#viewport-and-device-emulation] Browser sessions use a live page viewport. Set or update the viewport on `goto`, `screenshot`, or actions that use `payload.screenshot: true`. Viewport action options: ```json { "viewport": { "width": 1440, "height": 900 }, "scaleFactor": 1 } ``` Equivalent shorthand: ```json { "vw": 1440, "vh": 900, "deviceScaleFactor": 1 } ``` Device emulation uses the same device keys returned by `/screenshot/devices`: ```json { "emulateDevice": "iphone_14" } ``` When `emulateDevice` is present, it configures the viewport, user agent, touch support, and scale factor for that device and takes precedence over explicit viewport dimensions. Viewport changes are stateful: if an action changes the viewport, later actions use the new viewport until you change it again. Limits: viewport width and height can be up to `5000` and must be provided together; `scaleFactor` / `deviceScaleFactor` can be up to `3`. Invalid device keys are rejected. Close the session: ```bash curl -X DELETE "https://api.capture.page/v1/sessions/{sessionId}" \ -H "Authorization: Bearer " ``` ## Connect over CDP [#connect-over-cdp] When you need direct Chrome DevTools Protocol access, create the session with `cdp: true`. Capture returns a `connectUrl` that CDP clients can use to attach to the same cloud browser. ```bash curl -X POST "https://api.capture.page/v1/sessions" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"cdp":true,"maxTtlSeconds":300}' ``` Use the returned `session.connectUrl` with a CDP client such as Puppeteer or Playwright: ```ts import puppeteer from "puppeteer"; const browser = await puppeteer.connect({ browserWSEndpoint: session.connectUrl, }); ``` ```ts import { chromium } from "playwright"; const browser = await chromium.connectOverCDP(session.connectUrl); ``` `connectUrl` values are minted fresh and are only returned for active CDP-enabled sessions. If a client disconnects and you need to reconnect, fetch the session again while it is active: ```bash curl "https://api.capture.page/v1/sessions/{sessionId}" \ -H "Authorization: Bearer " ``` Disconnecting a CDP client does not close the Capture session. Close the session with `DELETE /v1/sessions/{sessionId}` when the workflow is finished so billing stops promptly. CDP sessions can be combined with `proxy: true` to route both the Capture-owned page and CDP-created targets through your configured browser proxy: ```bash curl -X POST "https://api.capture.page/v1/sessions" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"cdp":true,"proxy":true,"maxTtlSeconds":300}' ``` CDP sessions cannot be combined with `bypassBotDetection`. If you need bot detection bypass, create a regular browser session and use Capture actions instead of a raw CDP connection. ## Action types [#action-types] Actions are deterministic operations executed inside the active session page. Use them to navigate, inspect content, query matching elements, capture screenshots, and continue a workflow without losing browser state. The `query` action accepts `payload.fields` for built-in fields and `payload.attributes` for arbitrary DOM attributes such as `href`, `class`, or `data-tab`. Requested attributes are returned under each element's nested `attributes` object. `payload.limit` is capped at 500. Selector-based `click` and `hover` responses include diagnostics about the matched element, including `matched`, `visible`, `elementText`, `boundingBox`, and the interaction point. Use these fields to detect a wrong selector or a likely no-op interaction without taking another screenshot. Navigation actions (`goto`, `back`, `forward`, and `reload`) accept `payload.waitUntil` as `load`, `domcontentloaded`, or `commit`. The default is `domcontentloaded`. The `wait_for_timeout` action accepts `payload.timeoutMs` and clamps values above 2500ms. The `content` action accepts `payload.format` as `text`, `markdown`, or `html`. It defaults to cleaned readable text so agents do not receive raw page HTML unless you request `html` explicitly. The `batch` action accepts up to 25 nested actions and executes them in order. Use it when the next steps are known ahead of time, such as navigating, waiting, scrolling, reading the title, and taking a screenshot. See the generated API reference in this section for request and response schemas: * [Create a browser session](/docs/browser-sessions/sessions/createSession) * [Get session metadata](/docs/browser-sessions/sessions/getSession) * [Close a browser session](/docs/browser-sessions/sessions/closeSession) * [Execute a Capture action](/docs/browser-sessions/actions/executeAction) # Caching We cache all your requests so that you don't have pay for the same request again. ## What counts as a unique screenshot? [#what-counts-as-a-unique-screenshot] A unique screenshot is any combination of url and parameters that you have not requested before. ## How long do we cache? [#how-long-do-we-cache] The maximum TTL for any request is 7 days, so after 7 days your cache screenshot / PDF will be deleted. Maximum CDN bandwidth for cached requests is 10GB/day, you'll need an enterprise plan to upgrade this limit. # Capture CLI The Capture CLI lets you capture screenshots, generate PDFs, and extract content from any URL directly from your terminal. ## Installation [#installation] ### Go Install [#go-install] ```bash go install github.com/techulus/capture-go/cmd/capture@latest ``` ### Homebrew [#homebrew] ```bash brew tap techulus/tap brew install capture ``` ## Configuration [#configuration] Set your API credentials as environment variables: ```bash export CAPTURE_KEY="your_api_key" export CAPTURE_SECRET="your_api_secret" ``` Get your API key and secret from the [Capture Dashboard](https://capture.page/dashboard). ## Commands [#commands] ### Screenshot [#screenshot] Capture screenshots of any website: ```bash capture screenshot https://example.com -o screenshot.png capture screenshot https://example.com -X vw=1920 -X vh=1080 -X fullPage=true -o full.png ``` ### PDF [#pdf] Generate PDFs from any website: ```bash capture pdf https://example.com -o document.pdf capture pdf https://example.com -X format=A4 -X landscape=true -o landscape.pdf ``` ### Content [#content] Extract content from any website: ```bash capture content https://example.com --format markdown capture content https://example.com --format html -o page.html ``` ### Metadata [#metadata] Extract metadata from any website: ```bash capture metadata https://example.com --pretty ``` ### Animated [#animated] Create animated GIF recordings: ```bash capture animated https://example.com -X duration=5 -o recording.gif ``` ## Common Options [#common-options] | Option | Description | | ----------- | -------------------------------------------- | | `-o` | Output file path | | `-X` | Pass additional options (e.g., `-X vw=1920`) | | `--edge` | Use edge mode for faster response | | `--dry-run` | Preview the request URL without executing | ## Learn More [#learn-more] * **GitHub Repository**: [techulus/capture-go](https://github.com/techulus/capture-go) * [Screenshot Options](/docs/screenshot-options) * [PDF Options](/docs/pdf-options) * [Content Options](/docs/content-options) * [Metadata Options](/docs/metadata-options) # Get Started Welcome to Capture! This document will guide you through the process of making your first request. ## API Credentials [#api-credentials] In order to authenticate requests send to us, it is necesary for all requests to include user credentials. To get that you need to go to capture **[console](https://capture.techulus.in/console)**. Once you are are logged in to the console, you will see the API key and API secret in the Dashboard tab. We will use this key and secret for generating links to capture screenshots or PDFs. ## Generating links [#generating-links] To capture a screenshot we need to generate a URL which has our authentication credentials and request options. A basic requests URL will have the following parts: * `YOUR API KEY`, we'll get this from the console * `GENERATED HASH`, to validate the request, to make sure its you and not someone else * `REQUEST URL & OPTIONS`, URL to capture and query string that contains all of the options you want to set For example, if you want to capture `http://www.apple.com/`, our request url will be: ```text https://cdn.capture.page/api_key/generated_hash/image?url=http://www.apple.com/ ``` To generate the hash all we need to do is to create an `MD5` hash of the API secret and URL ```javascript md5(api_secret + 'url=http://www.apple.com/') ``` If you're using JavaScript or Python, we recommend using the official SDKs so you don't have to generate request hashes manually. Capture also provides official SDKs for Go, Rust, Ruby, and PHP. See the [SDK Overview](/docs/sdk-overview) for the full list. ## Displaying screenshots [#displaying-screenshots] To display the screenshot you can use the link generated in the previous step as image url. Using HTML tags: ```html ``` Using CSS: ```css .website-preview { background-image: url(https://cdn.capture.page/e1ab7054-dabc-48d6-a33f-c18038aac1c8/c87613a5bde6cdc09554e64c998cbffb/image?url=http://www.apple.com/&delay=2); } ``` Using Markdown: ```md ![](https://cdn.capture.page/e1ab7054-dabc-48d6-a33f-c18038aac1c8/c87613a5bde6cdc09554e64c998cbffb/image?url=http://www.apple.com/&delay=2) ``` Here is a live demo: ![](https://cdn.capture.page/e1ab7054-dabc-48d6-a33f-c18038aac1c8/c87613a5bde6cdc09554e64c998cbffb/image?url=http://www.apple.com/\&delay=2) Just treat the url as an image url and it will work anywhere you wish! ## Sample JavaScript Code [#sample-javascript-code] Install the official Node.js SDK: ```bash npm install capture-node ``` ```javascript import { Capture } from 'capture-node'; const capture = new Capture( 'API_KEY_FROM_CONSOLE', 'API_SECRET_FROM_CONSOLE' ); const targetUrl = 'https://techulus.xyz'; const imageUrl = capture.buildImageUrl(targetUrl, { delay: 2, }); const pdfUrl = capture.buildPdfUrl(targetUrl, { delay: 2, }); console.log(imageUrl); console.log(pdfUrl); ``` ## Sample Python Code [#sample-python-code] Install the official Python SDK: ```bash pip install capture-sdk ``` ```python from capture import Capture client = Capture( "API_KEY_FROM_CONSOLE", "API_SECRET_FROM_CONSOLE", ) target_url = "https://techulus.xyz" image_url = client.build_image_url(target_url, { "delay": 2, }) pdf_url = client.build_pdf_url(target_url, { "delay": 2, }) print(image_url) print(pdf_url) ``` # Hash Generation Guide Understanding how to generate the required MD5 hash is essential for using Capture API. The hash serves as a security mechanism to authenticate your requests and prevent unauthorized usage. ## How Hash Generation Works [#how-hash-generation-works] The Capture API uses MD5 hashing to verify that requests are coming from authenticated users. The hash is generated by combining your API secret with the request URL and parameters. ### Basic Formula [#basic-formula] ``` MD5(API_SECRET + REQUEST_URL_WITH_PARAMETERS) ``` ## URL Structure [#url-structure] All Capture API requests follow this structure: ``` https://cdn.capture.page/{API_KEY}/{GENERATED_HASH}/{ENDPOINT}?url={TARGET_URL}&{PARAMETERS} ``` **Components:** * `{API_KEY}`: Your API key from the console * `{GENERATED_HASH}`: MD5 hash you generate * `{ENDPOINT}`: API endpoint (image, pdf, content, metadata, animated) * `{TARGET_URL}`: The website URL you want to capture * `{PARAMETERS}`: Optional parameters for customization ## Step-by-Step Process [#step-by-step-process] ### 1. Prepare the Hash Input [#1-prepare-the-hash-input] The hash input consists of: ``` API_SECRET + 'url=' + TARGET_URL + '&' + PARAMETERS ``` ### 2. Generate MD5 Hash [#2-generate-md5-hash] Create an MD5 hash of the complete string from step 1. ### 3. Construct Final URL [#3-construct-final-url] Use the hash in your API request URL. ## Language-Specific Examples [#language-specific-examples] ### JavaScript/Node.js [#javascriptnodejs] ```javascript const crypto = require('crypto'); function generateCaptureURL(apiKey, apiSecret, targetUrl, endpoint = 'image', params = {}) { // Build parameter string const paramString = Object.keys(params) .map(key => `${key}=${encodeURIComponent(params[key])}`) .join('&'); // Create hash input const hashInput = apiSecret + 'url=' + encodeURIComponent(targetUrl) + (paramString ? '&' + paramString : ''); // Generate MD5 hash const hash = crypto.createHash('md5').update(hashInput).digest('hex'); // Construct final URL const finalUrl = `https://cdn.capture.page/${apiKey}/${hash}/${endpoint}?url=${encodeURIComponent(targetUrl)}` + (paramString ? '&' + paramString : ''); return finalUrl; } // Example usage const apiKey = 'your-api-key'; const apiSecret = 'your-api-secret'; const targetUrl = 'https://example.com'; // Simple screenshot const screenshotUrl = generateCaptureURL(apiKey, apiSecret, targetUrl, 'image'); console.log(screenshotUrl); // Screenshot with parameters const advancedUrl = generateCaptureURL(apiKey, apiSecret, targetUrl, 'image', { vw: 1920, vh: 1080, format: 'png', delay: 2 }); console.log(advancedUrl); ``` ### Python [#python] ```python import hashlib import urllib.parse def generate_capture_url(api_key, api_secret, target_url, endpoint='image', params=None): if params is None: params = {} # Build parameter string param_string = '&'.join([f"{key}={urllib.parse.quote_plus(str(value))}" for key, value in params.items()]) # Create hash input hash_input = (api_secret + 'url=' + urllib.parse.quote_plus(target_url) + ('&' + param_string if param_string else '')) # Generate MD5 hash hash_value = hashlib.md5(hash_input.encode()).hexdigest() # Construct final URL final_url = (f"https://cdn.capture.page/{api_key}/{hash_value}/{endpoint}" f"?url={urllib.parse.quote_plus(target_url)}") if param_string: final_url += '&' + param_string return final_url # Example usage api_key = 'your-api-key' api_secret = 'your-api-secret' target_url = 'https://example.com' # Simple screenshot screenshot_url = generate_capture_url(api_key, api_secret, target_url, 'image') print(screenshot_url) # PDF with parameters pdf_url = generate_capture_url(api_key, api_secret, target_url, 'pdf', { 'format': 'A4', 'landscape': 'true', 'delay': 3 }) print(pdf_url) ``` ### PHP [#php] ```php $value) { $paramPairs[] = $key . '=' . urlencode($value); } $paramString = implode('&', $paramPairs); } // Create hash input $hashInput = $apiSecret . 'url=' . urlencode($targetUrl) . ($paramString ? '&' . $paramString : ''); // Generate MD5 hash $hash = md5($hashInput); // Construct final URL $finalUrl = "https://cdn.capture.page/{$apiKey}/{$hash}/{$endpoint}?url=" . urlencode($targetUrl); if ($paramString) { $finalUrl .= '&' . $paramString; } return $finalUrl; } // Example usage $apiKey = 'your-api-key'; $apiSecret = 'your-api-secret'; $targetUrl = 'https://example.com'; // Simple screenshot $screenshotUrl = generateCaptureURL($apiKey, $apiSecret, $targetUrl, 'image'); echo $screenshotUrl . "\n"; // Advanced screenshot $advancedUrl = generateCaptureURL($apiKey, $apiSecret, $targetUrl, 'image', [ 'vw' => 1920, 'vh' => 1080, 'darkMode' => 'true', 'blockAds' => 'true' ]); echo $advancedUrl . "\n"; ?> ``` ### Go [#go] ```go package main import ( "crypto/md5" "fmt" "net/url" "strings" ) func generateCaptureURL(apiKey, apiSecret, targetURL, endpoint string, params map[string]string) string { // Build parameter string var paramPairs []string for key, value := range params { paramPairs = append(paramPairs, fmt.Sprintf("%s=%s", key, url.QueryEscape(value))) } paramString := strings.Join(paramPairs, "&") // Create hash input hashInput := apiSecret + "url=" + url.QueryEscape(targetURL) if paramString != "" { hashInput += "&" + paramString } // Generate MD5 hash hash := fmt.Sprintf("%x", md5.Sum([]byte(hashInput))) // Construct final URL finalURL := fmt.Sprintf("https://cdn.capture.page/%s/%s/%s?url=%s", apiKey, hash, endpoint, url.QueryEscape(targetURL)) if paramString != "" { finalURL += "&" + paramString } return finalURL } func main() { apiKey := "your-api-key" apiSecret := "your-api-secret" targetURL := "https://example.com" // Simple screenshot screenshotURL := generateCaptureURL(apiKey, apiSecret, targetURL, "image", nil) fmt.Println(screenshotURL) // Screenshot with parameters params := map[string]string{ "vw": "1920", "vh": "1080", "format": "png", "delay": "2", } advancedURL := generateCaptureURL(apiKey, apiSecret, targetURL, "image", params) fmt.Println(advancedURL) } ``` ### Rust [#rust] ```rust use std::collections::HashMap; fn generate_capture_url( api_key: &str, api_secret: &str, target_url: &str, endpoint: &str, params: Option>, ) -> String { // Build parameter string let param_string = if let Some(params) = params { params .iter() .map(|(key, value)| format!("{}={}", key, urlencoding::encode(value))) .collect::>() .join("&") } else { String::new() }; // Create hash input let mut hash_input = format!("{}url={}", api_secret, urlencoding::encode(target_url)); if !param_string.is_empty() { hash_input.push('&'); hash_input.push_str(¶m_string); } // Generate MD5 hash let hash = format!("{:x}", md5::compute(hash_input.as_bytes())); // Construct final URL let mut final_url = format!( "https://cdn.capture.page/{}/{}/{}?url={}", api_key, hash, endpoint, urlencoding::encode(target_url) ); if !param_string.is_empty() { final_url.push('&'); final_url.push_str(¶m_string); } final_url } fn main() { let api_key = "your-api-key"; let api_secret = "your-api-secret"; let target_url = "https://example.com"; // Simple screenshot let screenshot_url = generate_capture_url(api_key, api_secret, target_url, "image", None); println!("{}", screenshot_url); // Screenshot with parameters let mut params = HashMap::new(); params.insert("vw".to_string(), "1920".to_string()); params.insert("vh".to_string(), "1080".to_string()); params.insert("format".to_string(), "png".to_string()); let advanced_url = generate_capture_url(api_key, api_secret, target_url, "image", Some(params)); println!("{}", advanced_url); } ``` ### Ruby [#ruby] ```ruby require 'digest' require 'uri' def generate_capture_url(api_key, api_secret, target_url, endpoint = 'image', params = {}) # Build parameter string param_string = params.map { |key, value| "#{key}=#{URI.encode_www_form_component(value.to_s)}" }.join('&') # Create hash input hash_input = api_secret + 'url=' + URI.encode_www_form_component(target_url) hash_input += '&' + param_string unless param_string.empty? # Generate MD5 hash hash = Digest::MD5.hexdigest(hash_input) # Construct final URL final_url = "https://cdn.capture.page/#{api_key}/#{hash}/#{endpoint}?url=#{URI.encode_www_form_component(target_url)}" final_url += '&' + param_string unless param_string.empty? final_url end # Example usage api_key = 'your-api-key' api_secret = 'your-api-secret' target_url = 'https://example.com' # Simple screenshot screenshot_url = generate_capture_url(api_key, api_secret, target_url, 'image') puts screenshot_url # PDF with parameters pdf_url = generate_capture_url(api_key, api_secret, target_url, 'pdf', { format: 'A4', landscape: true, delay: 3 }) puts pdf_url ``` ## Common Examples [#common-examples] ### Screenshot Examples [#screenshot-examples] #### Basic Screenshot [#basic-screenshot] ```javascript // Hash input: api_secret + 'url=https://example.com' const hashInput = 'your-api-secret' + 'url=https://example.com'; const hash = crypto.createHash('md5').update(hashInput).digest('hex'); // URL: https://cdn.capture.page/your-api-key/{hash}/image?url=https://example.com ``` #### Screenshot with Viewport [#screenshot-with-viewport] ```javascript // Hash input: api_secret + 'url=https://example.com&vw=1920&vh=1080' const hashInput = 'your-api-secret' + 'url=https://example.com&vw=1920&vh=1080'; const hash = crypto.createHash('md5').update(hashInput).digest('hex'); // URL: https://cdn.capture.page/your-api-key/{hash}/image?url=https://example.com&vw=1920&vh=1080 ``` #### Mobile Screenshot [#mobile-screenshot] ```javascript // Hash input: api_secret + 'url=https://example.com&emulateDevice=iphone_15_pro' const hashInput = 'your-api-secret' + 'url=https://example.com&emulateDevice=iphone_15_pro'; const hash = crypto.createHash('md5').update(hashInput).digest('hex'); ``` ### PDF Examples [#pdf-examples] #### Basic PDF [#basic-pdf] ```javascript // Hash input: api_secret + 'url=https://example.com' const hashInput = 'your-api-secret' + 'url=https://example.com'; const hash = crypto.createHash('md5').update(hashInput).digest('hex'); // URL: https://cdn.capture.page/your-api-key/{hash}/pdf?url=https://example.com ``` #### PDF with Custom Format [#pdf-with-custom-format] ```javascript // Hash input: api_secret + 'url=https://example.com&format=A4&landscape=true' const hashInput = 'your-api-secret' + 'url=https://example.com&format=A4&landscape=true'; const hash = crypto.createHash('md5').update(hashInput).digest('hex'); ``` ### Content & Metadata Examples [#content--metadata-examples] #### Content Extraction [#content-extraction] ```javascript // Hash input: api_secret + 'url=https://example.com' const hashInput = 'your-api-secret' + 'url=https://example.com'; const hash = crypto.createHash('md5').update(hashInput).digest('hex'); // URL: https://cdn.capture.page/your-api-key/{hash}/content?url=https://example.com ``` #### Metadata with Delay [#metadata-with-delay] ```javascript // Hash input: api_secret + 'url=https://example.com&delay=3' const hashInput = 'your-api-secret' + 'url=https://example.com&delay=3'; const hash = crypto.createHash('md5').update(hashInput).digest('hex'); ``` ## Important Considerations [#important-considerations] ### 1. Parameter Order [#1-parameter-order] The order of parameters in your hash input **must match** the order in your final URL: ```javascript // ✅ Correct - same order // Hash: api_secret + 'url=example.com&vw=1920&vh=1080' // URL: .../image?url=example.com&vw=1920&vh=1080 // ❌ Incorrect - different order // Hash: api_secret + 'url=example.com&vw=1920&vh=1080' // URL: .../image?url=example.com&vh=1080&vw=1920 ``` ### 2. URL Encoding [#2-url-encoding] Always URL-encode parameter values consistently: ```javascript // ✅ Correct - URL encode special characters const targetUrl = 'https://example.com/page?id=123&ref=test'; const encodedUrl = encodeURIComponent(targetUrl); const hashInput = apiSecret + 'url=' + encodedUrl; ``` ### 3. Boolean Parameters [#3-boolean-parameters] Convert boolean values to strings: ```javascript // ✅ Correct const params = { darkMode: 'true', blockAds: 'false' }; // ❌ Incorrect const params = { darkMode: true, blockAds: false }; ``` ### 4. Empty Parameters [#4-empty-parameters] Exclude parameters with empty or undefined values: ```javascript // ✅ Correct - filter out empty values const params = { vw: 1920, vh: '', delay: 3 }; const validParams = Object.fromEntries( Object.entries(params).filter(([_, value]) => value !== '' && value != null) ); ``` ## Security Best Practices [#security-best-practices] ### 1. Keep API Secret Secure [#1-keep-api-secret-secure] * Never expose API secret in client-side code * Use environment variables for secrets * Rotate secrets periodically ### 2. Server-Side Hash Generation [#2-server-side-hash-generation] ```javascript // ✅ Server-side (secure) app.get('/generate-url', (req, res) => { const hash = generateHash(API_SECRET, req.query.url, req.query.params); res.json({ url: constructURL(API_KEY, hash, req.query.url, req.query.params) }); }); // ❌ Client-side (insecure) const hash = generateHash(API_SECRET, url, params); // Exposes secret! ``` ### 3. Validate Inputs [#3-validate-inputs] Always validate and sanitize inputs before hash generation: ```javascript function validateParams(params) { const allowedParams = ['vw', 'vh', 'format', 'delay', 'darkMode']; return Object.fromEntries( Object.entries(params).filter(([key]) => allowedParams.includes(key)) ); } ``` ## Debugging Hash Issues [#debugging-hash-issues] ### Common Problems [#common-problems] #### 1. Hash Mismatch [#1-hash-mismatch] ``` Error: Invalid hash ``` **Solution**: Verify hash input matches URL parameters exactly. #### 2. URL Encoding Issues [#2-url-encoding-issues] ```javascript // Debug: Print hash input console.log('Hash input:', hashInput); console.log('Generated hash:', hash); console.log('Final URL:', finalUrl); ``` #### 3. Parameter Order Problems [#3-parameter-order-problems] ```javascript // Use consistent parameter ordering function sortParams(params) { return Object.keys(params).sort().reduce((sorted, key) => { sorted[key] = params[key]; return sorted; }, {}); } ``` ### Testing Hash Generation [#testing-hash-generation] ```javascript function testHashGeneration() { const apiSecret = 'test-secret'; const testCases = [ { url: 'https://example.com', params: {}, expected: 'url=https://example.com' }, { url: 'https://example.com', params: { vw: 1920, vh: 1080 }, expected: 'url=https://example.com&vw=1920&vh=1080' } ]; testCases.forEach((test, index) => { const hashInput = apiSecret + test.expected; const hash = crypto.createHash('md5').update(hashInput).digest('hex'); console.log(`Test ${index + 1}: ${hash}`); }); } ``` ## Online Hash Generator [#online-hash-generator] For quick testing, you can use online MD5 generators: 1. Construct your hash input string 2. Paste into an MD5 generator (e.g., md5hashgenerator.com) 3. Use the resulting hash in your URL **Example:** * Hash input: `your-api-secreturl=https://example.com&vw=1920&vh=1080` * MD5 result: `a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6` * Final URL: `https://cdn.capture.page/your-api-key/a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6/image?url=https://example.com&vw=1920&vh=1080` # Outbound IP Ranges Capture API uses a set of outbound IP addresses for all requests made to your target URLs. You can use these IP ranges to allowlist Capture's traffic in your firewall or security configurations. ## Fetching IP Ranges [#fetching-ip-ranges] Get the current list of IP ranges via the JSON endpoint: ``` https://capture.page/ip-ranges.json ``` ### Response Format [#response-format] ```json { "prefixes": [ "162.220.234.0/23", "162.220.232.0/23", "208.77.246.0/23", "208.77.244.0/23", "66.33.22.0/23", "66.33.23.0/24" ] } ``` The response contains a `prefixes` array with IP address ranges in CIDR notation. ## Support [#support] If you have specific networking requirements, contact support through the [API Console](https://capture.page/console). # MCP (Model Context Protocol) ## What is MCP? [#what-is-mcp] The Model Context Protocol (MCP) lets any MCP-compatible AI client connect directly to Capture's API, enabling you to capture screenshots, generate PDFs, extract content, and drive interactive browser sessions from your AI conversations. Capture runs a remote MCP server over **Streamable HTTP**, so it works with any client that supports remote MCP servers — including Claude, Cursor, Codex, OpenCode, VS Code, and others. ## Connection Details [#connection-details] Most MCP clients only need two things: | Field | Value | | --------------- | --------------------------------------- | | **Server URL** | `https://capture.page/mcp/v1` | | **Transport** | Streamable HTTP | | **Auth header** | `Authorization: Bearer YOUR_TOKEN_HERE` | ### Get Your Bearer Token [#get-your-bearer-token] Visit the [MCP Integration page](https://capture.page/dashboard/mcp) in your Capture dashboard to get your auto-generated Bearer token. This token authenticates your MCP connection and combines your API key and secret. ## Setup [#setup] Config formats differ between clients — use the example that matches yours and replace `YOUR_TOKEN_HERE` with your Bearer token. Any client not shown here can be configured with the Server URL and Authorization header from the table above, following its own MCP docs. ### JSON config (Claude, Cursor, VS Code, and similar) [#json-config-claude-cursor-vs-code-and-similar] Paste this into your client's MCP config file (the exact location varies by client): ```json { "mcpServers": { "capture": { "type": "http", "url": "https://capture.page/mcp/v1", "headers": { "Authorization": "Bearer YOUR_TOKEN_HERE" } } } } ``` ### Codex [#codex] Add this to `~/.codex/config.toml`: ```toml [mcp_servers.capture] url = "https://capture.page/mcp/v1" http_headers = { Authorization = "Bearer YOUR_TOKEN_HERE" } ``` After saving the configuration, restart your client (or start a new conversation) for the Capture tools to appear. ## Available Tools [#available-tools] Once configured, you'll have access to these Capture tools directly from your AI assistant: ### capture\_screenshot [#capture_screenshot] Capture screenshots of any website with full customization options: * Full-page screenshots * Device emulation (iPhone, iPad, etc.) * Dark mode support * Block ads and cookie banners * Custom viewport sizes * Element selection * And more **Example usage:** ``` "Take a screenshot of example.com" "Capture a full-page screenshot of news.ycombinator.com in dark mode" ``` ### capture\_pdf [#capture_pdf] Generate PDFs from any website with custom settings: * Custom page sizes (A4, Letter, Legal, etc.) * Margin control * Landscape/portrait orientation * Print background graphics * Custom scaling **Example usage:** ``` "Generate a PDF of this article" "Create a PDF of example.com with A4 size" ``` ### capture\_content [#capture_content] Extract readable content from any website: * Cleaned text content * Markdown output * Raw HTML when needed * Useful for content analysis and web scraping **Example usage:** ``` "Extract the content from this blog post" "Get the text from example.com" ``` ### capture\_metadata [#capture_metadata] Extract metadata from any website: * Title and description * Open Graph tags * Author and publisher information * Useful for SEO analysis **Example usage:** ``` "Extract metadata from apple.com" "Get the SEO information for this website" ``` ### Browser sessions (interactive automation) [#browser-sessions-interactive-automation] For tasks that need more than a single capture — logging in, filling forms, clicking through pages, or reading content that only appears after interaction — Capture exposes a stateful **browser session** that your AI assistant can drive step by step. A session keeps a real browser open and is billed by duration — **1 credit per minute the session stays open** (rounded up), charged when the session closes or expires — so the assistant is instructed to close it as soon as the task is done. #### browser\_session\_create [#browser_session_create] Start an interactive browser session. Returns a `sessionId` and `expiresAt`. When `cdp: true` is set, it also returns a `connectUrl` for external CDP clients. * Optional `maxTtlSeconds` (max 900) to cap the session lifetime * Optional `proxy` to route through your configured proxy * Optional `bypassBotDetection` to use a stealth browser * Optional `cdp` to expose a Chrome DevTools Protocol connection URL Use `cdp: true` when an external automation client needs to attach directly to the browser. Pass the returned `connectUrl` to Puppeteer `connect` or Playwright `connectOverCDP`, then close the Capture session with `browser_session_close` when finished. Disconnecting the CDP client does not close the Capture session. `cdp` can be combined with `proxy` when CDP-created targets need to use your configured proxy. `cdp` cannot be combined with `bypassBotDetection`. #### browser\_session\_act [#browser_session_act] Run an action inside an open session. Takes the `sessionId`, an action `type`, and a `payload`. * Navigation: `goto`, `back`, `forward`, `reload` * Interaction: `click`, `type`, `type_text`, `fill`, `select`, `check`, `press`, `hover`, `scroll`, `move_mouse`, `drag_mouse` * Reading: `snapshot`, `content`, `query`, `title`, `url`, `console`, `errors` * Waiting: `wait_for_selector`, `wait_for_timeout` * Capture: `screenshot` (returned as an inline image; any action can set `payload.screenshot: true` to attach one) * `batch`: run several actions in one round-trip via `payload.actions` `goto`, `screenshot`, and action payloads with `screenshot: true` can include `viewport`, `vw` / `vh`, `scaleFactor` / `deviceScaleFactor`, or `emulateDevice` to update the live session viewport before the action. This is stateful: later actions keep using that viewport until another action changes it. Action results include `expiresInSeconds` when the session exists, letting the assistant renew, finish, or close the session before the TTL is reached. For `query`, use `payload.fields` for built-in fields and `payload.attributes` for arbitrary DOM attributes; requested attributes are returned under each element's nested `attributes` object. `payload.limit` is capped at 500. Selector `click` and `hover` results include matched element diagnostics such as `visible`, `elementText`, `boundingBox`, and the interaction point. For navigation actions, set `payload.waitUntil` to `load`, `domcontentloaded`, or `commit`; the default is `domcontentloaded`. For `wait_for_timeout`, `payload.timeoutMs` is capped at 2500ms. For `content`, set `payload.format` to `text`, `markdown`, or `html`. The default is cleaned text; request `html` only when the raw page source is needed. **Example usage:** ``` "Log into example.com with these credentials and take a screenshot of the dashboard" "Open this product page, accept the cookie banner, and extract the price" ``` #### browser\_session\_close [#browser_session_close] Close a session and stop billing. The assistant calls this automatically when finished. #### browser\_session\_get [#browser_session_get] Check a session's status — whether it's still active, when it expires, action counts, and credits billed so far. ## Usage Tips [#usage-tips] * Ask your AI assistant naturally - it will know when to use Capture tools * All standard Capture options are supported through the MCP tools * Screenshots and PDFs are automatically uploaded to your Capture CDN * Credits are deducted from your Capture account as normal ## Troubleshooting [#troubleshooting] ### Connection Failed [#connection-failed] If your client reports that it failed to connect: 1. Verify the Server URL is `https://capture.page/mcp/v1` and the transport is HTTP 2. Verify your Bearer token is correct 3. Ensure you've restarted your client after configuration 4. Check that you have an active internet connection ### Authentication Errors [#authentication-errors] If you receive authentication errors: 1. Regenerate your Bearer token from the [MCP Integration page](https://capture.page/dashboard/mcp) 2. Update your configuration with the new token 3. Restart your client ## Learn More [#learn-more] For more details about Capture's features and options: * [Screenshot Options](/docs/screenshot-options) * [PDF Options](/docs/pdf-options) * [Content Options](/docs/content-options) * [Metadata Options](/docs/metadata-options) # n8n integration ## Setup [#setup] n8n is a workflow automation tool that connects Capture to hundreds of services. With n8n, you can: * Automate screenshot and PDF capture workflows. * Build custom integrations without writing code. * Connect Capture to your existing tools and services. To get started, visit our [n8n integration](https://capture.page/n8n-integration) page for detailed instructions and configuration examples. # SDK Overview Capture API provides official SDKs for popular programming languages, making it easy to integrate screenshot, PDF, and content capture capabilities into your applications. ## Available SDKs [#available-sdks] ### Node.js SDK [#nodejs-sdk] * **Repository**: [techulus/capture-node](https://github.com/techulus/capture-node) * **Package**: `capture-node` * **Language**: JavaScript/TypeScript * **Features**: Full API coverage, TypeScript support, Promise-based ### Python SDK [#python-sdk] * **Repository**: [techulus/capture-py](https://github.com/techulus/capture-py) * **Package**: `capture-sdk` * **Language**: Python * **Features**: Async/await support, type hints, URL builders and direct fetch methods ### Go SDK [#go-sdk] * **Repository**: [techulus/capture-go](https://github.com/techulus/capture-go) * **Package**: `github.com/techulus/capture-go` * **Language**: Go * **Features**: Idiomatic Go interfaces, comprehensive error handling ### Rust SDK [#rust-sdk] * **Repository**: [techulus/capture-rust](https://github.com/techulus/capture-rust) * **Package**: `capture-rust` * **Language**: Rust * **Features**: Memory-safe, async/await support, strong typing ### Ruby SDK [#ruby-sdk] * **Repository**: [techulus/capture-ruby](https://github.com/techulus/capture-ruby) * **Package**: [`capture_page`](https://rubygems.org/gems/capture_page) * **Language**: Ruby * **Features**: Simple API, Rails-friendly, edge endpoint support ### PHP SDK [#php-sdk] * **Repository**: [techulus/capture-php](https://github.com/techulus/capture-php) * **Package**: [`techulus/capture`](https://packagist.org/packages/techulus/capture) * **Language**: PHP * **Install**: `composer require techulus/capture` * **Features**: Composer-friendly distribution, lightweight request URL generation, simple API authentication flow Need help deciding? Check out the individual SDK guides for comprehensive examples and integration patterns. # Slack integration ## Setup [#setup] Our slack integration lets you capture website screenshots in your Slack channels. To get started link your Capture account with Slack, visit our [slack integration](https://capture.techulus.in/connect-slack) page. ## Request screenshot [#request-screenshot] To request a screenshot you can use the `/screenshot` command followed by the URL you wish to capture. For example, the below command will fetch you a screenshot of `https://capture.techulus.in/pricing` ``` /screenshot https://capture.techulus.in ``` ## Customize request [#customize-request] You can also add options to customise the request, for example you can add a delay before capturing screenshot using the `delay` option. The below command will fetch you a screenshot of `https://capture.techulus.in/pricing` and will add a delay of 3 seconds before capturing the image. ``` /screenshot https://capture.techulus.in delay=3 ``` hence the anatomy of a request is the following; ``` /screenshot url [option_name=value] [option_name=value]... ``` Note. You can chain multiple options together separated by a space. You can find the full list of supported [screenshot options here](/docs/screenshot-options). # WordPress Plugin ## Setup [#setup] The Capture WordPress plugin makes it easy to integrate screenshot and PDF capture capabilities directly into your WordPress site. With the plugin, you can: * Capture screenshots and PDFs from your WordPress dashboard. * Embed automated screenshots in your posts and pages. * Use shortcodes to display dynamic content captures. To get started, visit our [WordPress plugin](https://capture.page/wordpress-plugin) page for installation instructions and usage examples. # Zapier integration ## Setup [#setup] Zapier connects Capture to all the software you rely on. Zapier lets you: * Automate repetitive tasks without writing code. * Build custom workflows to save time. * Connect 5,000+ apps you already use. To get started link your visit our [zapier integration](https://zapier.com/developer/public-invite/166490/98521eb3c78f8e50392f6bea04e2638a/) page. # Core APIs Core APIs are single-request endpoints for rendering or extracting data from a web page. Use them when the job can be described up front with a URL and a set of options. For workflows that need multiple steps, login state, clicks, or repeated actions against the same browser, use [Browser Sessions](/docs/browser-sessions-overview) instead. ## Screenshot [#screenshot] Capture a page as an image. Screenshots support viewport sizing, full-page capture, element capture, device emulation, dark mode, ad blocking, cookie banner handling, output formats, and storage options. Start with [Screenshot options](/docs/screenshot-options). ## PDF [#pdf] Render a page as a PDF. PDF requests support paper size, orientation, margins, print rendering, timing controls, authentication, and storage options. Start with [PDF options](/docs/pdf-options). ## Content [#content] Extract readable content from a page when you need text or structured page content instead of a rendered image or PDF. Start with [Content options](/docs/content-options). ## Metadata [#metadata] Fetch page metadata such as titles, descriptions, icons, and other document metadata useful for previews, indexing, and enrichment. Start with [Metadata options](/docs/metadata-options). ## Animated [#animated] Create animated screenshots when you need to show motion, transitions, loading states, or short product flows instead of a static image. Start with [Animated screenshot options](/docs/animated-screenshot-options). # Animated Screenshot Request The animated screenshot endpoint allows you to capture animated screenshots of web pages in GIF format. ## URL Format [#url-format] ``` https://cdn.capture.page/{API_KEY}/{GENERATED_HASH}/animated?url={TARGET_URL} ``` * **API\_KEY**: Your Capture API key * **GENERATED\_HASH**: MD5 hash of the target URL and your API secret * **TARGET\_URL**: The URL you want to capture (URL-encoded) ## Request Options [#request-options] | Query | Default value | Description | | ------------------ | ------------- | ---------------------------------------------------------------------------------------- | | url | - | URL-encoded target url | | preset | - | Apply predefined configuration preset | | duration | 5 | Recording duration in seconds (1-30) | | hideScrollbars | true | Hide scrollbars during capture for cleaner output | | vw | 1440 | Viewport width in pixels | | vh | 900 | Viewport height in pixels | | scaleFactor | 1 | Device scale factor | | emulateDevice | - | Emulate a specific device (e.g., `iphone_14`, `ipad`, `pixel_8`) - see device list below | | delay | 0 | Seconds to wait before starting capture (0-25) | | waitFor | - | Wait for CSS selector to appear | | waitForId | - | Wait for element with specific ID to appear | | darkMode | false | Enable dark mode | | blockCookieBanners | false | Automatically dismiss cookie consent popups | | blockAds | false | Block advertisements | | stealth | false | Use faster stealth mode to avoid triggering bot challenges | | httpAuth | - | HTTP Basic Authentication base64url encoded in format `base64url(username:password)` | | userAgent | - | Custom user agent (`base64url` encoded) | | fileName | - | Custom filename for the output file | ## Usage Examples [#usage-examples] ### Basic Animated Screenshot [#basic-animated-screenshot] ``` https://cdn.capture.page/your-api-key/hash/animated?url=https://example.com&duration=10 ``` ### Dark Mode Animation [#dark-mode-animation] ``` https://cdn.capture.page/your-api-key/hash/animated?url=https://example.com&duration=20&darkMode=true&hideScrollbars=true ``` ### Mobile Device Recording [#mobile-device-recording] ``` https://cdn.capture.page/your-api-key/hash/animated?url=https://example.com&emulateDevice=iphone_15_pro&duration=10 ``` ## Technical Limitations [#technical-limitations] * **Format**: GIF only * **Maximum Duration**: 30 seconds ## Device Emulation [#device-emulation] The `emulateDevice` parameter allows you to capture animated screenshots as they would appear on specific mobile devices. This is particularly useful for: * Testing responsive design behavior * Creating mobile app demos * Recording mobile-specific interactions ### Available Devices [#available-devices] To get the complete list of available devices with their specifications, use the devices endpoint: ```bash curl "https://edge.capture.page/screenshot/devices" ``` **Sample Response:** ```json { "success": true, "count": 120, "devices": [ { "name": "iPhone 15 Pro", "key": "iphone_15_pro", "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1", "viewport": { "width": 393, "height": 659, "deviceScaleFactor": 3, "isMobile": true, "hasTouch": true, "isLandscape": false } } ] } ``` Use the `key` field from the response as the value for the `emulateDevice` parameter in your animated screenshot requests. ### Device Emulation Notes [#device-emulation-notes] 1. When using `emulateDevice`, the viewport dimensions and scale factor are automatically set to match the selected device 2. Touch events and mobile user agents are properly configured 3. If an invalid device key is provided, the API falls back to default viewport settings # Content Request The content API allows for capturing the page content in HTML (including the `` section). This is useful for capturing the content of a page that has a lot of JavaScript or other interactivity. ## URL Format [#url-format] * `YOUR API KEY`, You'll get this from the console * `GENERATED HASH`, MD5 hash of full url and API Secret, `md5(API SECRET + REQUEST URL)` * `REQUEST URL`, Target URL ``` https://cdn.capture.page/e1ab7054-dabc-48d6-a33f-c18038aac1c8 /4d3e6e3d80d0ac77eaa72e87b1a31744/content?url=http://example.com/ ``` ## Request Options [#request-options] | Query | Default value | Description | | --------- | ------------- | ------------------------------------------------------------------------------------ | | url | - | URL-encoded target url | | preset | - | Apply predefined configuration preset | | httpAuth | - | HTTP Basic Authentication base64url encoded in format `base64url(username:password)` | | userAgent | - | Custom User agent (`base64url` encoded) | | delay | 0 | Delay in seconds before capturing | | waitFor | - | Capture will wait for this CSS selector to appear before taking content | | waitForId | - | Capture will wait for this id to appear before taking content | | stealth | false | Use faster stealth mode to avoid triggering bot challenges | ## Response [#response] The response will be a JSON in the following format: ```json { "success": true, "html": "\n Example Domain\n\n \n \n \n \n\n\n\n
\n

Example Domain

\n

This domain is established to be used for illustrative examples in documents. You may use this\n domain in examples without prior coordination or asking for permission.

\n

More information...

\n
\n\n\n", "textContent": "Example Domain\nThis domain is established to be used for illustrative examples in documents. You may use this domain in examples without prior coordination or asking for permission." } ``` # Metadata Request The metadata API allows for capturing the websites metadata in JSON format, providing essential details like title, description, logo, author, language, and more. ## URL Format [#url-format] * `YOUR API KEY`, You'll get this from the console * `GENERATED HASH`, MD5 hash of full url and API Secret, `md5(API SECRET + REQUEST URL)` * `REQUEST URL`, Target URL ``` https://cdn.capture.page/e1ab7054-dabc-48d6-a33f-c18038aac1c8 /4d3e6e3d80d0ac77eaa72e87b1a31744/metadata?url=http://example.com/ ``` ## Request Options [#request-options] | Query | Default value | Description | | ------- | ------------- | ---------------------------------------------------------- | | url | - | URL-encoded target url | | preset | - | Apply predefined configuration preset | | stealth | false | Use faster stealth mode to avoid triggering bot challenges | ## Response [#response] The response will be a JSON in the following format: ```json { "success": true, "metadata": { "author": "Techulus", "audio": null, "date": null, "description": "The ultimate solution for keeping your customers and stakeholders informed about the latest updates and news from your business.", "feed": null, "iframe": null, "image": "https://changes.page/api/blog/og?tag=changes.page&title=Changelog%20simplified.&content=The%20ultimate%20solution%20for%20keeping%20your%20customers%20and%20stakeholders%20informed%20about%20the%20latest%20updates%20and%20news%20from%20your%20business.&logo=https://changes.page/images/logo.png", "lang": "en", "logo": "https://changes.page/images/icons/icon-192x192.png", "publisher": "changes.page", "title": "changes.page | Changelog simplified.", "url": "https://changes.page", "video": null } } ``` # PDF Authentication & Headers Configure authentication and custom headers for generating PDFs from protected content, internal applications, and sites requiring specific browser identification. ## Authentication Options [#authentication-options] ### HTTP Basic Authentication (`httpAuth`) [#http-basic-authentication-httpauth] * **Default**: None * **Description**: Provides HTTP Basic Authentication credentials * **Format**: `base64url(username:password)` * **Example**: `httpAuth=YWRtaW46c2VjcmV0MTIz` ### Custom User Agent (`userAgent`) [#custom-user-agent-useragent] * **Default**: Standard Chrome user agent * **Description**: Override the browser's user agent string * **Format**: Base64URL encoded string * **Example**: `userAgent=TW96aWxsYS81LjAgKGN1c3RvbSBib3Qp` ## Usage Examples [#usage-examples] ### Basic Authentication [#basic-authentication] ``` https://cdn.capture.page/KEY/HASH/pdf?url=https://protected.example.com&httpAuth=YWRtaW46cGFzc3dvcmQ ``` ### Custom User Agent [#custom-user-agent] ``` https://cdn.capture.page/KEY/HASH/pdf?url=https://example.com&userAgent=TW96aWxsYS81LjAgKGJvdCkgQXBwbGVXZWJLaXQ ``` ### Combined Authentication [#combined-authentication] ``` https://cdn.capture.page/KEY/HASH/pdf?url=https://internal.app.com&httpAuth=YWRtaW46c2VjcmV0&userAgent=Q3VzdG9tQm90LzEuMA ``` # PDF Request ## URL Format [#url-format] * `YOUR API KEY`, You'll get this from the console * `GENERATED HASH`, MD5 hash of full url including query string and API Secret, `md5(API SECRET + REQUEST URL & OPTIONS)` * `REQUEST URL & OPTIONS`, Target URL and query string that contains all of the options you want to set ```text https://cdn.capture.page/e1ab7054-dabc-48d6-a33f-c18038aac1c8 /10958f7757e331dcacf235340f0beb81/pdf?url=https://news.ycombinator.com/ ``` ## Request Options [#request-options] | Query | Default value | Description | | --------------- | ------------- | ------------------------------------------------------------------------------------------------ | | url | - | URL-encoded target url | | preset | - | Apply predefined configuration preset | | httpAuth | - | HTTP Basic Authentication base64url encoded in format `base64url(username:password)` | | userAgent | - | Custom User agent (`base64url` encoded) | | width | - | Paper width, accepts values labeled with units. | | height | - | Paper height, accepts values labeled with units. | | marginTop | - | Top margin, accepts values labeled with units. | | marginRight | - | Right margin, accepts values labeled with units. | | marginBottom | - | Bottom margin, accepts values labeled with units. | | marginLeft | - | Left margin, accepts values labeled with units. | | scale | 1 | Scale of the webpage rendering | | landscape | false | Paper orientation | | delay | 0 | Delay in seconds before capturing | | stealth | false | Use faster stealth mode to avoid triggering bot challenges | | timestamp | - | This will force reload the image | | format | A4 | Paper format. The format options are Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6. | | fileName | - | File name used while saving to S3 | | s3Acl | - | The canned S3 ACL to apply to S3 uploads | | s3Redirect | false | Set as true to redirect response to uploaded S3 url | | printBackground | false | When true, prints background graphics | Check the following [**reference**](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property) for valid S3 ACL values. ## Custom Paper Size [#custom-paper-size] To capture using custom paper size, you can use the `width` and `height` options. Please note that both are mandatory for setting custom paper size. You can also customise the paper margins using `marginTop`, `marginRight`, `marginBottom` and `marginLeft` options. All four margins must be specified for setting custom margin. # Paper Size & Format Configure the paper dimensions, orientation, and format for your PDF output. These settings determine the layout and appearance of your generated PDFs. ## Paper Format [#paper-format] ### Format (`format`) [#format-format] * **Default**: `A4` * **Options**: `Letter`, `Legal`, `Tabloid`, `Ledger`, `A0`, `A1`, `A2`, `A3`, `A4`, `A5`, `A6` * **Example**: `format=Letter` * **Note**: Predefined sizes following international standards ### Landscape Orientation (`landscape`) [#landscape-orientation-landscape] * **Default**: `false` (portrait) * **Description**: Rotate paper to landscape orientation * **Example**: `landscape=true` * **Effect**: Swaps width and height dimensions ## Custom Paper Size [#custom-paper-size] ### Width (`width`) [#width-width] * **Default**: None (uses format) * **Description**: Custom paper width * **Example**: `width=8.5in` or `width=210mm` * **Required**: Must be used with height ### Height (`height`) [#height-height] * **Default**: None (uses format) * **Description**: Custom paper height * **Example**: `height=11in` or `height=297mm` * **Required**: Must be used with width ### Supported Units [#supported-units] * **Inches**: `in` (e.g., `8.5in`) * **Millimeters**: `mm` (e.g., `210mm`) * **Centimeters**: `cm` (e.g., `21cm`) * **Points**: `pt` (e.g., `612pt`) * **Pixels**: `px` (e.g., `816px` at 96 DPI) # PDF Rendering Options Control how web content is rendered into PDF format, including scaling and background graphics. ## Rendering Parameters [#rendering-parameters] ### Scale (`scale`) [#scale-scale] * **Default**: `1` * **Range**: 0.1 to 2 * **Example**: `scale=0.8` ### Print Background (`printBackground`) [#print-background-printbackground] * **Default**: `false` * **Description**: Include background colors and images * **Example**: `printBackground=true` ## Usage Examples [#usage-examples] ``` // Basic rendering https://cdn.capture.page/KEY/HASH/pdf?url=https://example.com // With backgrounds &printBackground=true // Scaled for smaller file &scale=0.75 ``` ## Scale Factor Guide [#scale-factor-guide] | Scale | Use Case | | ----- | ------------------------------- | | 0.75 | Reduced file size, good balance | | 1.0 | Default, full quality | | 1.25 | Enlarged text, easier reading | Scale affects text size, image resolution, file size, and page layout. # PDF Storage Options Configure how your generated PDFs are stored, named, and delivered. These options allow integration with AWS S3 and control over file management. ## Storage Parameters [#storage-parameters] ### File Name (`fileName`) [#file-name-filename] * **Default**: Auto-generated based on URL hash * **Description**: Custom filename for S3 storage * **Example**: `fileName=report-2024-q1` * **Note**: `.pdf` extension added automatically ### S3 Access Control (`s3Acl`) [#s3-access-control-s3acl] * **Default**: Private * **Description**: AWS S3 canned ACL for uploaded files * **Example**: `s3Acl=public-read` * **Reference**: [AWS S3 ACL Documentation](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property) ### S3 Redirect (`s3Redirect`) [#s3-redirect-s3redirect] * **Default**: `false` * **Description**: Redirect to S3 URL instead of serving PDF directly * **Example**: `s3Redirect=true` * **Result**: Returns 302 redirect to S3 location ## Usage Examples [#usage-examples] ### Basic S3 Upload [#basic-s3-upload] ``` https://cdn.capture.page/KEY/HASH/pdf?url=https://example.com&fileName=example-report ``` ### Public PDF with Redirect [#public-pdf-with-redirect] ``` https://cdn.capture.page/KEY/HASH/pdf?url=https://example.com&s3Acl=public-read&s3Redirect=true ``` ### Private Storage [#private-storage] ``` https://cdn.capture.page/KEY/HASH/pdf?url=https://example.com&fileName=confidential-doc&s3Acl=private ``` ## S3 Configuration [#s3-configuration] ### ACL Options [#acl-options] | ACL Value | Description | Use Case | | --------------------------- | ------------------------ | ------------------------- | | `private` | Only owner can access | Confidential documents | | `public-read` | Anyone can read | Public reports, brochures | | `public-read-write` | Anyone can read/write | Rarely used | | `authenticated-read` | AWS authenticated users | Internal sharing | | `bucket-owner-read` | Bucket owner can read | Cross-account access | | `bucket-owner-full-control` | Bucket owner full access | Managed services | # PDF Timing Options Control when the PDF is generated by adding delays or cache management. These options ensure content is fully loaded and manage how PDFs are cached. ## Timing Parameters [#timing-parameters] ### Delay (`delay`) [#delay-delay] * **Default**: `0` seconds * **Description**: Wait time before generating the PDF * **Range**: 0-60 seconds * **Example**: `delay=5` waits 5 seconds * **Note**: Use edge endpoint for delays > 25 seconds ### Timestamp (`timestamp`) [#timestamp-timestamp] * **Default**: None * **Description**: Force cache invalidation * **Example**: `timestamp=1677649200` * **Purpose**: Ensures fresh PDF generation ## Usage Examples [#usage-examples] ### Simple Delay [#simple-delay] Wait for animations to complete: ``` https://cdn.capture.page/KEY/HASH/pdf?url=https://example.com&delay=3 ``` ### Force Fresh Generation [#force-fresh-generation] Bypass cached version: ``` https://cdn.capture.page/KEY/HASH/pdf?url=https://example.com×tamp=1677649200 ``` ### Long Delay (Edge Endpoint) [#long-delay-edge-endpoint] For delays exceeding 25 seconds: ``` https://edge.capture.page/KEY/HASH/pdf?url=https://example.com&delay=45 ``` # Authentication & Headers Configure authentication and custom headers for capturing protected content, internal applications, and sites requiring specific browser identification. ## Authentication Options [#authentication-options] ### HTTP Basic Authentication (`httpAuth`) [#http-basic-authentication-httpauth] * **Default**: None * **Description**: Provides HTTP Basic Authentication credentials * **Format**: `base64url(username:password)` * **Example**: `httpAuth=YWRtaW46c2VjcmV0MTIz` ### Custom User Agent (`userAgent`) [#custom-user-agent-useragent] * **Default**: Standard Chrome user agent * **Description**: Override the browser's user agent string * **Format**: Base64URL encoded string * **Example**: `userAgent=TW96aWxsYS81LjAgKGN1c3RvbSBib3Qp` ## Usage Examples [#usage-examples] ### Basic Authentication [#basic-authentication] ``` https://cdn.capture.page/KEY/HASH/image?url=https://protected.example.com&httpAuth=YWRtaW46cGFzc3dvcmQ ``` ### Custom User Agent [#custom-user-agent] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&userAgent=TW96aWxsYS81LjAgKGJvdCkgQXBwbGVXZWJLaXQ ``` ### Combined Authentication [#combined-authentication] ``` https://cdn.capture.page/KEY/HASH/image?url=https://internal.app.com&httpAuth=YWRtaW46c2VjcmV0&userAgent=Q3VzdG9tQm90LzEuMA ``` ## HTTP Basic Authentication [#http-basic-authentication] ### How It Works [#how-it-works] 1. Credentials are base64url encoded 2. Sent as `Authorization: Basic {encoded}` header 3. Server validates before serving content 4. Screenshot captures authenticated page ### Encoding Credentials [#encoding-credentials] ```javascript // JavaScript const username = 'admin'; const password = 'secret123'; const credentials = btoa(`${username}:${password}`) .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=/g, ''); // Result: httpAuth=YWRtaW46c2VjcmV0MTIz ``` ```python # Python import base64 import urllib.parse username = 'admin' password = 'secret123' credentials = base64.urlsafe_b64encode( f'{username}:{password}'.encode() ).decode().rstrip('=') # Result: httpAuth=YWRtaW46c2VjcmV0MTIz ``` ```bash # Command line echo -n "admin:secret123" | base64 | tr '+/' '-_' | tr -d '=' ``` ### Common Use Cases [#common-use-cases] #### Internal Tools [#internal-tools] ``` // Corporate intranet &httpAuth=ZW1wbG95ZWU6Y29ycF9wYXNz&url=https://intranet.company.com // Staging environment &httpAuth=dGVzdDp0ZXN0MTIz&url=https://staging.app.com ``` #### Development Environments [#development-environments] ``` // Local development with auth &httpAuth=ZGV2OnNlY3JldA&url=https://dev.local.app // Password-protected staging &httpAuth=c3RhZ2U6cHJldmlldw&url=https://preview.site.com ``` #### Client Previews [#client-previews] ``` // Client review site &httpAuth=Y2xpZW50OnJldmlld18yMDI0&url=https://review.agency.com ``` ## User Agent Configuration [#user-agent-configuration] ### Why Customize User Agent [#why-customize-user-agent] 1. **Bot Detection**: Some sites block automated browsers 2. **Mobile Detection**: Trigger mobile-specific layouts 3. **Version Testing**: Test browser-specific features 4. **Analytics**: Identify screenshot traffic ### Common User Agents [#common-user-agents] #### Desktop Browsers [#desktop-browsers] ```javascript // Chrome on Windows const chrome = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'; // Firefox on Mac const firefox = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15) Gecko/20100101 Firefox/122.0'; // Safari on Mac const safari = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15'; ``` #### Mobile Browsers [#mobile-browsers] ```javascript // iPhone Safari const iphone = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1'; // Android Chrome const android = 'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Mobile Safari/537.36'; ``` #### Custom Bots [#custom-bots] ```javascript // Search engine bot const googlebot = 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'; // Custom crawler const custom = 'MyCompanyBot/1.0 (+https://company.com/bot)'; ``` ### Encoding User Agents [#encoding-user-agents] ```javascript // JavaScript function encodeUserAgent(ua) { return btoa(ua) .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=/g, ''); } const encoded = encodeUserAgent('MyBot/1.0'); // Use: &userAgent={encoded} ``` ## Advanced Authentication Patterns [#advanced-authentication-patterns] ### Multi-Step Authentication [#multi-step-authentication] For complex auth flows: ```javascript // 1. First capture login page const loginUrl = 'https://app.com/login'; // 2. Use session handling // Consider using headless browser locally // 3. Capture authenticated page const authenticatedUrl = 'https://app.com/dashboard'; ``` ### Token-Based Authentication [#token-based-authentication] For JWT or OAuth: ```javascript // Can't pass tokens directly // Options: // 1. Use httpAuth for basic auth gateway // 2. Create temporary access URL // 3. Use proxy with authentication ``` ### IP Whitelisting [#ip-whitelisting] For IP-restricted content: ``` // Contact support for: // - Dedicated IP options // - Proxy configuration // - VPN gateway setup ``` ## Security Best Practices [#security-best-practices] ### 1. Credential Management [#1-credential-management] ```javascript // DON'T hardcode credentials const auth = 'YWRtaW46MTIzNDU2'; // Bad // DO use environment variables const username = process.env.AUTH_USER; const password = process.env.AUTH_PASS; const auth = encodeCredentials(username, password); ``` ### 2. Temporary Credentials [#2-temporary-credentials] ```javascript // Generate time-limited credentials const tempUser = `temp_${Date.now()}`; const tempPass = generateSecurePassword(); // Revoke after use setTimeout(() => revokeCredentials(tempUser), 3600000); ``` ### 3. Secure Transmission [#3-secure-transmission] * Always use HTTPS URLs * Rotate credentials regularly * Monitor access logs * Use least privilege principle ## Troubleshooting [#troubleshooting] ### Authentication Failures [#authentication-failures] #### 401 Unauthorized [#401-unauthorized] ``` // Check encoding console.log(atob(auth.replace(/-/g, '+').replace(/_/g, '/'))); // Verify credentials work in browser // Check for special characters encoding ``` #### 403 Forbidden [#403-forbidden] * IP restrictions in place * Additional headers required * Session-based auth needed #### Blank Screenshots [#blank-screenshots] * JavaScript-based authentication * Multi-step login required * Cookie-based sessions ### User Agent Issues [#user-agent-issues] #### Site Still Detects Bot [#site-still-detects-bot] ``` // Try more complete UA &userAgent={full_browser_ua}&bypassBotDetection=true // Include all browser headers // Consider residential proxy ``` #### Mobile Site Not Loading [#mobile-site-not-loading] ``` // Combine with device emulation &emulateDevice=iphone_15&userAgent={mobile_ua} // Ensure UA matches device ``` ## Integration Examples [#integration-examples] ### CI/CD Pipeline [#cicd-pipeline] ```yaml # GitHub Actions example - name: Capture staging screenshot env: AUTH: ${{ secrets.STAGING_AUTH }} run: | curl "https://cdn.capture.page/KEY/HASH/image?url=https://staging.app.com&httpAuth=${AUTH}" ``` ### Monitoring Dashboard [#monitoring-dashboard] ```javascript // Capture internal metrics const dashboards = [ { url: 'metrics.internal', auth: 'bWV0cmljczpyZWFkb25seQ' }, { url: 'logs.internal', auth: 'bG9nczp2aWV3ZXI' }, { url: 'alerts.internal', auth: 'YWxlcnRzOm1vbml0b3I' } ]; dashboards.forEach(dashboard => { captureScreenshot(dashboard.url, dashboard.auth); }); ``` ### A/B Testing [#ab-testing] ```javascript // Test different user agents const userAgents = [ { name: 'Chrome', ua: encodedChromeUA }, { name: 'Firefox', ua: encodedFirefoxUA }, { name: 'Safari', ua: encodedSafariUA } ]; userAgents.forEach(({ name, ua }) => { const url = `...&userAgent=${ua}&fileName=test-${name}`; captureScreenshot(url); }); ``` ## Best Practices Summary [#best-practices-summary] ### 1. Authentication [#1-authentication] * Use HTTPS for all authenticated requests * Implement credential rotation * Monitor authentication failures * Use temporary credentials when possible ### 2. User Agents [#2-user-agents] * Match UA to your use case * Keep user agents updated * Test across different agents * Document custom agents used ### 3. Security [#3-security] * Never log credentials * Use environment variables * Implement access controls * Regular security audits # Capture Area & Selection Control exactly what part of the page gets captured in your screenshot. From full-page captures to specific elements, these options give you precise control over the capture area. ## Capture Modes [#capture-modes] ### Full Page Capture (`full`) [#full-page-capture-full] * **Default**: `false` * **Description**: Captures the entire page height, including content below the fold * **Example**: `full=true` * **Note**: Overrides any height clipping settings ### Element Selection [#element-selection] #### CSS Selector (`selector`) [#css-selector-selector] * **Default**: None * **Description**: Captures only the element matching the CSS selector * **Example**: `selector=.main-content` or `selector=header nav` * **URL Encoding**: Remember to URL-encode complex selectors #### Element ID (`selectorId`) [#element-id-selectorid] * **Default**: None * **Description**: Captures only the element with the specified ID * **Example**: `selectorId=hero-section` * **Note**: More performant than CSS selector for ID-based selection ## Clipping Rectangle [#clipping-rectangle] Define a specific rectangular area to capture within the viewport: ### Left Offset (`left`) [#left-offset-left] * **Default**: `0` * **Description**: X-coordinate of the top-left corner in pixels * **Range**: 0 to viewport width ### Top Offset (`top`) [#top-offset-top] * **Default**: `0` * **Description**: Y-coordinate of the top-left corner in pixels * **Range**: 0 to viewport height ### Width (`width`) [#width-width] * **Default**: Viewport width * **Description**: Width of the clipping rectangle in pixels * **Note**: Cannot exceed viewport width minus left offset ### Height (`height`) [#height-height] * **Default**: Viewport height * **Description**: Height of the clipping rectangle in pixels * **Note**: Cannot exceed viewport height minus top offset ## Usage Examples [#usage-examples] ### Full Page Screenshot [#full-page-screenshot] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&full=true ``` ### Capture Specific Element by Class [#capture-specific-element-by-class] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&selector=.featured-article ``` ### Capture Element by ID [#capture-element-by-id] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&selectorId=main-navigation ``` ### Custom Clipping Rectangle [#custom-clipping-rectangle] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&top=100&left=50&width=800&height=600 ``` ## Common Use Cases [#common-use-cases] ### Hero Section Capture [#hero-section-capture] Capture just the hero section of a landing page: ``` &selectorId=hero-section // or &selector=.hero-banner ``` ### Navigation Bar [#navigation-bar] Capture only the navigation area: ``` &selector=header nav // or with clipping &top=0&height=80&width=1920 ``` ### Content Area Without Sidebar [#content-area-without-sidebar] ``` &selector=main.content // or manually clip &left=300&width=900&top=100&height=800 ``` ### Footer Capture [#footer-capture] ``` &selector=footer // or &selectorId=site-footer ``` ## Selector Best Practices [#selector-best-practices] ### 1. Use Specific Selectors [#1-use-specific-selectors] ``` // Good &selector=article.post-content &selector=#main-content .featured-section // Avoid if possible &selector=div &selector=.content (too generic) ``` ### 2. ID vs Class Selection [#2-id-vs-class-selection] * Use `selectorId` when targeting elements with unique IDs (faster) * Use `selector` for class-based or complex selections ### 3. URL Encoding [#3-url-encoding] Always URL-encode complex selectors: ``` // Original: section[data-type="hero"] &selector=section%5Bdata-type%3D%22hero%22%5D // Original: .class1.class2 &selector=.class1.class2 ``` ## Clipping Best Practices [#clipping-best-practices] ### 1. Stay Within Viewport [#1-stay-within-viewport] Ensure your clipping rectangle stays within the viewport bounds: ```javascript // Valid (assuming 1920x1080 viewport) top=100&left=100&width=1720&height=880 // Invalid (exceeds viewport) top=100&left=100&width=2000&height=1200 ``` ### 2. Account for Responsive Design [#2-account-for-responsive-design] Different viewport sizes may require different clipping coordinates: ``` // Desktop &vw=1920&vh=1080&left=460&width=1000 // Mobile (adjusted proportionally) &vw=375&vh=667&left=37&width=300 ``` ### 3. Combine with Full Page [#3-combine-with-full-page] When using `full=true`, clipping width is respected but height is ignored: ``` &full=true&left=100&width=1200 // Captures full height but only 1200px width starting from left=100 ``` ## Advanced Techniques [#advanced-techniques] ### Dynamic Element Capture [#dynamic-element-capture] For elements that load dynamically, combine with wait options: ``` &waitFor=.dynamic-content&selector=.dynamic-content ``` ### Multiple Element Capture [#multiple-element-capture] To capture multiple elements, use a parent selector that contains all desired elements: ``` // Capture all articles &selector=.articles-container // Capture specific sections &selector=main section:nth-of-type(2) ``` ### Viewport-Relative Capture [#viewport-relative-capture] Calculate clipping based on viewport percentages: ```javascript const vw = 1920; const vh = 1080; // Capture center 80% of viewport const left = vw * 0.1; // 10% from left const width = vw * 0.8; // 80% width const top = vh * 0.1; // 10% from top const height = vh * 0.8; // 80% height const url = `&left=${left}&width=${width}&top=${top}&height=${height}`; ``` ## Performance Tips [#performance-tips] ### 1. Element Selection vs Clipping [#1-element-selection-vs-clipping] * Element selection is more reliable for dynamic content * Clipping is faster for fixed-position content ### 2. Full Page Considerations [#2-full-page-considerations] * Full page captures use more memory and time * Consider element selection for long pages ### 3. Selector Performance [#3-selector-performance] * ID selectors are fastest * Complex CSS selectors may slow down capture * Avoid universal selectors (\*) ## Common Issues and Solutions [#common-issues-and-solutions] ### Element Not Found [#element-not-found] If selector doesn't match any element: * Verify selector syntax * Check if element is dynamically loaded (use `waitFor`) * Ensure proper URL encoding ### Clipping Outside Viewport [#clipping-outside-viewport] If clipping appears cut off: * Verify coordinates are within viewport bounds * Check viewport size settings * Consider using element selection instead ### Dynamic Content [#dynamic-content] For content that changes position: * Use element selectors instead of fixed coordinates * Implement wait strategies * Consider multiple captures # Device Emulation Capture screenshots as they would appear on specific devices. Device emulation automatically configures viewport, user agent, touch capabilities, and pixel density. ## Device Emulation Parameter [#device-emulation-parameter] ### emulateDevice (`emulateDevice`) [#emulatedevice-emulatedevice] * **Default**: None * **Example**: `emulateDevice=iphone_15_pro` * **Effect**: Overrides viewport, user agent, and scale factor settings ## Get Available Devices [#get-available-devices] Retrieve the complete list of supported devices: ```bash curl "https://edge.capture.page/screenshot/devices" ``` **Sample Response:** ```json { "success": true, "count": 120, "devices": [ { "name": "iPhone 15 Pro", "key": "iphone_15_pro", "viewport": { "width": 393, "height": 852, "deviceScaleFactor": 3 } } ] } ``` ## Common Devices [#common-devices] **Smartphones:** `iphone_15_pro`, `iphone_15`, `pixel_8`, `galaxy_s23` **Tablets:** `ipad_pro_12_9`, `ipad_air`, `galaxy_tab_s9` **Desktop:** `desktop_hd`, `laptop` **For complete list:** Use the `/screenshot/devices` API endpoint ## Usage Examples [#usage-examples] ``` // iPhone https://cdn.capture.page/KEY/HASH/image?url=https://example.com&emulateDevice=iphone_15_pro // iPad &emulateDevice=ipad_air // Desktop &emulateDevice=desktop_hd ``` ## What's Included [#whats-included] Device emulation automatically configures: * Viewport dimensions (exact screen size) * Device scale factor (pixel density) * User agent string * Touch capabilities * Mobile-optimized rendering ## Best Practices [#best-practices] **Use real device profiles:** * ✅ `emulateDevice=iphone_15_pro` * ❌ `vw=393&vh=852&scaleFactor=3` (manual viewport) **Match your audience:** Use iPhone for iOS users, Pixel/Galaxy for Android users. ## Troubleshooting [#troubleshooting] **Device Not Found:** Check `/screenshot/devices` endpoint for correct key **Unexpected Layout:** Device emulation triggers mobile/tablet layouts, site may detect and redirect **Wrong Screen Size:** Device emulation overrides manual viewport settings # Screenshot Request ## URL Format [#url-format] * `YOUR API KEY`, You'll get this from the console * `GENERATED HASH`, MD5 hash of full url including query string and API Secret, `md5(API SECRET + REQUEST URL & OPTIONS)` * `REQUEST URL & OPTIONS`, Target URL and query string that contains all of the options you want to set ```html ``` > **Note:** > If your requests could take more than 60 seconds to complete due to delay or wait time, you should use the `edge` endpoint (`edge.capture.page`) instead of `cdn` endpoint. Our CDN is optimized for fast response times and is not suitable for long running requests. ## Request Options [#request-options] | Query | Default value | Description | | ------------------ | --------------- | ---------------------------------------------------------------------------------------- | | url | - | URL-encoded target url | | preset | - | Apply predefined configuration preset | | httpAuth | - | HTTP Basic Authentication base64url encoded in format `base64url(username:password)` | | vw | 1440 | Viewport Width | | vh | 900 | Viewport Height | | scaleFactor | 1 | Specify screen scale factor (dpr) | | top | 0 | Top offset for clipping rectangle | | left | 0 | Left offset for clipping rectangle | | width | Viewport Width | Clipping Width | | height | Viewport Height | Clipping Height | | waitFor | - | Capture will wait for this CSS selector to appear before taking screenshot | | waitForId | - | Capture will wait for this id to appear before taking screenshot | | delay | 0 | Delay in seconds before capturing | | full | false | Set full as true to capture full page | | darkMode | false | Take a dark mode screenshot | | blockCookieBanners | false | Dismiss cookie consent banners or popups before taking screenshot | | blockAds | false | Block ads before taking screenshot | | bypassBotDetection | false | Bypass bot detection / solve captchas | | stealth | false | Use faster stealth mode to avoid triggering bot challenges | | selector | false | Take a screenshot of the element that matches this selector | | selectorId | false | Take a screenshot of the element that matches this element ID | | transparent | false | Capture with a transparent background | | userAgent | - | Custom User agent (`base64url` encoded) | | emulateDevice | - | Emulate a specific device (e.g., `iphone_14`, `ipad`, `pixel_8`) - see device list below | | timestamp | - | This will force reload the image | | fresh | false | Take a fresh screenshot instead of getting a cached version | | resizeWidth | - | Resize the captured image to provided width, both resize height and width is mandatory | | resizeHeight | - | Resize the captured image to provided height, both resize height and width is mandatory | | fileName | - | File name used while saving to S3 | | s3Acl | - | The canned S3 ACL to apply to S3 uploads | | s3Redirect | false | Set as true to redirect response to uploaded S3 url | | skipUpload | false | Avoid uploading to S3 when this options is set as true | | type | png | Specify screenshot type, can be either `jpeg`, `png` or `webp`. | | bestFormat | false | Use best image format, this will try to use webp for modern browsers, png for older ones | Check the following [**reference**](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property) for valid S3 ACL values. ## Stealth vs. Bot Detection Bypass [#stealth-vs-bot-detection-bypass] Use `stealth=true` when you want a faster capture mode that reduces the chance of triggering bot challenges. Stealth mode cannot solve captchas; it tries to avoid causing them. Use `bypassBotDetection=true` when a page is expected to show bot detection or captchas. This mode can solve captchas, but it is slower than stealth mode. # Image Output Options Control the format, quality, and dimensions of your screenshot output. ## Image Format Options [#image-format-options] ### Image Type (`type`) [#image-type-type] * **Default**: `png` * **Options**: `png`, `jpeg`, `webp` * **Example**: `type=jpeg` ### Best Format (`bestFormat`) [#best-format-bestformat] * **Default**: `false` * **Description**: Automatically selects optimal format based on browser support * **Example**: `bestFormat=true` ## Format Specifications [#format-specifications] **PNG:** Lossless, supports transparency, larger files. Best for text/UI. **JPEG:** Lossy, no transparency, smaller files (200-500 KB). Best for photos. **WebP:** Modern format, 25-35% smaller, supports transparency. Best for web. ## Image Resizing [#image-resizing] Both width and height must be specified together: * `resizeWidth`: Target width in pixels * `resizeHeight`: Target height in pixels ``` // Social media (Open Graph) &resizeWidth=1200&resizeHeight=630 // Thumbnail &resizeWidth=300&resizeHeight=200 ``` ## Transparent Background [#transparent-background] ### Transparent (`transparent`) [#transparent-transparent] * **Default**: `false` * **Format**: PNG or WebP only * **Example**: `transparent=true` ## Usage Examples [#usage-examples] ``` // High-quality PNG https://cdn.capture.page/KEY/HASH/image?url=https://example.com&type=png // Optimized JPEG &type=jpeg // WebP with resize &type=webp&resizeWidth=1200&resizeHeight=630 // Transparent logo &selector=.logo&transparent=true&type=png ``` ## Best Practices [#best-practices] **Format Selection:** * PNG: Text clarity, UI elements, transparency required * JPEG: Photos, file size constraints * WebP: Modern web apps, best compression **Maintain Aspect Ratio:** ```javascript const aspectRatio = 1920 / 1080; const targetHeight = Math.round(targetWidth / aspectRatio); ``` **Viewport vs Resize:** * Viewport: Renders at specific size * Resize: Captures then scales * Combined: Render large, output small (best quality) ## Troubleshooting [#troubleshooting] **Black Background:** Ensure `type=png` or `type=webp`, page must have CSS transparency **Blurry Images:** Use higher source resolution, avoid upscaling **Format Not Supported:** Use `bestFormat=true` for auto-selection # Page Enhancements Enhance and modify web pages before capturing screenshots. These options help you capture cleaner, more consistent screenshots by removing distractions and applying visual modifications. ## Enhancement Options [#enhancement-options] ### Dark Mode (`darkMode`) [#dark-mode-darkmode] * **Default**: `false` * **Description**: Automatically applies dark mode styling to the page * **Example**: `darkMode=true` * **How it works**: Injects CSS to invert colors and adjust brightness ### Block Cookie Banners (`blockCookieBanners`) [#block-cookie-banners-blockcookiebanners] * **Default**: `false` * **Description**: Automatically dismisses cookie consent popups * **Example**: `blockCookieBanners=true` * **Coverage**: Works with most popular cookie consent solutions ### Block Ads (`blockAds`) [#block-ads-blockads] * **Default**: `false` * **Description**: Removes advertisements before screenshot * **Example**: `blockAds=true` ### Bypass Bot Detection (`bypassBotDetection`) [#bypass-bot-detection-bypassbotdetection] * **Default**: `false` * **Description**: Attempts to bypass anti-bot systems and CAPTCHAs * **Example**: `bypassBotDetection=true` * **Note**: Uses advanced browser fingerprinting techniques ## Usage Examples [#usage-examples] ### Clean Content Screenshot [#clean-content-screenshot] Remove all distractions: ``` https://cdn.capture.page/KEY/HASH/image?url=https://news-site.com&blockAds=true&blockCookieBanners=true ``` ### Dark Mode Screenshot [#dark-mode-screenshot] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&darkMode=true ``` ### Access Protected Content [#access-protected-content] ``` https://cdn.capture.page/KEY/HASH/image?url=https://protected-site.com&bypassBotDetection=true ``` ### All Enhancements Combined [#all-enhancements-combined] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&darkMode=true&blockAds=true&blockCookieBanners=true ``` ## Dark Mode Details [#dark-mode-details] ### How It Works [#how-it-works] The dark mode feature applies intelligent color inversion: 1. Inverts light backgrounds to dark 2. Adjusts text colors for readability 3. Preserves images and videos 4. Maintains brand colors where possible ### Best Use Cases [#best-use-cases] * Creating dark theme previews * Generating night-mode documentation * Consistent screenshot styling * Accessibility testing ### Limitations [#limitations] * May not work perfectly with all sites * Sites with existing dark themes might double-invert * Some custom CSS might override the effect ### Tips for Better Results [#tips-for-better-results] ``` // Wait for dark mode to fully apply &darkMode=true&delay=1 // Combine with specific selectors &darkMode=true&selector=.main-content // Some sites need body class detection &darkMode=true&waitFor=body.dark-mode ``` ## Cookie Banner Blocking [#cookie-banner-blocking] ### Supported Providers [#supported-providers] * CookieBot * OneTrust * TrustArc * Quantcast Choice * Cookie Notice * GDPR Cookie Consent * And many more... ### How It Works [#how-it-works-1] 1. Detects common cookie banner patterns 2. Automatically clicks accept/dismiss buttons 3. Hides banners that can't be dismissed 4. Removes overlay elements ### Best Practices [#best-practices] ``` // Allow time for banner to appear and be dismissed &blockCookieBanners=true&delay=2 // Combine with element waiting &blockCookieBanners=true&waitFor=.content-loaded ``` ### When It Might Not Work [#when-it-might-not-work] * Custom-built consent systems * Banners requiring scrolling * Multi-step consent flows * Region-specific implementations ## Ad Blocking [#ad-blocking] ### What Gets Blocked [#what-gets-blocked] * Display advertisements * Video ad overlays * Popup advertisements * Tracking pixels * Social media widgets (optionally) * Newsletter popups ### Performance Benefits [#performance-benefits] * Faster page load times * Reduced bandwidth usage * Cleaner screenshots * Less JavaScript execution ### Use Cases [#use-cases] ``` // News article without ads &url=https://news-site.com/article&blockAds=true // Product page focused on content &url=https://shopping-site.com/product&blockAds=true&selector=.product-details ``` ## Bot Detection Bypass [#bot-detection-bypass] ### Supported Systems [#supported-systems] * Cloudflare challenges * ReCAPTCHA (limited) * Basic bot detection scripts * Fingerprinting protection ### Technical Approach [#technical-approach] * Realistic browser fingerprints * Human-like behavior simulation * Proper browser headers * Cookie handling ### Important Notes [#important-notes] * Not 100% guaranteed * Respects robots.txt * Should be used responsibly * May increase processing time ### When to Use [#when-to-use] ``` // Sites with Cloudflare protection &url=https://protected-site.com&bypassBotDetection=true // Sites checking for automation &url=https://anti-bot-site.com&bypassBotDetection=true&delay=3 ``` ## Combining Enhancements [#combining-enhancements] ### News Site Screenshot [#news-site-screenshot] Clean article capture: ``` &blockAds=true&blockCookieBanners=true&selector=article ``` ### E-commerce Product Page [#e-commerce-product-page] ``` &blockAds=true&blockCookieBanners=true&waitFor=.product-image ``` ### Documentation Site [#documentation-site] ``` &darkMode=true&blockCookieBanners=true&selector=.docs-content ``` ### Social Media [#social-media] ``` &blockAds=true&bypassBotDetection=true&waitFor=.feed-loaded ``` ## Performance Considerations [#performance-considerations] ### Processing Time [#processing-time] Each enhancement adds processing time: * Dark Mode: +0.5-1s * Cookie Banners: +1-2s * Ad Blocking: +0.5-1s * Bot Bypass: +2-5s ### Resource Usage [#resource-usage] * Ad blocking reduces bandwidth * Bot bypass increases CPU usage * Dark mode has minimal impact * Cookie blocking may trigger reflows ### Optimization Tips [#optimization-tips] 1. Only enable needed enhancements 2. Combine with appropriate delays 3. Use specific selectors when possible 4. Monitor timeout occurrences ## Troubleshooting [#troubleshooting] ### Dark Mode Issues [#dark-mode-issues] * **Double inversion**: Site already has dark mode * **Broken layouts**: Complex CSS interactions * **Missing elements**: JavaScript-dependent styles ### Cookie Banner Problems [#cookie-banner-problems] * **Banner reappears**: Session-based consent * **Partial blocking**: Multi-layer popups * **Site breaks**: Consent required for function ### Ad Blocking Conflicts [#ad-blocking-conflicts] * **Missing content**: Overly aggressive filtering * **Layout shifts**: Ad placeholder removal * **False positives**: Content misidentified as ads ### Bot Detection Failures [#bot-detection-failures] * **Still blocked**: Advanced protection * **CAPTCHAs appear**: Manual intervention required * **Rate limiting**: Too many requests ## Best Practices [#best-practices-1] ### 1. Test Enhancement Combinations [#1-test-enhancement-combinations] Different sites respond differently: ``` // Start simple &blockAds=true // Add enhancements gradually &blockAds=true&blockCookieBanners=true // Full enhancement suite &blockAds=true&blockCookieBanners=true&darkMode=true ``` ### 2. Allow Processing Time [#2-allow-processing-time] Enhancements need time to apply: ``` // Quick enhancements &blockAds=true&delay=1 // Complex scenarios &blockAds=true&blockCookieBanners=true&bypassBotDetection=true&delay=3 ``` ### 3. Monitor Results [#3-monitor-results] * Check for visual artifacts * Verify content completeness * Ensure consistent results * Track processing times # Storage & Caching Control how screenshots are stored, cached, and delivered. These options help optimize performance, reduce costs, and integrate with your existing storage infrastructure. ## Storage Options [#storage-options] ### File Name (`fileName`) [#file-name-filename] * **Default**: Auto-generated based on URL hash * **Description**: Custom filename for S3 storage * **Example**: `fileName=homepage-screenshot.png` * **Note**: Extension added automatically based on image type ### S3 Access Control (`s3Acl`) [#s3-access-control-s3acl] * **Default**: Private * **Description**: AWS S3 canned ACL for uploaded files * **Example**: `s3Acl=public-read` * **Options**: See [AWS S3 ACL Reference](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property) ### S3 Redirect (`s3Redirect`) [#s3-redirect-s3redirect] * **Default**: `false` * **Description**: Redirect to S3 URL instead of serving image directly * **Example**: `s3Redirect=true` * **Result**: Returns 302 redirect to S3 location ### Skip Upload (`skipUpload`) [#skip-upload-skipupload] * **Default**: `false` * **Description**: Return image directly without S3 upload * **Example**: `skipUpload=true` * **Use case**: When you want to handle storage yourself ## Caching Options [#caching-options] ### Fresh Screenshot (`fresh`) [#fresh-screenshot-fresh] * **Default**: `false` * **Description**: Force a new screenshot, bypassing cache * **Example**: `fresh=true` * **Effect**: Ignores cached version if exists ### Cache Buster (`timestamp`) [#cache-buster-timestamp] * **Default**: None * **Description**: Force cache invalidation with unique value * **Example**: `timestamp=1677649200` * **Common use**: `timestamp={current_unix_time}` ## Usage Examples [#usage-examples] ### Basic S3 Upload [#basic-s3-upload] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&fileName=example-homepage ``` ### Public S3 with Redirect [#public-s3-with-redirect] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&s3Acl=public-read&s3Redirect=true ``` ### Force Fresh Screenshot [#force-fresh-screenshot] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&fresh=true ``` ### Skip Storage [#skip-storage] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&skipUpload=true ``` ## S3 Configuration [#s3-configuration] ### Available ACL Options [#available-acl-options] | ACL Value | Description | Use Case | | --------------------------- | -------------------------------- | -------------------- | | `private` | Owner has full control | Internal use only | | `public-read` | Public can read, owner can write | Public websites | | `public-read-write` | Public can read and write | Rarely used | | `authenticated-read` | AWS users can read | Shared within AWS | | `bucket-owner-read` | Bucket owner can read | Cross-account access | | `bucket-owner-full-control` | Bucket owner has full control | Managed services | ### Setting Up S3 Storage [#setting-up-s3-storage] 1. **Configure S3 Bucket** in your Capture account 2. **Set appropriate permissions** for Capture to write 3. **Choose ACL strategy** based on your needs 4. **Configure CORS** if serving directly from S3 ### S3 File Organization [#s3-file-organization] ``` // Default structure /screenshots/ /{year}/{month}/{day}/ /{generated-hash}.{extension} // With custom fileName /screenshots/ /{year}/{month}/{day}/ /{your-filename}.{extension} ``` ## Caching Strategy [#caching-strategy] ### How Caching Works [#how-caching-works] 1. **Request received** with URL and options 2. **Cache check** based on URL + options hash 3. **If cached**: Return existing screenshot 4. **If not cached**: Generate and store new screenshot ### Cache Duration [#cache-duration] * **CDN Edge**: 24 hours * **Browser**: Controlled by headers * **S3 Storage**: Permanent until deleted ### Cache Key Components [#cache-key-components] Cache is based on: * Target URL * All screenshot options * API key * Timestamp (if provided) ## Common Patterns [#common-patterns] ### Daily Screenshots [#daily-screenshots] Force daily updates: ```javascript const today = new Date().toISOString().split('T')[0]; const url = `...×tamp=${today}`; ``` ### Hourly Updates [#hourly-updates] More frequent updates: ```javascript const hour = new Date().getHours(); const url = `...×tamp=${Date.now()}-${hour}`; ``` ### Version-based Caching [#version-based-caching] Tie to deployments: ```javascript const version = 'v1.2.3'; const url = `...×tamp=${version}`; ``` ### User-specific Screenshots [#user-specific-screenshots] Personalized content: ```javascript const userId = 'user123'; const url = `...&fileName=dashboard-${userId}&fresh=true`; ``` ## Performance Optimization [#performance-optimization] ### 1. Leverage Caching [#1-leverage-caching] ``` // First request: Generated https://cdn.capture.page/KEY/HASH/image?url=site.com // Subsequent requests: Cached https://cdn.capture.page/KEY/HASH/image?url=site.com ``` ### 2. Smart Cache Invalidation [#2-smart-cache-invalidation] ```javascript // Only refresh when content changes const contentHash = generateContentHash(); const url = `...×tamp=${contentHash}`; ``` ### 3. Pregenerate Common Screenshots [#3-pregenerate-common-screenshots] ```javascript // Warm cache for popular pages const popularPages = ['/', '/about', '/products']; popularPages.forEach(page => { // Generate screenshot in background fetch(`capture.page/...?url=${domain}${page}`); }); ``` ## S3 Integration Patterns [#s3-integration-patterns] ### Direct S3 Serving [#direct-s3-serving] ``` // 1. Generate with public ACL &s3Acl=public-read&s3Redirect=true // 2. Store S3 URL from redirect const s3Url = response.headers.location; // 3. Serve directly from S3 ``` ### CDN Integration [#cdn-integration] ``` // Upload to S3 with CloudFront &s3Acl=public-read&fileName=cdn-optimized // Configure CloudFront origin // Serve via CDN URL ``` ### Backup Strategy [#backup-strategy] ``` // Keep local copy and S3 backup &fileName=backup-${date}&s3Acl=private // Retrieve later if needed // Access via S3 API ``` ## Cost Optimization [#cost-optimization] ### 1. Cache Effectively [#1-cache-effectively] * Use default caching when possible * Avoid `fresh=true` unless necessary * Implement smart timestamp strategies ### 2. Storage Management [#2-storage-management] ``` // Skip S3 for temporary screenshots &skipUpload=true // Use public-read for CDN serving &s3Acl=public-read&s3Redirect=true ``` ### 3. Filename Strategy [#3-filename-strategy] ``` // Organize by date &fileName=screenshots/2024/03/homepage // Organize by feature &fileName=products/widget-preview // Version control &fileName=v2/dashboard-dark-mode ``` ## Advanced Techniques [#advanced-techniques] ### Conditional Caching [#conditional-caching] ```javascript // Fresh for logged-in users const options = isLoggedIn ? '&fresh=true' : ''; // Fresh during business hours const isBusinessHours = hour >= 9 && hour <= 17; const options = isBusinessHours ? '&fresh=true' : ''; ``` ### Multi-Region Strategy [#multi-region-strategy] ``` // Use different buckets per region &fileName=us-east-1/screenshot &fileName=eu-west-1/screenshot ``` ### Lifecycle Policies [#lifecycle-policies] Configure S3 lifecycle rules: * Move to Glacier after 30 days * Delete after 90 days * Transition to IA storage ## Troubleshooting [#troubleshooting] ### S3 Upload Failures [#s3-upload-failures] Common causes: * Invalid ACL permissions * Bucket policy restrictions * Region mismatches * Filename conflicts Solutions: * Verify bucket permissions * Check ACL compatibility * Use unique filenames * Enable S3 logging ### Cache Not Updating [#cache-not-updating] Issues: * CDN edge cache * Browser cache * Incorrect timestamp Solutions: ``` // Force fresh everywhere &fresh=true×tamp=${Date.now()} // Clear browser cache Cache-Control: no-cache // Purge CDN cache // Use CDN API or console ``` ### Redirect Issues [#redirect-issues] If S3 redirect fails: * Check CORS configuration * Verify public-read ACL * Ensure bucket policy allows * Test S3 URL directly ## Best Practices [#best-practices] ### 1. Plan Your Storage [#1-plan-your-storage] ``` // Organized structure &fileName=year/month/project/page-state // Searchable naming &fileName=client-name/project-id/screenshot-type ``` ### 2. Cache Strategically [#2-cache-strategically] ``` // Static content: Use default cache // Dynamic content: Use timestamp // User content: Use fresh=true ``` ### 3. Monitor Usage [#3-monitor-usage] * Track cache hit rates * Monitor S3 storage costs * Set up alerts for failures * Regular cleanup old files ## Security Considerations [#security-considerations] ### 1. ACL Selection [#1-acl-selection] ``` // Public content &s3Acl=public-read // Private content &s3Acl=private // Default // Temporary access // Use presigned URLs ``` ### 2. Filename Security [#2-filename-security] * Avoid sensitive info in filenames * Use hashes for user content * Implement access controls ### 3. Cache Security [#3-cache-security] * Don't cache sensitive content * Use fresh=true for private data * Consider separate buckets # Timing & Waiting Options Control when the screenshot is taken by adding delays or waiting for specific elements to appear. These options are essential for capturing dynamic content, animations, and JavaScript-rendered pages. ## Timing Parameters [#timing-parameters] ### Delay (`delay`) [#delay-delay] * **Default**: `0` seconds * **Description**: Fixed delay before capturing the screenshot * **Range**: 0-60 seconds (use edge endpoint for delays > 25 seconds) * **Example**: `delay=3` waits 3 seconds before capture ### Wait for CSS Selector (`waitFor`) [#wait-for-css-selector-waitfor] * **Default**: None * **Description**: Waits for an element matching the CSS selector to appear * **Timeout**: 30 seconds maximum * **Example**: `waitFor=.loading-complete` ### Wait for Element ID (`waitForId`) [#wait-for-element-id-waitforid] * **Default**: None * **Description**: Waits for an element with specific ID to appear * **Timeout**: 30 seconds maximum * **Example**: `waitForId=content-loaded` ## Usage Examples [#usage-examples] ### Simple Delay [#simple-delay] Wait 5 seconds for page animations: ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&delay=5 ``` ### Wait for Specific Element [#wait-for-specific-element] Wait for dynamic content to load: ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&waitFor=.chart-container ``` ### Wait for Element by ID [#wait-for-element-by-id] ``` https://cdn.capture.page/KEY/HASH/image?url=https://example.com&waitForId=data-table ``` ## Common Scenarios [#common-scenarios] ### Single Page Applications (SPAs) [#single-page-applications-spas] SPAs often render content after initial page load: ``` // Wait for React app to mount &waitFor=.app-ready // Wait for Vue component &waitFor=[data-v-mounted="true"] // Wait for Angular component &waitFor=app-root.ng-star-inserted ``` ### Lazy-Loaded Images [#lazy-loaded-images] Ensure images are loaded before capture: ``` // Wait for specific image &waitFor=img.hero-image // Wait for all images in container &waitFor=.gallery img:last-child ``` ### Loading Animations [#loading-animations] Skip loading states: ``` // Wait for loader to disappear &waitFor=body:not(.loading) // Wait for skeleton screens to be replaced &waitFor=.content:not(.skeleton) ``` ### Data Visualizations [#data-visualizations] Capture charts after they render: ``` // Chart.js &waitFor=canvas.chart-rendered // D3.js visualizations &waitFor=svg.visualization-complete // Highcharts &waitFor=.highcharts-container ``` ## Best Practices [#best-practices] ### 1. Prefer waitFor Over delay [#1-prefer-waitfor-over-delay] Dynamic waits are more reliable and faster than fixed delays: ``` // Better: Wait for specific condition &waitFor=.content-loaded // Avoid: Arbitrary delay &delay=10 ``` ### 2. Use Specific Selectors [#2-use-specific-selectors] Target the exact element you're waiting for: ``` // Good: Specific to content &waitFor=article.post-content // Bad: Too generic &waitFor=div ``` ### 3. Combine Multiple Strategies [#3-combine-multiple-strategies] For complex loading scenarios: ``` // Initial delay + element wait &delay=1&waitFor=.charts-container // Wait for ID then add small delay for animations &waitForId=dashboard&delay=0.5 ``` ### 4. Handle Timeout Gracefully [#4-handle-timeout-gracefully] If element might not appear: * Set appropriate expectations * Consider fallback strategies * Monitor timeout failures ## Advanced Waiting Strategies [#advanced-waiting-strategies] ### Wait for Text Content [#wait-for-text-content] ``` // Wait for specific text to appear &waitFor=h1:contains("Welcome") // Wait for non-empty element &waitFor=.price:not(:empty) ``` ### Wait for Attribute Changes [#wait-for-attribute-changes] ``` // Wait for data attribute &waitFor=[data-loaded="true"] // Wait for class addition &waitFor=.modal.open ``` ### Wait for Network Idle [#wait-for-network-idle] While not directly supported, you can approximate: ``` // Wait for loading indicators to disappear &waitFor=body:not(.ajax-loading) // Wait for final element in AJAX response &waitFor=.pagination-loaded ``` ## Performance Optimization [#performance-optimization] ### 1. Minimize Wait Times [#1-minimize-wait-times] * Use the most specific selector possible * Target the first reliable indicator of readiness * Avoid waiting for elements that load last ### 2. Edge Endpoint for Long Waits [#2-edge-endpoint-for-long-waits] For delays exceeding 25 seconds: ``` // Use edge endpoint https://edge.capture.page/KEY/HASH/image?url=site.com&delay=45 // Instead of CDN endpoint https://cdn.capture.page/... ``` ### 3. Timeout Considerations [#3-timeout-considerations] * Default timeout is 30 seconds * Plan for timeout scenarios * Log and monitor timeout occurrences ## Common Patterns by Framework [#common-patterns-by-framework] ### React Applications [#react-applications] ``` // Root component mounted &waitFor=#root>div // Specific component loaded &waitFor=[data-testid="main-content"] // Redux state updated &waitFor=[data-ready="true"] ``` ### Vue.js Applications [#vuejs-applications] ``` // Vue app mounted &waitFor=#app>div // Component lifecycle &waitFor=.vue-component-mounted // Vuex store populated &waitFor=[data-store-ready] ``` ### Angular Applications [#angular-applications] ``` // Angular bootstrapped &waitFor=app-root>* // Component rendered &waitFor=.ng-star-inserted // HTTP calls completed &waitFor=.data-loaded ``` ## Debugging Tips [#debugging-tips] ### 1. Element Not Found [#1-element-not-found] If waitFor times out: * Verify selector in browser DevTools * Check if element is in iframe * Ensure element isn't removed after appearing ### 2. Premature Capture [#2-premature-capture] If capturing too early: * Element might appear briefly then change * Use more specific end-state selector * Add small delay after element appears ### 3. Inconsistent Results [#3-inconsistent-results] For flaky captures: * Identify all dynamic elements * Use most stable indicator * Consider multiple wait conditions ## Combining with Other Options [#combining-with-other-options] ### With Full Page Capture [#with-full-page-capture] ``` // Wait for content then capture full page &waitFor=.all-content-loaded&full=true ``` ### With Element Selection [#with-element-selection] ``` // Wait for element then capture it &waitFor=.chart-container&selector=.chart-container ``` ### With Dark Mode [#with-dark-mode] ``` // Wait for theme to apply &darkMode=true&waitFor=body.dark-theme ``` # Viewport Configuration The viewport defines the visible area of the web page that will be captured in your screenshot. Properly configuring the viewport is crucial for capturing web pages exactly as they appear on different devices and screen sizes. ## Viewport Parameters [#viewport-parameters] ### Width (`vw`) [#width-vw] * **Default**: `1440` pixels * **Description**: Sets the viewport width in pixels * **Range**: Any positive integer value * **Example**: `vw=1920` for Full HD width ### Height (`vh`) [#height-vh] * **Default**: `900` pixels * **Description**: Sets the viewport height in pixels * **Range**: Any positive integer value * **Example**: `vh=1080` for Full HD height ### Scale Factor (`scaleFactor`) [#scale-factor-scalefactor] * **Default**: `1` * **Description**: Device pixel ratio (DPR) that affects the pixel density * **Range**: Typically between 1 and 3 * **Common Values**: * `1` - Standard resolution (non-retina) * `2` - High resolution (retina displays) * `3` - Ultra-high resolution (modern mobile devices) ## Usage Examples [#usage-examples] ### Standard Desktop Screenshot [#standard-desktop-screenshot] ``` https://cdn.capture.page/YOUR_API_KEY/HASH/image?url=https://example.com&vw=1920&vh=1080 ``` ### Mobile-sized Screenshot [#mobile-sized-screenshot] ``` https://cdn.capture.page/YOUR_API_KEY/HASH/image?url=https://example.com&vw=375&vh=667 ``` ### High-DPI Screenshot [#high-dpi-screenshot] ``` https://cdn.capture.page/YOUR_API_KEY/HASH/image?url=https://example.com&vw=1440&vh=900&scaleFactor=2 ``` ## Common Viewport Sizes [#common-viewport-sizes] ### Desktop Resolutions [#desktop-resolutions] | Resolution | Width | Height | Use Case | | ---------- | ----- | ------ | ----------------------------- | | HD | 1366 | 768 | Most common laptop resolution | | Full HD | 1920 | 1080 | Standard desktop monitor | | 2K | 2560 | 1440 | High-end monitors | | 4K | 3840 | 2160 | Ultra HD displays | ### Mobile Resolutions [#mobile-resolutions] | Device Type | Width | Height | Scale Factor | | ------------------ | ----- | ------ | ------------ | | iPhone SE | 375 | 667 | 2 | | iPhone 14 | 390 | 844 | 3 | | iPhone 14 Plus | 428 | 926 | 3 | | Pixel 5 | 393 | 851 | 2.75 | | Samsung Galaxy S21 | 360 | 800 | 3 | ### Tablet Resolutions [#tablet-resolutions] | Device Type | Width | Height | Scale Factor | | -------------- | ----- | ------ | ------------ | | iPad Mini | 768 | 1024 | 2 | | iPad Air | 820 | 1180 | 2 | | iPad Pro 11" | 834 | 1194 | 2 | | iPad Pro 12.9" | 1024 | 1366 | 2 | ## Best Practices [#best-practices] ### 1. Match Target Audience [#1-match-target-audience] Choose viewport dimensions that match your target audience's most common devices. Use analytics data to determine the most popular screen sizes among your users. ### 2. Consider Responsive Breakpoints [#2-consider-responsive-breakpoints] Test your website at common responsive design breakpoints: * Mobile: 320-768px * Tablet: 768-1024px * Desktop: 1024px and above ### 3. Scale Factor Considerations [#3-scale-factor-considerations] * Use `scaleFactor=1` for faster processing and smaller file sizes * Use `scaleFactor=2` or higher for crisp, high-quality screenshots * Higher scale factors increase processing time and file size ### 4. Viewport vs Full Page [#4-viewport-vs-full-page] Remember that viewport settings only affect the visible area. To capture the entire page height, use the `full=true` parameter along with your viewport settings. ## Advanced Tips [#advanced-tips] ### Testing Responsive Design [#testing-responsive-design] Create multiple screenshots at different viewport sizes to test responsive behavior: ```javascript const viewports = [ { width: 320, height: 568 }, // Mobile { width: 768, height: 1024 }, // Tablet { width: 1920, height: 1080 } // Desktop ]; viewports.forEach(vp => { const url = `https://cdn.capture.page/KEY/HASH/image?url=site.com&vw=${vp.width}&vh=${vp.height}`; // Generate screenshot URL }); ``` ### Simulating Device Pixel Ratios [#simulating-device-pixel-ratios] To accurately simulate how your site appears on high-DPI displays: ``` // Standard display &vw=1920&vh=1080&scaleFactor=1 // Retina display &vw=1920&vh=1080&scaleFactor=2 // Mobile with high DPI &vw=375&vh=667&scaleFactor=3 ``` ## Relationship with Other Options [#relationship-with-other-options] * **Device Emulation**: When using `emulateDevice`, viewport settings are automatically configured * **Full Page Capture**: Viewport width affects the layout when using `full=true` * **Clipping**: Viewport defines the default capture area when no clipping is specified ## Performance Considerations [#performance-considerations] * Larger viewports require more memory and processing time * High scale factors multiply the effective resolution (e.g., 1920x1080 at scale 2 = 3840x2160 pixels) * Consider using smaller viewports with clipping for specific page sections # Create a browser session Creates a stateful browser session on the handling Capture API instance. The session is automatically closed when its TTL expires. Billable sessions charge 1 credit per elapsed minute, rounded up. Each user can have up to 5 active sessions at a time. # Get session metadata # Close a browser session Closes an active session and charges duration credits once. Repeated close requests for an already-finalized session are idempotent. # Execute a Capture action Executes a deterministic browser action against the session's active page. If the request lands on a non-owner API instance, Capture routes the action to the owning instance through Redis. Responses for existing sessions include `expiresInSeconds`, the remaining lifetime at the time the action response is sent.