# Introduction (/docs) import { Cards, Card } from 'fumadocs-ui/components/card'; # AllScreenshots API AllScreenshots is a powerful screenshot API that lets you capture high-quality images of any website programmatically. Whether you need to generate social media previews, create visual testing snapshots, or build a link preview service, our API handles the complexity of rendering web pages so you don't have to. ## Quick example Capture a screenshot with a single API call: ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"url": "https://example.com"}' ``` The API returns the screenshot image directly, ready to use. ## Key features ## Use cases * **Social media previews**: Generate Open Graph and Twitter Card images * **Visual regression testing**: Capture baseline screenshots for automated testing * **Link previews**: Build rich previews for URLs shared in your app * **Competitor monitoring**: Track visual changes to competitor websites * **Documentation**: Automatically capture screenshots for product docs * **Archiving**: Create visual records of web pages over time ## Getting started ## Base URL All API requests are made to: ``` https://api.allscreenshots.com ``` ## Response formats The API can return screenshots in two ways: * **Binary** (default): Returns the image directly with the appropriate content type * **JSON**: Returns a URL to the stored image with metadata Set `responseType: "json"` in your request to receive JSON responses. # LLM.txt (/docs/llm-txt) import { Callout } from 'fumadocs-ui/components/callout'; # LLM.txt This documentation is available in a machine-readable format designed for AI assistants and large language models (LLMs). Access the full documentation as plain text at /llms-full.txt ## What is LLM.txt? LLM.txt is a standard format that makes documentation accessible to AI tools. Instead of parsing HTML, AI assistants can fetch a single text file containing all documentation content in a structured, easy-to-process format. ## Available endpoints | Endpoint | Description | | ---------------- | -------------------------------------------- | | `/llms-full.txt` | Complete documentation in a single text file | ## Format The `llms-full.txt` file contains all documentation pages concatenated together. Each page includes: * **Title and URL** — `# Page title (/docs/path)` * **Content** — The full page content in Markdown format Example structure: ```markdown # Introduction (/docs) AllScreenshots is a powerful screenshot API... # Quickstart (/docs/getting-started/quickstart) Capture your first screenshot in under 5 minutes... # Screenshots API (/docs/api-reference/screenshots) The screenshots endpoint captures images of web pages... ``` ## Use cases ### AI coding assistants Tools like GitHub Copilot, Cursor, or Claude can fetch this file to understand the AllScreenshots API and provide accurate code suggestions. ### Custom AI integrations Build your own AI-powered tools that understand the AllScreenshots documentation: ```python import requests # Fetch the full documentation response = requests.get("https://docs.allscreenshots.com/llms-full.txt") docs_content = response.text # Use with your AI model # ... ``` ### Documentation search Create semantic search over the documentation by indexing the LLM.txt content with embeddings. ## Best practices for AI tools When using this documentation with AI assistants: 1. **Fetch fresh content** — The documentation is updated regularly 2. **Cache responsibly** — Cache for a reasonable period (e.g., 1 hour) to reduce load 3. **Respect rate limits** — Don't fetch more often than necessary ## Related standards This implementation follows the [llms.txt specification](https://llmstxt.org/) for making documentation AI-accessible. # Support (/docs/support) import { Callout } from 'fumadocs-ui/components/callout'; # Support We're here to help you succeed with AllScreenshots. Whether you're stuck on an implementation, found a bug, or have a question about the API, we'd love to hear from you. ## Contact us For the fastest response, email us at **[support@allscreenshots.com](mailto:support@allscreenshots.com)**. We typically respond within a few hours during business days. ## When to reach out ### Implementation help Stuck trying to integrate AllScreenshots into your project? We can help with: * Choosing the right API endpoints for your use case * Debugging unexpected behavior * Optimizing your screenshot capture workflow * Best practices for your specific framework or language ### Documentation feedback Found something confusing, incorrect, or missing in the docs? Let us know: * Typos or errors in code examples * Unclear explanations * Missing information * Suggestions for new guides or examples We take documentation seriously and will fix issues quickly. ### Bug reports If you've encountered a bug, please include: * The API endpoint you're calling * Your request payload (redact any sensitive data) * The response you received * What you expected to happen * Any error messages ### Feature requests Have an idea for a new feature? We'd love to hear it. Tell us: * What you're trying to accomplish * How you're currently working around the limitation * How a new feature would help ## Before contacting support A few things to check first: 1. **Check the docs** — Your question might already be answered in our [API reference](/docs/api-reference/screenshots) or [guides](/docs/guides/social-media-previews) 2. **Verify your API key** — Make sure you're using a valid API key with the correct `Bearer` prefix 3. **Check your quota** — You can view your usage in the [dashboard](https://dashboard.allscreenshots.com) 4. **Review error messages** — Our API returns descriptive error messages that often point to the solution ## Response times | Channel | Typical response | | ------------- | ---------------------------------- | | Email | Within a few hours (business days) | | Urgent issues | Same day | ## What to include in your email To help us help you faster, please include: ``` Subject: [Brief description of issue] 1. What I'm trying to do: [Your goal] 2. What's happening: [The problem or error] 3. Code/request I'm using: [Your code snippet or curl command] 4. Error message (if any): [Full error response] 5. My environment: - Language/framework: [e.g., Node.js 20, Python 3.11] - SDK version (if using): [e.g., @allscreenshots/sdk 1.0.0] ``` ## Enterprise support Need dedicated support, custom SLAs, or priority assistance? [Contact us](mailto:support@allscreenshots.com) about our Enterprise plans. *** We genuinely want you to succeed with AllScreenshots. Don't hesitate to reach out — no question is too small. **[support@allscreenshots.com](mailto:support@allscreenshots.com)** # Async jobs (/docs/api-reference/async-jobs) import { Callout } from 'fumadocs-ui/components/callout'; # Async jobs For long-running captures or when you don't want to wait for the response, use async jobs. The API immediately returns a job ID, and you can poll for status or receive a webhook when complete. ## Create async job ```http POST /v1/screenshots/async ``` ### Request body Same parameters as the [screenshots endpoint](/docs/api-reference/screenshots), plus: | Parameter | Type | Description | | --------------- | ------ | ----------------------------------------- | | `webhookUrl` | string | URL to receive completion notification | | `webhookSecret` | string | Secret for webhook signature verification | ### Example request ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots/async' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "fullPage": true, "webhookUrl": "https://your-server.com/webhooks/screenshot" }' ``` ### Response ```json { "jobId": "job_abc123xyz", "status": "pending", "createdAt": "2025-01-15T10:30:00Z" } ``` ## Get job status ```http GET /v1/screenshots/jobs/{jobId} ``` ### Example request ```bash curl 'https://api.allscreenshots.com/v1/screenshots/jobs/job_abc123xyz' \ -H 'Authorization: Bearer YOUR_API_KEY' ``` ### Response (pending) ```json { "jobId": "job_abc123xyz", "status": "pending", "createdAt": "2025-01-15T10:30:00Z" } ``` ### Response (completed) ```json { "jobId": "job_abc123xyz", "status": "completed", "createdAt": "2025-01-15T10:30:00Z", "completedAt": "2025-01-15T10:30:05Z", "result": { "url": "https://storage.allscreenshots.com/screenshots/abc123.png", "expiresAt": "2025-01-30T10:30:05Z", "size": 245678, "width": 1920, "height": 4500, "format": "png", "renderTime": 4250 } } ``` ### Response (failed) ```json { "jobId": "job_abc123xyz", "status": "failed", "createdAt": "2025-01-15T10:30:00Z", "completedAt": "2025-01-15T10:31:00Z", "error": { "code": "timeout", "message": "Page load timed out after 60 seconds" } } ``` ## Get job result Download the screenshot once the job is complete: ```http GET /v1/screenshots/jobs/{jobId}/result ``` Returns the image binary with appropriate content type. ```bash curl 'https://api.allscreenshots.com/v1/screenshots/jobs/job_abc123xyz/result' \ -H 'Authorization: Bearer YOUR_API_KEY' \ --output screenshot.png ``` Job results are available for 24 hours after completion. Download or store them before expiration. ## Job statuses | Status | Description | | ------------ | --------------------------------------- | | `pending` | Job is queued for processing | | `processing` | Screenshot capture in progress | | `completed` | Capture successful, result available | | `failed` | Capture failed, error details available | ## Polling vs webhooks ### Polling Simple to implement but less efficient: ```javascript async function waitForJob(jobId) { while (true) { const response = await fetch( `https://api.allscreenshots.com/v1/screenshots/jobs/${jobId}`, { headers: { 'Authorization': `Bearer ${API_KEY}` } } ); const job = await response.json(); if (job.status === 'completed') { return job.result; } if (job.status === 'failed') { throw new Error(job.error.message); } await new Promise(resolve => setTimeout(resolve, 1000)); } } ``` ### Webhooks (recommended) More efficient—no polling required: ```javascript // Create job with webhook const response = await fetch('https://api.allscreenshots.com/v1/screenshots/async', { method: 'POST', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: 'https://example.com', webhookUrl: 'https://your-server.com/webhooks/screenshot', webhookSecret: 'your-webhook-secret', }), }); // Handle webhook in your server app.post('/webhooks/screenshot', (req, res) => { // Verify signature (see Webhooks docs) const job = req.body; if (job.status === 'completed') { console.log('Screenshot ready:', job.result.url); } res.sendStatus(200); }); ``` See [Webhooks](/docs/api-reference/webhooks) for complete webhook documentation. ## Use cases Async jobs are ideal for: * **Full page captures**: Pages that take longer to render * **Batch processing**: When combined with bulk jobs * **Background tasks**: When you don't need immediate results * **Long timeouts**: Pages with heavy JavaScript or slow loading assets ## Example workflow ```javascript // 1. Create async job const { jobId } = await createAsyncJob({ url: 'https://example.com/report', fullPage: true, waitUntil: 'networkidle', }); // 2. Store job ID in your database await db.screenshots.create({ jobId, url: 'https://example.com/report', status: 'processing', }); // 3. Process webhook when complete app.post('/webhooks/screenshot', async (req, res) => { const { jobId, status, result, error } = req.body; await db.screenshots.update(jobId, { status, screenshotUrl: result?.url, error: error?.message, }); res.sendStatus(200); }); ``` # Bulk screenshots (/docs/api-reference/bulk) import { Callout } from 'fumadocs-ui/components/callout'; # Bulk screenshots Capture up to 100 URLs in a single API call. Bulk jobs run asynchronously and notify you via webhook when all captures are complete. ## Create bulk job ```http POST /v1/screenshots/bulk ``` ### Request body ```json { "urls": [ { "url": "https://example1.com" }, { "url": "https://example2.com" }, { "url": "https://example3.com", "options": { "fullPage": true } } ], "defaults": { "format": "png", "viewport": { "width": 1280, "height": 720 }, "blockAds": true }, "webhookUrl": "https://your-server.com/webhooks/bulk", "webhookSecret": "your-secret" } ``` ### Parameters #### urls (required) Array of URL objects (1-100 items): | Field | Type | Description | | --------- | ------ | ------------------------- | | `url` | string | URL to capture (required) | | `options` | object | Per-URL option overrides | #### defaults Default options applied to all URLs unless overridden: | Field | Type | Default | Description | | -------------------- | ------- | ----------------------------- | ------------------------- | | `viewport` | object | `{width: 1920, height: 1080}` | Viewport configuration | | `device` | string | - | Device preset | | `format` | string | `"png"` | Output format | | `fullPage` | boolean | `false` | Capture full page | | `quality` | integer | `80` | Image quality (1-100) | | `delay` | integer | `0` | Delay before capture (ms) | | `waitFor` | string | - | CSS selector to wait for | | `waitUntil` | string | `"load"` | Page load event | | `timeout` | integer | `30000` | Max wait time (ms) | | `darkMode` | boolean | `false` | Dark mode emulation | | `customCss` | string | - | Custom CSS to inject | | `blockAds` | boolean | `false` | Block ads | | `blockCookieBanners` | boolean | `false` | Block cookie banners | | `blockLevel` | string | `"none"` | Domain blocking level | #### webhookUrl / webhookSecret Optional webhook configuration for completion notification. ### Response ```json { "bulkJobId": "bulk_abc123xyz", "status": "pending", "totalUrls": 3, "createdAt": "2025-01-15T10:30:00Z" } ``` ## Get bulk job status ```http GET /v1/screenshots/bulk/{bulkJobId} ``` ### Response (in progress) ```json { "bulkJobId": "bulk_abc123xyz", "status": "processing", "totalUrls": 3, "completedUrls": 1, "failedUrls": 0, "createdAt": "2025-01-15T10:30:00Z", "jobs": [ { "jobId": "job_001", "url": "https://example1.com", "status": "completed" }, { "jobId": "job_002", "url": "https://example2.com", "status": "processing" }, { "jobId": "job_003", "url": "https://example3.com", "status": "pending" } ] } ``` ### Response (completed) ```json { "bulkJobId": "bulk_abc123xyz", "status": "completed", "totalUrls": 3, "completedUrls": 3, "failedUrls": 0, "createdAt": "2025-01-15T10:30:00Z", "completedAt": "2025-01-15T10:30:45Z", "jobs": [ { "jobId": "job_001", "url": "https://example1.com", "status": "completed", "result": { "url": "https://storage.allscreenshots.com/abc.png", "size": 123456, "width": 1280, "height": 720 } }, { "jobId": "job_002", "url": "https://example2.com", "status": "completed", "result": { "url": "https://storage.allscreenshots.com/def.png", "size": 234567, "width": 1280, "height": 720 } }, { "jobId": "job_003", "url": "https://example3.com", "status": "completed", "result": { "url": "https://storage.allscreenshots.com/ghi.png", "size": 345678, "width": 1280, "height": 3200 } } ] } ``` ## Examples ### Capture competitor homepages ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots/bulk' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "urls": [ { "url": "https://competitor1.com" }, { "url": "https://competitor2.com" }, { "url": "https://competitor3.com" } ], "defaults": { "viewport": { "width": 1920, "height": 1080 }, "blockAds": true, "blockCookieBanners": true }, "webhookUrl": "https://your-server.com/webhooks/competitors" }' ``` ### Multiple devices for one URL ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots/bulk' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "urls": [ { "url": "https://yoursite.com", "options": { "device": "desktop_hd" } }, { "url": "https://yoursite.com", "options": { "device": "iphone_15" } }, { "url": "https://yoursite.com", "options": { "device": "ipad_pro_11" } } ], "defaults": { "format": "png", "blockAds": true } }' ``` ### Social media previews ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots/bulk' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "urls": [ { "url": "https://blog.example.com/post-1" }, { "url": "https://blog.example.com/post-2" }, { "url": "https://blog.example.com/post-3" } ], "defaults": { "device": "twitter_card", "waitUntil": "networkidle" } }' ``` ## Best practices Bulk jobs are more efficient than individual requests. Use them whenever you need to capture more than 2-3 URLs. ### Group similar captures Put URLs with similar options in the same bulk job to simplify defaults: ```json { "urls": [ { "url": "https://site1.com" }, { "url": "https://site2.com" }, { "url": "https://site3.com" } ], "defaults": { "device": "iphone_15", "fullPage": true } } ``` ### Handle partial failures Some URLs may fail while others succeed. Check individual job statuses: ```javascript const bulkJob = await getBulkJob(bulkJobId); const successful = bulkJob.jobs.filter(j => j.status === 'completed'); const failed = bulkJob.jobs.filter(j => j.status === 'failed'); console.log(`${successful.length} succeeded, ${failed.length} failed`); // Retry failed URLs if needed if (failed.length > 0) { const retryUrls = failed.map(j => ({ url: j.url })); await createBulkJob({ urls: retryUrls }); } ``` ### Use webhooks for completion Instead of polling, use webhooks to receive notifications: ```javascript app.post('/webhooks/bulk', async (req, res) => { const { bulkJobId, status, jobs } = req.body; if (status === 'completed') { for (const job of jobs) { if (job.status === 'completed') { await saveScreenshot(job.url, job.result.url); } } } res.sendStatus(200); }); ``` ## Limits | Limit | Value | | ---------------------------- | -------- | | Maximum URLs per bulk job | 100 | | Maximum concurrent bulk jobs | 5 | | Job result retention | 24 hours | # Compose (/docs/api-reference/compose) import { Callout } from 'fumadocs-ui/components/callout'; # Screenshot composition Combine multiple screenshots into a single image with automatic layout, labels, and styling. Perfect for comparison images, galleries, and social media content. ## Endpoint ```http POST /v1/screenshots/compose ``` ## Modes The compose API supports two modes: ### Captures mode Capture multiple different URLs: ```json { "captures": [ { "url": "https://site1.com", "label": "Site 1" }, { "url": "https://site2.com", "label": "Site 2" }, { "url": "https://site3.com", "label": "Site 3" } ], "output": { "layout": "grid" } } ``` ### Variants mode Capture one URL with different configurations: ```json { "url": "https://example.com", "variants": [ { "device": "desktop_hd", "label": "Desktop" }, { "device": "iphone_15", "label": "iPhone" }, { "device": "ipad_pro_11", "label": "iPad" } ], "output": { "layout": "horizontal" } } ``` ## Layout types | Layout | Description | | -------------- | ------------------------------------------------------------------------- | | `auto` | Automatically selects the best layout based on image count and dimensions | | `grid` | Equal-sized cells in rows and columns | | `horizontal` | Single row, all images side by side | | `vertical` | Single column, all images stacked | | `masonry` | Pinterest-style staggered layout | | `mondrian` | Abstract art-inspired geometric blocks | | `partitioning` | Balanced rows like Google Photos/Telegram | ## Request body ### Captures mode ```json { "captures": [ { "url": "https://example.com", "id": "capture-1", "label": "Example Site", "viewport": { "width": 1280, "height": 720 }, "device": null, "fullPage": false, "darkMode": false, "delay": 0 } ], "defaults": { "viewport": { "width": 1920, "height": 1080 }, "format": "png", "quality": 80, "fullPage": false, "delay": 0, "waitFor": null, "waitUntil": "load", "timeout": 30000, "darkMode": false, "customCss": null, "hideSelectors": [], "blockAds": false, "blockCookieBanners": false, "blockLevel": "none" }, "output": { ... }, "async": false, "webhookUrl": null, "webhookSecret": null } ``` ### Output options ```json { "output": { "layout": "grid", "format": "png", "quality": 90, "columns": 2, "spacing": 10, "padding": 20, "background": "#ffffff", "alignment": "center", "maxWidth": 2000, "maxHeight": 2000, "thumbnailWidth": null, "labels": { "show": true, "position": "bottom", "fontSize": 14, "fontColor": "#333333", "background": "#ffffff", "padding": 8 }, "border": { "width": 1, "color": "#cccccc", "radius": 8 }, "shadow": { "enabled": true, "blur": 10, "offsetX": 0, "offsetY": 4, "color": "rgba(0,0,0,0.2)" } } } ``` ### Output parameters | Parameter | Type | Default | Description | | ---------------- | ------- | ----------- | --------------------------------------------- | | `layout` | string | `"auto"` | Layout algorithm | | `format` | string | `"png"` | Output format: `png`, `jpeg`, `webp` | | `quality` | integer | `90` | Image quality (1-100) | | `columns` | integer | auto | Fixed number of columns (grid layout) | | `spacing` | integer | `10` | Space between images (0-100px) | | `padding` | integer | `0` | Padding around edges (0-100px) | | `background` | string | `"#ffffff"` | Background color or `"transparent"` | | `alignment` | string | `"center"` | Vertical alignment: `top`, `center`, `bottom` | | `maxWidth` | integer | - | Maximum output width (100-10000) | | `maxHeight` | integer | - | Maximum output height (100-10000) | | `thumbnailWidth` | integer | - | Resize captures to this width (50-2000) | ### Label options | Parameter | Type | Default | Description | | ------------ | ------- | ----------- | --------------------------- | | `show` | boolean | `true` | Show labels | | `position` | string | `"bottom"` | Position: `top` or `bottom` | | `fontSize` | integer | `14` | Font size (8-48) | | `fontColor` | string | `"#333333"` | Text color | | `background` | string | `"#ffffff"` | Label background | | `padding` | integer | `8` | Label padding (0-20) | ### Border options | Parameter | Type | Default | Description | | --------- | ------- | ----------- | -------------------- | | `width` | integer | `1` | Border width (0-10) | | `color` | string | `"#cccccc"` | Border color | | `radius` | integer | `0` | Corner radius (0-20) | ### Shadow options | Parameter | Type | Default | Description | | --------- | ------- | ------------------- | ----------------------------- | | `enabled` | boolean | `true` | Show shadow | | `blur` | integer | `10` | Shadow blur (0-50) | | `offsetX` | integer | `0` | Horizontal offset (-20 to 20) | | `offsetY` | integer | `4` | Vertical offset (-20 to 20) | | `color` | string | `"rgba(0,0,0,0.2)"` | Shadow color | ## Examples ### Side-by-side comparison ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots/compose' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "captures": [ { "url": "https://old-design.example.com", "label": "Before" }, { "url": "https://new-design.example.com", "label": "After" } ], "output": { "layout": "horizontal", "spacing": 20, "padding": 20, "background": "#f5f5f5" } }' --output comparison.png ``` ### Responsive showcase ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots/compose' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "variants": [ { "device": "desktop_hd", "label": "Desktop" }, { "device": "laptop", "label": "Laptop" }, { "device": "ipad_pro_11", "label": "Tablet" }, { "device": "iphone_15", "label": "Mobile" } ], "output": { "layout": "grid", "columns": 2, "spacing": 15, "border": { "width": 1, "color": "#e0e0e0", "radius": 8 }, "shadow": { "enabled": true } } }' --output responsive.png ``` ### Photo gallery ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots/compose' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "captures": [ { "url": "https://unsplash.com/photos/abc" }, { "url": "https://unsplash.com/photos/def" }, { "url": "https://unsplash.com/photos/ghi" }, { "url": "https://unsplash.com/photos/jkl" }, { "url": "https://unsplash.com/photos/mno" } ], "output": { "layout": "partitioning", "spacing": 4, "maxWidth": 1200 } }' --output gallery.png ``` ### Dark vs light mode ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots/compose' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "variants": [ { "darkMode": false, "label": "Light Mode" }, { "darkMode": true, "label": "Dark Mode" } ], "output": { "layout": "horizontal", "background": "#1a1a1a", "labels": { "fontColor": "#ffffff", "background": "transparent" } } }' --output themes.png ``` Compositions count as one screenshot per captured URL. A composition of 4 URLs uses 4 screenshots from your quota. ## Async composition For large compositions, use async mode: ```json { "captures": [ ... ], "async": true, "webhookUrl": "https://your-server.com/webhooks/compose" } ``` Returns a job ID that you can poll or receive via webhook when complete. # Scheduled screenshots (/docs/api-reference/schedules) import { Callout } from 'fumadocs-ui/components/callout'; # Scheduled screenshots Set up recurring screenshot captures that run automatically. Monitor website changes, track competitor updates, or build visual archives over time. ## Create schedule ```http POST /v1/schedules ``` ### Request body ```json { "name": "Homepage Monitor", "url": "https://example.com", "schedule": "0 9 * * *", "timezone": "America/New_York", "options": { "viewport": { "width": 1920, "height": 1080 }, "format": "png", "fullPage": false, "blockAds": true }, "webhookUrl": "https://your-server.com/webhooks/scheduled", "webhookSecret": "your-secret", "retentionDays": 30, "startsAt": "2025-02-01T00:00:00Z", "endsAt": null } ``` ### Parameters | Parameter | Type | Required | Description | | --------------- | ------- | -------- | ------------------------------------------ | | `name` | string | Yes | Schedule name (max 255 chars) | | `url` | string | Yes | URL to capture | | `schedule` | string | Yes | Cron expression or interval | | `timezone` | string | No | Timezone for cron (default: `UTC`) | | `options` | object | No | Screenshot options | | `webhookUrl` | string | No | Webhook for capture notifications | | `webhookSecret` | string | No | Webhook signature secret | | `retentionDays` | integer | No | Days to keep captures (1-365, default: 30) | | `startsAt` | string | No | ISO 8601 start time | | `endsAt` | string | No | ISO 8601 end time | ### Schedule formats #### Cron expressions Standard 5-field cron format: ``` ┌───────────── minute (0-59) │ ┌───────────── hour (0-23) │ │ ┌───────────── day of month (1-31) │ │ │ ┌───────────── month (1-12) │ │ │ │ ┌───────────── day of week (0-6, Sunday=0) │ │ │ │ │ * * * * * ``` Examples: | Expression | Description | | ----------------- | ----------------------------------- | | `0 9 * * *` | Every day at 9:00 AM | | `0 */4 * * *` | Every 4 hours | | `0 9 * * 1-5` | Weekdays at 9:00 AM | | `0 0 1 * *` | First day of each month at midnight | | `0 9,12,18 * * *` | At 9 AM, 12 PM, and 6 PM daily | #### Interval format Simple intervals for common schedules: | Format | Description | | ---------- | ------------------------------ | | `@hourly` | Every hour at minute 0 | | `@daily` | Every day at midnight | | `@weekly` | Every Sunday at midnight | | `@monthly` | First day of month at midnight | ### Screenshot options Same as [screenshot API](/docs/api-reference/screenshots): ```json { "options": { "viewport": { "width": 1920, "height": 1080 }, "device": null, "format": "png", "fullPage": false, "quality": 80, "delay": 0, "waitFor": null, "waitUntil": "load", "timeout": 30000, "darkMode": false, "customCss": null, "hideSelectors": [], "blockAds": false, "blockCookieBanners": false, "blockLevel": "none" } } ``` ### Response ```json { "scheduleId": "sched_abc123xyz", "name": "Homepage Monitor", "url": "https://example.com", "schedule": "0 9 * * *", "timezone": "America/New_York", "status": "active", "nextRunAt": "2025-01-16T14:00:00Z", "createdAt": "2025-01-15T10:30:00Z" } ``` ## List schedules ```http GET /v1/schedules ``` ### Response ```json { "schedules": [ { "scheduleId": "sched_abc123xyz", "name": "Homepage Monitor", "url": "https://example.com", "schedule": "0 9 * * *", "status": "active", "nextRunAt": "2025-01-16T14:00:00Z", "lastRunAt": "2025-01-15T14:00:00Z" } ], "total": 1 } ``` ## Get schedule ```http GET /v1/schedules/{scheduleId} ``` ### Response Full schedule details including recent captures. ## Update schedule ```http PATCH /v1/schedules/{scheduleId} ``` ### Request body Only include fields you want to update: ```json { "name": "Updated Name", "schedule": "0 */2 * * *", "options": { "fullPage": true } } ``` ## Pause/resume schedule ```http POST /v1/schedules/{scheduleId}/pause POST /v1/schedules/{scheduleId}/resume ``` ## Delete schedule ```http DELETE /v1/schedules/{scheduleId} ``` Deleting a schedule also deletes all associated captures. This cannot be undone. ## Get schedule captures ```http GET /v1/schedules/{scheduleId}/captures ``` ### Query parameters | Parameter | Type | Default | Description | | ----------- | ------- | ------- | --------------------------- | | `limit` | integer | `20` | Results per page (1-100) | | `offset` | integer | `0` | Pagination offset | | `startDate` | string | - | Filter from date (ISO 8601) | | `endDate` | string | - | Filter to date (ISO 8601) | ### Response ```json { "captures": [ { "captureId": "cap_001", "capturedAt": "2025-01-15T14:00:00Z", "status": "completed", "result": { "url": "https://storage.allscreenshots.com/abc.png", "size": 245678, "width": 1920, "height": 1080 } }, { "captureId": "cap_002", "capturedAt": "2025-01-14T14:00:00Z", "status": "completed", "result": { "url": "https://storage.allscreenshots.com/def.png", "size": 234567, "width": 1920, "height": 1080 } } ], "total": 30, "limit": 20, "offset": 0 } ``` ## Examples ### Daily homepage monitoring ```bash curl -X POST 'https://api.allscreenshots.com/v1/schedules' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "name": "Daily Homepage", "url": "https://example.com", "schedule": "0 9 * * *", "timezone": "America/New_York", "options": { "fullPage": true, "blockAds": true, "blockCookieBanners": true }, "webhookUrl": "https://your-server.com/webhooks/daily-capture", "retentionDays": 90 }' ``` ### Hourly competitor tracking ```bash curl -X POST 'https://api.allscreenshots.com/v1/schedules' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "name": "Competitor Pricing", "url": "https://competitor.com/pricing", "schedule": "@hourly", "options": { "waitFor": ".pricing-table", "waitUntil": "networkidle" }, "retentionDays": 7 }' ``` ### Business hours only ```bash curl -X POST 'https://api.allscreenshots.com/v1/schedules' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "name": "Dashboard Status", "url": "https://internal-dashboard.example.com", "schedule": "0 9-17 * * 1-5", "timezone": "Europe/London", "options": { "viewport": { "width": 1920, "height": 1080 } } }' ``` ## Schedule limits | Plan | Active schedules | Minimum interval | | ---------- | ---------------- | ---------------- | | Free | 1 | Daily | | Starter | 5 | Hourly | | Pro | 25 | 15 minutes | | Enterprise | Custom | 1 minute | Scheduled captures count against your monthly quota. A daily schedule uses \~30 screenshots per month. # Screenshots (/docs/api-reference/screenshots) import { Callout } from 'fumadocs-ui/components/callout'; # Screenshots API The screenshots endpoint is the core of AllScreenshots. Use it to capture any website as a PNG, JPEG, WebP, or PDF. ## Endpoint ```http POST /v1/screenshots ``` ## Request body ```json { "url": "https://example.com", "viewport": { "width": 1920, "height": 1080, "deviceScaleFactor": 1 }, "format": "png", "quality": 80, "fullPage": false, "delay": 0, "waitFor": null, "waitUntil": "load", "timeout": 30000, "darkMode": false, "customCss": null, "hideSelectors": [], "selector": null, "blockAds": false, "blockCookieBanners": false, "blockLevel": "none", "responseType": "binary" } ``` ## Parameters ### Required | Parameter | Type | Description | | --------- | ------ | ------------------------------------------------------------ | | `url` | string | The URL to capture. Must start with `http://` or `https://`. | ### Viewport options | Parameter | Type | Default | Description | | ---------------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------- | | `viewport.width` | integer | `1920` | Viewport width in pixels (100-4096) | | `viewport.height` | integer | `1080` | Viewport height in pixels (100-4096) | | `viewport.deviceScaleFactor` | integer | `1` | Device pixel ratio (1-3) | | `device` | string | - | Device preset name (alternative to viewport). See [devices](/docs/features/viewport-and-devices). | ### Output options | Parameter | Type | Default | Description | | -------------- | ------- | ---------- | ---------------------------------------------- | | `format` | string | `"png"` | Output format: `png`, `jpeg`, `webp`, or `pdf` | | `quality` | integer | `80` | Image quality for JPEG/WebP (1-100) | | `fullPage` | boolean | `false` | Capture the full scrollable page | | `selector` | string | - | CSS selector to capture a specific element | | `responseType` | string | `"binary"` | Response type: `binary` or `json` | ### Timing options | Parameter | Type | Default | Description | | ----------- | ------- | -------- | ---------------------------------------------------------------------- | | `delay` | integer | `0` | Wait time in ms after page load before capture (0-30000) | | `waitFor` | string | - | CSS selector to wait for before capturing | | `waitUntil` | string | `"load"` | Page load event to wait for: `load`, `domcontentloaded`, `networkidle` | | `timeout` | integer | `30000` | Maximum time to wait in ms (1000-60000) | ### Styling options | Parameter | Type | Default | Description | | --------------- | ------- | ------- | --------------------------------------------- | | `darkMode` | boolean | `false` | Emulate `prefers-color-scheme: dark` | | `customCss` | string | - | CSS to inject into the page (max 10000 chars) | | `hideSelectors` | array | `[]` | CSS selectors to hide (max 50 selectors) | ### Blocking options | Parameter | Type | Default | Description | | -------------------- | ------- | -------- | ------------------------------------------------------------------------------- | | `blockAds` | boolean | `false` | Block common ad networks | | `blockCookieBanners` | boolean | `false` | Block cookie consent banners | | `blockLevel` | string | `"none"` | Domain blocking level: `none`, `light`, `normal`, `pro`, `pro_plus`, `ultimate` | See [Blocking](/docs/features/blocking) for details on blocking options. ## Response ### Binary response (default) Returns the image data with appropriate content type: * `image/png` for PNG format * `image/jpeg` for JPEG format * `image/webp` for WebP format * `application/pdf` for PDF format ### JSON response When `responseType: "json"`: ```json { "url": "https://storage.allscreenshots.com/screenshots/abc123.png", "expiresAt": "2025-01-30T12:00:00Z", "size": 245678, "width": 1920, "height": 1080, "format": "png", "renderTime": 1234, "cached": false } ``` | Field | Type | Description | | ------------ | ------- | ------------------------------------------- | | `url` | string | URL to download the screenshot | | `expiresAt` | string | ISO 8601 timestamp when the URL expires | | `size` | integer | File size in bytes | | `width` | integer | Image width in pixels | | `height` | integer | Image height in pixels (null for full page) | | `format` | string | Image format | | `renderTime` | integer | Time to render in milliseconds | | `cached` | boolean | Whether result was served from cache | ## Examples ### Basic screenshot ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"url": "https://github.com"}' \ --output screenshot.png ``` ### Mobile device ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://github.com", "device": "iphone_15" }' \ --output mobile.png ``` ### Full page with dark mode ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://github.com", "fullPage": true, "darkMode": true, "blockAds": true, "blockCookieBanners": true }' \ --output fullpage-dark.png ``` ### Capture specific element ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://github.com", "selector": "header.AppHeader" }' \ --output header.png ``` ### Wait for dynamic content ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com/dashboard", "waitFor": ".chart-loaded", "waitUntil": "networkidle", "delay": 500 }' \ --output dashboard.png ``` ### PDF output ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com/invoice", "format": "pdf", "fullPage": true }' \ --output invoice.pdf ``` ## Error responses | Status | Error | Description | | ------ | --------------------- | -------------------------- | | `400` | `invalid_request` | Invalid request parameters | | `401` | `unauthorized` | Missing or invalid API key | | `402` | `quota_exceeded` | Monthly quota exceeded | | `408` | `timeout` | Page load timed out | | `422` | `capture_failed` | Screenshot capture failed | | `429` | `rate_limit_exceeded` | Rate limit exceeded | Example error response: ```json { "error": "invalid_request", "message": "URL must start with http:// or https://", "field": "url" } ``` For capturing many URLs or long-running captures, consider using [async jobs](/docs/api-reference/async-jobs) or [bulk processing](/docs/api-reference/bulk). # Webhooks (/docs/api-reference/webhooks) import { Callout } from 'fumadocs-ui/components/callout'; # Webhooks Receive HTTP notifications when async jobs, bulk jobs, or scheduled captures complete. Webhooks eliminate the need for polling and enable real-time integrations. ## Setting up webhooks Include `webhookUrl` in your request to enable notifications: ```json { "url": "https://example.com", "webhookUrl": "https://your-server.com/webhooks/screenshot", "webhookSecret": "your-secret-key" } ``` ## Webhook payload When a job completes, we send a POST request to your webhook URL: ### Successful capture ```json { "event": "job.completed", "jobId": "job_abc123xyz", "status": "completed", "timestamp": "2025-01-15T10:30:05Z", "result": { "url": "https://storage.allscreenshots.com/screenshots/abc123.png", "expiresAt": "2025-01-30T10:30:05Z", "size": 245678, "width": 1920, "height": 1080, "format": "png", "renderTime": 1234 } } ``` ### Failed capture ```json { "event": "job.failed", "jobId": "job_abc123xyz", "status": "failed", "timestamp": "2025-01-15T10:31:00Z", "error": { "code": "timeout", "message": "Page load timed out after 60 seconds" } } ``` ### Bulk job completed ```json { "event": "bulk.completed", "bulkJobId": "bulk_abc123xyz", "status": "completed", "timestamp": "2025-01-15T10:30:45Z", "summary": { "total": 10, "completed": 9, "failed": 1 }, "jobs": [ { "jobId": "job_001", "url": "https://example1.com", "status": "completed", "result": { ... } }, { "jobId": "job_002", "url": "https://example2.com", "status": "failed", "error": { ... } } ] } ``` ### Scheduled capture ```json { "event": "schedule.captured", "scheduleId": "sched_abc123xyz", "captureId": "cap_001", "timestamp": "2025-01-15T14:00:05Z", "result": { "url": "https://storage.allscreenshots.com/screenshots/abc123.png", "size": 245678, "width": 1920, "height": 1080 } } ``` ## Verifying signatures To ensure webhooks are from AllScreenshots, verify the signature using your webhook secret. ### Signature header Every webhook includes a signature in the `X-Allscreenshots-Signature` header: ``` X-Allscreenshots-Signature: sha256=abc123... ``` ### Verification code ```javascript const crypto = require('crypto'); function verifyWebhook(payload, signature, secret) { const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(payload, 'utf8') .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); } // Express middleware app.post('/webhooks/screenshot', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-allscreenshots-signature']; const payload = req.body.toString(); if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); } const event = JSON.parse(payload); // Process the webhook... res.sendStatus(200); }); ``` ### Python ```python import hmac import hashlib def verify_webhook(payload: bytes, signature: str, secret: str) -> bool: expected = 'sha256=' + hmac.new( secret.encode('utf-8'), payload, hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected) # Flask example @app.route('/webhooks/screenshot', methods=['POST']) def handle_webhook(): signature = request.headers.get('X-Allscreenshots-Signature') payload = request.get_data() if not verify_webhook(payload, signature, WEBHOOK_SECRET): return 'Invalid signature', 401 event = request.get_json() # Process the webhook... return '', 200 ``` Always verify webhook signatures in production. Without verification, attackers could send fake webhook payloads to your endpoint. ## Responding to webhooks ### Success response Return a `2xx` status code to acknowledge receipt: ```javascript app.post('/webhooks/screenshot', (req, res) => { // Process webhook asynchronously if needed processWebhook(req.body).catch(console.error); // Respond immediately res.sendStatus(200); }); ``` ### Retry behavior If your endpoint returns an error or times out, we retry with exponential backoff: | Attempt | Delay | | ------- | ---------- | | 1 | Immediate | | 2 | 1 minute | | 3 | 5 minutes | | 4 | 30 minutes | | 5 | 2 hours | After 5 failed attempts, the webhook is marked as failed. Webhook endpoints must respond within 30 seconds. For long processing, acknowledge immediately and process asynchronously. ## Event types | Event | Description | | ------------------- | ------------------------------------------- | | `job.completed` | Async screenshot job completed successfully | | `job.failed` | Async screenshot job failed | | `bulk.completed` | Bulk job completed (all URLs processed) | | `schedule.captured` | Scheduled capture completed | | `schedule.failed` | Scheduled capture failed | ## Best practices ### Use a dedicated endpoint Create a separate endpoint for AllScreenshots webhooks: ``` https://your-app.com/webhooks/allscreenshots ``` ### Process asynchronously Don't block the webhook response with heavy processing: ```javascript app.post('/webhooks/screenshot', async (req, res) => { // Acknowledge immediately res.sendStatus(200); // Process in background try { await processScreenshot(req.body); } catch (error) { console.error('Webhook processing failed:', error); } }); ``` ### Store webhook payloads Log incoming webhooks for debugging: ```javascript app.post('/webhooks/screenshot', async (req, res) => { // Store for debugging await db.webhookLogs.create({ receivedAt: new Date(), headers: req.headers, body: req.body, }); // Process... res.sendStatus(200); }); ``` ### Handle duplicates Webhooks may be delivered more than once. Use the `jobId` to deduplicate: ```javascript app.post('/webhooks/screenshot', async (req, res) => { const { jobId } = req.body; // Check if already processed const existing = await db.processedJobs.findOne({ jobId }); if (existing) { return res.sendStatus(200); // Already processed } // Mark as processing await db.processedJobs.create({ jobId, processedAt: new Date() }); // Process webhook... res.sendStatus(200); }); ``` ## Testing webhooks Use tools like [webhook.site](https://webhook.site) or [ngrok](https://ngrok.com) to test locally: ```bash # Start ngrok tunnel ngrok http 3000 # Use the ngrok URL as your webhook { "url": "https://example.com", "webhookUrl": "https://abc123.ngrok.io/webhooks/screenshot" } ``` # Ad and content blocking (/docs/features/blocking) import { Callout } from 'fumadocs-ui/components/callout'; # Ad and content blocking Remove unwanted content like ads, trackers, and cookie consent banners to capture clean screenshots. ## Quick options ### Block ads Remove common advertising networks: ```json { "url": "https://example.com", "blockAds": true } ``` This blocks: * Google Ads * Facebook Ads * Amazon Ads * Common ad networks and exchanges * Tracking pixels ### Block cookie banners Remove GDPR/CCPA cookie consent popups: ```json { "url": "https://example.com", "blockCookieBanners": true } ``` This handles: * OneTrust * Cookiebot * TrustArc * Custom consent implementations * EU cookie notices ### Combine both Use both options together for clean screenshots: ```json { "url": "https://example.com", "blockAds": true, "blockCookieBanners": true } ``` ## Block levels For more comprehensive blocking, use the `blockLevel` parameter: ```json { "url": "https://example.com", "blockLevel": "pro" } ``` ### Available levels | Level | Description | Use case | | ---------- | ----------------------- | -------------------- | | `none` | No domain blocking | Full page render | | `light` | Basic ad networks | Minimal blocking | | `normal` | Common trackers and ads | General use | | `pro` | Aggressive blocking | Clean screenshots | | `pro_plus` | Very aggressive | Maximum blocking | | `ultimate` | Most aggressive | May break some sites | Higher block levels may break some websites that depend on blocked resources. Test your target URLs before using aggressive levels in production. ### What gets blocked Each level includes everything from lower levels plus: **Light** * Major ad networks (Google, Facebook, Amazon) * Basic analytics (Google Analytics) **Normal** * Social media trackers * Marketing pixels * A/B testing platforms * Session recording tools **Pro** * All third-party tracking * CDN-hosted trackers * Fingerprinting scripts * Most advertising **Pro Plus** * Aggressive list additions * Regional ad networks * Crypto miners * Malware domains **Ultimate** * Everything above * Edge cases and new trackers * May over-block legitimate resources ## Hide specific elements For fine-grained control, hide elements by CSS selector: ```json { "url": "https://example.com", "hideSelectors": [ ".newsletter-popup", "#chat-widget", "[data-testid='promo-banner']", ".sticky-footer-ad" ] } ``` ### Selector examples | Element | Selector | | -------------------- | ------------------------------------------------ | | Chat widgets | `#intercom-container`, `.drift-widget` | | Newsletter popups | `.modal-newsletter`, `[data-popup='newsletter']` | | Promo banners | `.promo-banner`, `.announcement-bar` | | Social share buttons | `.share-buttons`, `.social-links` | | Fixed headers | `.sticky-header` | You can hide up to 50 selectors per request. ## Custom CSS Inject CSS to hide or modify elements: ```json { "url": "https://example.com", "customCss": ".newsletter-modal { display: none !important; } .hero-section { background: #fff; }" } ``` ### Common patterns **Hide multiple elements:** ```css .ad-container, .sponsored-content, .affiliate-link { display: none !important; } ``` **Remove sticky positioning:** ```css .sticky-header, .fixed-sidebar { position: relative !important; } ``` **Disable animations:** ```css *, *::before, *::after { animation: none !important; transition: none !important; } ``` ## Examples ### Clean article screenshot ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com/article", "blockAds": true, "blockCookieBanners": true, "hideSelectors": [ ".newsletter-modal", ".related-articles", ".comments-section" ], "fullPage": true }' --output clean-article.png ``` ### E-commerce product page ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://shop.example.com/product", "blockLevel": "pro", "hideSelectors": [ "#chat-widget", ".upsell-section" ], "customCss": ".price-tag { font-size: 24px !important; }" }' --output product.png ``` ### News website ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://news.example.com", "blockAds": true, "blockCookieBanners": true, "blockLevel": "normal", "customCss": "video { display: none; } .paywall-overlay { display: none !important; }" }' --output news.png ``` ## Best practices ### Start with quick options Begin with `blockAds` and `blockCookieBanners`: ```json { "blockAds": true, "blockCookieBanners": true } ``` Only increase `blockLevel` if needed. ### Test before production Some sites break with aggressive blocking. Test your target URLs: ```javascript const levels = ['none', 'light', 'normal', 'pro']; for (const level of levels) { const screenshot = await capture({ url: 'https://example.com', blockLevel: level, }); // Verify output visually } ``` ### Use selectors for specific elements If blocking breaks functionality, switch to targeted selectors: ```json { "blockLevel": "none", "hideSelectors": [ ".specific-ad-container", "#that-annoying-popup" ] } ``` ### Combine approaches Layer blocking methods for best results: ```json { "blockAds": true, "blockCookieBanners": true, "blockLevel": "light", "hideSelectors": [".newsletter-modal"], "customCss": ".chat-widget { visibility: hidden; }" } ``` # Full page capture (/docs/features/full-page-capture) import { Callout } from 'fumadocs-ui/components/callout'; # Full page capture Capture complete web pages beyond the visible viewport, including all scrollable content. AllScreenshots offers two capture modes optimized for different scenarios. ## Basic usage Enable full page capture with the `fullPage` parameter: ```json { "url": "https://example.com", "fullPage": true } ``` ## Capture modes Choose between two capture algorithms based on your needs: ### Stitch mode (default) The stitch mode captures the page in viewport-sized sections and intelligently stitches them together. This mode properly handles fixed/sticky elements like headers and footers. ```json { "url": "https://example.com", "fullPage": true, "fullPageMode": "stitch" } ``` **How it works:** 1. Scrolls through the page to trigger lazy-loaded content and animations 2. Detects fixed/sticky elements (headers, footers, floating buttons) 3. Captures each viewport section while hiding fixed elements 4. Stitches sections together 5. Overlays fixed elements at correct positions (headers at top, footers at bottom) **Best for:** * Pages with fixed headers or footers * Sites with lazy-loaded content * Pages with scroll-triggered animations * Long landing pages and documentation ### Native mode Uses the browser's built-in full page screenshot capability. Faster but doesn't handle fixed elements. ```json { "url": "https://example.com", "fullPage": true, "fullPageMode": "native" } ``` **How it works:** 1. Scrolls through the page to trigger lazy-loaded content 2. Takes a single full-page screenshot using Playwright's native capability **Best for:** * Simple pages without fixed elements * Maximum speed when quality trade-offs are acceptable * Pages where fixed element duplication is not a concern ## Parameters | Parameter | Type | Default | Description | | ---------------- | ------- | ---------- | ----------------------------------------------- | | `fullPage` | boolean | `false` | Enable full page capture | | `fullPageMode` | string | `"stitch"` | Capture mode: `"stitch"` or `"native"` | | `freezeFixed` | boolean | `true` | Handle fixed/sticky elements (stitch mode only) | | `scrollInterval` | integer | `150` | Delay between scroll steps in ms (50-1000) | | `maxSections` | integer | `100` | Maximum sections to capture (1-200) | ## Fixed element handling When `freezeFixed` is enabled (default), stitch mode intelligently handles fixed elements: ### Headers Fixed headers are captured once and placed at the top of the final image: ```json { "url": "https://example.com", "fullPage": true, "freezeFixed": true } ``` ### Footers Fixed footers are placed at the bottom of the final image, not repeated in every section. ### Floating elements Floating buttons, chat widgets, and side elements are positioned at their relative vertical location. If you're experiencing issues with specific fixed elements, you can disable this feature with `"freezeFixed": false` and the elements will appear in their natural scroll position. ## Scroll timing Control how quickly the page scrolls during capture: ```json { "url": "https://example.com", "fullPage": true, "scrollInterval": 300 } ``` | Value | Use case | | ---------- | ------------------------------------- | | `50-100` | Fast sites, static content | | `150` | Default, works for most sites | | `200-300` | Sites with animations or lazy loading | | `500-1000` | Heavy sites with complex animations | Lower values are faster but may miss lazy-loaded content. Higher values ensure all content loads but increase capture time. ## Limiting page height For very long pages, limit the capture height: ```json { "url": "https://example.com", "fullPage": true, "maxHeight": 10000 } ``` Or limit by number of sections: ```json { "url": "https://example.com", "fullPage": true, "maxSections": 50 } ``` ## Examples ### Landing page with sticky header ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "fullPage": true, "fullPageMode": "stitch", "freezeFixed": true }' --output landing-page.png ``` ### Fast capture without fixed handling ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "fullPage": true, "fullPageMode": "native" }' --output quick-capture.png ``` ### Heavy page with animations ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "fullPage": true, "scrollInterval": 400, "delay": 2000, "waitUntil": "networkidle" }' --output animated-page.png ``` ## Best practices ### Choose the right mode | Scenario | Recommended mode | | ---------------------------- | ---------------- | | Pages with sticky navigation | Stitch | | Simple blog posts | Native | | E-commerce product pages | Stitch | | Documentation sites | Stitch | | Quick previews | Native | | Marketing landing pages | Stitch | ### Combine with wait options For best results with dynamic content: ```json { "url": "https://example.com", "fullPage": true, "waitUntil": "networkidle", "delay": 1000, "scrollInterval": 200 } ``` ### Consider file size Full page screenshots can be large. Consider: * Using JPEG format for photos: `"format": "jpeg", "quality": 85` * Limiting height for very long pages: `"maxHeight": 15000` * Using WebP for best compression: `"format": "webp"` ## Troubleshooting ### Fixed elements appearing multiple times Switch to stitch mode with fixed element handling: ```json { "fullPage": true, "fullPageMode": "stitch", "freezeFixed": true } ``` ### Missing lazy-loaded content Increase scroll interval and add delay: ```json { "fullPage": true, "scrollInterval": 300, "delay": 2000, "waitUntil": "networkidle" } ``` ### Page too long / timeout Limit the capture height: ```json { "fullPage": true, "maxHeight": 20000, "maxSections": 50 } ``` ### Animations causing duplicate content Use stitch mode which pre-scrolls to trigger all animations before capture: ```json { "fullPage": true, "fullPageMode": "stitch", "scrollInterval": 250 } ``` # Social images (/docs/features/social-images) import { Callout } from 'fumadocs-ui/components/callout'; # Social images Generate Open Graph (OG) images automatically for your website. When someone shares a link to your site on social media, a screenshot of that page is used as the preview image. ## How it works 1. **Verify your domain** in the [dashboard](/dashboard/domains) 2. **Add the meta tag** to your pages pointing to our service 3. **We capture screenshots** when social platforms request your OG image 4. **Results are cached** so subsequent requests are instant and free ```html ``` No API key is needed in the URL. Your domain must be verified for images to be generated. Cache hits don't count toward your quota. ## Setting up ### 1. Add your domain Go to the [Social images page](/dashboard/domains) in your dashboard and add your domain (e.g., `example.com`). ### 2. Verify ownership Choose one of three verification methods: | Method | How it works | | ------------ | ---------------------------------------------- | | **DNS TXT** | Add a TXT record to your domain's DNS settings | | **Meta tag** | Add a verification meta tag to your homepage | | **File** | Upload a verification file to your web server | ### 3. Add the OG meta tag Add the following meta tag to each page where you want social images: ```html ``` For dynamic pages, generate the URL programmatically: ```javascript // Next.js example export const metadata = { openGraph: { images: [`https://og.allscreenshots.com?url=${encodeURIComponent('https://yourdomain.com' + pathname)}`], }, } ``` ## Configuration Configure default capture settings for your domain in the dashboard. These settings apply to all social images generated for that domain. ### Image dimensions | Setting | Default | Description | | ------- | ------- | ---------------------- | | Width | 1200 | Image width in pixels | | Height | 630 | Image height in pixels | Standard OG image size is 1200×630. Twitter recommends 1200×600. ### Cache duration Control how long images are cached before regeneration. Longer cache times mean fewer billable captures but slower updates when your pages change. | Duration | Use case | | ---------- | ------------------------------ | | 1-3 days | Frequently updated content | | 7 days | Standard websites (default) | | 14-30 days | Static content, rarely changes | ### Subdomains Enable subdomain support to generate images for all subdomains (e.g., `blog.example.com`, `docs.example.com`) without verifying each one separately. ### Appearance options | Setting | Description | | -------------------- | ----------------------------------------------------- | | Dark mode | Capture pages in dark mode (if your site supports it) | | Block ads | Hide advertisements in captured images | | Block cookie banners | Hide cookie consent popups | ### Output options | Setting | Options | Description | | ------- | --------------- | ------------------------------------------ | | Format | PNG, JPEG, WebP | Image format (PNG recommended for quality) | | Quality | 50-100% | Compression quality for JPEG/WebP | | Scale | 1x, 2x, 3x | Device scale factor for sharper images | ### Timing options | Setting | Default | Description | | ---------- | ------------ | ------------------------------------ | | Wait until | Network idle | When to consider the page ready | | Delay | 0ms | Additional wait time after page load | | Timeout | 30000ms | Maximum time to wait for page load | ### Customization | Setting | Description | | ------------- | ------------------------------------------------------------ | | Hide elements | CSS selectors for elements to hide (e.g., `.popup, #banner`) | | Custom CSS | Inject CSS before capturing (e.g., fix sticky headers) | ## URL parameters Override domain defaults for specific pages using URL parameters: ``` https://og.allscreenshots.com?url=https://yourdomain.com/page&width=1200&height=600&darkMode=true ``` | Parameter | Type | Description | | ---------- | ------- | ------------------------------------- | | `url` | string | **Required.** The page URL to capture | | `width` | integer | Image width (200-2400) | | `height` | integer | Image height (200-2400) | | `darkMode` | boolean | Enable dark mode | | `delay` | integer | Wait time in ms after page load | ## Caching Social images are automatically cached to improve performance and reduce costs. ### How caching works 1. First request for a URL generates a new screenshot (billable) 2. Subsequent requests serve the cached image (free) 3. After the cache TTL expires, the next request regenerates the image ### Cache management * **Clear cache**: Clear all cached images for a domain from the dashboard * **Force refresh**: Add `&refresh=true` to regenerate a specific image (counts as new capture) Clearing the cache will cause all subsequent requests to generate new screenshots until the cache is rebuilt. ## Usage and billing ### What counts toward quota | Action | Billable | | -------------------------------- | -------- | | First capture of a URL | Yes | | Cache hit (serving cached image) | No | | Refresh after cache expiry | Yes | | Manual cache clear + recapture | Yes | ### Monitoring usage View your social image usage in the dashboard: * **Images generated**: Billable captures this month * **Cache hits**: Free cached responses * **Cache hit rate**: Percentage of requests served from cache ## Best practices ### Optimize for social platforms Different platforms have different requirements: | Platform | Recommended size | Notes | | -------- | ---------------- | ------------------- | | Facebook | 1200×630 | Standard OG size | | Twitter | 1200×600 | Slightly shorter | | LinkedIn | 1200×627 | Similar to Facebook | | Discord | 1200×630 | Uses OG tags | ### Design pages for screenshots For best results: * **Above the fold**: Key content should be visible without scrolling * **Clean layout**: Remove distracting elements with hide selectors * **Readable text**: Ensure text is large enough to read in thumbnails * **Branding**: Include your logo in a consistent position ### Handle dynamic content For pages with user-specific or frequently changing content: ```html ``` Create dedicated preview routes that show a clean, static version of the content. ## Troubleshooting ### Image not updating The image may be cached. Either: 1. Wait for the cache TTL to expire 2. Clear the domain cache from the dashboard 3. Use `&refresh=true` to force regeneration ### Wrong content captured Check your timing settings: ``` ?url=https://yourdomain.com/page&delay=2000&waitUntil=networkidle ``` ### Elements blocking content Use hide selectors to remove popups or banners: ``` ?url=https://yourdomain.com/page&hideSelectors=.cookie-banner,.popup ``` ### Domain not verified Ensure you've completed one of the verification methods. DNS changes can take up to 48 hours to propagate. # Styling and customization (/docs/features/styling) import { Callout } from 'fumadocs-ui/components/callout'; # Styling and customization Control how pages appear in your screenshots with dark mode emulation, custom CSS injection, and precise timing controls. ## Dark mode Capture pages with dark color scheme: ```json { "url": "https://example.com", "darkMode": true } ``` This emulates `prefers-color-scheme: dark`, triggering: * CSS media queries * JavaScript-based theme detection * Framework dark themes (Tailwind, Bootstrap, etc.) ### Example ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://github.com", "darkMode": true }' --output dark-github.png ``` ### Compare light and dark Use [composition](/docs/api-reference/compose) to show both themes: ```json { "url": "https://example.com", "variants": [ { "darkMode": false, "label": "Light" }, { "darkMode": true, "label": "Dark" } ], "output": { "layout": "horizontal" } } ``` ## Custom CSS Inject CSS to modify page appearance: ```json { "url": "https://example.com", "customCss": "body { font-family: 'Inter', sans-serif; }" } ``` Custom CSS is limited to 10,000 characters. ### Common use cases **Change fonts:** ```json { "customCss": "@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap'); body { font-family: 'Inter', sans-serif !important; }" } ``` **Adjust colors:** ```json { "customCss": ":root { --primary-color: #007bff; } .brand-element { color: var(--primary-color) !important; }" } ``` **Remove animations:** ```json { "customCss": "*, *::before, *::after { animation: none !important; transition: none !important; }" } ``` **Highlight elements:** ```json { "customCss": ".feature-highlight { box-shadow: 0 0 0 4px #ff6b6b !important; border-radius: 8px; }" } ``` **Adjust spacing:** ```json { "customCss": ".hero-section { padding: 80px 40px !important; } .content { max-width: 800px; margin: 0 auto; }" } ``` ## Timing controls Control when the screenshot is captured for pages with dynamic content. ### Wait until Specify which page load event to wait for: ```json { "url": "https://example.com", "waitUntil": "networkidle" } ``` | Value | Description | | ------------------ | -------------------------------------------------- | | `load` | Wait for `load` event (default) | | `domcontentloaded` | Wait for DOM to be ready | | `networkidle` | Wait until network is idle (no requests for 500ms) | **When to use each:** * `load` - Most sites, standard content * `domcontentloaded` - Fast capture, static content * `networkidle` - SPAs, lazy-loaded content, API-driven pages ### Delay Add a delay after page load: ```json { "url": "https://example.com", "delay": 2000 } ``` Useful for: * Animation completion * Lazy image loading * JavaScript hydration * Cookie banner auto-dismiss Maximum delay is 30,000ms (30 seconds). For longer waits, consider async jobs. ### Wait for selector Wait for a specific element to appear: ```json { "url": "https://example.com/dashboard", "waitFor": ".chart-container.loaded" } ``` This waits until the CSS selector matches an element in the DOM. ### Combine timing options For complex pages, combine multiple timing controls: ```json { "url": "https://example.com/dashboard", "waitUntil": "networkidle", "waitFor": "[data-loaded='true']", "delay": 500 } ``` Order of execution: 1. Page loads until `waitUntil` event 2. Wait for `waitFor` selector (if specified) 3. Apply `delay` (if specified) 4. Capture screenshot ### Timeout Set maximum wait time: ```json { "url": "https://example.com", "timeout": 60000 } ``` | Range | Description | | ------- | --------------------- | | Minimum | 1,000ms (1 second) | | Default | 30,000ms (30 seconds) | | Maximum | 60,000ms (60 seconds) | ## Element capture Capture a specific element instead of the full viewport: ```json { "url": "https://example.com", "selector": "#hero-section" } ``` The image is automatically cropped to the element's bounding box. ### Complex selectors ```json { "selector": "main article:first-child" } ``` ```json { "selector": "[data-testid='product-card']" } ``` ```json { "selector": ".pricing-table .enterprise-plan" } ``` ## Examples ### Dashboard with charts ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://dashboard.example.com", "waitUntil": "networkidle", "waitFor": ".chart-loaded", "delay": 1000, "customCss": ".loading-spinner { display: none !important; }" }' --output dashboard.png ``` ### Hero section only ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "selector": "section.hero", "customCss": ".hero { padding: 60px 0; }" }' --output hero.png ``` ### Styled documentation ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://docs.example.com/api", "darkMode": true, "customCss": "pre code { font-size: 14px !important; } .sidebar { display: none; } .content { max-width: 100%; }", "hideSelectors": [".feedback-widget", ".toc"] }' --output docs.png ``` ## Best practices ### Test timing settings Different pages need different timing: ```javascript // SPA with lazy loading const spaSettings = { waitUntil: 'networkidle', waitFor: '[data-hydrated]', delay: 500, }; // Static marketing page const staticSettings = { waitUntil: 'load', delay: 0, }; ``` ### Use !important sparingly Custom CSS should use `!important` for overrides: ```css /* May not work */ .element { color: red; } /* Will override */ .element { color: red !important; } ``` ### Prefer selectors over CSS hiding For hiding elements, `hideSelectors` is cleaner than CSS: ```json { "hideSelectors": [".modal", ".banner"] } ``` vs. ```json { "customCss": ".modal { display: none !important; } .banner { display: none !important; }" } ``` # Viewport and devices (/docs/features/viewport-and-devices) import { Callout } from 'fumadocs-ui/components/callout'; # Viewport and devices Control how pages are rendered by setting custom viewport dimensions or emulating real devices. This is essential for capturing responsive designs and mobile-specific layouts. ## Custom viewport Set exact viewport dimensions: ```json { "url": "https://example.com", "viewport": { "width": 1440, "height": 900, "deviceScaleFactor": 2 } } ``` ### Viewport parameters | Parameter | Type | Range | Default | Description | | ------------------- | ------- | -------- | ------- | ----------------------------- | | `width` | integer | 100-4096 | 1920 | Viewport width in CSS pixels | | `height` | integer | 100-4096 | 1080 | Viewport height in CSS pixels | | `deviceScaleFactor` | integer | 1-3 | 1 | Device pixel ratio (DPR) | ### Device scale factor The `deviceScaleFactor` controls the pixel density: * `1` - Standard display (96 DPI) * `2` - Retina/HiDPI display (192 DPI) * `3` - Ultra-high DPI (288 DPI) Higher values produce sharper images but larger file sizes. ## Device presets Use device presets instead of manual viewport configuration: ```json { "url": "https://example.com", "device": "iphone_15" } ``` Device presets automatically configure: * Viewport dimensions * Device scale factor * Mobile/touch behavior * User agent (where applicable) ### Desktop devices | Preset | Dimensions | DPR | Description | | ---------------- | ---------- | --- | ------------------- | | `desktop_hd` | 1920×1080 | 1 | Standard HD desktop | | `desktop_large` | 2560×1440 | 1 | Large/QHD desktop | | `desktop_retina` | 1920×1080 | 2 | Retina desktop | | `laptop` | 1440×900 | 1 | Standard laptop | | `laptop_retina` | 1440×900 | 2 | MacBook Pro style | ### iPhone devices | Preset | Dimensions | DPR | Description | | ------------------- | ---------- | --- | ----------------- | | `iphone_se` | 375×667 | 2 | iPhone SE | | `iphone_xr` | 414×896 | 2 | iPhone XR | | `iphone_12` | 390×844 | 3 | iPhone 12 | | `iphone_12_pro_max` | 428×926 | 3 | iPhone 12 Pro Max | | `iphone_14` | 390×844 | 3 | iPhone 14 | | `iphone_14_pro_max` | 430×932 | 3 | iPhone 14 Pro Max | | `iphone_15` | 393×852 | 3 | iPhone 15 | | `iphone_15_pro_max` | 430×932 | 3 | iPhone 15 Pro Max | ### iPad devices | Preset | Dimensions | DPR | Description | | --------------- | ---------- | --- | -------------- | | `ipad` | 768×1024 | 2 | Standard iPad | | `ipad_mini` | 768×1024 | 2 | iPad Mini | | `ipad_pro_11` | 834×1194 | 2 | iPad Pro 11" | | `ipad_pro_12_9` | 1024×1366 | 2 | iPad Pro 12.9" | ### Android devices | Preset | Dimensions | DPR | Description | | -------------------- | ---------- | ----- | ----------------------- | | `pixel_5` | 393×851 | 2.75 | Google Pixel 5 | | `pixel_7` | 412×915 | 2.625 | Google Pixel 7 | | `pixel_7_pro` | 412×892 | 3.5 | Google Pixel 7 Pro | | `samsung_galaxy_s21` | 360×800 | 3 | Samsung Galaxy S21 | | `samsung_galaxy_s23` | 360×780 | 3 | Samsung Galaxy S23 | | `galaxy_tab_s7` | 800×1280 | 2 | Samsung Galaxy Tab S7 | | `surface_pro_7` | 912×1368 | 2 | Microsoft Surface Pro 7 | ### Social media presets Optimized dimensions for social platforms: | Preset | Dimensions | Description | | -------------------- | ---------- | ------------------- | | `facebook_og` | 1200×630 | Facebook Open Graph | | `twitter_card` | 1200×675 | Twitter/X Card | | `linkedin_post` | 1200×627 | LinkedIn Post | | `instagram_square` | 1080×1080 | Instagram Square | | `instagram_portrait` | 1080×1350 | Instagram Portrait | | `instagram_story` | 1080×1920 | Instagram Story | ## Examples ### Mobile screenshot ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "device": "iphone_15" }' --output mobile.png ``` ### Retina desktop ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "viewport": { "width": 1920, "height": 1080, "deviceScaleFactor": 2 } }' --output retina.png ``` ### Social media preview ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "device": "twitter_card" }' --output og-image.png ``` ### Responsive comparison Use [composition](/docs/api-reference/compose) to capture multiple devices: ```json { "url": "https://example.com", "variants": [ { "device": "desktop_hd", "label": "Desktop" }, { "device": "ipad_pro_11", "label": "Tablet" }, { "device": "iphone_15", "label": "Mobile" } ], "output": { "layout": "horizontal" } } ``` ## Full page screenshots Capture the entire scrollable page: ```json { "url": "https://example.com", "fullPage": true, "viewport": { "width": 1920, "height": 1080 } } ``` For full page captures, the `height` in viewport only sets the initial viewport. The final image height matches the page content. ## Best practices ### Match your target audience Use device presets that match your users' devices: ```javascript // Analytics shows 60% mobile traffic const mobileScreenshot = await capture({ url: 'https://example.com', device: 'iphone_15', }); ``` ### Use appropriate DPR Higher DPR produces sharper images but larger files: | Use case | Recommended DPR | | ------------- | --------------- | | Thumbnails | 1 | | Documentation | 1-2 | | Marketing | 2 | | Print | 2-3 | ### Consider aspect ratios Social platforms have specific requirements: ```javascript // Twitter/X card const twitterCard = await capture({ url: 'https://example.com', device: 'twitter_card', // 1200×675 (16:9) }); // Instagram const instagramSquare = await capture({ url: 'https://example.com', device: 'instagram_square', // 1080×1080 (1:1) }); ``` # Authentication (/docs/getting-started/authentication) import { Callout } from 'fumadocs-ui/components/callout'; # Authentication All API requests require authentication using an API key. This page explains how to create and use API keys. ## Creating an API key 1. Sign in to the [AllScreenshots dashboard](https://dashboard.allscreenshots.com) 2. Navigate to **API Keys** in the sidebar 3. Click **Create API Key** 4. Give your key a descriptive name (e.g., "Production", "Development") 5. Copy the key immediately—it won't be shown again API keys are displayed only once when created. If you lose a key, you'll need to create a new one. ## Using your API key Include your API key in the `Authorization` header with a `Bearer` prefix: ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer sk_live_abc123...' \ -H 'Content-Type: application/json' \ -d '{"url": "https://example.com"}' ``` ## Key prefixes API keys have prefixes to indicate their type: | Prefix | Description | | ---------- | --------------------------------------- | | `sk_live_` | Production keys with full access | | `sk_test_` | Test keys for development (coming soon) | ## Security best practices Never expose your API key in client-side code, public repositories, or browser requests. Follow these practices to keep your keys secure: ### Use environment variables Store keys in environment variables, not in code: ```bash # .env file (never commit this) ALLSCREENSHOTS_API_KEY=sk_live_abc123... ``` ```javascript // Access via environment variable const apiKey = process.env.ALLSCREENSHOTS_API_KEY; ``` ### Use server-side requests only Always make API calls from your server, never from the browser: ```javascript // Good: Server-side API route app.post('/api/screenshot', async (req, res) => { const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: req.body.url }), }); // ... }); ``` ### Rotate keys regularly Periodically create new keys and delete old ones, especially if: * A team member leaves your organization * You suspect a key may have been exposed * You haven't rotated keys in several months ### Use separate keys for environments Create different keys for development, staging, and production: * Easier to track usage per environment * Limits blast radius if a key is compromised * Allows different rate limits per environment ## Managing API keys From your dashboard, you can: * **View all keys**: See key names and creation dates * **Delete keys**: Revoke access immediately * **Track usage**: Monitor requests per key (coming soon) ## Error responses If authentication fails, you'll receive a `401 Unauthorized` response: ```json { "error": "unauthorized", "message": "Invalid or missing API key" } ``` Common causes: * Missing `Authorization` header * Missing `Bearer` prefix * Invalid or revoked API key * Key from wrong organization ## Rate limits API keys are subject to rate limits based on your plan. See [Rate limits](/docs/getting-started/rate-limits) for details. # Quickstart (/docs/getting-started/quickstart) import { Steps, Step } from 'fumadocs-ui/components/steps'; import { Callout } from 'fumadocs-ui/components/callout'; # Quickstart Get up and running with AllScreenshots in just a few minutes. ## Create an account Sign up at [allscreenshots.com](https://dashboard.allscreenshots.com) using your email or GitHub account. You'll get 100 free screenshots to start with. ## Get your API key After signing in, go to your dashboard and create an API key. Copy it somewhere safe—you'll only see the full key once. Keep your API key secret. Don't commit it to version control or expose it in client-side code. ## Capture your first screenshot Make a POST request to capture a screenshot: ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"url": "https://github.com"}' \ --output screenshot.png ``` This saves the screenshot as `screenshot.png` in your current directory. ## Next steps Now that you've captured your first screenshot, explore more options: ### Customize the viewport Capture at a specific resolution: ```json { "url": "https://github.com", "viewport": { "width": 1440, "height": 900 } } ``` ### Emulate a device Render as if viewed on an iPhone: ```json { "url": "https://github.com", "device": "iphone_15" } ``` ### Capture full pages Scroll and capture the entire page: ```json { "url": "https://github.com", "fullPage": true } ``` ### Get a JSON response Instead of binary image data, receive a URL: ```json { "url": "https://github.com", "responseType": "json" } ``` Response: ```json { "url": "https://storage.allscreenshots.com/abc123.png", "expiresAt": "2025-01-30T12:00:00Z", "size": 245678, "width": 1920, "height": 1080, "format": "png", "renderTime": 1234 } ``` ## Common options | Option | Type | Default | Description | | ----------------- | ------- | -------- | ------------------------------------------- | | `url` | string | required | The URL to capture | | `format` | string | `"png"` | Output format: `png`, `jpeg`, `webp`, `pdf` | | `viewport.width` | number | `1920` | Viewport width in pixels | | `viewport.height` | number | `1080` | Viewport height in pixels | | `fullPage` | boolean | `false` | Capture the full scrollable page | | `delay` | number | `0` | Wait time in ms before capture | | `darkMode` | boolean | `false` | Emulate dark color scheme | See the [API reference](/docs/api-reference/screenshots) for all available options. ## Code examples ### JavaScript ```javascript const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ url: 'https://github.com', format: 'png', viewport: { width: 1280, height: 720 } }), }); const screenshot = await response.blob(); ``` ### Python ```python import requests response = requests.post( 'https://api.allscreenshots.com/v1/screenshots', headers={'Authorization': 'Bearer YOUR_API_KEY'}, json={ 'url': 'https://github.com', 'format': 'png', 'viewport': {'width': 1280, 'height': 720} } ) with open('screenshot.png', 'wb') as f: f.write(response.content) ``` ### Go ```go package main import ( "bytes" "encoding/json" "io" "net/http" "os" ) func main() { payload := map[string]interface{}{ "url": "https://github.com", "format": "png", } body, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", "https://api.allscreenshots.com/v1/screenshots", bytes.NewBuffer(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() file, _ := os.Create("screenshot.png") defer file.Close() io.Copy(file, resp.Body) } ``` # Rate limits (/docs/getting-started/rate-limits) import { Callout } from 'fumadocs-ui/components/callout'; # Rate limits AllScreenshots applies rate limits to ensure fair usage and platform stability. This page explains how limits work and how to handle them. ## How rate limiting works Rate limits are applied per API key and measured in requests per minute (RPM). When you exceed the limit, the API returns a `429 Too Many Requests` response. ## Plan limits | Plan | Requests per minute | Monthly quota | | ---------- | ------------------- | ------------------ | | Free | 10 RPM | 100 screenshots | | Starter | 60 RPM | 1,000 screenshots | | Pro | 120 RPM | 10,000 screenshots | | Enterprise | Custom | Custom | ## Rate limit headers Every response includes headers showing your current rate limit status: ```http X-RateLimit-Limit: 60 X-RateLimit-Remaining: 45 X-RateLimit-Reset: 1704067200 ``` | Header | Description | | ----------------------- | ------------------------------------ | | `X-RateLimit-Limit` | Maximum requests allowed per minute | | `X-RateLimit-Remaining` | Requests remaining in current window | | `X-RateLimit-Reset` | Unix timestamp when the limit resets | ## Handling rate limits When you hit the rate limit, you'll receive: ```http HTTP/1.1 429 Too Many Requests Retry-After: 30 { "error": "rate_limit_exceeded", "message": "Rate limit exceeded. Please retry after 30 seconds." } ``` ### Retry with exponential backoff Implement exponential backoff to handle rate limits gracefully: ```javascript async function captureWithRetry(url, maxRetries = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url }), }); if (response.status === 429) { const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt); await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)); continue; } return response; } throw new Error('Max retries exceeded'); } ``` ## Best practices ### Use bulk endpoints Instead of making 100 individual requests, use the [bulk endpoint](/docs/api-reference/bulk) to capture multiple URLs in one request: ```json { "urls": [ { "url": "https://example1.com" }, { "url": "https://example2.com" }, { "url": "https://example3.com" } ] } ``` ### Use async processing For large workloads, use [async jobs](/docs/api-reference/async-jobs) with webhooks instead of waiting synchronously: ```json { "url": "https://example.com", "webhookUrl": "https://your-server.com/webhook" } ``` ### Cache results Store screenshots locally and reuse them when possible: ```javascript const cacheKey = `screenshot:${url}:${JSON.stringify(options)}`; const cached = await cache.get(cacheKey); if (cached) { return cached; } const screenshot = await captureScreenshot(url, options); await cache.set(cacheKey, screenshot, { ttl: 3600 }); return screenshot; ``` Need higher limits? Contact us about Enterprise plans with custom rate limits and dedicated capacity. ## Monthly quotas In addition to rate limits, your plan has a monthly screenshot quota. When you reach your quota: * Requests return `402 Payment Required` * You can upgrade your plan to continue * Quotas reset at the start of each billing period Track your usage in the dashboard under **Usage**. # CI/CD integration (/docs/guides/ci-cd-integration) import { Callout } from 'fumadocs-ui/components/callout'; import { Steps, Step } from 'fumadocs-ui/components/steps'; # CI/CD integration Integrate screenshot capture into your CI/CD pipeline for automated visual testing, documentation updates, and deployment previews. ## Use cases * **Visual regression testing**: Catch UI bugs before they reach production * **Deploy previews**: Generate screenshots of preview deployments for PR reviews * **Documentation automation**: Update screenshots in docs when UI changes * **Release artifacts**: Generate marketing screenshots for app store submissions ## GitHub Actions ### Visual testing on pull requests ```yaml # .github/workflows/visual-tests.yml name: Visual Tests on: pull_request: branches: [main] jobs: visual-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: Build application run: npm run build env: NODE_ENV: production - name: Start application run: npm start & - name: Wait for server run: npx wait-on http://localhost:3000 --timeout 60000 - name: Capture screenshots run: node scripts/capture-screenshots.js env: ALLSCREENSHOTS_API_KEY: ${{ secrets.ALLSCREENSHOTS_API_KEY }} BASE_URL: http://localhost:3000 - name: Compare with baselines run: node scripts/compare-screenshots.js - name: Upload diff images if: failure() uses: actions/upload-artifact@v4 with: name: visual-diffs path: screenshots/diffs/ - name: Comment on PR if: failure() uses: actions/github-script@v7 with: script: | github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: '⚠️ Visual differences detected. See artifacts for details.' }) ``` ### Deploy preview screenshots Generate screenshots after Vercel/Netlify deployments: ```yaml # .github/workflows/preview-screenshots.yml name: Preview Screenshots on: deployment_status: jobs: screenshot: if: github.event.deployment_status.state == 'success' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Get preview URL id: preview run: | echo "url=${{ github.event.deployment_status.target_url }}" >> $GITHUB_OUTPUT - name: Capture preview screenshots run: | curl -X POST 'https://api.allscreenshots.com/v1/screenshots/bulk' \ -H 'Authorization: Bearer ${{ secrets.ALLSCREENSHOTS_API_KEY }}' \ -H 'Content-Type: application/json' \ -d '{ "urls": [ { "url": "${{ steps.preview.outputs.url }}" }, { "url": "${{ steps.preview.outputs.url }}/pricing" }, { "url": "${{ steps.preview.outputs.url }}/about" } ], "defaults": { "viewport": { "width": 1920, "height": 1080 }, "blockAds": true } }' > bulk-job.json - name: Wait for screenshots run: | BULK_JOB_ID=$(jq -r '.bulkJobId' bulk-job.json) for i in {1..30}; do STATUS=$(curl -s -H "Authorization: Bearer ${{ secrets.ALLSCREENSHOTS_API_KEY }}" \ "https://api.allscreenshots.com/v1/screenshots/bulk/$BULK_JOB_ID" \ | jq -r '.status') if [ "$STATUS" = "completed" ]; then break fi sleep 5 done - name: Comment screenshots on PR uses: actions/github-script@v7 with: script: | const response = await fetch( `https://api.allscreenshots.com/v1/screenshots/bulk/${process.env.BULK_JOB_ID}`, { headers: { 'Authorization': `Bearer ${process.env.API_KEY}` } } ); const job = await response.json(); const screenshots = job.jobs .filter(j => j.status === 'completed') .map(j => `![${j.url}](${j.result.url})`) .join('\n\n'); github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `## Deploy Preview Screenshots\n\n${screenshots}` }); env: BULK_JOB_ID: ${{ steps.bulk.outputs.job_id }} API_KEY: ${{ secrets.ALLSCREENSHOTS_API_KEY }} ``` ## GitLab CI ```yaml # .gitlab-ci.yml stages: - build - test - screenshot visual-tests: stage: screenshot image: node:20 script: - npm ci - npm run build - npm start & - npx wait-on http://localhost:3000 - node scripts/visual-tests.js variables: ALLSCREENSHOTS_API_KEY: $ALLSCREENSHOTS_API_KEY artifacts: when: on_failure paths: - screenshots/diffs/ expire_in: 1 week only: - merge_requests ``` ## CircleCI ```yaml # .circleci/config.yml version: 2.1 jobs: visual-tests: docker: - image: cimg/node:20.0 steps: - checkout - restore_cache: keys: - npm-deps-{{ checksum "package-lock.json" }} - run: name: Install dependencies command: npm ci - save_cache: paths: - node_modules key: npm-deps-{{ checksum "package-lock.json" }} - run: name: Build and start app command: | npm run build npm start & background: true - run: name: Wait for app command: npx wait-on http://localhost:3000 - run: name: Run visual tests command: node scripts/visual-tests.js - store_artifacts: path: screenshots/diffs destination: visual-diffs workflows: test: jobs: - visual-tests ``` ## Screenshot capture script A reusable script for CI environments: ```javascript // scripts/capture-screenshots.js const pages = [ { name: 'home', path: '/' }, { name: 'pricing', path: '/pricing' }, { name: 'login', path: '/login' }, { name: 'dashboard', path: '/dashboard' }, ]; const viewports = [ { name: 'desktop', width: 1920, height: 1080 }, { name: 'mobile', width: 375, height: 667 }, ]; async function captureScreenshots() { const baseUrl = process.env.BASE_URL || 'http://localhost:3000'; const outputDir = process.env.OUTPUT_DIR || './screenshots/current'; // Ensure output directory exists await fs.mkdir(outputDir, { recursive: true }); const urls = []; for (const page of pages) { for (const viewport of viewports) { urls.push({ url: `${baseUrl}${page.path}`, options: { viewport: { width: viewport.width, height: viewport.height }, }, filename: `${page.name}-${viewport.name}.png`, }); } } // Use bulk API for efficiency const response = await fetch('https://api.allscreenshots.com/v1/screenshots/bulk', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ urls: urls.map(u => ({ url: u.url, options: u.options, })), defaults: { format: 'png', waitUntil: 'networkidle', blockAds: true, blockCookieBanners: true, }, }), }); const { bulkJobId } = await response.json(); console.log(`Bulk job started: ${bulkJobId}`); // Poll for completion let result; for (let i = 0; i < 60; i++) { const statusResponse = await fetch( `https://api.allscreenshots.com/v1/screenshots/bulk/${bulkJobId}`, { headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}` } } ); result = await statusResponse.json(); if (result.status === 'completed') break; if (result.status === 'failed') throw new Error('Bulk job failed'); console.log(`Progress: ${result.completedUrls}/${result.totalUrls}`); await new Promise(resolve => setTimeout(resolve, 2000)); } // Download screenshots for (let i = 0; i < result.jobs.length; i++) { const job = result.jobs[i]; if (job.status !== 'completed') continue; const imageResponse = await fetch(job.result.url); const buffer = await imageResponse.arrayBuffer(); await fs.writeFile( `${outputDir}/${urls[i].filename}`, Buffer.from(buffer) ); console.log(`Saved: ${urls[i].filename}`); } console.log('Screenshots captured successfully'); } captureScreenshots().catch(err => { console.error(err); process.exit(1); }); ``` ## Secrets management Never commit API keys to your repository. Use your CI provider's secrets management. ### GitHub Actions ```yaml env: ALLSCREENSHOTS_API_KEY: ${{ secrets.ALLSCREENSHOTS_API_KEY }} ``` ### GitLab CI ```yaml variables: ALLSCREENSHOTS_API_KEY: $ALLSCREENSHOTS_API_KEY # Set in CI/CD settings ``` ### CircleCI ```yaml # Set in Project Settings > Environment Variables - run: command: echo $ALLSCREENSHOTS_API_KEY ``` ## Best practices ### Parallel execution Run visual tests in parallel with other test suites: ```yaml jobs: unit-tests: # ... integration-tests: # ... visual-tests: # ... # All jobs run in parallel by default ``` ### Caching Cache dependencies to speed up builds: ```yaml - name: Cache node modules uses: actions/cache@v4 with: path: node_modules key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} ``` ### Conditional execution Only run visual tests when relevant files change: ```yaml on: pull_request: paths: - 'src/**' - 'public/**' - 'package.json' ``` ### Baseline management Store baselines in your repository or a separate storage: ```yaml # Update baselines on main branch merges - name: Update baselines if: github.ref == 'refs/heads/main' run: | mv screenshots/current/* screenshots/baseline/ git add screenshots/baseline/ git commit -m "Update visual baselines" git push ``` # Capturing full page screenshots (/docs/guides/full-page-screenshots) import { Callout } from 'fumadocs-ui/components/callout'; import { Steps, Step } from 'fumadocs-ui/components/steps'; # Capturing full page screenshots Learn how to capture complete web pages, from simple blog posts to complex landing pages with sticky headers and dynamic content. ## Use cases * **Documentation**: Archive complete pages for reference * **Legal compliance**: Full page evidence for disputes or audits * **Marketing**: Capture competitor landing pages * **Design review**: Share full page mockups with stakeholders * **Visual testing**: Compare entire page layouts across releases ## Quick start Capture a full page with a single API call: ```bash curl -X POST 'https://api.allscreenshots.com/v1/screenshots' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com", "fullPage": true }' --output full-page.png ``` ## Understanding capture modes AllScreenshots offers two capture modes, each optimized for different scenarios. ### When to use stitch mode (default) Use stitch mode for most websites, especially those with: * **Fixed navigation bars** that stay visible while scrolling * **Sticky headers or footers** like cookie banners * **Lazy-loaded content** that appears as you scroll * **Scroll-triggered animations** that need to complete before capture ```json { "url": "https://example.com", "fullPage": true, "fullPageMode": "stitch" } ``` ### When to use native mode Use native mode when you need: * **Maximum speed** and can accept quality trade-offs * **Simple pages** without fixed elements * **Server-rendered content** that doesn't rely on scroll events ```json { "url": "https://example.com", "fullPage": true, "fullPageMode": "native" } ``` ## Step-by-step tutorials ### Capture a landing page with sticky header Most marketing sites have fixed navigation. Here's how to capture them properly: ```javascript const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'X-API-Key': process.env.ALLSCREENSHOTS_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: 'https://stripe.com', fullPage: true, fullPageMode: 'stitch', freezeFixed: true, waitUntil: 'networkidle', delay: 1000, }), }); const imageBlob = await response.blob(); ``` **What happens:** 1. Page loads and waits for network activity to stop 2. Additional 1 second delay for animations to settle 3. Scrolls through the entire page to trigger lazy content 4. Detects the sticky header 5. Captures each section while hiding the header 6. Stitches sections together 7. Places header at the top of the final image ### Capture a page with lazy-loaded images E-commerce sites often load product images as you scroll: ```javascript const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'X-API-Key': process.env.ALLSCREENSHOTS_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: 'https://shop.example.com/products', fullPage: true, scrollInterval: 300, // Slower scroll to allow images to load waitUntil: 'networkidle', delay: 2000, // Extra time for images }), }); ``` The `scrollInterval` parameter controls how long to wait between scroll steps. Increase it for sites with heavy lazy-loading. ### Capture documentation pages Documentation sites are often long but straightforward: ```javascript const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'X-API-Key': process.env.ALLSCREENSHOTS_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: 'https://docs.example.com/api-reference', fullPage: true, viewport: { width: 1440, height: 900, }, blockAds: true, blockCookieBanners: true, }), }); ``` ### Handle very long pages For extremely long pages, set limits to prevent timeouts: ```javascript const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'X-API-Key': process.env.ALLSCREENSHOTS_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: 'https://example.com/very-long-page', fullPage: true, maxHeight: 20000, // Limit to 20,000 pixels maxSections: 50, // Or limit to 50 viewport sections timeout: 60000, // 60 second timeout }), }); ``` ## Common scenarios ### Blog posts and articles ```json { "url": "https://blog.example.com/my-article", "fullPage": true, "viewport": { "width": 800, "height": 600 }, "blockAds": true, "blockCookieBanners": true } ``` ### Product pages ```json { "url": "https://shop.example.com/product/123", "fullPage": true, "scrollInterval": 250, "waitUntil": "networkidle", "delay": 1500 } ``` ### Social media profiles ```json { "url": "https://twitter.com/username", "fullPage": true, "maxHeight": 10000, "scrollInterval": 400, "delay": 2000 } ``` ### Single page applications (SPAs) ```json { "url": "https://app.example.com/dashboard", "fullPage": true, "waitUntil": "networkidle", "delay": 3000, "scrollInterval": 300 } ``` ## Optimizing for quality ### Image format selection | Format | Best for | File size | | ------ | ---------------------------------- | --------- | | PNG | Screenshots with text, UI elements | Larger | | JPEG | Photo-heavy pages | Smaller | | WebP | Best compression, modern browsers | Smallest | ```json { "url": "https://example.com", "fullPage": true, "format": "webp", "quality": 90 } ``` ### Retina/HiDPI captures For crisp text and UI elements: ```json { "url": "https://example.com", "fullPage": true, "viewport": { "width": 1920, "height": 1080, "deviceScaleFactor": 2 } } ``` Higher device scale factors significantly increase file size and capture time. ## Troubleshooting ### Header appears multiple times **Problem:** Using native mode on a page with fixed header. **Solution:** Switch to stitch mode: ```json { "fullPage": true, "fullPageMode": "stitch", "freezeFixed": true } ``` ### Content missing at bottom of page **Problem:** Lazy content not loading. **Solution:** Increase scroll interval and add delay: ```json { "fullPage": true, "scrollInterval": 400, "delay": 2000, "waitUntil": "networkidle" } ``` ### Capture times out **Problem:** Page is too long or slow. **Solution:** Limit capture height and increase timeout: ```json { "fullPage": true, "maxHeight": 15000, "timeout": 60000 } ``` ### Animations causing visual artifacts **Problem:** Scroll-triggered animations captured mid-transition. **Solution:** Use stitch mode with higher scroll interval: ```json { "fullPage": true, "fullPageMode": "stitch", "scrollInterval": 300, "delay": 1000 } ``` ### Cookie banner blocking content **Solution:** Enable cookie banner blocking: ```json { "fullPage": true, "blockCookieBanners": true } ``` ## Batch full page captures Capture multiple pages efficiently using the bulk API: ```javascript const response = await fetch('https://api.allscreenshots.com/v1/screenshots/bulk', { method: 'POST', headers: { 'X-API-Key': process.env.ALLSCREENSHOTS_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ urls: [ { url: 'https://example.com/page-1' }, { url: 'https://example.com/page-2' }, { url: 'https://example.com/page-3' }, ], defaults: { fullPage: true, fullPageMode: 'stitch', waitUntil: 'networkidle', }, webhookUrl: 'https://your-app.com/webhook', }), }); const { jobId } = await response.json(); console.log(`Batch job started: ${jobId}`); ``` ## Best practices ### 1. Start with defaults The default settings work well for most sites: ```json { "url": "https://example.com", "fullPage": true } ``` ### 2. Add wait conditions for dynamic sites ```json { "fullPage": true, "waitUntil": "networkidle", "delay": 1000 } ``` ### 3. Use appropriate viewport width * **Desktop documentation:** 1200-1440px * **Marketing pages:** 1920px * **Mobile responsive:** 375-414px ### 4. Consider file size Full page screenshots can be large. Optimize with: ```json { "fullPage": true, "format": "webp", "quality": 85, "maxHeight": 20000 } ``` ### 5. Test incrementally Start with a simple capture and add options as needed: ```javascript // Start simple let options = { url, fullPage: true }; // If header repeats, add stitch mode options.fullPageMode = 'stitch'; // If content missing, add wait options.waitUntil = 'networkidle'; options.delay = 1000; // If still issues, increase scroll interval options.scrollInterval = 300; ``` # Build a link preview service (/docs/guides/link-preview-service) import { Callout } from 'fumadocs-ui/components/callout'; import { Steps, Step } from 'fumadocs-ui/components/steps'; # Build a link preview service Create a service that generates rich previews for URLs shared in chat applications, social platforms, or content management systems. ## What you'll build A link preview service that returns: * Title and description from meta tags * A thumbnail screenshot of the page * Favicon and site name ```json { "url": "https://example.com/article", "title": "Example Article", "description": "This is an example article...", "siteName": "Example Site", "favicon": "https://example.com/favicon.ico", "thumbnail": "https://storage.allscreenshots.com/preview-abc123.png" } ``` ## Architecture ``` ┌──────────┐ ┌──────────────┐ ┌─────────────────┐ │ Client │ --> │ Your API │ --> │ AllScreenshots │ └──────────┘ │ (cache + │ │ API │ │ metadata) │ └─────────────────┘ └──────────────┘ ``` ## Implementation ### Create the API endpoint ```javascript // api/preview/route.js import { parse } from 'node-html-parser'; export async function GET(request) { const { searchParams } = new URL(request.url); const url = searchParams.get('url'); if (!url) { return Response.json({ error: 'URL required' }, { status: 400 }); } // Check cache first const cacheKey = `preview:${url}`; const cached = await cache.get(cacheKey); if (cached) { return Response.json(cached); } // Generate preview const preview = await generatePreview(url); // Cache for 24 hours await cache.set(cacheKey, preview, { ttl: 86400 }); return Response.json(preview); } ``` ### Fetch metadata ```javascript async function fetchMetadata(url) { try { const response = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0 (compatible; LinkPreviewBot/1.0)', }, }); const html = await response.text(); const root = parse(html); // Extract Open Graph tags const og = (property) => root.querySelector(`meta[property="og:${property}"]`)?.getAttribute('content'); // Extract Twitter tags as fallback const twitter = (name) => root.querySelector(`meta[name="twitter:${name}"]`)?.getAttribute('content'); // Extract standard meta tags const meta = (name) => root.querySelector(`meta[name="${name}"]`)?.getAttribute('content'); return { title: og('title') || twitter('title') || root.querySelector('title')?.text || '', description: og('description') || twitter('description') || meta('description') || '', siteName: og('site_name') || new URL(url).hostname, image: og('image') || twitter('image') || null, favicon: root.querySelector('link[rel="icon"]')?.getAttribute('href') || root.querySelector('link[rel="shortcut icon"]')?.getAttribute('href') || `${new URL(url).origin}/favicon.ico`, }; } catch (error) { console.error('Failed to fetch metadata:', error); return { title: new URL(url).hostname, description: '', siteName: new URL(url).hostname, image: null, favicon: null, }; } } ``` ### Capture thumbnail ```javascript async function captureThumbnail(url) { const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url, viewport: { width: 1200, height: 630, // OG image dimensions }, format: 'png', quality: 80, waitUntil: 'networkidle', blockAds: true, blockCookieBanners: true, responseType: 'json', }), }); if (!response.ok) { throw new Error('Failed to capture screenshot'); } const result = await response.json(); return result.url; } ``` ### Combine into preview ```javascript async function generatePreview(url) { // Fetch metadata and thumbnail in parallel const [metadata, thumbnail] = await Promise.all([ fetchMetadata(url), captureThumbnail(url).catch(() => null), ]); return { url, title: metadata.title, description: metadata.description, siteName: metadata.siteName, favicon: metadata.favicon, // Use OG image if available, fall back to screenshot thumbnail: metadata.image || thumbnail, }; } ``` ## Frontend component ```jsx function LinkPreview({ url }) { const { data: preview, isLoading, error } = useQuery( ['preview', url], () => fetch(`/api/preview?url=${encodeURIComponent(url)}`).then(r => r.json()), { staleTime: 86400000 } // Cache for 24 hours ); if (isLoading) { return (
); } if (error || !preview) { return ( {url} ); } return ( {preview.thumbnail && ( {preview.title} )}
{preview.favicon && ( )} {preview.siteName}

{preview.title}

{preview.description && (

{preview.description}

)}
); } ``` ### Styling ```css .link-preview { display: flex; flex-direction: column; border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; text-decoration: none; color: inherit; max-width: 400px; } .link-preview:hover { border-color: #ccc; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } .preview-image { width: 100%; height: 200px; object-fit: cover; } .preview-content { padding: 12px; } .preview-site { display: flex; align-items: center; gap: 6px; font-size: 12px; color: #666; margin-bottom: 4px; } .favicon { width: 16px; height: 16px; } .preview-title { font-size: 16px; font-weight: 600; margin: 0 0 4px; line-height: 1.3; } .preview-description { font-size: 14px; color: #666; margin: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } ``` ## Optimizations ### Queue processing For high-volume applications, queue preview generation: ```javascript import { Queue } from 'bullmq'; const previewQueue = new Queue('link-previews'); // API endpoint adds to queue app.get('/api/preview', async (req, res) => { const { url } = req.query; // Check cache const cached = await cache.get(`preview:${url}`); if (cached) { return res.json(cached); } // Check if already processing const existing = await previewQueue.getJob(url); if (existing) { // Wait for existing job const result = await existing.waitUntilFinished(previewQueue.queueEvents); return res.json(result); } // Add to queue const job = await previewQueue.add('generate', { url }, { jobId: url }); const result = await job.waitUntilFinished(previewQueue.queueEvents); res.json(result); }); // Worker processes queue const worker = new Worker('link-previews', async (job) => { const preview = await generatePreview(job.data.url); await cache.set(`preview:${job.data.url}`, preview, { ttl: 86400 }); return preview; }); ``` ### Bulk preview generation When users paste multiple links: ```javascript async function generateBulkPreviews(urls) { // First, check cache for all URLs const cached = await Promise.all( urls.map(url => cache.get(`preview:${url}`)) ); const uncachedUrls = urls.filter((_, i) => !cached[i]); if (uncachedUrls.length === 0) { return urls.map((url, i) => cached[i]); } // Generate screenshots for uncached URLs const bulkResponse = await fetch('https://api.allscreenshots.com/v1/screenshots/bulk', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ urls: uncachedUrls.map(url => ({ url })), defaults: { viewport: { width: 1200, height: 630 }, format: 'png', blockAds: true, blockCookieBanners: true, }, }), }); // Fetch metadata in parallel const metadataResults = await Promise.all( uncachedUrls.map(url => fetchMetadata(url)) ); // Wait for bulk job to complete const { bulkJobId } = await bulkResponse.json(); const screenshotResults = await waitForBulkJob(bulkJobId); // Combine and cache results const newPreviews = uncachedUrls.map((url, i) => ({ url, ...metadataResults[i], thumbnail: screenshotResults.jobs[i]?.result?.url || null, })); await Promise.all( newPreviews.map(preview => cache.set(`preview:${preview.url}`, preview, { ttl: 86400 }) ) ); // Merge cached and new results let newIndex = 0; return urls.map((url, i) => { if (cached[i]) return cached[i]; return newPreviews[newIndex++]; }); } ``` ## Best practices Always cache previews aggressively. Most link content doesn't change frequently. ### Rate limiting Protect your endpoint from abuse: ```javascript import rateLimit from 'express-rate-limit'; const previewLimiter = rateLimit({ windowMs: 60 * 1000, // 1 minute max: 30, // 30 requests per minute message: { error: 'Too many requests' }, }); app.use('/api/preview', previewLimiter); ``` ### URL validation Validate and sanitize input URLs: ```javascript function validateUrl(url) { try { const parsed = new URL(url); // Only allow HTTP(S) if (!['http:', 'https:'].includes(parsed.protocol)) { return null; } // Block private IPs if (isPrivateIP(parsed.hostname)) { return null; } return parsed.href; } catch { return null; } } ``` ### Error handling Gracefully handle failures: ```javascript async function generatePreview(url) { const preview = { url, title: new URL(url).hostname, description: null, siteName: new URL(url).hostname, favicon: null, thumbnail: null, error: null, }; try { const metadata = await fetchMetadata(url); Object.assign(preview, metadata); } catch (e) { preview.error = 'metadata_failed'; } try { preview.thumbnail = await captureThumbnail(url); } catch (e) { preview.error = preview.error || 'thumbnail_failed'; } return preview; } ``` # Generate PDFs from web pages (/docs/guides/pdf-generation) import { Callout } from 'fumadocs-ui/components/callout'; import { Steps, Step } from 'fumadocs-ui/components/steps'; # Generate PDFs from web pages Convert any web page to a PDF document with full styling, images, and formatting preserved. ## Use cases * **Invoice generation**: Convert invoice pages to downloadable PDFs * **Report exports**: Generate PDF reports from dashboards * **Documentation**: Create offline documentation from web docs * **Contracts**: Generate signed agreement PDFs * **Receipts**: Create transaction receipts ## Basic PDF generation ```javascript async function generatePdf(url) { const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url, format: 'pdf', fullPage: true, waitUntil: 'networkidle', }), }); return response.blob(); } // Usage const pdf = await generatePdf('https://example.com/invoice/123'); ``` ## Invoice generation workflow ### Create an invoice template Design a web page optimized for PDF output: ```jsx // pages/invoice/[id].jsx export default function InvoicePage({ invoice }) { return (
Company

INVOICE

#{invoice.number}

{formatDate(invoice.date)}

Bill To:

{invoice.customer.name}

{invoice.customer.address}

{invoice.customer.email}

{invoice.items.map(item => ( ))}
Description Qty Price Total
{item.description} {item.quantity} ${item.price} ${item.total}
Total: ${invoice.total}

Payment due within 30 days

Bank: {invoice.bankDetails}

); } ```
### Generate the PDF ```javascript // API route: /api/invoices/[id]/pdf export async function GET(request, { params }) { const invoice = await db.invoices.findUnique({ where: { id: params.id }, include: { customer: true, items: true }, }); if (!invoice) { return new Response('Invoice not found', { status: 404 }); } const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: `${process.env.APP_URL}/invoice/${params.id}`, format: 'pdf', fullPage: true, viewport: { width: 794, // A4 at 96 DPI height: 1123, }, waitUntil: 'networkidle', }), }); const pdf = await response.arrayBuffer(); return new Response(pdf, { headers: { 'Content-Type': 'application/pdf', 'Content-Disposition': `attachment; filename="invoice-${invoice.number}.pdf"`, }, }); } ``` ### Add download button ```jsx function InvoiceActions({ invoiceId }) { const downloadPdf = async () => { const response = await fetch(`/api/invoices/${invoiceId}/pdf`); const blob = await response.blob(); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `invoice-${invoiceId}.pdf`; a.click(); URL.revokeObjectURL(url); }; return ( ); } ```
## PDF styling tips ### Print-optimized CSS ```css @media print { /* Hide non-printable elements */ .no-print, nav, .sidebar { display: none !important; } /* Avoid page breaks inside elements */ .keep-together { page-break-inside: avoid; } /* Force page break before element */ .page-break { page-break-before: always; } /* Remove backgrounds for cleaner print */ body { background: white !important; } } ``` ### Inject print styles via API ```javascript const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: pageUrl, format: 'pdf', fullPage: true, customCss: ` @page { margin: 20mm; } body { font-size: 12pt; line-height: 1.5; } .no-print { display: none !important; } table { page-break-inside: avoid; } `, }), }); ``` ## Multi-page reports Generate reports that span multiple pages: ```jsx // Report template with multiple sections function ReportTemplate({ data }) { return (
{/* Cover page */}

{data.title}

{data.date}

{/* Executive summary */}

Executive Summary

{data.summary}

{/* Data sections */} {data.sections.map(section => (

{section.title}

{section.content} {section.chart && }
))}
); } ``` ## Async PDF generation for large documents For large documents, use async jobs: ```javascript async function generateLargeReport(reportId) { // Start async job const response = await fetch('https://api.allscreenshots.com/v1/screenshots/async', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: `${process.env.APP_URL}/reports/${reportId}`, format: 'pdf', fullPage: true, timeout: 60000, // Allow longer timeout for complex reports webhookUrl: `${process.env.APP_URL}/webhooks/pdf-ready`, }), }); const { jobId } = await response.json(); // Store job ID for later reference await db.reports.update({ where: { id: reportId }, data: { pdfJobId: jobId, pdfStatus: 'generating' }, }); return jobId; } // Webhook handler app.post('/webhooks/pdf-ready', async (req, res) => { const { jobId, status, result } = req.body; const report = await db.reports.findFirst({ where: { pdfJobId: jobId }, }); if (status === 'completed') { await db.reports.update({ where: { id: report.id }, data: { pdfUrl: result.url, pdfStatus: 'ready' }, }); // Notify user await sendEmail(report.userEmail, { subject: 'Your report is ready', body: `Download your report: ${result.url}`, }); } res.sendStatus(200); }); ``` ## Best practices Use fixed widths (like A4: 794px at 96 DPI) for predictable PDF layouts. ### Font handling Ensure fonts are loaded before capture: ```javascript const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { body: JSON.stringify({ url: pageUrl, format: 'pdf', waitUntil: 'networkidle', delay: 500, // Extra time for fonts to load }), }); ``` ### Image optimization * Use absolute URLs for images * Ensure images are loaded before capture * Consider embedding base64 images for reliability ### Page size reference | Paper Size | Width (px) | Height (px) | At DPI | | ---------- | ---------- | ----------- | ------ | | A4 | 794 | 1123 | 96 | | Letter | 816 | 1056 | 96 | | Legal | 816 | 1344 | 96 | | A4 (print) | 595 | 842 | 72 | # Generate social media previews (/docs/guides/social-media-previews) import { Callout } from 'fumadocs-ui/components/callout'; import { Steps, Step } from 'fumadocs-ui/components/steps'; # Generate social media previews Create eye-catching Open Graph (OG) images that make your content stand out when shared on Twitter, Facebook, LinkedIn, and other platforms. ## What you'll build An automated system that generates preview images for blog posts, product pages, or any content you want to share on social media. ## Prerequisites * AllScreenshots API key * A template page or dynamic route for generating previews ## Approach 1: Screenshot existing pages The simplest approach—capture your actual pages with social media dimensions. ### Basic implementation ```javascript async function generateOgImage(pageUrl) { const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: pageUrl, device: 'twitter_card', // 1200x675 waitUntil: 'networkidle', blockAds: true, blockCookieBanners: true, }), }); return response.blob(); } ``` ### For multiple platforms Different platforms have different optimal dimensions: ```javascript const platforms = { twitter: 'twitter_card', // 1200x675 facebook: 'facebook_og', // 1200x630 linkedin: 'linkedin_post', // 1200x627 }; async function generateAllPreviews(pageUrl) { const previews = {}; for (const [platform, device] of Object.entries(platforms)) { const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: pageUrl, device, responseType: 'json', }), }); const result = await response.json(); previews[platform] = result.url; } return previews; } ``` ## Approach 2: Dedicated OG template Create a special page designed specifically for OG images, then screenshot it. ### Create an OG template route ```jsx // pages/og/[slug].jsx or app/og/[slug]/page.jsx export default function OgTemplate({ params }) { const post = getPost(params.slug); return (

{post.title}

{post.description}

yoursite.com
); } ```
### Capture the template ```javascript async function generateOgImage(slug) { const templateUrl = `https://yoursite.com/og/${slug}`; const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: templateUrl, viewport: { width: 1200, height: 630 }, format: 'png', }), }); return response; } ``` ### Serve the OG image ```javascript // API route: /api/og/[slug] export async function GET(request, { params }) { const { slug } = params; // Check cache first const cached = await cache.get(`og:${slug}`); if (cached) { return new Response(cached, { headers: { 'Content-Type': 'image/png' }, }); } // Generate new image const image = await generateOgImage(slug); const buffer = await image.arrayBuffer(); // Cache for 24 hours await cache.set(`og:${slug}`, buffer, { ttl: 86400 }); return new Response(buffer, { headers: { 'Content-Type': 'image/png' }, }); } ``` ### Add meta tags ```html ```
## Approach 3: Bulk generation at build time Generate all OG images during your build process: ```javascript // scripts/generate-og-images.js const posts = getAllPosts(); async function generateAllOgImages() { // Use bulk API for efficiency const response = await fetch('https://api.allscreenshots.com/v1/screenshots/bulk', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ urls: posts.map(post => ({ url: `https://yoursite.com/og/${post.slug}`, })), defaults: { viewport: { width: 1200, height: 630 }, format: 'png', }, webhookUrl: process.env.BUILD_WEBHOOK_URL, }), }); const { bulkJobId } = await response.json(); console.log(`Bulk job started: ${bulkJobId}`); } ``` ## Best practices ### Cache aggressively OG images rarely change—cache them for at least 24 hours: ```javascript // With CDN headers return new Response(image, { headers: { 'Content-Type': 'image/png', 'Cache-Control': 'public, max-age=86400, s-maxage=604800', }, }); ``` ### Invalidate on content updates When content changes, regenerate the OG image: ```javascript async function updatePost(slug, data) { await db.posts.update(slug, data); // Invalidate cached OG image await cache.delete(`og:${slug}`); // Optionally pre-generate new image await generateOgImage(slug); } ``` ### Test with social media debuggers Verify your images with platform tools: * [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/) * [Twitter Card Validator](https://cards-dev.twitter.com/validator) * [LinkedIn Post Inspector](https://www.linkedin.com/post-inspector/) Social platforms cache OG images aggressively. Use their debugger tools to force a refresh after updating images. ## Complete example: Next.js integration ```typescript // app/api/og/[slug]/route.ts import { NextRequest } from 'next/server'; export async function GET( request: NextRequest, { params }: { params: { slug: string } } ) { const { slug } = params; const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: `${process.env.NEXT_PUBLIC_URL}/og/${slug}`, viewport: { width: 1200, height: 630 }, format: 'png', waitUntil: 'networkidle', }), }); const image = await response.arrayBuffer(); return new Response(image, { headers: { 'Content-Type': 'image/png', 'Cache-Control': 'public, max-age=86400', }, }); } ``` # Visual regression testing (/docs/guides/visual-regression-testing) import { Callout } from 'fumadocs-ui/components/callout'; import { Steps, Step } from 'fumadocs-ui/components/steps'; # Visual regression testing Automatically detect unintended visual changes in your UI by comparing screenshots over time. ## What you'll build A visual testing system that: 1. Captures baseline screenshots of your pages 2. Compares new screenshots against baselines 3. Alerts you when visual differences are detected ## How it works ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Baseline │ │ New │ │ Compare │ │ Screenshot │ => │ Screenshot │ => │ & Report │ └─────────────┘ └─────────────┘ └─────────────┘ ``` ## Basic implementation ### Define pages to test ```javascript // visual-tests/pages.js export const pages = [ { name: 'homepage', url: '/' }, { name: 'pricing', url: '/pricing' }, { name: 'login', url: '/login' }, { name: 'dashboard', url: '/dashboard', auth: true }, { name: 'settings', url: '/settings', auth: true }, ]; export const viewports = [ { name: 'desktop', width: 1920, height: 1080 }, { name: 'tablet', width: 768, height: 1024 }, { name: 'mobile', width: 375, height: 667 }, ]; ``` ### Capture screenshots ```javascript // visual-tests/capture.js import { pages, viewports } from './pages.js'; const BASE_URL = process.env.TEST_URL || 'http://localhost:3000'; async function captureScreenshots() { const screenshots = []; for (const page of pages) { for (const viewport of viewports) { const response = await fetch('https://api.allscreenshots.com/v1/screenshots', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: `${BASE_URL}${page.url}`, viewport: { width: viewport.width, height: viewport.height }, format: 'png', waitUntil: 'networkidle', // Hide dynamic content that changes between runs hideSelectors: [ '[data-testid="timestamp"]', '[data-testid="random-content"]', ], }), }); const buffer = await response.arrayBuffer(); const filename = `${page.name}-${viewport.name}.png`; screenshots.push({ name: `${page.name}/${viewport.name}`, filename, buffer, }); } } return screenshots; } ``` ### Compare with baselines Use a library like `pixelmatch` or `looks-same` for comparison: ```javascript // visual-tests/compare.js import pixelmatch from 'pixelmatch'; import { PNG } from 'pngjs'; async function compareScreenshots(baseline, current) { const baselineImg = PNG.sync.read(baseline); const currentImg = PNG.sync.read(current); const { width, height } = baselineImg; const diff = new PNG({ width, height }); const mismatchedPixels = pixelmatch( baselineImg.data, currentImg.data, diff.data, width, height, { threshold: 0.1 } ); const totalPixels = width * height; const diffPercentage = (mismatchedPixels / totalPixels) * 100; return { passed: diffPercentage < 0.1, // Less than 0.1% difference diffPercentage, diffImage: PNG.sync.write(diff), }; } ``` ### Generate report ```javascript // visual-tests/report.js async function generateReport(results) { const passed = results.filter(r => r.passed); const failed = results.filter(r => !r.passed); console.log(`\nVisual Regression Test Results`); console.log(`==============================`); console.log(`Passed: ${passed.length}`); console.log(`Failed: ${failed.length}`); if (failed.length > 0) { console.log(`\nFailed tests:`); for (const result of failed) { console.log(` - ${result.name}: ${result.diffPercentage.toFixed(2)}% different`); } } // Save diff images for review for (const result of failed) { await fs.writeFile( `visual-tests/diffs/${result.name.replace('/', '-')}-diff.png`, result.diffImage ); } return failed.length === 0; } ``` ## Integration with CI/CD ### GitHub Actions ```yaml # .github/workflows/visual-tests.yml name: Visual Regression Tests on: pull_request: branches: [main] jobs: visual-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci - name: Start application run: npm run build && npm start & env: NODE_ENV: production - name: Wait for app to be ready run: npx wait-on http://localhost:3000 - name: Run visual tests run: npm run test:visual env: ALLSCREENSHOTS_API_KEY: ${{ secrets.ALLSCREENSHOTS_API_KEY }} TEST_URL: http://localhost:3000 - name: Upload diff images if: failure() uses: actions/upload-artifact@v4 with: name: visual-diffs path: visual-tests/diffs/ ``` ### Updating baselines When intentional changes are made, update the baseline images: ```bash # Update all baselines npm run test:visual:update # Update specific page npm run test:visual:update -- --page=homepage ``` ```javascript // visual-tests/update-baselines.js async function updateBaselines(filter) { const screenshots = await captureScreenshots(); for (const screenshot of screenshots) { if (filter && !screenshot.name.includes(filter)) { continue; } await fs.writeFile( `visual-tests/baselines/${screenshot.filename}`, Buffer.from(screenshot.buffer) ); console.log(`Updated baseline: ${screenshot.filename}`); } } ``` ## Advanced techniques ### Test different states Capture pages in different states: ```javascript const states = [ { name: 'empty', setup: () => clearData() }, { name: 'loading', setup: () => mockSlowResponse() }, { name: 'error', setup: () => mockErrorResponse() }, { name: 'populated', setup: () => seedTestData() }, ]; for (const state of states) { await state.setup(); await captureScreenshot(`${page.name}-${state.name}`); } ``` ### Test dark mode ```javascript const themes = [ { name: 'light', darkMode: false }, { name: 'dark', darkMode: true }, ]; for (const theme of themes) { const screenshot = await capture({ url: pageUrl, darkMode: theme.darkMode, }); } ``` ### Test responsive breakpoints ```javascript const breakpoints = [ { name: 'mobile-sm', width: 320 }, { name: 'mobile-md', width: 375 }, { name: 'mobile-lg', width: 425 }, { name: 'tablet', width: 768 }, { name: 'laptop', width: 1024 }, { name: 'desktop', width: 1440 }, { name: 'desktop-xl', width: 1920 }, ]; ``` ### Handle dynamic content Hide or stabilize dynamic content: ```javascript const screenshot = await capture({ url: pageUrl, hideSelectors: [ '.timestamp', '.random-avatar', '[data-dynamic]', ], customCss: ` /* Disable animations */ *, *::before, *::after { animation: none !important; transition: none !important; } /* Stabilize randomized content */ .random-element { background: #ccc !important; } `, }); ``` ## Best practices Visual tests work best when the environment is consistent. Use the same browser, viewport, and wait conditions for every run. ### Threshold tuning * Start with a low threshold (0.1%) and adjust based on false positives * Different pages may need different thresholds * Anti-aliasing can cause small differences—account for this ### Selective testing Don't test everything—focus on: * Critical user flows * Components with complex styling * Recently changed pages * Pages with historical visual bugs ### Test isolation * Use consistent test data * Mock external content (images, ads) * Disable analytics and third-party scripts * Use deterministic timestamps ```javascript const screenshot = await capture({ url: pageUrl, blockLevel: 'pro', // Block third-party content customCss: ` img[src*="external"] { visibility: hidden; } `, }); ``` # Website monitoring dashboard (/docs/guides/website-monitoring) import { Callout } from 'fumadocs-ui/components/callout'; import { Steps, Step } from 'fumadocs-ui/components/steps'; # Website monitoring dashboard Build a system that automatically captures screenshots of websites on a schedule and alerts you to changes. ## Use cases * **Competitor monitoring**: Track pricing pages, feature updates, and design changes * **Compliance**: Document website states for regulatory requirements * **Brand monitoring**: Ensure partner sites display your brand correctly * **Uptime visualization**: Visual proof of website availability ## Architecture ``` ┌──────────────┐ ┌─────────────────┐ ┌──────────────┐ │ Scheduled │ --> │ AllScreenshots │ --> │ Webhook │ │ Capture │ │ API │ │ Handler │ └──────────────┘ └─────────────────┘ └──────────────┘ │ v ┌──────────────┐ │ Database │ │ Storage │ └──────────────┘ │ v ┌──────────────┐ │ Dashboard │ │ UI │ └──────────────┘ ``` ## Implementation ### Set up scheduled captures Use the AllScreenshots scheduling API: ```javascript // Create schedules for websites to monitor const websites = [ { name: 'Competitor Pricing', url: 'https://competitor.com/pricing', schedule: '0 9 * * *', // Daily at 9 AM }, { name: 'Partner Homepage', url: 'https://partner.com', schedule: '0 */4 * * *', // Every 4 hours }, { name: 'Our Status Page', url: 'https://status.oursite.com', schedule: '*/15 * * * *', // Every 15 minutes }, ]; async function setupMonitoring() { for (const site of websites) { const response = await fetch('https://api.allscreenshots.com/v1/schedules', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ALLSCREENSHOTS_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ name: site.name, url: site.url, schedule: site.schedule, timezone: 'America/New_York', options: { viewport: { width: 1920, height: 1080 }, fullPage: true, blockAds: true, blockCookieBanners: true, }, webhookUrl: 'https://your-app.com/webhooks/screenshot', webhookSecret: process.env.WEBHOOK_SECRET, retentionDays: 90, }), }); const schedule = await response.json(); console.log(`Created schedule: ${schedule.scheduleId}`); } } ``` ### Handle webhook notifications ```javascript // Webhook handler app.post('/webhooks/screenshot', async (req, res) => { // Verify webhook signature const signature = req.headers['x-allscreenshots-signature']; if (!verifyWebhook(req.body, signature, process.env.WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); } const { scheduleId, captureId, result, timestamp } = req.body; // Store capture in database await db.captures.create({ scheduleId, captureId, screenshotUrl: result.url, capturedAt: timestamp, width: result.width, height: result.height, size: result.size, }); // Check for changes (optional) await detectChanges(scheduleId, captureId); res.sendStatus(200); }); ``` ### Detect visual changes Compare new captures with previous ones: ```javascript async function detectChanges(scheduleId, captureId) { // Get current and previous captures const [current, previous] = await db.captures.findMany({ where: { scheduleId }, orderBy: { capturedAt: 'desc' }, take: 2, }); if (!previous) return; // First capture, nothing to compare // Download both images const currentImage = await fetch(current.screenshotUrl).then(r => r.buffer()); const previousImage = await fetch(previous.screenshotUrl).then(r => r.buffer()); // Compare images const { diffPercentage, diffImage } = await compareImages(currentImage, previousImage); // If significant change detected, alert if (diffPercentage > 1) { await sendAlert({ scheduleId, captureId, diffPercentage, diffImage, currentUrl: current.screenshotUrl, previousUrl: previous.screenshotUrl, }); } } ``` ### Send alerts ```javascript async function sendAlert({ scheduleId, diffPercentage, currentUrl, previousUrl }) { const schedule = await db.schedules.findUnique({ where: { id: scheduleId } }); // Send Slack notification await fetch(process.env.SLACK_WEBHOOK_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: `Visual change detected on ${schedule.name}`, attachments: [ { color: 'warning', fields: [ { title: 'Website', value: schedule.url, short: true }, { title: 'Change', value: `${diffPercentage.toFixed(2)}%`, short: true }, ], image_url: currentUrl, }, ], }), }); // Or send email await sendEmail({ to: 'team@yourcompany.com', subject: `Visual change detected: ${schedule.name}`, html: `

Visual change detected

Website: ${schedule.url}

Change: ${diffPercentage.toFixed(2)}%

Current

Previous

`, }); } ```
### Build the dashboard Create a UI to view captures and history: ```jsx // Dashboard component function MonitoringDashboard() { const { data: schedules } = useQuery('schedules', fetchSchedules); return (
{schedules?.map(schedule => ( ))}
); } function WebsiteCard({ schedule }) { const { data: captures } = useQuery( ['captures', schedule.id], () => fetchCaptures(schedule.id) ); const latestCapture = captures?.[0]; return (

{schedule.name}

{schedule.url}

{latestCapture && ( <> {schedule.name}

Last captured: {formatDate(latestCapture.capturedAt)}

)}
); } ```
## Timeline view Show captures over time with a timeline: ```jsx function CaptureTimeline({ scheduleId }) { const { data: captures } = useQuery( ['captures', scheduleId], () => fetchCaptures(scheduleId, { limit: 30 }) ); return (
{captures?.map((capture, index) => (
{`Capture openFullScreen(capture)} />

{formatDate(capture.capturedAt)}

))}
); } ``` ## Side-by-side comparison ```jsx function CompareCaptures({ capture1, capture2 }) { const [sliderPosition, setSliderPosition] = useState(50); return (
{/* Before image (full width) */} {/* After image (clipped) */}
{/* Slider */} setSliderPosition(e.target.value)} className="absolute bottom-4 left-1/2 transform -translate-x-1/2" />
); } ``` ## Best practices Store screenshot URLs in your database, not the actual images. AllScreenshots handles storage and CDN delivery. ### Retention strategy * High-frequency monitors: Keep 7-30 days * Daily monitors: Keep 90 days * Compliance monitors: Keep as required (up to 365 days) ### Alert fatigue prevention * Set appropriate change thresholds (1-5%) * Group similar changes * Implement snooze functionality * Use digest emails for low-priority monitors ### Cost optimization * Use appropriate capture frequencies * Don't monitor pages that rarely change * Use viewport sizes appropriate for your needs * Consider thumbnail sizes for dashboard previews # .NET SDK (/docs/sdks/csharp) import { Callout } from 'fumadocs-ui/components/callout'; # .NET SDK The official .NET SDK for the AllScreenshots API. Requires .NET 8.0 or later. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-dotnet) | **Package:** [AllScreenshots.Sdk](https://www.nuget.org/packages/AllScreenshots.Sdk) ## Installation ```bash dotnet add package AllScreenshots.Sdk ``` Or via Package Manager Console: ```powershell Install-Package AllScreenshots.Sdk ``` ## Quick start ```csharp using AllScreenshots.Sdk; using AllScreenshots.Sdk.Models; // Create client (reads API key from ALLSCREENSHOTS_API_KEY environment variable) using var client = new AllScreenshotsClient(); // Take a screenshot var imageBytes = await client.Screenshots.CaptureAsync(new ScreenshotRequest { Url = "https://github.com", Device = "Desktop HD" }); // Save to file File.WriteAllBytes("screenshot.png", imageBytes); ``` ## Configuration ### Direct configuration ```csharp using var client = new AllScreenshotsClient(new AllScreenshotsOptions { ApiKey = "your-api-key", BaseUrl = "https://api.allscreenshots.com", Timeout = TimeSpan.FromSeconds(60), MaxRetries = 3 }); ``` ### Environment variables Set `ALLSCREENSHOTS_API_KEY` to automatically configure authentication: ```csharp // Client will read API key from environment using var client = new AllScreenshotsClient(); ``` ## Capture screenshots ### Basic capture ```csharp var imageBytes = await client.Screenshots.CaptureAsync(new ScreenshotRequest { Url = "https://example.com" }); File.WriteAllBytes("screenshot.png", imageBytes); ``` ### With options ```csharp var imageBytes = await client.Screenshots.CaptureAsync(new ScreenshotRequest { Url = "https://example.com", Device = "Desktop HD", Format = "png", FullPage = true, DarkMode = true, BlockAds = true, BlockCookieBanners = true, Delay = 1000 }); ``` ### Device presets ```csharp // Desktop var desktop = await client.Screenshots.CaptureAsync(new ScreenshotRequest { Url = "https://example.com", Device = "Desktop HD" }); // Mobile var mobile = await client.Screenshots.CaptureAsync(new ScreenshotRequest { Url = "https://example.com", Device = "iPhone 15" }); // Tablet var tablet = await client.Screenshots.CaptureAsync(new ScreenshotRequest { Url = "https://example.com", Device = "iPad Pro 11" }); ``` ## Async jobs For long-running captures: ```csharp // Create async job var job = await client.Screenshots.CaptureAsyncJobAsync(new ScreenshotRequest { Url = "https://example.com", FullPage = true }); Console.WriteLine($"Job ID: {job.JobId}"); // Poll for completion var status = await client.Jobs.GetAsync(job.JobId); if (status.Status == "completed") { var imageBytes = await client.Jobs.GetResultAsync(job.JobId); File.WriteAllBytes("screenshot.png", imageBytes); } ``` ## Bulk capture Process multiple URLs efficiently: ```csharp var bulkJob = await client.Bulk.CreateAsync(new BulkRequest { Urls = new[] { new BulkUrl { Url = "https://example1.com" }, new BulkUrl { Url = "https://example2.com" }, new BulkUrl { Url = "https://example3.com" } }, Defaults = new BulkDefaults { Device = "Desktop HD", Format = "png" } }); // Check status var status = await client.Bulk.GetAsync(bulkJob.BulkJobId); ``` ## Composition Combine multiple screenshots into a single image: ```csharp var composed = await client.Screenshots.ComposeAsync(new ComposeRequest { Url = "https://example.com", Variants = new[] { new Variant { Device = "Desktop HD", Label = "Desktop" }, new Variant { Device = "iPhone 15", Label = "Mobile" } }, Output = new OutputOptions { Layout = "horizontal", Spacing = 20 } }); ``` ## Schedules Create recurring screenshot captures: ```csharp // Create a schedule var schedule = await client.Schedules.CreateAsync(new CreateScheduleRequest { Name = "Daily Homepage", Url = "https://example.com", Schedule = "0 9 * * *", Timezone = "America/New_York" }); // List schedules var schedules = await client.Schedules.ListAsync(); // Get captures var captures = await client.Schedules.GetCapturesAsync(schedule.ScheduleId); ``` ## Usage tracking Monitor your API usage: ```csharp var usage = await client.Usage.GetAsync(); Console.WriteLine($"Screenshots: {usage.ScreenshotCount}/{usage.Quota}"); ``` ## ASP.NET Core integration ```csharp // Program.cs builder.Services.AddAllScreenshots(options => { options.ApiKey = builder.Configuration["AllScreenshots:ApiKey"]; }); // In your controller public class ScreenshotController : ControllerBase { private readonly IAllScreenshotsClient _client; public ScreenshotController(IAllScreenshotsClient client) { _client = client; } [HttpPost] public async Task Capture([FromBody] CaptureRequest request) { var imageBytes = await _client.Screenshots.CaptureAsync(new ScreenshotRequest { Url = request.Url }); return File(imageBytes, "image/png"); } } ``` ## Error handling ```csharp using AllScreenshots.Sdk.Exceptions; try { var imageBytes = await client.Screenshots.CaptureAsync(request); } catch (RateLimitException ex) { Console.WriteLine($"Rate limited. Retry after {ex.RetryAfter}s"); } catch (AuthenticationException) { Console.WriteLine("Invalid API key"); } catch (ValidationException ex) { Console.WriteLine($"Validation error: {ex.Message}"); } catch (AllScreenshotsException ex) { Console.WriteLine($"API error: {ex.Message}"); } ``` ## Requirements * .NET 8.0 or later ## License Apache License 2.0 # Go SDK (/docs/sdks/go) import { Callout } from 'fumadocs-ui/components/callout'; # Go SDK The official Go SDK for the AllScreenshots API with idiomatic Go patterns and context support. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-go) | **Package:** `github.com/allscreenshots/allscreenshots-sdk-go` ## Installation ```bash go get github.com/allscreenshots/allscreenshots-sdk-go ``` ## Quick start ```go package main import ( "context" "log" "os" "github.com/allscreenshots/allscreenshots-sdk-go/pkg/allscreenshots" ) func main() { client := allscreenshots.NewClient() imageData, err := client.Screenshot(context.Background(), &allscreenshots.ScreenshotRequest{ URL: "https://github.com", Device: "Desktop HD", }) if err != nil { log.Fatal(err) } os.WriteFile("screenshot.png", imageData, 0644) } ``` ## Configuration ### Functional options ```go client := allscreenshots.NewClient( allscreenshots.WithAPIKey("your-api-key"), allscreenshots.WithBaseURL("https://api.allscreenshots.com"), allscreenshots.WithTimeout(60*time.Second), allscreenshots.WithMaxRetries(3), allscreenshots.WithHTTPClient(customHTTPClient), ) ``` ### Environment variables Set `ALLSCREENSHOTS_API_KEY` to automatically configure authentication: ```go // Client will read API key from environment client := allscreenshots.NewClient() ``` ## Capture screenshots ### Basic capture ```go imageData, err := client.Screenshot(ctx, &allscreenshots.ScreenshotRequest{ URL: "https://example.com", }) if err != nil { log.Fatal(err) } os.WriteFile("screenshot.png", imageData, 0644) ``` ### With options ```go imageData, err := client.Screenshot(ctx, &allscreenshots.ScreenshotRequest{ URL: "https://example.com", Device: "Desktop HD", Format: "png", FullPage: true, DarkMode: true, BlockAds: true, BlockCookieBanners: true, Delay: 1000, }) ``` ### Device presets ```go // Desktop desktop, _ := client.Screenshot(ctx, &allscreenshots.ScreenshotRequest{ URL: "https://example.com", Device: "Desktop HD", }) // Mobile mobile, _ := client.Screenshot(ctx, &allscreenshots.ScreenshotRequest{ URL: "https://example.com", Device: "iPhone 15", }) // Tablet tablet, _ := client.Screenshot(ctx, &allscreenshots.ScreenshotRequest{ URL: "https://example.com", Device: "iPad Pro 11", }) ``` ## Async jobs For long-running captures: ```go // Create async job job, err := client.ScreenshotAsync(ctx, &allscreenshots.ScreenshotRequest{ URL: "https://example.com", FullPage: true, }) if err != nil { log.Fatal(err) } fmt.Printf("Job ID: %s\n", job.JobID) // Poll for completion result, err := client.GetJob(ctx, job.JobID) if err != nil { log.Fatal(err) } if result.Status == "completed" { imageData, _ := client.GetJobResult(ctx, job.JobID) os.WriteFile("screenshot.png", imageData, 0644) } ``` ## Bulk capture Process multiple URLs efficiently: ```go bulkJob, err := client.Bulk(ctx, &allscreenshots.BulkRequest{ URLs: []allscreenshots.BulkURL{ {URL: "https://example1.com"}, {URL: "https://example2.com"}, {URL: "https://example3.com"}, }, Defaults: &allscreenshots.BulkDefaults{ Device: "Desktop HD", Format: "png", }, }) // Check status status, _ := client.GetBulkJob(ctx, bulkJob.BulkJobID) ``` ## Composition Combine multiple screenshots into a single image: ```go composed, err := client.Compose(ctx, &allscreenshots.ComposeRequest{ URL: "https://example.com", Variants: []allscreenshots.Variant{ {Device: "Desktop HD", Label: "Desktop"}, {Device: "iPhone 15", Label: "Mobile"}, }, Output: &allscreenshots.OutputOptions{ Layout: "horizontal", Spacing: 20, }, }) ``` ## Schedules Create recurring screenshot captures: ```go // Create a schedule schedule, err := client.Schedules.Create(ctx, &allscreenshots.CreateScheduleRequest{ Name: "Daily Homepage", URL: "https://example.com", Schedule: "0 9 * * *", Timezone: "America/New_York", }) // List schedules schedules, _ := client.Schedules.List(ctx) // Get captures captures, _ := client.Schedules.GetCaptures(ctx, schedule.ScheduleID) ``` ## Usage tracking Monitor your API usage: ```go usage, err := client.Usage.Get(ctx) fmt.Printf("Screenshots: %d/%d\n", usage.ScreenshotCount, usage.Quota) ``` ## Error handling The SDK provides typed errors with helper functions: ```go imageData, err := client.Screenshot(ctx, request) if err != nil { if allscreenshots.IsRateLimited(err) { var rateLimitErr *allscreenshots.RateLimitError errors.As(err, &rateLimitErr) fmt.Printf("Rate limited. Retry after %d seconds\n", rateLimitErr.RetryAfter) return } if allscreenshots.IsUnauthorized(err) { fmt.Println("Invalid API key") return } if allscreenshots.IsValidationError(err) { fmt.Printf("Validation error: %s\n", err.Error()) return } if allscreenshots.IsServerError(err) { fmt.Printf("Server error: %s\n", err.Error()) return } log.Fatal(err) } ``` ## License Apache License 2.0 # SDKs overview (/docs/sdks) import { Cards, Card } from 'fumadocs-ui/components/card'; # SDKs Official client libraries make it easy to integrate AllScreenshots into your applications. Each SDK provides type-safe methods, automatic retries, and idiomatic patterns for your language. ## Available SDKs ## Quick comparison | Language | Package | Source | | ---------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------- | | TypeScript | [`allscreenshots`](https://www.npmjs.com/package/allscreenshots) | [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-typescript) | | JavaScript | [`allscreenshots`](https://www.npmjs.com/package/allscreenshots) | [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-typescript) | | Python | [`allscreenshots`](https://pypi.org/project/allscreenshots/) | [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-python) | | Go | `github.com/allscreenshots/allscreenshots-sdk-go` | [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-go) | | Java | `com.allscreenshots:allscreenshots-sdk` | [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-java) | | Kotlin | Uses Java SDK | [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-java) | | PHP | `allscreenshots/allscreenshots-sdk` | [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-php) | | .NET | `AllScreenshots` | [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-dotnet) | | Rust | `allscreenshots` | [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-rust) | | Swift | `allscreenshots-sdk-swift` | [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-swift) | ## Common features All SDKs provide: * **Type-safe requests** - Compile-time validation of parameters * **Automatic retries** - Handles transient failures with exponential backoff * **Rate limit handling** - Automatically waits and retries on 429 responses * **Streaming downloads** - Efficient handling of large screenshots * **Webhook verification** - Built-in signature validation helpers * **Async support** - Non-blocking operations where applicable ## Request an SDK Need an SDK for a language not listed? [Let us know](mailto:support@allscreenshots.com) and we'll prioritize based on demand. # Java SDK (/docs/sdks/java) import { Callout } from 'fumadocs-ui/components/callout'; # Java SDK The official Java SDK for the AllScreenshots API. Requires Java 17 or higher. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-java) | **Maven:** `com.allscreenshots.sdk:allscreenshots-sdk` ## Installation ### Maven ```xml com.allscreenshots.sdk allscreenshots-sdk 1.0.0 ``` ### Gradle (Kotlin DSL) ```kotlin dependencies { implementation("com.allscreenshots.sdk:allscreenshots-sdk:1.0.0") } ``` ### Gradle (Groovy) ```groovy dependencies { implementation 'com.allscreenshots.sdk:allscreenshots-sdk:1.0.0' } ``` ## Quick start ```java import com.allscreenshots.sdk.AllscreenshotsClient; import com.allscreenshots.sdk.models.ScreenshotRequest; import java.nio.file.Files; import java.nio.file.Path; public class Example { public static void main(String[] args) throws Exception { AllscreenshotsClient client = AllscreenshotsClient.builder().build(); byte[] image = client.screenshots().capture( ScreenshotRequest.builder() .url("https://example.com") .device("Desktop HD") .fullPage(true) .build() ); Files.write(Path.of("screenshot.png"), image); } } ``` ## Configuration ### Builder pattern ```java AllscreenshotsClient client = AllscreenshotsClient.builder() .apiKey("your-api-key") .baseUrl("https://api.allscreenshots.com") .timeout(Duration.ofSeconds(60)) .maxRetries(3) .build(); ``` ### Environment variables Set `ALLSCREENSHOTS_API_KEY` to automatically configure authentication: ```java // Client will read API key from environment AllscreenshotsClient client = AllscreenshotsClient.builder().build(); ``` ## Capture screenshots ### Basic capture ```java byte[] image = client.screenshots().capture( ScreenshotRequest.builder() .url("https://example.com") .build() ); Files.write(Path.of("screenshot.png"), image); ``` ### With options ```java byte[] image = client.screenshots().capture( ScreenshotRequest.builder() .url("https://example.com") .device("Desktop HD") .format("png") .fullPage(true) .darkMode(true) .blockAds(true) .blockCookieBanners(true) .delay(1000) .build() ); ``` ### Device presets ```java // Desktop byte[] desktop = client.screenshots().capture( ScreenshotRequest.builder() .url("https://example.com") .device("Desktop HD") .build() ); // Mobile byte[] mobile = client.screenshots().capture( ScreenshotRequest.builder() .url("https://example.com") .device("iPhone 15") .build() ); // Tablet byte[] tablet = client.screenshots().capture( ScreenshotRequest.builder() .url("https://example.com") .device("iPad Pro 11") .build() ); ``` ## Async jobs For long-running captures: ```java // Create async job Job job = client.screenshots().captureAsync( ScreenshotRequest.builder() .url("https://example.com") .fullPage(true) .build() ); System.out.println("Job ID: " + job.getJobId()); // Poll for completion JobStatus status = client.jobs().get(job.getJobId()); if ("completed".equals(status.getStatus())) { byte[] imageData = client.jobs().getResult(job.getJobId()); Files.write(Path.of("screenshot.png"), imageData); } ``` ## Bulk capture Process multiple URLs efficiently: ```java BulkJob bulkJob = client.bulk().create( BulkRequest.builder() .urls(List.of( BulkUrl.of("https://example1.com"), BulkUrl.of("https://example2.com"), BulkUrl.of("https://example3.com") )) .defaults(BulkDefaults.builder() .device("Desktop HD") .format("png") .build()) .build() ); // Check status BulkJobStatus status = client.bulk().get(bulkJob.getBulkJobId()); ``` ## Composition Combine multiple screenshots into a single image: ```java byte[] composed = client.screenshots().compose( ComposeRequest.builder() .url("https://example.com") .variants(List.of( Variant.builder().device("Desktop HD").label("Desktop").build(), Variant.builder().device("iPhone 15").label("Mobile").build() )) .output(OutputOptions.builder() .layout("horizontal") .spacing(20) .build()) .build() ); ``` ## Schedules Create recurring screenshot captures: ```java // Create a schedule Schedule schedule = client.schedules().create( CreateScheduleRequest.builder() .name("Daily Homepage") .url("https://example.com") .schedule("0 9 * * *") .timezone("America/New_York") .build() ); // List schedules List schedules = client.schedules().list(); // Get captures List captures = client.schedules().getCaptures(schedule.getScheduleId()); ``` ## Usage tracking Monitor your API usage: ```java Usage usage = client.usage().get(); System.out.printf("Screenshots: %d/%d%n", usage.getScreenshotCount(), usage.getQuota()); ``` ## Error handling ```java import com.allscreenshots.sdk.exceptions.*; try { byte[] image = client.screenshots().capture(request); } catch (RateLimitException e) { System.out.println("Rate limited. Retry after " + e.getRetryAfter() + "s"); } catch (AuthenticationException e) { System.out.println("Invalid API key"); } catch (ValidationException e) { System.out.println("Validation error: " + e.getMessage()); } catch (AllscreenshotsException e) { System.out.println("API error: " + e.getMessage()); } ``` ## Requirements * Java 17 or higher ## License Apache License 2.0 # JavaScript SDK (/docs/sdks/javascript) import { Callout } from 'fumadocs-ui/components/callout'; # JavaScript SDK The JavaScript SDK uses the same package as the [TypeScript SDK](/docs/sdks/typescript). For complete documentation, installation instructions, and examples, see the **[TypeScript SDK documentation](/docs/sdks/typescript)**. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-typescript) | **Package:** [@allscreenshots/sdk](https://www.npmjs.com/package/@allscreenshots/sdk) ## Installation ```bash npm install @allscreenshots/sdk ``` ## Quick start ```javascript import { AllscreenshotsClient } from '@allscreenshots/sdk'; import fs from 'fs'; const client = new AllscreenshotsClient(); const imageBuffer = await client.screenshot({ url: 'https://github.com', device: 'Desktop HD', fullPage: true }); fs.writeFileSync('screenshot.png', imageBuffer); ``` ## Full documentation For complete API documentation, configuration options, and advanced examples, see the [TypeScript SDK documentation](/docs/sdks/typescript). The SDK works identically in JavaScript and TypeScript projects - TypeScript users benefit from full type definitions and IntelliSense support. # Kotlin SDK (/docs/sdks/kotlin) import { Callout } from 'fumadocs-ui/components/callout'; # Kotlin SDK For Kotlin projects, use the [Java SDK](/docs/sdks/java). The Java SDK works seamlessly with Kotlin and provides full compatibility with Kotlin's language features. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-java) | **Maven:** `com.allscreenshots.sdk:allscreenshots-sdk` ## Installation ### Gradle (Kotlin DSL) ```kotlin dependencies { implementation("com.allscreenshots.sdk:allscreenshots-sdk:1.0.0") } ``` ### Gradle (Groovy) ```groovy dependencies { implementation 'com.allscreenshots.sdk:allscreenshots-sdk:1.0.0' } ``` ## Quick start ```kotlin import com.allscreenshots.sdk.AllscreenshotsClient import com.allscreenshots.sdk.models.ScreenshotRequest import java.io.File fun main() { val client = AllscreenshotsClient.builder().build() val image = client.screenshots().capture( ScreenshotRequest.builder() .url("https://example.com") .device("Desktop HD") .fullPage(true) .build() ) File("screenshot.png").writeBytes(image) } ``` ## Configuration ```kotlin val client = AllscreenshotsClient.builder() .apiKey("your-api-key") .baseUrl("https://api.allscreenshots.com") .timeout(Duration.ofSeconds(60)) .maxRetries(3) .build() ``` ## Capture with options ```kotlin val image = client.screenshots().capture( ScreenshotRequest.builder() .url("https://example.com") .device("Desktop HD") .format("png") .fullPage(true) .darkMode(true) .blockAds(true) .build() ) ``` ## Coroutines support For async operations with Kotlin coroutines, you can wrap the SDK calls: ```kotlin import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext suspend fun captureScreenshot(url: String): ByteArray = withContext(Dispatchers.IO) { client.screenshots().capture( ScreenshotRequest.builder() .url(url) .build() ) } ``` ## Full documentation For complete API documentation, configuration options, and advanced examples, see the [Java SDK documentation](/docs/sdks/java). # PHP SDK (/docs/sdks/php) import { Callout } from 'fumadocs-ui/components/callout'; # PHP SDK The official PHP SDK for the AllScreenshots API with PSR-compatible HTTP client support. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-php) | **Package:** [allscreenshots/sdk](https://packagist.org/packages/allscreenshots/sdk) ## Installation ```bash composer require allscreenshots/sdk ``` ## Quick start ```php build(); $request = new ScreenshotRequest('https://github.com'); $imageData = $client->screenshot($request); file_put_contents('screenshot.png', $imageData); ``` ## Configuration ### Builder pattern ```php $client = AllscreenshotsClient::builder() ->apiKey('your-api-key') ->baseUrl('https://api.allscreenshots.com') ->timeout(60) ->maxRetries(3) ->build(); ``` ### Environment variables Set `ALLSCREENSHOTS_API_KEY` to automatically configure authentication: ```php // Client will read API key from environment $client = AllscreenshotsClient::builder()->build(); ``` ## Capture screenshots ### Basic capture ```php $request = new ScreenshotRequest('https://example.com'); $imageData = $client->screenshot($request); file_put_contents('screenshot.png', $imageData); ``` ### With options ```php $request = new ScreenshotRequest('https://example.com'); $request->setDevice('Desktop HD'); $request->setFormat('png'); $request->setFullPage(true); $request->setDarkMode(true); $request->setBlockAds(true); $request->setBlockCookieBanners(true); $request->setDelay(1000); $imageData = $client->screenshot($request); ``` ### Device presets ```php // Desktop $request = new ScreenshotRequest('https://example.com'); $request->setDevice('Desktop HD'); $desktop = $client->screenshot($request); // Mobile $request = new ScreenshotRequest('https://example.com'); $request->setDevice('iPhone 15'); $mobile = $client->screenshot($request); // Tablet $request = new ScreenshotRequest('https://example.com'); $request->setDevice('iPad Pro 11'); $tablet = $client->screenshot($request); ``` ## Async jobs For long-running captures: ```php // Create async job $request = new ScreenshotRequest('https://example.com'); $request->setFullPage(true); $job = $client->screenshotAsync($request); echo "Job ID: " . $job->jobId . "\n"; // Poll for completion $status = $client->jobs()->get($job->jobId); if ($status->status === 'completed') { $imageData = $client->jobs()->getResult($job->jobId); file_put_contents('screenshot.png', $imageData); } ``` ## Bulk capture Process multiple URLs efficiently: ```php $bulkJob = $client->bulk()->create([ 'urls' => [ ['url' => 'https://example1.com'], ['url' => 'https://example2.com'], ['url' => 'https://example3.com'], ], 'defaults' => [ 'device' => 'Desktop HD', 'format' => 'png', ], ]); // Check status $status = $client->bulk()->get($bulkJob->bulkJobId); ``` ## Composition Combine multiple screenshots into a single image: ```php $composed = $client->compose([ 'url' => 'https://example.com', 'variants' => [ ['device' => 'Desktop HD', 'label' => 'Desktop'], ['device' => 'iPhone 15', 'label' => 'Mobile'], ], 'output' => [ 'layout' => 'grid', 'spacing' => 20, ], ]); ``` ## Schedules Create recurring screenshot captures: ```php // Create a schedule $schedule = $client->schedules()->create([ 'name' => 'Daily Homepage', 'url' => 'https://example.com', 'schedule' => '0 9 * * *', 'timezone' => 'America/New_York', ]); // List schedules $schedules = $client->schedules()->list(); // Get captures $captures = $client->schedules()->getCaptures($schedule->scheduleId); ``` ## Usage tracking Monitor your API usage: ```php $usage = $client->usage()->get(); echo "Screenshots: {$usage->screenshotCount}/{$usage->quota}\n"; ``` ## Laravel integration ```php // config/services.php 'allscreenshots' => [ 'api_key' => env('ALLSCREENSHOTS_API_KEY'), ], // app/Providers/AppServiceProvider.php use Allscreenshots\Sdk\Client\AllscreenshotsClient; public function register() { $this->app->singleton(AllscreenshotsClient::class, function () { return AllscreenshotsClient::builder() ->apiKey(config('services.allscreenshots.api_key')) ->build(); }); } // In your controller public function capture(Request $request, AllscreenshotsClient $client) { $screenshotRequest = new ScreenshotRequest($request->url); $imageData = $client->screenshot($screenshotRequest); return response($imageData)->header('Content-Type', 'image/png'); } ``` ## Error handling ```php use Allscreenshots\Sdk\Exceptions\AuthenticationException; use Allscreenshots\Sdk\Exceptions\ValidationException; use Allscreenshots\Sdk\Exceptions\RateLimitException; use Allscreenshots\Sdk\Exceptions\NotFoundException; use Allscreenshots\Sdk\Exceptions\ServerException; use Allscreenshots\Sdk\Exceptions\NetworkException; try { $imageData = $client->screenshot($request); } catch (RateLimitException $e) { echo "Rate limited. Retry after {$e->getRetryAfter()}s\n"; } catch (AuthenticationException $e) { echo "Invalid API key\n"; } catch (ValidationException $e) { echo "Validation error: {$e->getMessage()}\n"; } catch (ServerException $e) { echo "Server error: {$e->getMessage()}\n"; } ``` ## License Apache License 2.0 # Python SDK (/docs/sdks/python) import { Callout } from 'fumadocs-ui/components/callout'; # Python SDK The official Python SDK for the AllScreenshots API with synchronous and asynchronous client support. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-python) | **Package:** [allscreenshots-sdk](https://pypi.org/project/allscreenshots-sdk/) ## Installation ```bash pip install allscreenshots-sdk # or uv add allscreenshots-sdk ``` ## Quick start ```python from allscreenshots_sdk import AllscreenshotsClient client = AllscreenshotsClient.builder().build() image_bytes = client.screenshots.capture("https://example.com") with open("screenshot.png", "wb") as f: f.write(image_bytes) client.close() ``` ## Configuration ### Builder pattern ```python client = ( AllscreenshotsClient.builder() .with_api_key("your-api-key") .with_base_url("https://api.allscreenshots.com") .with_timeout(60) .with_max_retries(3) .build() ) ``` ### Environment variables Set `ALLSCREENSHOTS_API_KEY` to automatically configure authentication: ```python # Client will read API key from environment client = AllscreenshotsClient.builder().build() ``` ### Context manager ```python with AllscreenshotsClient.builder().with_api_key("your-api-key").build() as client: image = client.screenshots.capture("https://example.com", device="Desktop HD") with open("screenshot.png", "wb") as f: f.write(image) ``` ## Async client ```python import asyncio from allscreenshots_sdk import AllscreenshotsClient async def main(): async with AllscreenshotsClient.builder().with_api_key("your-api-key").build_async() as client: image = await client.screenshots.capture("https://example.com") with open("screenshot.png", "wb") as f: f.write(image) asyncio.run(main()) ``` ## Capture screenshots ### Basic capture ```python image_bytes = client.screenshots.capture("https://example.com") with open("screenshot.png", "wb") as f: f.write(image_bytes) ``` ### With options ```python image = client.screenshots.capture( "https://example.com", device="Desktop HD", format="png", full_page=True, dark_mode=True, block_ads=True, block_cookie_banners=True, delay=1000, ) ``` ### Device presets ```python # Desktop desktop = client.screenshots.capture("https://example.com", device="Desktop HD") # Mobile mobile = client.screenshots.capture("https://example.com", device="iPhone 15") # Tablet tablet = client.screenshots.capture("https://example.com", device="iPad Pro 11") ``` ## Async jobs For long-running captures: ```python # Create async job job = client.screenshots.capture_async("https://example.com", full_page=True) print(f"Job ID: {job.job_id}") # Poll for completion result = client.jobs.get(job.job_id) if result.status == "completed": image_data = client.jobs.get_result(job.job_id) with open("screenshot.png", "wb") as f: f.write(image_data) ``` ## Bulk capture Process multiple URLs efficiently: ```python bulk_job = client.bulk.create( urls=[ {"url": "https://example1.com"}, {"url": "https://example2.com"}, {"url": "https://example3.com"}, ], defaults={ "device": "Desktop HD", "format": "png", }, ) # Check status status = client.bulk.get(bulk_job.bulk_job_id) ``` ## Composition Combine multiple screenshots into a single image: ```python composed = client.screenshots.compose( url="https://example.com", variants=[ {"device": "Desktop HD", "label": "Desktop"}, {"device": "iPhone 15", "label": "Mobile"}, ], output={ "layout": "HORIZONTAL", "spacing": 20, }, ) ``` Available layouts: `GRID`, `HORIZONTAL`, `VERTICAL`, `MASONRY`, `MONDRIAN` ## Schedules Create recurring screenshot captures: ```python # Create a schedule schedule = client.schedules.create( name="Daily Homepage", url="https://example.com", schedule="0 9 * * *", timezone="America/New_York", ) # List schedules schedules = client.schedules.list() # Get captures captures = client.schedules.get_captures(schedule.schedule_id) ``` ## Usage tracking Monitor your API usage: ```python usage = client.usage.get() print(f"Screenshots: {usage.screenshot_count}/{usage.quota}") ``` ## Error handling ```python from allscreenshots_sdk import ( AllscreenshotsError, AuthenticationError, ValidationError, RateLimitError, NotFoundException, ServerError, ) try: screenshot = client.screenshots.capture("https://example.com") except RateLimitError as e: print(f"Rate limited. Retry after {e.retry_after}s") except AuthenticationError: print("Invalid API key") except ValidationError as e: print(f"Validation error: {e.message}") except AllscreenshotsError as e: print(f"API error: {e.message}") ``` ## License Apache License 2.0 # Ruby SDK (/docs/sdks/ruby) import { Callout } from 'fumadocs-ui/components/callout'; # Ruby SDK The Ruby SDK is coming soon. Sign up for updates at [allscreenshots.com](https://allscreenshots.com). ## Installation ```ruby # Gemfile gem 'allscreenshots' ``` ```bash bundle install ``` Or install directly: ```bash gem install allscreenshots ``` ## Quick start ```ruby require 'allscreenshots' client = AllScreenshots::Client.new(api_key: ENV['ALLSCREENSHOTS_API_KEY']) # Capture a screenshot screenshot = client.screenshots.capture(url: 'https://example.com') # Save to file File.binwrite('screenshot.png', screenshot) ``` ## Capture options ```ruby screenshot = client.screenshots.capture( url: 'https://example.com', viewport: { width: 1920, height: 1080 }, full_page: true, dark_mode: true, block_ads: true, block_cookie_banners: true ) # JSON response result = client.screenshots.capture( url: 'https://example.com', response_type: :json ) puts result.url ``` ## Device presets ```ruby screenshot = client.screenshots.capture( url: 'https://example.com', device: :iphone_15 ) ``` ## Bulk capture ```ruby bulk_job = client.screenshots.bulk( urls: [ { url: 'https://example1.com' }, { url: 'https://example2.com' }, { url: 'https://example3.com' } ], defaults: { format: :png, viewport: { width: 1280, height: 720 } } ) results = client.bulk.wait_for(bulk_job.bulk_job_id) ``` ## Composition ```ruby composed = client.screenshots.compose( url: 'https://example.com', variants: [ { device: :desktop_hd, label: 'Desktop' }, { device: :iphone_15, label: 'Mobile' } ], output: { layout: :horizontal, spacing: 20 } ) ``` ## Rails integration ```ruby # config/initializers/allscreenshots.rb AllScreenshots.configure do |config| config.api_key = Rails.application.credentials.allscreenshots_api_key end # In your controller or service class ScreenshotService def capture(url) AllScreenshots.client.screenshots.capture(url: url) end end ``` ## Webhook verification ```ruby # app/controllers/webhooks_controller.rb class WebhooksController < ApplicationController skip_before_action :verify_authenticity_token def allscreenshots signature = request.headers['X-Allscreenshots-Signature'] payload = request.raw_post unless AllScreenshots::Webhook.verify(payload, signature, webhook_secret) head :unauthorized return end event = JSON.parse(payload) # Process webhook... head :ok end private def webhook_secret Rails.application.credentials.allscreenshots_webhook_secret end end ``` ## Error handling ```ruby begin screenshot = client.screenshots.capture(url: 'https://example.com') rescue AllScreenshots::RateLimitError => e puts "Rate limited. Retry after #{e.retry_after}s" rescue AllScreenshots::APIError => e puts "API error: #{e.message}" end ``` ## Configuration ```ruby client = AllScreenshots::Client.new( api_key: 'your-api-key', base_url: 'https://api.allscreenshots.com', timeout: 60, max_retries: 3 ) ``` # Rust SDK (/docs/sdks/rust) import { Callout } from 'fumadocs-ui/components/callout'; # Rust SDK The official Rust SDK for the AllScreenshots API with async-first design using the tokio runtime. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-rust) | **Crate:** [allscreenshots-sdk](https://crates.io/crates/allscreenshots-sdk) ## Installation Add to your `Cargo.toml`: ```toml [dependencies] allscreenshots-sdk = "0.1" tokio = { version = "1", features = ["full"] } ``` ## Quick start ```rust use allscreenshots_sdk::{AllscreenshotsClient, ScreenshotRequest}; #[tokio::main] async fn main() -> Result<(), Box> { let client = AllscreenshotsClient::from_env()?; let request = ScreenshotRequest::builder() .url("https://github.com") .device("Desktop HD") .build()?; let image_bytes = client.screenshot(&request).await?; std::fs::write("screenshot.png", &image_bytes)?; println!("Screenshot saved to screenshot.png"); Ok(()) } ``` ## Configuration ### From environment ```rust // Reads API key from ALLSCREENSHOTS_API_KEY environment variable let client = AllscreenshotsClient::from_env()?; ``` ### Builder pattern ```rust use std::time::Duration; let client = AllscreenshotsClient::builder() .api_key("your-api-key") .base_url("https://api.allscreenshots.com") .timeout(Duration::from_secs(60)) .max_retries(3) .build()?; ``` ## Capture screenshots ### Basic capture ```rust let request = ScreenshotRequest::builder() .url("https://example.com") .build()?; let image_bytes = client.screenshot(&request).await?; std::fs::write("screenshot.png", &image_bytes)?; ``` ### With options ```rust let request = ScreenshotRequest::builder() .url("https://example.com") .device("Desktop HD") .format("png") .full_page(true) .dark_mode(true) .block_ads(true) .block_cookie_banners(true) .delay(1000) .build()?; let image_bytes = client.screenshot(&request).await?; ``` ### Device presets ```rust // Desktop let desktop = client.screenshot( &ScreenshotRequest::builder() .url("https://example.com") .device("Desktop HD") .build()? ).await?; // Mobile let mobile = client.screenshot( &ScreenshotRequest::builder() .url("https://example.com") .device("iPhone 15") .build()? ).await?; // Tablet let tablet = client.screenshot( &ScreenshotRequest::builder() .url("https://example.com") .device("iPad Pro 11") .build()? ).await?; ``` ## Async jobs For long-running captures: ```rust // Create async job let job = client.screenshot_async( &ScreenshotRequest::builder() .url("https://example.com") .full_page(true) .build()? ).await?; println!("Job ID: {}", job.job_id); // Poll for completion let status = client.get_job(&job.job_id).await?; if status.status == "completed" { let image_bytes = client.get_job_result(&job.job_id).await?; std::fs::write("screenshot.png", &image_bytes)?; } ``` ## Bulk capture Process multiple URLs efficiently: ```rust use allscreenshots_sdk::{BulkRequest, BulkUrl, BulkDefaults}; let bulk_job = client.bulk(&BulkRequest { urls: vec![ BulkUrl { url: "https://example1.com".to_string(), ..Default::default() }, BulkUrl { url: "https://example2.com".to_string(), ..Default::default() }, BulkUrl { url: "https://example3.com".to_string(), ..Default::default() }, ], defaults: Some(BulkDefaults { device: Some("Desktop HD".to_string()), format: Some("png".to_string()), ..Default::default() }), }).await?; // Check status let status = client.get_bulk_job(&bulk_job.bulk_job_id).await?; ``` ## Composition Combine multiple screenshots into a single image: ```rust use allscreenshots_sdk::{ComposeRequest, Variant, OutputOptions}; let composed = client.compose(&ComposeRequest { url: "https://example.com".to_string(), variants: vec![ Variant { device: "Desktop HD".to_string(), label: Some("Desktop".to_string()) }, Variant { device: "iPhone 15".to_string(), label: Some("Mobile".to_string()) }, ], output: Some(OutputOptions { layout: Some("horizontal".to_string()), spacing: Some(20), ..Default::default() }), }).await?; ``` ## Schedules Create recurring screenshot captures: ```rust use allscreenshots_sdk::CreateScheduleRequest; // Create a schedule let schedule = client.schedules().create(&CreateScheduleRequest { name: "Daily Homepage".to_string(), url: "https://example.com".to_string(), schedule: "0 9 * * *".to_string(), timezone: Some("America/New_York".to_string()), ..Default::default() }).await?; // List schedules let schedules = client.schedules().list().await?; // Get captures let captures = client.schedules().get_captures(&schedule.schedule_id).await?; ``` ## Usage tracking Monitor your API usage: ```rust let usage = client.usage().get().await?; println!("Screenshots: {}/{}", usage.screenshot_count, usage.quota); ``` ## Error handling The SDK provides typed errors for different scenarios: ```rust use allscreenshots_sdk::Error; match client.screenshot(&request).await { Ok(image_bytes) => { std::fs::write("screenshot.png", &image_bytes)?; } Err(Error::RateLimit { retry_after }) => { println!("Rate limited. Retry after {}s", retry_after); } Err(Error::Authentication(_)) => { println!("Invalid API key"); } Err(Error::Validation(msg)) => { println!("Validation error: {}", msg); } Err(Error::Timeout) => { println!("Request timed out"); } Err(e) => { println!("Error: {}", e); } } ``` ## Concurrent requests ```rust use futures::future::join_all; let urls = vec![ "https://example1.com", "https://example2.com", "https://example3.com", ]; let futures: Vec<_> = urls.iter().map(|url| { let client = client.clone(); async move { let request = ScreenshotRequest::builder() .url(*url) .build() .unwrap(); client.screenshot(&request).await } }).collect(); let results = join_all(futures).await; ``` ## License Apache License 2.0 # Swift SDK (/docs/sdks/swift) import { Callout } from 'fumadocs-ui/components/callout'; # Swift SDK The official Swift SDK for the AllScreenshots API with native async/await support. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-swift) | **Package:** `allscreenshots-sdk-swift` ## Requirements * Swift 5.9 or higher * iOS 15.0+ / macOS 12.0+ / tvOS 15.0+ / watchOS 8.0+ ## Installation Add to your `Package.swift`: ```swift dependencies: [ .package(url: "https://github.com/allscreenshots/allscreenshots-sdk-swift.git", from: "1.0.0") ] ``` Then add the dependency to your target: ```swift targets: [ .target( name: "YourTarget", dependencies: ["AllScreenshotsSDK"] ) ] ``` ## Quick start ```swift import AllScreenshotsSDK let client = try AllScreenshotsClient() let request = ScreenshotRequest( url: "https://example.com", device: "Desktop HD" ) let imageData = try await client.takeScreenshot(request) try imageData.write(to: URL(fileURLWithPath: "screenshot.png")) ``` ## Configuration ### From environment ```swift // Reads API key from ALLSCREENSHOTS_API_KEY environment variable let client = try AllScreenshotsClient() ``` ### Direct configuration ```swift let client = try AllScreenshotsClient( apiKey: "your-api-key", baseUrl: "https://api.allscreenshots.com", timeout: 60 ) ``` ## Capture screenshots ### Basic capture ```swift let request = ScreenshotRequest(url: "https://example.com") let imageData = try await client.takeScreenshot(request) ``` ### With options ```swift let request = ScreenshotRequest( url: "https://example.com", device: "Desktop HD", format: .png, fullPage: true, darkMode: true, blockAds: true, blockCookieBanners: true, delay: 1000 ) let imageData = try await client.takeScreenshot(request) ``` ### Device presets ```swift // Desktop let desktop = try await client.takeScreenshot( ScreenshotRequest(url: "https://example.com", device: "Desktop HD") ) // Mobile let mobile = try await client.takeScreenshot( ScreenshotRequest(url: "https://example.com", device: "iPhone 15") ) // Tablet let tablet = try await client.takeScreenshot( ScreenshotRequest(url: "https://example.com", device: "iPad Pro 11") ) ``` ## Async jobs For long-running captures: ```swift // Create async job let job = try await client.takeScreenshotAsync( ScreenshotRequest(url: "https://example.com", fullPage: true) ) print("Job ID: \(job.id)") // Poll for completion while true { let status = try await client.getJob(job.id) if status.status == .completed { let imageData = try await client.getJobResult(job.id) try imageData.write(to: URL(fileURLWithPath: "screenshot.png")) break } try await Task.sleep(nanoseconds: 1_000_000_000) // 1 second } ``` ## Bulk capture Process multiple URLs efficiently: ```swift let bulkJob = try await client.createBulkJob( urls: [ BulkUrl(url: "https://example1.com"), BulkUrl(url: "https://example2.com"), BulkUrl(url: "https://example3.com") ], defaults: BulkDefaults( device: "Desktop HD", format: .png ) ) // Check status let status = try await client.getBulkJob(bulkJob.bulkJobId) ``` ## Composition Combine multiple screenshots into a single image: ```swift let composed = try await client.compose( url: "https://example.com", variants: [ Variant(device: "Desktop HD", label: "Desktop"), Variant(device: "iPhone 15", label: "Mobile") ], output: OutputOptions(layout: .horizontal, spacing: 20) ) ``` ## Schedules Create recurring screenshot captures: ```swift // Create a schedule let schedule = try await client.createSchedule( name: "Daily Homepage", url: "https://example.com", schedule: "0 9 * * *", timezone: "America/New_York" ) // List schedules let schedules = try await client.listSchedules() // Get captures let captures = try await client.getScheduleCaptures(schedule.scheduleId) ``` ## Usage tracking Monitor your API usage: ```swift let usage = try await client.getUsage() print("Screenshots: \(usage.screenshotCount)/\(usage.quota)") ``` ## SwiftUI integration ```swift import SwiftUI import AllScreenshotsSDK struct ScreenshotView: View { @State private var image: UIImage? @State private var isLoading = false let client = try! AllScreenshotsClient() var body: some View { VStack { if let image = image { Image(uiImage: image) .resizable() .aspectRatio(contentMode: .fit) } else if isLoading { ProgressView() } Button("Take Screenshot") { Task { await captureScreenshot() } } } } func captureScreenshot() async { isLoading = true defer { isLoading = false } do { let request = ScreenshotRequest( url: "https://example.com", device: "iPhone 15" ) let data = try await client.takeScreenshot(request) image = UIImage(data: data) } catch { print("Error: \(error)") } } } ``` ## Error handling ```swift do { let imageData = try await client.takeScreenshot(request) } catch AllScreenshotsError.rateLimited(let retryAfter) { print("Rate limited. Retry after \(retryAfter)s") } catch AllScreenshotsError.authentication { print("Invalid API key") } catch AllScreenshotsError.validation(let message) { print("Validation error: \(message)") } catch AllScreenshotsError.timeout { print("Request timed out") } catch { print("Error: \(error)") } ``` ## Concurrent requests ```swift let urls = [ "https://example1.com", "https://example2.com", "https://example3.com" ] let screenshots = try await withThrowingTaskGroup(of: (String, Data).self) { group in for url in urls { group.addTask { let request = ScreenshotRequest(url: url) let data = try await client.takeScreenshot(request) return (url, data) } } var results: [(String, Data)] = [] for try await result in group { results.append(result) } return results } ``` ## License Apache License 2.0 # TypeScript SDK (/docs/sdks/typescript) import { Callout } from 'fumadocs-ui/components/callout'; # TypeScript SDK The official TypeScript SDK for the AllScreenshots API with full type definitions and IntelliSense support. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-sdk-typescript) | **Package:** [@allscreenshots/sdk](https://www.npmjs.com/package/@allscreenshots/sdk) ## Requirements * Node.js 18.0.0 or higher * TypeScript 5.0+ (for TypeScript projects) ## Installation ```bash npm install @allscreenshots/sdk # or pnpm add @allscreenshots/sdk # or yarn add @allscreenshots/sdk ``` ## Quick start ```typescript import { AllscreenshotsClient } from '@allscreenshots/sdk'; import fs from 'fs'; const client = new AllscreenshotsClient(); const imageBuffer = await client.screenshot({ url: 'https://github.com', device: 'Desktop HD', fullPage: true }); fs.writeFileSync('screenshot.png', imageBuffer); ``` ## Configuration The client can be configured using the builder pattern, direct configuration, or environment variables. ### Builder pattern ```typescript import { AllscreenshotsClient } from '@allscreenshots/sdk'; const client = AllscreenshotsClient.builder() .apiKey(process.env.ALLSCREENSHOTS_API_KEY!) .baseUrl('https://api.allscreenshots.com') .timeout(60000) .maxRetries(3) .build(); ``` ### Direct configuration ```typescript const client = new AllscreenshotsClient({ apiKey: process.env.ALLSCREENSHOTS_API_KEY!, baseUrl: 'https://api.allscreenshots.com', timeout: 60000, autoRetry: true, maxRetries: 3, }); ``` ### Environment variables Set `ALLSCREENSHOTS_API_KEY` to automatically configure authentication: ```typescript // Client will read API key from environment const client = new AllscreenshotsClient(); ``` ## Capture screenshots ### Basic capture ```typescript const screenshot = await client.screenshot({ url: 'https://example.com', }); fs.writeFileSync('screenshot.png', screenshot); ``` ### With options ```typescript const screenshot = await client.screenshot({ url: 'https://example.com', device: 'Desktop HD', format: 'png', quality: 90, fullPage: true, darkMode: true, blockAds: true, blockCookieBanners: true, delay: 1000, }); ``` ### Device presets ```typescript // Desktop const desktop = await client.screenshot({ url: 'https://example.com', device: 'Desktop HD', }); // Mobile const mobile = await client.screenshot({ url: 'https://example.com', device: 'iPhone 15', }); // Tablet const tablet = await client.screenshot({ url: 'https://example.com', device: 'iPad Pro 11', }); ``` ## Async jobs For long-running captures, use async jobs: ```typescript // Create async job const job = await client.screenshotAsync({ url: 'https://example.com', fullPage: true, }); console.log(`Job ID: ${job.jobId}`); // Poll for completion const result = await client.getJob(job.jobId); if (result.status === 'completed') { const imageData = await client.getJobResult(job.jobId); fs.writeFileSync('screenshot.png', imageData); } ``` ## Bulk capture Process multiple URLs efficiently: ```typescript const bulkJob = await client.bulk({ urls: [ { url: 'https://example1.com' }, { url: 'https://example2.com' }, { url: 'https://example3.com' }, ], defaults: { device: 'Desktop HD', format: 'png', }, }); // Check status const status = await client.getBulkJob(bulkJob.bulkJobId); ``` ## Composition Combine multiple screenshots into a single image: ```typescript const composed = await client.compose({ url: 'https://example.com', variants: [ { device: 'Desktop HD', label: 'Desktop' }, { device: 'iPhone 15', label: 'Mobile' }, ], output: { layout: 'horizontal', spacing: 20, }, }); ``` ## Schedules Create recurring screenshot captures: ```typescript // Create a schedule const schedule = await client.schedules.create({ name: 'Daily Homepage', url: 'https://example.com', schedule: '0 9 * * *', timezone: 'America/New_York', }); // List schedules const schedules = await client.schedules.list(); // Get captures const captures = await client.schedules.getCaptures(schedule.scheduleId); ``` ## Usage tracking Monitor your API usage: ```typescript const usage = await client.usage.get(); console.log(`Screenshots: ${usage.screenshotCount}/${usage.quota}`); ``` ## Error handling The SDK provides typed error classes for granular exception handling: ```typescript import { AllscreenshotsError, AuthenticationError, ValidationError, RateLimitError, QuotaExceededError, ServerError, NetworkError, TimeoutError } from '@allscreenshots/sdk'; try { const screenshot = await client.screenshot({ url: 'https://example.com', }); } catch (error) { if (error instanceof RateLimitError) { console.log(`Rate limited. Retry after ${error.retryAfter}s`); } else if (error instanceof QuotaExceededError) { console.log('Quota exceeded for this billing period'); } else if (error instanceof AuthenticationError) { console.log('Invalid API key'); } else if (error instanceof ValidationError) { console.log(`Validation error: ${error.message}`); } else if (error instanceof AllscreenshotsError) { console.log(`API error: ${error.message}`); } } ``` ## Type definitions ### ScreenshotOptions ```typescript interface ScreenshotOptions { url: string; viewport?: { width?: number; // 100-4096, default: 1920 height?: number; // 100-4096, default: 1080 deviceScaleFactor?: number; // 1-3, default: 1 }; device?: DevicePreset; format?: 'png' | 'jpeg' | 'webp' | 'pdf'; quality?: number; // 1-100 fullPage?: boolean; selector?: string; delay?: number; // 0-30000 waitFor?: string; waitUntil?: 'load' | 'domcontentloaded' | 'networkidle'; timeout?: number; // 1000-60000 darkMode?: boolean; customCss?: string; hideSelectors?: string[]; blockAds?: boolean; blockCookieBanners?: boolean; } ``` ### DevicePreset ```typescript type DevicePreset = // Desktop | 'Desktop HD' | 'Desktop Large' | 'Laptop' // iPhone | 'iPhone SE' | 'iPhone 12' | 'iPhone 14' | 'iPhone 15' | 'iPhone 15 Pro Max' // iPad | 'iPad' | 'iPad Mini' | 'iPad Pro 11' | 'iPad Pro 12.9' // Android | 'Pixel 7' | 'Samsung Galaxy S23' // Social | 'Facebook OG' | 'Twitter Card' | 'LinkedIn Post'; ``` ## License Apache License 2.0 # CLI (/docs/tools/cli) import { Callout } from 'fumadocs-ui/components/callout'; import { Steps, Step } from 'fumadocs-ui/components/steps'; import { Tabs, Tab } from 'fumadocs-ui/components/tabs'; # Command line interface Capture website screenshots directly from your terminal. Perfect for automation, shell scripts, and quick captures. **Source code:** [GitHub](https://github.com/allscreenshots/allscreenshots-cli) | **Homebrew:** `brew install allscreenshots/allscreenshots/allscreenshots` ## Installation ```bash brew tap allscreenshots/allscreenshots brew install allscreenshots ``` ```bash cargo install allscreenshots-cli ``` ```bash git clone https://github.com/allscreenshots/allscreenshots-cli cd allscreenshots-cli cargo build --release ``` ## Quick start ### Set up authentication Get your API key from the [dashboard](https://dashboard.allscreenshots.com/api-keys), then store it for future use: ```bash allscreenshots config add-authtoken YOUR_API_KEY ``` Or set it as an environment variable: ```bash export ALLSCREENSHOTS_API_KEY=YOUR_API_KEY ``` ### Capture your first screenshot ```bash allscreenshots https://github.com ``` This captures the URL and displays the screenshot directly in your terminal (if your terminal supports images). ### Save to a file ```bash allscreenshots https://github.com -o github.png ``` ## Basic usage ### Quick capture (displays in terminal) ```bash allscreenshots https://example.com ``` ### Save to file ```bash allscreenshots https://example.com -o screenshot.png ``` ### Mobile screenshot ```bash allscreenshots https://example.com --device "iPhone 14" ``` ### Full page capture ```bash allscreenshots https://example.com --full-page -o fullpage.png ``` ## Commands ### capture Take a synchronous screenshot (default command): ```bash allscreenshots capture https://example.com [OPTIONS] ``` Options: * `-o, --output ` - Save to file * `-d, --device ` - Device preset (e.g., "Desktop HD", "iPhone 14") * `--full-page` - Capture full scrollable page * `--format ` - Output format: png, jpeg, webp, pdf * `--display` - Show in terminal * `--no-display` - Don't show in terminal ### async Async capture with job tracking: ```bash allscreenshots async https://example.com --wait ``` Options: * `--wait` - Wait for completion and download result * `--poll-interval ` - Polling interval (default: 2) ### batch Capture multiple URLs: ```bash # From arguments allscreenshots batch https://site1.com https://site2.com -o ./screenshots/ # From file allscreenshots batch -f urls.txt -o ./screenshots/ ``` Options: * `-f, --file ` - Read URLs from file (one per line) * `-o, --output-dir ` - Output directory (default: ./screenshots) * `--device ` - Device preset for all captures * `--format ` - Output format ### compose Combine multiple screenshots into one image: ```bash allscreenshots compose https://example.com \ --devices "Desktop HD" "iPhone 14" "iPad Pro" \ --layout horizontal \ -o comparison.png ``` Options: * `--devices ` - Device presets to capture * `--layout ` - Layout: horizontal, vertical, grid * `--spacing ` - Spacing between images * `--labels` - Add device labels ### gallery Browse screenshots with thumbnails: ```bash # Show recent API jobs allscreenshots gallery # Show local directory allscreenshots gallery --dir ./screenshots/ ``` Options: * `--dir ` - Local directory to browse * `--limit ` - Max images to show (default: 10) * `--size ` - Thumbnail size: small, medium ### usage Show API usage and quota: ```bash allscreenshots usage ``` Displays a visual graph of your current usage against your plan limits. ### schedule Manage scheduled screenshots: ```bash # List schedules allscreenshots schedule list # Create a schedule allscreenshots schedule create \ --name "Daily homepage" \ --url https://example.com \ --cron "0 9 * * *" \ --timezone "America/New_York" # View history allscreenshots schedule history ``` Subcommands: `list`, `create`, `get`, `update`, `delete`, `pause`, `resume`, `trigger`, `history` ### jobs Manage screenshot jobs: ```bash # List recent jobs allscreenshots jobs list # Get job status allscreenshots jobs get # Download result allscreenshots jobs result -o screenshot.png ``` ### config Manage authentication and settings: ```bash # Store API key allscreenshots config add-authtoken YOUR_API_KEY # Show config allscreenshots config show # Show config file path allscreenshots config path # Remove stored key allscreenshots config remove-authtoken ``` ### devices Show available device presets: ```bash allscreenshots devices ``` ### completions Generate shell completions: ```bash # Bash allscreenshots completions bash > ~/.local/share/bash-completion/completions/allscreenshots # Zsh allscreenshots completions zsh > ~/.zfunc/_allscreenshots # Fish allscreenshots completions fish > ~/.config/fish/completions/allscreenshots.fish ``` ## Global options These options work with any command: | Option | Description | | ----------------------- | ---------------------------------- | | `-k, --api-key ` | API key (overrides env and config) | | `-o, --output ` | Output file path | | `-d, --device ` | Device preset | | `--full-page` | Capture full page | | `--display` | Show in terminal | | `--no-display` | Don't show in terminal | | `--json` | Output as JSON | | `-v, --verbose` | Verbose output | | `--no-color` | Disable colors | ## Device presets Common device presets: **Desktop:** * `Desktop HD` (1920x1080) * `Desktop 4K` (3840x2160) * `Laptop` (1366x768) **Mobile:** * `iPhone 14` (390x844) * `iPhone 14 Pro Max` (430x932) * `iPhone SE` (375x667) * `Android` (360x800) **Tablet:** * `iPad Pro 12.9` (1024x1366) * `iPad Pro 11` (834x1194) * `iPad Air` (820x1180) Run `allscreenshots devices` for the complete list. ## Examples ### CI/CD integration Capture screenshots as part of your build: ```bash #!/bin/bash allscreenshots batch \ -f ./test-urls.txt \ -o ./screenshots/ \ --device "Desktop HD" \ --format png ``` ### Watch mode for development Re-capture at intervals: ```bash allscreenshots watch http://localhost:3000 --interval 5 ``` ### Batch with different devices ```bash for device in "Desktop HD" "iPhone 14" "iPad Pro"; do allscreenshots https://example.com \ --device "$device" \ -o "screenshot-${device// /-}.png" done ``` ### Combine with other tools ```bash # Capture and upload to S3 allscreenshots https://example.com -o - | aws s3 cp - s3://bucket/screenshot.png # Capture and optimize allscreenshots https://example.com -o screenshot.png && optipng screenshot.png ``` ## Terminal image support The CLI can display screenshots directly in your terminal if it supports: * **Kitty graphics protocol** - Kitty, WezTerm * **iTerm2 inline images** - iTerm2, Hyper * **Sixel graphics** - xterm, mlterm, foot For unsupported terminals, the image is rendered using Unicode block characters. ## Configuration file The CLI stores settings in: * **macOS:** `~/Library/Application Support/com.allscreenshots.cli/config.toml` * **Linux:** `~/.config/allscreenshots/config.toml` Example config: ```toml [auth] api_key = "as_live_xxxx" [defaults] device = "Desktop HD" format = "png" output_dir = "./screenshots" ``` # Figma Plugin (/docs/tools/figma) import { Callout } from 'fumadocs-ui/components/callout'; import { Steps, Step } from 'fumadocs-ui/components/steps'; # Figma plugin Capture website screenshots directly into your Figma designs. Perfect for creating mockups, responsive design presentations, and visual documentation without leaving Figma. **Install:** [Figma Community](https://www.figma.com/community/plugin/1588979915457270548/allscreenshots) ## Installation ### Open Figma Open any Figma design file where you want to use the plugin. ### Install from Figma Community Go to **Resources** (Shift+I) → **Plugins** → Search for "AllScreenshots" → Click **Run** or **Save** to install. Alternatively, visit the [Figma Community page](https://www.figma.com/community/plugin/1588979915457270548/allscreenshots) and click **Open in Figma**. ### Run the plugin Right-click on the canvas → **Plugins** → **AllScreenshots**, or use the Resources panel to run it. ## Quick start ### Set up your API key Get your API key from the [dashboard](https://dashboard.allscreenshots.com/api-keys). Click the settings icon (gear) in the plugin and paste your API key. The free tier includes 100 screenshots per month. Your API key is stored securely in Figma's local storage. ### Enter a URL Type or paste any website URL in the input field. Press Enter or click the Capture button. ### Screenshot inserted The screenshot is automatically inserted onto your canvas as an image fill. The viewport centers on the new image and selects it for immediate use. ## Features ### Device presets Choose from 50+ device presets across desktop, mobile, and tablet categories. Select a category tab, then pick a specific device from the dropdown. ### Main options | Option | Description | | ---------------- | --------------------------------------------------------------- | | **Block Ads** | Remove advertisements from the captured page | | **Hide Cookies** | Remove cookie consent banners and GDPR popups | | **Full Page** | Capture the entire scrollable page instead of just the viewport | | **Dark Mode** | Render the website in dark color scheme (if supported) | ### Custom dimensions Select the **Custom** tab to specify exact pixel dimensions. Width and height can range from 100 to 4096 pixels. ## Device presets ### Desktop | Device | Resolution | | ------------- | ----------- | | Desktop HD | 1920 x 1080 | | Desktop Large | 2560 x 1440 | | Laptop | 1440 x 900 | | Laptop Small | 1280 x 800 | ### Mobile | Device | Resolution | | ------------------ | ---------- | | iPhone 15 Pro Max | 430 x 932 | | iPhone 15 Pro | 393 x 852 | | iPhone 15 | 393 x 852 | | iPhone 14 Pro Max | 430 x 932 | | iPhone 14 | 390 x 844 | | iPhone SE | 375 x 667 | | Pixel 7 Pro | 412 x 892 | | Pixel 7 | 412 x 732 | | Samsung Galaxy S23 | 360 x 780 | | Samsung Galaxy S21 | 360 x 800 | ### Tablet | Device | Resolution | | -------------- | ----------- | | iPad Pro 12.9" | 1024 x 1366 | | iPad Pro 11" | 834 x 1194 | | iPad Air | 820 x 1180 | | iPad | 810 x 1080 | | iPad Mini | 768 x 1024 | | Surface Pro 7 | 912 x 1368 | | Galaxy Tab S7 | 800 x 1280 | ## Advanced options Click **Advanced options** to expand additional settings: | Option | Description | | ------------------ | --------------------------------------------------------------------------------------------------------- | | **Format** | Output format: PNG (default), JPEG, or WebP | | **Quality** | Quality level for JPEG/WebP (1-100%). Higher values produce larger files with better quality. | | **Delay** | Wait time in seconds (0-30) before capturing. Useful for pages with animations or lazy-loaded content. | | **Selector** | CSS selector to capture a specific element instead of the full viewport (e.g., `#hero`, `.product-card`). | | **Custom CSS** | Inject custom CSS before capture. Useful for hiding elements or adjusting styles. | | **Hide selectors** | Comma-separated CSS selectors for elements to hide (e.g., `.popup, #banner, .chat-widget`). | ### Examples **Capture after animations complete:** * Set **Delay** to 2-3 seconds **Capture specific element:** * Set **Selector** to `.hero-section` or `#main-content` **Hide distracting elements:** * Set **Hide selectors** to `.newsletter-popup, .chat-widget, #sticky-footer` **Custom styling:** ```css /* Hide navigation and increase contrast */ nav { display: none !important; } body { background: #fff !important; } ``` ## Large image handling Figma has a maximum image dimension of 4096 x 4096 pixels. When capturing full-page screenshots that exceed this limit, the plugin automatically: 1. Detects oversized images 2. Splits them into a grid of smaller chunks 3. Creates separate image rectangles for each chunk 4. Groups all chunks together for easy manipulation This allows you to capture extremely long pages while maintaining full resolution. The chunks are precisely positioned so the complete image appears seamless. ## Settings and usage Click the **settings icon** (gear) in the top-right corner to: * Enter or update your API key * View your current usage and remaining quota * See your plan tier (FREE, PRO, etc.) * Check when your monthly quota resets ## Use cases ### Design mockups Quickly insert real website screenshots into your design mockups. Capture competitor sites, reference designs, or your own staging environment. ### Responsive design documentation Use different device presets to capture the same URL across desktop, tablet, and mobile. Compare layouts side-by-side in your Figma file. ### Client presentations Create presentation decks with actual website captures. Use full-page captures to show entire landing pages or specific sections. ### Visual QA Capture staging or production sites to document bugs, review implementations, or create before/after comparisons. ### Content placeholders Replace placeholder images with real website captures during the design process. Update them as the actual site evolves. ## Troubleshooting ### Invalid API key Ensure your API key is correct and active. Get a new key from the [dashboard](https://dashboard.allscreenshots.com/api-keys). ### Quota exceeded Your monthly screenshot limit has been reached. Upgrade your plan or wait for the next billing period. ### Screenshot timeout Some complex pages may take longer to render. Try increasing the **Delay** setting or capturing a specific element with **Selector**. ### Image not appearing Check that you have an active Figma file open with edit permissions. The screenshot is inserted at the center of your current viewport. # MkDocs plugin (/docs/tools/mkdocs) import { Callout } from 'fumadocs-ui/components/callout'; import { Steps, Step } from 'fumadocs-ui/components/steps'; # MkDocs plugin Automatically generate dynamic OpenGraph images for every page in your MkDocs documentation. When someone shares a link to your docs, they see a live screenshot of that page. **Install:** `pip install mkdocs-allscreenshots-og-screenshot` ## Installation ### Install the plugin ```bash pip install mkdocs-allscreenshots-og-screenshot ``` Requires Python 3.8 or higher. ### Add to mkdocs.yml ```yaml site_url: https://yourdomain.com plugins: - search - allscreenshots-og-screenshot ``` ### Verify your domain Go to the [Social images page](/dashboard/domains) in your dashboard and verify your documentation domain. That's it. Every page in your documentation now has a unique OG image. ## How it works The plugin adds an `og:image` meta tag to each page: ```html ``` When someone shares a link on social media: 1. The platform requests the OG image URL 2. Allscreenshots captures a screenshot of that page 3. The screenshot is cached for fast subsequent requests 4. Cache hits are free and don't count toward your quota ## Configuration | Option | Default | Description | | --------------------- | ------------------------------- | ------------------------------------------- | | `screenshot_base_url` | `https://og.allscreenshots.com` | Screenshot API endpoint | | `site_url` | MkDocs `site_url` | Override the site URL used in OG image URLs | ### Custom configuration ```yaml plugins: - allscreenshots-og-screenshot: screenshot_base_url: https://og.allscreenshots.com site_url: https://docs.example.com ``` ## Requirements * Python 3.8+ * MkDocs * A verified domain in your [Allscreenshots dashboard](/dashboard/domains) ## Example Given this MkDocs structure: ``` docs/ ├── index.md ├── getting-started.md └── api/ └── reference.md ``` The plugin generates these OG images: | Page | OG Image URL | | ------------------- | --------------------------------------------------------------------------- | | `/` | `https://og.allscreenshots.com?url=https://yourdomain.com/` | | `/getting-started/` | `https://og.allscreenshots.com?url=https://yourdomain.com/getting-started/` | | `/api/reference/` | `https://og.allscreenshots.com?url=https://yourdomain.com/api/reference/` | ## Troubleshooting ### Images not generating Ensure your domain is verified in the [dashboard](/dashboard/domains). Unverified domains will receive an error response. ### Wrong site URL If your OG images point to the wrong URL, set the `site_url` option explicitly: ```yaml plugins: - allscreenshots-og-screenshot: site_url: https://docs.example.com ``` ### Local development OG images only work for publicly accessible URLs. During local development, the images will show an error. This is expected—the images will work once deployed. ## Source code The plugin is open source and available on [PyPI](https://pypi.org/project/mkdocs-allscreenshots-og-screenshot/). ```bash # Install for development pip install -e . ``` MIT License. # CI/CD workflows (/docs/use-cases/ci-cd-workflows) import { Cards, Card } from 'fumadocs-ui/components/card'; import { Callout } from 'fumadocs-ui/components/callout'; Integrate automated screenshot capture into your continuous integration and deployment pipelines for visual testing, documentation, and quality assurance. ## The problem Manual screenshot capture doesn't scale. Every time you deploy, someone needs to manually verify that pages render correctly. This leads to: * Inconsistent testing coverage * Delayed releases waiting for manual QA * Visual bugs slipping through to production * No historical record of how pages looked at each release ## How Allscreenshots helps Add screenshot capture to any CI/CD pipeline with a simple API call. Capture screenshots on every commit, pull request, or deployment without managing browser infrastructure. * **Zero infrastructure** — No need to install browsers or manage Playwright/Puppeteer * **Parallel execution** — Capture hundreds of pages simultaneously * **Consistent results** — Same rendering environment every time * **Async processing** — Don't block your pipeline waiting for screenshots Use async jobs for large batches to avoid blocking your CI pipeline. Poll for completion or use webhooks to get notified. ## Quick example Add screenshot capture to a GitHub Actions workflow: ```yaml # .github/workflows/screenshots.yml name: Capture Screenshots on: pull_request: branches: [main] jobs: screenshots: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Start app run: npm ci && npm run build && npm start & - name: Wait for app run: npx wait-on http://localhost:3000 - name: Capture screenshots run: | curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer ${{ secrets.ALLSCREENSHOTS_API_KEY }}" \ -H "Content-Type: application/json" \ -d '{"url": "http://localhost:3000", "fullPage": true}' \ -o screenshot.png - name: Upload artifact uses: actions/upload-artifact@v4 with: name: screenshots path: screenshot.png ``` ## Key features for this use case ## Next steps * [CI/CD integration guide](/docs/guides/cicd-integration) — Detailed examples for GitHub Actions, GitLab CI, Jenkins, and more * [Visual regression testing](/docs/use-cases/visual-regression-testing) — Compare screenshots to catch visual bugs * [Async jobs API](/docs/api-reference/async-jobs) — Non-blocking screenshot capture # Compliance and auditing (/docs/use-cases/compliance-auditing) import { Cards, Card } from 'fumadocs-ui/components/card'; import { Callout } from 'fumadocs-ui/components/callout'; Capture verifiable, time-stamped screenshots of web content for compliance documentation, regulatory audits, and organizational records. ## The problem Many industries require proof of what was displayed on websites at specific points in time: * **Financial services** — Document disclosures, terms, and pricing as shown to customers * **Healthcare** — Archive patient-facing content for HIPAA compliance * **E-commerce** — Preserve records of pricing, promotions, and product descriptions * **Legal** — Capture terms of service, privacy policies, and consent forms Manual screenshots aren't reliable. They lack timestamps, can be edited, and don't scale across hundreds of pages. ## How Allscreenshots helps Automatically capture time-stamped screenshots that serve as reliable evidence of web content at specific moments in time. * **Metadata capture** — Timestamps, URLs, and capture parameters recorded * **Scheduled archiving** — Automate compliance captures on a regular basis * **Full page capture** — Document entire pages including below-the-fold content * **Bulk processing** — Archive hundreds of pages in a single operation Store screenshots in your own S3-compatible storage for complete control over retention and chain of custody. ## Quick example Capture a terms of service page with full metadata: ```bash curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://yoursite.com/terms-of-service", "fullPage": true, "format": "png", "waitUntil": "networkidle", "metadata": { "purpose": "compliance-archive", "documentType": "terms-of-service", "version": "2.1" } }' ``` The response includes capture timestamp and all parameters used: ```json { "url": "https://yoursite.com/terms-of-service", "capturedAt": "2024-01-15T14:30:00Z", "imageUrl": "https://...", "metadata": { "purpose": "compliance-archive", "documentType": "terms-of-service", "version": "2.1" } } ``` ## Key features for this use case ## Next steps * [PDF generation](/docs/guides/pdf-generation) — Create PDF archives of web content * [Schedules API](/docs/api-reference/schedules) — Set up automated compliance captures * [Content archiving](/docs/use-cases/content-archiving) — Long-term web content preservation # Content archiving (/docs/use-cases/content-archiving) import { Cards, Card } from 'fumadocs-ui/components/card'; import { Callout } from 'fumadocs-ui/components/callout'; Archive web content by capturing screenshots for long-term preservation, research, or organizational record-keeping. ## The problem Web content is ephemeral. Pages get updated, redesigned, or taken offline entirely. For researchers, historians, and organizations, losing access to web content can mean: * Lost research data and citations * Missing historical records * Broken references in documentation * No proof of what was published The Internet Archive helps, but it doesn't capture everything, and you can't control the timing or coverage. ## How Allscreenshots helps Build your own web archive by capturing screenshots on demand or on a schedule. Preserve exactly the content you need, when you need it. * **Full page capture** — Archive entire pages including all scrollable content * **PDF generation** — Create document-format archives * **Scheduled archiving** — Automatically capture pages at regular intervals * **Bulk capture** — Archive hundreds of pages in a single operation For comprehensive archiving, combine full page screenshots with PDF generation to preserve both visual appearance and text content. ## Quick example Archive a web page as both a screenshot and PDF: ```bash # Capture as full page screenshot curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/important-article", "fullPage": true, "format": "png", "waitUntil": "networkidle" }' # Capture as PDF curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/important-article", "format": "pdf", "pdfOptions": { "printBackground": true, "format": "A4" } }' ``` Set up weekly archiving: ```bash curl -X POST https://api.allscreenshots.com/v1/schedules \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Weekly archive", "url": "https://example.com/important-page", "schedule": "0 0 * * 0", "fullPage": true }' ``` ## Key features for this use case ## Next steps * [PDF generation guide](/docs/guides/pdf-generation) — Create PDF archives * [Full page capture](/docs/features/full-page-capture) — Capture entire pages * [Compliance and auditing](/docs/use-cases/compliance-auditing) — Archiving for regulatory requirements # Customer onboarding (/docs/use-cases/customer-onboarding) import { Cards, Card } from 'fumadocs-ui/components/card'; import { Callout } from 'fumadocs-ui/components/callout'; Automatically generate up-to-date screenshots for product documentation, help centers, and onboarding tutorials. ## The problem Product documentation needs screenshots, but keeping them current is painful: * UI changes constantly, making screenshots outdated * Manual capture is tedious and inconsistent * Different screen sizes and locales multiply the work * Dark mode and themes require separate screenshots Teams often let documentation screenshots fall out of date, hurting the customer experience. ## How Allscreenshots helps Automate screenshot capture from your live product. Keep documentation always current by regenerating screenshots as part of your build or deployment process. * **Always current** — Screenshots update when your UI changes * **Consistent styling** — Same viewport, zoom, and wait conditions every time * **Multi-locale support** — Capture different language versions * **Theme variants** — Generate light and dark mode screenshots Use element selectors to capture specific UI components rather than full pages for cleaner documentation images. ## Quick example Capture a specific UI component for your docs: ```bash curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://app.yourproduct.com/settings", "selector": "#billing-section", "viewport": {"width": 1200, "height": 800}, "waitUntil": "networkidle" }' ``` Capture the same component in dark mode: ```bash curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://app.yourproduct.com/settings", "selector": "#billing-section", "darkMode": true, "viewport": {"width": 1200, "height": 800} }' ``` ## Key features for this use case ## Next steps * [Screenshots API reference](/docs/api-reference/screenshots) — Selector and viewport options * [Viewport and devices](/docs/features/viewport-and-devices) — Mobile and tablet emulation * [CI/CD workflows](/docs/use-cases/ci-cd-workflows) — Automate screenshot updates on deploy # E-commerce monitoring (/docs/use-cases/ecommerce-monitoring) import { Cards, Card } from 'fumadocs-ui/components/card'; import { Callout } from 'fumadocs-ui/components/callout'; Monitor competitor e-commerce sites to track pricing changes, inventory status, promotional campaigns, and product page updates. ## The problem E-commerce is fiercely competitive. Pricing and promotions change constantly, and staying informed requires continuous monitoring: * Competitors adjust prices daily or even hourly * Flash sales and promotions appear without warning * Product availability affects your competitive positioning * Manual monitoring doesn't scale across hundreds of SKUs ## How Allscreenshots helps Schedule automatic captures of competitor product and pricing pages. Build a visual history of changes and integrate with your pricing intelligence systems. * **Scheduled captures** — Monitor pages hourly, daily, or at custom intervals * **Visual history** — Track how pricing and promotions evolve * **Bulk monitoring** — Watch hundreds of product pages simultaneously * **Clean captures** — Block ads and popups for consistent results Use the bulk API to monitor multiple competitor product pages in a single request, then process the results with your pricing intelligence tools. ## Quick example Set up hourly monitoring of a competitor's pricing page: ```bash curl -X POST https://api.allscreenshots.com/v1/schedules \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Competitor product monitor", "url": "https://competitor.com/products/widget-pro", "schedule": "0 * * * *", "viewport": {"width": 1920, "height": 1080}, "fullPage": true, "blockLevel": "basic", "webhookUrl": "https://yoursite.com/webhooks/price-monitor" }' ``` Monitor multiple products at once: ```bash curl -X POST https://api.allscreenshots.com/v1/screenshots/bulk \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "urls": [ "https://competitor.com/products/widget-pro", "https://competitor.com/products/widget-basic", "https://competitor.com/products/widget-enterprise" ], "options": { "fullPage": true, "blockLevel": "basic" }, "webhookUrl": "https://yoursite.com/webhooks/bulk-complete" }' ``` ## Key features for this use case ## Next steps * [Schedules API reference](/docs/api-reference/schedules) — Set up automated monitoring * [Bulk API reference](/docs/api-reference/bulk) — Monitor multiple URLs efficiently * [Website monitoring](/docs/use-cases/website-monitoring) — General website change detection # Use cases (/docs/use-cases) import { Cards, Card } from 'fumadocs-ui/components/card'; Allscreenshots powers a wide range of workflows across development, marketing, legal, and operations teams. Explore how you can use our screenshot API to solve your specific challenges. ## Not sure where to start? If you're new to Allscreenshots, check out our [quickstart guide](/docs/getting-started/quickstart) to capture your first screenshot in under a minute. Then explore these use cases to see how you can integrate screenshots into your workflows. # Legal evidence (/docs/use-cases/legal-evidence) import { Cards, Card } from 'fumadocs-ui/components/card'; import { Callout } from 'fumadocs-ui/components/callout'; Capture web content with timestamps and metadata to create verifiable evidence for legal proceedings, intellectual property disputes, and litigation. ## The problem Web content is constantly changing, and proving what was displayed at a specific time is critical in legal contexts: * **Intellectual property** — Document infringement or prior art * **Defamation** — Capture harmful content before it's deleted * **Contract disputes** — Prove what terms were displayed * **Trademark violations** — Document unauthorized use * **Fraud investigation** — Preserve evidence of misleading claims Manual screenshots lack credibility. They have no chain of custody, timestamps can be faked, and metadata is missing. ## How Allscreenshots helps Capture web content through a third-party service that provides verifiable timestamps, complete metadata, and a clear chain of custody. * **Third-party verification** — Screenshots captured by an independent service * **Complete metadata** — URL, timestamp, capture parameters all recorded * **Full page capture** — Document entire pages including all content * **Immediate capture** — Preserve evidence before it disappears For use in legal proceedings, consult with your legal counsel about evidence requirements in your jurisdiction. Consider combining API captures with additional verification methods. ## Quick example Capture a web page with full metadata for evidence: ```bash curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/page-to-document", "fullPage": true, "format": "png", "waitUntil": "networkidle", "metadata": { "caseNumber": "2024-CV-12345", "purpose": "evidence-preservation", "capturedBy": "legal-department" } }' ``` The response includes verifiable details: ```json { "url": "https://example.com/page-to-document", "capturedAt": "2024-01-15T14:30:00.000Z", "imageUrl": "https://...", "metadata": { "caseNumber": "2024-CV-12345", "purpose": "evidence-preservation", "capturedBy": "legal-department" } } ``` ## Key features for this use case ## Next steps * [PDF generation guide](/docs/guides/pdf-generation) — Create PDF evidence documents * [Screenshots API reference](/docs/api-reference/screenshots) — Metadata and capture options * [Compliance and auditing](/docs/use-cases/compliance-auditing) — Regulatory documentation # Automated report generation (/docs/use-cases/report-generation) import { Cards, Card } from 'fumadocs-ui/components/card'; import { Callout } from 'fumadocs-ui/components/callout'; Automate the creation of visual reports by capturing screenshots of dashboards, analytics, and data visualizations. ## The problem Creating visual reports is time-consuming and error-prone: * Manually capturing dashboard screenshots is tedious * Reports need to be generated at specific times (end of day, week, month) * Multiple stakeholders need different views * Screenshots become outdated by the time reports are delivered ## How Allscreenshots helps Automate report generation by capturing screenshots of your dashboards and data visualizations on a schedule. Combine multiple captures into comprehensive reports. * **Scheduled captures** — Generate reports at end of day, week, or month * **Multiple viewports** — Capture different dashboard views * **Composition** — Combine multiple screenshots into a single report * **Bulk capture** — Grab all dashboard sections in one request Use the compose API to combine multiple dashboard screenshots into a single report image with grid or custom layouts. ## Quick example Capture a dashboard and wait for data to load: ```bash curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://analytics.yourcompany.com/dashboard", "viewport": {"width": 1920, "height": 1080}, "fullPage": true, "waitUntil": "networkidle", "delay": 2000 }' ``` Schedule a daily report at end of business: ```bash curl -X POST https://api.allscreenshots.com/v1/schedules \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Daily sales dashboard", "url": "https://analytics.yourcompany.com/sales", "schedule": "0 18 * * 1-5", "fullPage": true, "webhookUrl": "https://yoursite.com/webhooks/daily-report" }' ``` Combine multiple dashboards into one report: ```bash curl -X POST https://api.allscreenshots.com/v1/compose \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "screenshots": [ {"url": "https://analytics.yourcompany.com/sales"}, {"url": "https://analytics.yourcompany.com/marketing"}, {"url": "https://analytics.yourcompany.com/support"} ], "layout": "grid", "columns": 1 }' ``` ## Key features for this use case ## Next steps * [Compose API reference](/docs/api-reference/compose) — Combine screenshots into reports * [Schedules API reference](/docs/api-reference/schedules) — Set up automated captures * [CI/CD workflows](/docs/use-cases/ci-cd-workflows) — Integrate with your build pipeline # Social media OG images (/docs/use-cases/social-media-og-images) import { Cards, Card } from 'fumadocs-ui/components/card'; import { Callout } from 'fumadocs-ui/components/callout'; Automatically generate branded Open Graph images and Twitter cards for blog posts, product pages, user profiles, and any dynamic content. ## The problem Social media previews matter. When someone shares your link, a compelling preview image dramatically increases click-through rates. But creating custom OG images for every page is tedious: * Design tools don't scale to thousands of pages * Static images get outdated when content changes * Dynamic content (user profiles, product pages) needs unique images * Managing image assets becomes a maintenance burden ## How Allscreenshots helps Create a template page with your branding, then generate unique OG images by capturing screenshots with dynamic data. Every share gets a fresh, accurate preview. * **Dynamic generation** — Pass parameters to customize each image * **Consistent branding** — Use your own HTML/CSS templates * **Always current** — Images reflect the latest content * **Scale infinitely** — Generate thousands of images on demand Use a fixed viewport size like 1200x630 (Facebook/LinkedIn) or 1200x600 (Twitter) for optimal social media display. ## Quick example Capture a branded OG image from your template page: ```bash curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://yoursite.com/og-template?title=How%20to%20Build%20a%20SaaS&author=Jane%20Doe", "viewport": {"width": 1200, "height": 630}, "format": "png", "selector": "#og-card" }' ``` Or generate from raw HTML: ```bash curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "html": "
My Blog Post Title
", "viewport": {"width": 1200, "height": 630} }' ``` ## Key features for this use case ## Next steps * [Social media previews guide](/docs/guides/social-media-previews) — Build a complete OG image generation system * [Screenshots API reference](/docs/api-reference/screenshots) — HTML and selector options * [Bulk API](/docs/api-reference/bulk) — Generate images at scale # Visual regression testing (/docs/use-cases/visual-regression-testing) import { Cards, Card } from 'fumadocs-ui/components/card'; import { Callout } from 'fumadocs-ui/components/callout'; Automatically detect unintended visual changes in your UI by comparing screenshots captured at different points in time. ## The problem CSS changes can break UI in unexpected ways. A tweak to one component might cascade into layout issues elsewhere. Manual testing doesn't scale, and customers often discover visual bugs before your team does. Without automated visual testing, you're relying on: * Manual QA that misses edge cases * User reports after bugs reach production * Expensive rollbacks and hotfixes ## How Allscreenshots helps Capture consistent, high-fidelity screenshots in your CI/CD pipeline. Compare new screenshots against baselines and get immediate alerts when visual differences exceed your threshold. * **Consistent rendering** — Same browser, viewport, and wait conditions every time * **Pixel-perfect comparisons** — Detect even subtle visual regressions * **CI/CD integration** — Fail builds automatically when visual bugs are detected Use `hideSelectors` to exclude dynamic content like timestamps, avatars, or ads from comparisons. ## Quick example Capture a screenshot of your staging environment for comparison: ```bash curl -X POST https://api.allscreenshots.com/v1/screenshots \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://staging.example.com/checkout", "viewport": {"width": 1920, "height": 1080}, "format": "png", "waitUntil": "networkidle", "hideSelectors": [".timestamp", ".random-avatar"] }' ``` Then use a comparison library like `pixelmatch` or `looks-same` to diff against your baseline. ## Key features for this use case ## Next steps * [Visual regression testing guide](/docs/guides/visual-regression-testing) — Full implementation walkthrough with code examples * [CI/CD integration guide](/docs/guides/cicd-integration) — GitHub Actions, GitLab CI, and Jenkins examples * [Screenshots API reference](/docs/api-reference/screenshots) — Complete parameter documentation # Website monitoring (/docs/use-cases/website-monitoring) import { Cards, Card } from 'fumadocs-ui/components/card'; import { Callout } from 'fumadocs-ui/components/callout'; Monitor websites for visual changes by capturing screenshots on a schedule and comparing them over time. ## The problem Websites change constantly. Competitors update pricing, content gets modified, and your own site might change unexpectedly. Without monitoring: * You miss competitor pricing changes and promotions * Content drift goes unnoticed until customers complain * Third-party embeds break without warning * Unauthorized changes slip through ## How Allscreenshots helps Schedule automatic screenshot captures and build a visual history of any website. Compare captures over time to detect changes, or simply archive a visual record. * **Scheduled captures** — Hourly, daily, weekly, or custom intervals * **Visual history** — Track how pages evolve over time * **Change detection** — Compare screenshots to spot differences * **Competitor intelligence** — Monitor pricing and feature pages Combine scheduled captures with webhooks to get notified immediately when new screenshots are available for comparison. ## Quick example Set up a daily capture of a competitor's pricing page: ```bash curl -X POST https://api.allscreenshots.com/v1/schedules \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Competitor pricing monitor", "url": "https://competitor.com/pricing", "schedule": "0 9 * * *", "viewport": {"width": 1920, "height": 1080}, "fullPage": true, "webhookUrl": "https://yoursite.com/webhooks/screenshot" }' ``` This captures the page every day at 9 AM and sends the result to your webhook. ## Key features for this use case ## Next steps * [Website monitoring guide](/docs/guides/website-monitoring) — Build a complete monitoring system * [Schedules API reference](/docs/api-reference/schedules) — Cron expressions and interval options * [Visual regression testing](/docs/use-cases/visual-regression-testing) — Compare screenshots to detect changes