ScreenshotNeo

BlogHow-to

How to Capture a Website Screenshot on Mobile with ScreenshotAPI.net

Capture a mobile-sized website screenshot with ScreenshotAPI.net using viewport dimensions, bearer authentication, and image-byte handling in cURL, Python, and Node.js.

By the ScreenshotNeo team4 October 20268 min read

To capture a mobile-sized website screenshot with ScreenshotAPI.net, send a GET request to https://screenshot-api.net/v1/screenshot with the page URL, a mobile viewport width and height, and your API key in an Authorization: Bearer header. Save the response body directly as an image: the endpoint returns image bytes, not JSON containing an image URL.

A useful starting viewport is 375 × 812 CSS pixels, the example shown on the service’s product page. This sets the page’s viewport dimensions; the available documentation does not establish that it reproduces a specific phone model or its browser interface. See the current ScreenshotAPI.net documentation and product page.

1. Get an API key and choose a mobile viewport

  1. Create an account and obtain an API key through ScreenshotAPI.net’s account flow.
  2. Choose the viewport width and height in CSS pixels. Use 375 × 812 as a starting point, or set dimensions that match the layout you need to inspect.
  3. Keep the key in an environment variable or a server-side secret store. The documentation warns that a key in a query string can be exposed through page source or server logs.

The endpoint requires a page URL using HTTP or HTTPS, up to 2,048 characters. The documented width default is 1,280 and maximum is 3,840; height defaults to 800 and has a maximum of 4,320. Set both explicitly for a mobile capture so the result does not silently use a desktop-sized default.

2. Capture a mobile screenshot with cURL

Set the API key in your shell, then request the screenshot. --data-urlencode safely encodes the page URL, and -o writes the returned image bytes to a file.

export SCREENSHOT_API_KEY="your_api_key"
curl -G "https://screenshot-api.net/v1/screenshot" \
  -H "Authorization: Bearer $SCREENSHOT_API_KEY" \
  --data-urlencode "url=https://example.com" \
  --data-urlencode "width=375" \
  --data-urlencode "height=812" \
  --data-urlencode "format=png" \
  -o mobile-shot.png

Do not add -H options containing private credentials to a command that will be committed or shared. For repeatable use, load the key from your secret manager or protected environment.

3. Capture with Python

This example uses the requests package. Install it with python -m pip install requests, set the environment variable, and run the script. It checks the HTTP response before writing the body so an API error is not accidentally saved as a PNG.

import os
import requests

api_key = os.environ["SCREENSHOT_API_KEY"]
response = requests.get(
    "https://screenshot-api.net/v1/screenshot",
    headers={"Authorization": f"Bearer {api_key}"},
    params={
        "url": "https://example.com",
        "width": 375,
        "height": 812,
        "format": "png",
    },
    timeout=35,
)
response.raise_for_status()

with open("mobile-shot.png", "wb") as image_file:
    image_file.write(response.content)

print("Saved mobile-shot.png")
print("Final page status:", response.headers.get("X-Page-Status", "not provided"))

The API documents a timeout parameter for capture requests separately from your client’s network timeout. Its documented capture timeout defaults to 25 seconds and ranges from 1 to 30 seconds; your HTTP client timeout should allow time for the request and response to complete.

4. Capture with Node.js

Use a recent Node.js release that provides the built-in fetch and URLSearchParams APIs. The example stores the response as bytes and reports the final page status header.

import { writeFile } from "node:fs/promises";

const apiKey = process.env.SCREENSHOT_API_KEY;
if (!apiKey) throw new Error("Set SCREENSHOT_API_KEY first");

const query = new URLSearchParams({
  url: "https://example.com",
  width: "375",
  height: "812",
  format: "png",
});

const response = await fetch(
  `https://screenshot-api.net/v1/screenshot?${query}`,
  {
    headers: { Authorization: `Bearer ${apiKey}` },
    signal: AbortSignal.timeout(35_000),
  },
);

if (!response.ok) {
  throw new Error(`Screenshot request failed: HTTP ${response.status}`);
}

const bytes = new Uint8Array(await response.arrayBuffer());
await writeFile("mobile-shot.png", bytes);
console.log("Saved mobile-shot.png");
console.log("Final page status:", response.headers.get("X-Page-Status"));

5. Pick format, scale, and rendering options

The endpoint supports PNG, JPEG, and WebP. PNG is lossless, and its quality setting is ignored. Choose PNG when preserving crisp text or detail matters; use a lossy format when a smaller file is more useful. Compare captures using the same viewport, format, and scale so the results are comparable.

Setting How to use it Documented details
url Page to render. Required. HTTP or HTTPS; maximum 2,048 characters.
width, height Viewport dimensions in CSS pixels. Set both for mobile. Width default 1,280, maximum 3,840. Height default 800, maximum 4,320.
format Output image format. PNG, JPEG, or WebP; PNG is lossless and ignores quality.
scale Device pixel ratio for output sharpness and pixel dimensions. Default 1; documented range 0.1–3.
delay Wait after page load for delayed content. Maximum 10,000 milliseconds.
timeout Capture time limit. Default 25 seconds; documented range 1–30 seconds.

A scale above 1 can produce a sharper, larger image while retaining the same CSS viewport. For example, a 375-pixel-wide viewport at scale 2 has more output pixels, but the page still lays out at a 375 CSS-pixel width. Do not interpret that as a different phone model. If the page needs time for client-side rendering, use the documented delay option modestly; increasing waits adds latency and cannot fix a page that never becomes available.

6. Handle pages that need a session or load dynamically

If the target page depends on authentication, the service documentation lists cookies and headers among the available options. Pass only the session data needed for the capture, protect it as a secret, and avoid logging complete request URLs or headers when they contain credentials. For pages that render content after initial navigation, try a short delay within the documented maximum. Check the resulting capture rather than assuming that a longer wait fixes every dynamic page.

Inspect the X-Page-Status response header if the image shows an error or login screen. It represents the final document status after redirects. A 401 or 403 may mean the captured page is an authentication or access-denied response rather than the intended content.

7. Troubleshooting

Symptom Likely cause What to do
401 response from the API Missing, invalid, or malformed bearer token. Confirm the key is set and send it as Authorization: Bearer YOUR_KEY. Check for accidental whitespace or a revoked key.
Saved file is text or JSON instead of an image The request failed, but the error body was written to the image path. Check the HTTP status before saving. Inspect the response content type and error body without exposing secrets.
Screenshot shows a login page The target requires a session or authentication headers. Use the documented cookie or header options where appropriate, then inspect X-Page-Status for the final document status.
Screenshot shows a 401 or 403 page The page denied access after redirects, or the capture does not have the needed credentials. Check the final page status header, the target URL, and any required cookies or headers.
Mobile layout still looks like desktop Width or height was omitted, misspelled, or exceeded the supported limit; the page may also use its own responsive breakpoints. Set width and height explicitly within the documented ranges. Verify the URL and inspect the page’s responsive behavior at that CSS viewport.
Content is missing from the image The page renders content after navigation or needs session data. Try a short documented delay or provide required cookies and headers. Confirm the content appears in a normal browser under the same access conditions.
Request times out The page or capture took longer than the configured limit, or your client stopped waiting too soon. Keep the client timeout longer than the capture timeout; use a suitable API timeout within the documented 1–30 second range. Check whether the page is reachable and simplify the target if possible.
URL is rejected It may lack an HTTP(S) scheme or exceed 2,048 characters. Use a complete https:// or http:// URL and shorten unnecessary query parameters.
Output is blurry or unexpectedly large The selected scale affects output pixel density and file size. Use scale 1 as a baseline; raise it only when sharper output is needed, and compare at the same scale.

8. Performance, reliability, and cost

Capture time depends on the target page, its resources, and any delay you request. A larger scale creates more output pixels and can increase transfer and storage needs. Use only the viewport and image format your downstream task needs, avoid unnecessary delays, and set a client timeout that allows the capture request to finish.

For production workflows, check HTTP success before treating bytes as an image, record the final page status when diagnosing unexpected content, and retry only transient failures with a bounded retry policy. A retry can create another render request; check the current plan and billing terms before building high-volume automation. ScreenshotAPI.net’s product page advertises 100 free renders per month with no credit card. Treat that as the vendor’s offer and verify current plan terms on its site before relying on it.

9. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. Send one GET request with a URL to receive a PNG, JPEG, WebP, or PDF. Its capture flow accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the page verdict and billing status in headers. AI agents can use its MCP server tools: take_screenshot, get_page_info, and capture_pdf.

Install the Python dependency with python -m pip install requests, set SCREENSHOTNEO_API_KEY, and run:

import os
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={
        "access_key": os.environ["SCREENSHOTNEO_API_KEY"],
        "url": "https://example.com",
        "width": 375,
        "height": 812,
        "format": "png",
    },
    timeout=90,
)
r.raise_for_status()
with open("mobile-shot.png", "wb") as image_file:
    image_file.write(r.content)

The same request in cURL:

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://example.com \
  -d width=375 \
  -d height=812 \
  -d format=png \
  -o mobile-shot.png

And in Node.js:

const q = new URLSearchParams({
  access_key: process.env.SCREENSHOTNEO_API_KEY,
  url: 'https://example.com',
  width: '375',
  height: '812',
  format: 'png',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo request failed: HTTP ${res.status}`);
await import('node:fs/promises').then(({ writeFile }) =>
  writeFile('mobile-shot.png', new Uint8Array(await res.arrayBuffer()))
);

ScreenshotNeo has 63 options, including 12 device presets, custom viewports, full-page capture with lazy images loaded, element capture, dark mode, custom CSS and JavaScript, waits, request blocking, cookies, headers, user agents, and caching with a chosen TTL. See the ScreenshotNeo API documentation for request options. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for ScreenshotNeo free.

FAQ

Does setting a mobile viewport reproduce a real phone?

It sets the page’s CSS viewport dimensions. The researched documentation does not establish equivalence to a particular phone’s browser interface or hardware behavior.

Can I get a JSON response with a URL to the screenshot?

The documented endpoint returns the image bytes themselves. Write the response body to a binary file.

How do I compare two mobile screenshots fairly?

Use the same viewport width and height, format, and scale, and make sure both captures use the same target state and session conditions.

Can I use a viewport wider than 3840 pixels?

The current documentation lists 3840 as the maximum width. Choose a supported width and height for the capture.