How to capture a mobile website screenshot with Browshot
Capture a mobile website screenshot with Browshot using a virtual mobile browser, then handle redirects, full-page output, JavaScript delays, and common errors.
To capture a mobile website screenshot with Browshot, request the page through Browshot’s Simple API and select a mobile virtual browser instance. The response may redirect while the capture is being prepared, so follow redirects and save the final PNG response. Browshot’s command-line example uses a portrait virtual iPhone 4 instance; that is a virtual browser profile, not a physical phone. See Browshot’s API documentation and command-line guide for the current endpoint and available instances.
What you need
- A Browshot account and API key from its account dashboard.
- The ID of a mobile virtual browser instance available to your account.
- The target page URL, publicly reachable by Browshot.
- A command-line HTTP client or a runtime such as Python or Node.js.
Choose a mobile instance that matches the orientation and device profile you want to render. Browshot’s documented example uses instance_id=22 for a portrait virtual iPhone 4. Instance availability can vary, so confirm the ID in the current dashboard or API before relying on it.
Capture a mobile screenshot with cURL
The Simple API request has this general form. Replace the placeholders with your API key, mobile instance ID, and page URL:
curl -L --fail --get 'https://api.browshot.com/api/v1/simple' \
--data-urlencode 'url=https://example.com' \
--data-urlencode 'instance_id=22' \
--data-urlencode 'key=YOUR_BROWSHOT_API_KEY' \
--output mobile-screenshot.png
-L follows redirects, which matters because Browshot can return a redirect while a screenshot is still being generated. --fail makes cURL return an error for an HTTP failure rather than silently treating an error response as the image. The URL encoding option safely handles query strings and other reserved characters in the target URL.
For a full-page image instead of the visible screen, add --data-urlencode 'size=page'. Without it, the documented default is a screen-sized capture.
Capture from Python
This example follows redirects, checks the HTTP result, and writes the response bytes to disk:
import requests
api_url = "https://api.browshot.com/api/v1/simple"
params = {
"url": "https://example.com",
"instance_id": "22", # Replace with a mobile instance in your account.
"key": "YOUR_BROWSHOT_API_KEY",
}
response = requests.get(api_url, params=params, allow_redirects=True, timeout=120)
if response.status_code != 200:
raise RuntimeError(
f"Browshot returned HTTP {response.status_code}: "
f"{response.headers.get('X-Error', response.text[:500])}"
)
content_type = response.headers.get("Content-Type", "")
if "image/" not in content_type:
raise RuntimeError(f"Expected an image, received Content-Type: {content_type}")
with open("mobile-screenshot.png", "wb") as image_file:
image_file.write(response.content)
Install the dependency with python -m pip install requests. For a full-page capture, add "size": "page" to params. Keep the API key in an environment variable or secrets manager in deployed code rather than committing it to source control.
Capture from Node.js
On Node.js versions with built-in fetch, construct the query with URLSearchParams so the target URL is encoded correctly. Fetch follows redirects by default:
const params = new URLSearchParams({
url: 'https://example.com',
instance_id: '22', // Replace with a mobile instance in your account.
key: process.env.BROWSHOT_API_KEY || 'YOUR_BROWSHOT_API_KEY',
});
const response = await fetch(
`https://api.browshot.com/api/v1/simple?${params}`,
{ signal: AbortSignal.timeout(120_000) }
);
if (!response.ok) {
throw new Error(
`Browshot returned HTTP ${response.status}: ` +
(response.headers.get('X-Error') || await response.text())
);
}
const contentType = response.headers.get('content-type') || '';
if (!contentType.startsWith('image/')) {
throw new Error(`Expected an image, received Content-Type: ${contentType}`);
}
const image = Buffer.from(await response.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('mobile-screenshot.png', image));
To request a full-page screenshot, include size: 'page' in the URLSearchParams object.
Choose screen capture or full-page capture
| Need | Setting | What to expect |
|---|---|---|
| What appears in the mobile viewport | Omit size |
The documented default is a screen capture. |
| The whole page in one image | size=page |
Requests a full-page image. Very long pages can take more time and produce larger files. |
A full-page screenshot is useful for archiving or reviewing a page layout, but it may not represent a single screen a mobile visitor sees. For a visual check of above-the-fold layout, use the default screen capture.
Wait for JavaScript and lazy content
Browshot documents a delay parameter for waiting a number of seconds after page load. Its documented default is five seconds. Increase the delay when a page fills in important content after its initial load, such as client-rendered results or images that appear after scripts run. The current maximum can differ by endpoint or account context, so check the live documentation rather than assuming a fixed upper limit.
Browshot also supports a custom JavaScript step that runs after the page-load event; the script must finish before the request’s delay expires. A script can scroll down before a full-page capture to trigger content that loads on scroll, or hide and show elements. See the Browshot JavaScript instructions for syntax and current limits.
Do not add a long delay by default. It increases response time and may not help if the page is blocked, its scripts fail, or the content requires an interaction. Start with the default, inspect the result, then increase the wait or use a targeted script if a known page element is missing.
Pages that require interaction
A basic request is suitable for publicly accessible pages that render without user input. For pages requiring login or other interaction, Browshot documents automation steps such as clicking, typing, sleeping, navigating, and then taking a screenshot. Its documentation describes these steps under advanced options for premium and private browsers. Treat this as an account and browser capability to verify before designing a workflow around it.
Only automate pages you are authorized to access. Do not put passwords or session tokens in logs, source code, or URLs that may be recorded by intermediaries.
Handle responses and errors
Check both the HTTP status and the response headers before treating a response body as an image. Browshot documents 400 for an invalid request and 404 when a page could not be captured; the X-Error header describes the error. A redirect can indicate that the capture is still in progress, so clients should follow it and allow enough time for the eventual response.
| Symptom | Likely cause | Fix |
|---|---|---|
| HTTP 400 | Invalid or incomplete request parameters. | Check the API key, URL encoding, instance ID, and parameter names. Read X-Error. |
| HTTP 404 | Browshot could not capture the requested page. | Check that the URL is reachable and correctly formed. Try opening the target independently and review the error header. |
| A redirect response or no saved image | The client did not follow the redirect to the completed screenshot. | Use cURL’s -L, Python’s redirect handling, or a redirect-following fetch client; allow a suitable request timeout. |
| The file contains text or is unexpectedly small | An error body was saved as though it were a PNG. | Check HTTP status, Content-Type, and X-Error before writing the file. |
| Blank or incomplete content | The page may render after load, require interaction, or have failed scripts/resources. | Use a longer delay, a documented JavaScript step, or interaction automation where supported. |
| The layout looks desktop-sized | A desktop instance was selected, or the selected profile is not the intended mobile profile. | Verify the virtual mobile instance ID in the dashboard and capture again. |
| Important content is missing from full-page output | Content may load only after scrolling or an application action. | Use an appropriate script to scroll or interact, then capture after the content has loaded. |
Performance, reliability, and cost considerations
- Latency: Capture time includes page navigation, rendering, any configured delay, and any redirect while the screenshot is produced. Keep delays only as long as the page needs and set client timeouts with room for the redirect and image response.
- Reliability: Treat capture as a remote operation that can fail because of the target page or request. Check status and error headers, and retry only transient failures with a bounded retry policy. Avoid rapid repeated retries for invalid parameters or pages that consistently cannot be reached.
- Output size: Full-page screenshots can be much larger than screen captures. Consider the required extent before storing or transferring the result.
- Cost and account limits: The supplied Browshot documentation does not establish current pricing, quotas, or instance availability. Check the live account dashboard and pricing information before estimating production cost.
- Reproducibility: Record the target URL, virtual instance ID, capture settings, and capture time with your own job metadata. This makes differences in output easier to diagnose if the page or instance changes.
Or skip the browser setup
ScreenshotNeo can return a website screenshot with one GET request, without choosing and maintaining a browser capture setup. Its cookie handling accepts consent banners like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response includes X-Page-Verdict and X-Billed headers. ScreenshotNeo also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents.
For a mobile-sized viewport, pass the viewport options supported by the API; see the ScreenshotNeo API documentation for parameters and configuration.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo includes 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan. Sign up for the free plan to make your first capture.
FAQ
Does Browshot take the screenshot on my physical phone?
No. This workflow selects a virtual browser instance configured for a mobile profile.
Can I use a URL that contains query parameters?
Yes. Ensure the URL is encoded as a parameter value; the cURL, Python, and Node.js examples handle encoding for you.
Why did the response take longer than a normal web request?
The service must load and render the target page, may wait for the configured post-load delay, and can return a redirect while the image is being prepared.
Can I capture a page behind a login?
Browshot documents interaction automation for supported premium and private browsers. Confirm that the required capability is available for your account and instance.
Does size=page mean a mobile screenshot?
It requests full-page extent. The selected virtual browser instance determines the mobile rendering profile.


