What is BrowserGrab?
BrowserGrab is a screenshot API that captures any public webpage as a pixel-perfect image with a single HTTP request. No browser to run, no Puppeteer to manage — just send a URL and get back an image.
It runs on Cloudflare's global network, so captures are fast from anywhere in the world. You can store results on BrowserGrab's CDN, save directly to Google Drive, or receive the raw image as a base64 string in the API response.
Screenshot API
POST a URL, get back an image URL. Works in any language that can make HTTP requests.
JavaScript SDK
npm install browsergrab — a zero-dependency TypeScript client with full types and retry logic.
Chrome Extension
Press Alt+Shift+S on any tab to capture and save a screenshot using your account defaults.
Quick Start
Get your first screenshot in under a minute:
bg_live_xxxxxxxxxxxxxxxxxxxx.https://browsergrab.app/api/screenshot with your URL. See the full request format in the Postman collection.<img> tags, store in your database, or share anywhere.Authentication
All API requests require a Bearer token in the Authorization header. Create and manage your keys from the API Keys page.
Authorization: Bearer bg_live_xxxxxxxxxxxxxxxxxxxxKeep your keys secret — they carry your quota. If a key is compromised, delete it from the dashboard and create a new one.
Parameters
Send a JSON body to POST /api/screenshot. Only url is required — everything else has a sensible default.
Core (all plans)
| Parameter | Type | Default | Description |
|---|---|---|---|
| url | string | required | Fully-qualified URL to capture (must include https://) |
| format | string | "png" | Output format: png, jpeg, or webp |
| width | integer | 1280 | Viewport width in pixels (320–1920 on Free, up to 3840 on Super) |
| height | integer | 800 | Viewport height in pixels (240–1080 on Free, up to 2160 on Super) |
| fullPage | boolean | false | Capture the full scrollable page height, not just the viewport |
| waitFor | integer | 0 | Extra milliseconds to wait after page load (0–5000). Useful for animations or lazy-loaded content. |
| storage | string | "cloud" | Where to store the result: cloud, gdrive, or none |
Super plan only
| Parameter | Type | Default | Description |
|---|---|---|---|
| retina | boolean | false | Render at 2× device pixel ratio (HiDPI / Retina). Output image is double the width/height. |
| darkMode | boolean | false | Force prefers-color-scheme: dark before capturing |
| blockAds | boolean | false | Block common ad networks and trackers before capture |
| quality | integer | 85 | JPEG/WebP compression quality (1–100). Ignored for PNG. |
Bulk Screenshots
Capture up to 20 URLs in a single API call. Each URL counts as one screenshot credit. The entire batch is checked against your quota upfront — if you don't have enough credits for all URLs, the whole request is rejected rather than processing a partial batch.
Two ways to send multiple URLs
{
"urls": [
"https://example.com",
"https://github.com",
"https://stripe.com"
],
"format": "png",
"width": 1280,
"storage": "cloud"
}{
"url": "https://example.com,https://github.com,https://stripe.com",
"format": "png"
}Bulk response shape
When 2 or more URLs are sent, the response wraps individual results in a results array. Each item has its own success flag and charged indicator.
{
"success": true,
"count": 3,
"captured": 2,
"failed": 1,
"results": [
{
"url": "https://example.com",
"success": true,
"data": {
"url": "https://pub-....r2.dev/screenshots/2025-04/abc123.png",
"width": 1280,
"height": 800,
"format": "png",
"storage": "cloud"
},
"charged": true
},
{
"url": "https://github.com",
"success": true,
"data": { "url": "https://pub-....r2.dev/screenshots/...", ... },
"charged": true
},
{
"url": "https://bad-url.xyz",
"success": false,
"error": "page_load_failed",
"message": "DNS lookup failed",
"charged": false
}
]
}Bulk behaviour
| Scenario | Behaviour |
|---|---|
| One URL fails (DNS, blank page) | Not charged. Rest of the batch continues normally. |
| Insufficient quota for full batch | Entire request rejected with quota_exceeded before any captures run. |
| More than 20 URLs | Rejected with too_many_urls. Max is 20 per request. |
| Single URL (backward-compatible) | Returns the standard { "success": true, "data": {...} } shape, not the bulk wrapper. |
Storage Options
The storage parameter controls where the screenshot ends up after capture.
| Value | Plan | What you get back |
|---|---|---|
| cloud | Super, Pro | A permanent public CDN URL (e.g. https://pub-....r2.dev/screenshots/...) |
| gdrive | Super, Pro | A shareable Google Drive link. Requires Drive connected in Account settings. |
| none | All plans | A data:image/...;base64,... string in the response body. Nothing stored remotely. |
CDN URLs are permanent — they don't expire. You can link to them directly in emails, embed them in <img> tags, or store them in your own database.
Response Format
All responses are JSON. A successful capture returns:
{
"success": true,
"data": {
"url": "https://pub-....r2.dev/screenshots/2025-04/abc123.png",
"width": 1280,
"height": 800,
"format": "png",
"storage": "cloud"
}
}data.url is the image you store or display. For storage: "none" this is a base64 data URL instead of a CDN link.
Error Codes
Errors follow a consistent shape: { "error": "code", "message": "Human description" }. The charged field will be false when no screenshot credit was consumed.
| HTTP | Error code | Meaning | Charged? |
|---|---|---|---|
| 400 | validation_error | Missing or invalid parameter in the request body | No |
| 400 | unsafe_url | URL targets a private/internal IP — blocked for security | No |
| 401 | missing_api_key | No Authorization header provided | No |
| 401 | invalid_api_key | Key not found or has been deleted | No |
| 403 | dimension_exceeds_plan | Requested resolution exceeds your plan maximum | No |
| 403 | feature_requires_super | retina, darkMode, blockAds, or quality used on Free plan — requires Super or Pro | No |
| 403 | gdrive_not_available | Google Drive storage requires Super or Pro plan | No |
| 422 | page_load_failed | Page couldn't be loaded (DNS error, blank page, timeout) | No |
| 429 | quota_exceeded | Monthly screenshot limit reached. Includes current, limit, and resetAt. | No |
| 500 | internal_error | Something went wrong on our side — retry with exponential backoff | No |
Rate Limits
There is no per-second rate limit — burst as fast as you like within your monthly allocation. Quotas reset on the 1st of each month UTC. Need more? Contact us for a custom plan.
JavaScript / TypeScript SDK
The official SDK is published on npm as browsergrab. Zero dependencies. Works in Node.js 18+, Deno, Bun, and any runtime with the Fetch API. Full TypeScript types included.
Installation
npm install browsergrabUsage
import BrowserGrab from "browsergrab";
const client = new BrowserGrab("bg_live_your_api_key");
// Basic screenshot — returns CDN URL
const result = await client.screenshot({
url: "https://stripe.com",
});
console.log(result.url); // https://pub-....r2.dev/screenshots/...
// Full page in WebP with dark mode (Super plan)
const dark = await client.screenshot({
url: "https://github.com",
format: "webp",
fullPage: true,
darkMode: true,
storage: "cloud",
});
// Mobile viewport
const mobile = await client.screenshot({
url: "https://example.com",
width: 375,
height: 812,
});Client options:
const client = new BrowserGrab("bg_live_xxx", {
retries: 3, // retry on 5xx errors (default: 2)
timeoutMs: 60_000, // per-request timeout in ms (default: 90000)
baseUrl: "...", // override API base URL
});Error Handling
All API errors throw a BrowserGrabError with machine-readable fields.
import BrowserGrab, { BrowserGrabError } from "browsergrab";
const client = new BrowserGrab("bg_live_xxx");
try {
const result = await client.screenshot({ url: "https://example.com" });
console.log(result.url);
} catch (err) {
if (err instanceof BrowserGrabError) {
console.error(err.message); // "Monthly quota exceeded (15/15 screenshots used...)"
console.error(err.code); // "quota_exceeded"
console.error(err.status); // 429
console.error(err.charged); // false — no credit used
}
}The SDK retries automatically on 5xx server errors with exponential backoff. 4xx errors are not retried since they represent caller mistakes.
Chrome Extension
The BrowserGrab Chrome extension lets you screenshot any tab with a single keyboard shortcut. Captures are sent to your BrowserGrab account and stored using your default settings — no copy-paste, no API calls to write.
Installation
Setup
bg_live_xxx.Using the Keyboard Shortcut
Press Alt+Shift+S on any https:// page to capture a screenshot.
You'll see a Capturing… notification while the screenshot processes, then a Screenshot Captured! notification with the result URL. Clicking the notification opens the image in a new tab.
You can also click the extension popup and hit Capture This Page to trigger a capture without using the keyboard.
chrome://extensions/shortcuts to change the default Alt+Shift+S binding to any key combination you prefer.The extension cannot capture Chrome internal pages (chrome://), the New Tab page, or the Chrome Web Store — only regular http:// and https:// URLs.
Postman Collection
Every endpoint pre-wired with example bodies and expected responses. The fastest way to explore the API without writing any code.
Open Postman Documenter
Interactive API reference — run requests directly in Postman or your browser
The collection includes: Basic screenshot, all options, full page, mobile viewport, wait for animations, bulk screenshots (multiple URLs), Super features (retina + dark mode + block ads), base64 response, and Google Drive storage — each as a ready-to-run request.
Plans & Limits
| Feature | Free | Basic ($4.99/mo) | Super ($9.99/mo) | Pro ($39/mo) |
|---|---|---|---|---|
| Screenshots / month | 50 | 500 | 5,000 | 25,000 |
| Max resolution | 1920×1080 | 1920×1080 | 3840×2160 | 3840×2160 |
| Formats | PNG, JPEG, WebP | PNG, JPEG, WebP | PNG, JPEG, WebP | PNG, JPEG, WebP |
| Cloud storage (CDN) | — | 1 GB | 15 GB | 100 GB |
| Google Drive | — | — | ✓ | ✓ |
| Retina (2×) | — | — | ✓ | ✓ |
| Dark mode emulation | — | — | ✓ | ✓ |
| Ad blocking | — | — | ✓ | ✓ |
| Custom JPEG/WebP quality | — | — | ✓ | ✓ |
Failed captures (DNS errors, blank pages, invalid URLs) are never charged against your quota. You only pay for successful screenshots.
Ready to start building?
Create a free account and start capturing screenshots in minutes.
Get support on Discord
Ask questions, share feedback, and get help from the community and the team.