How to capture a website screenshot as a PDF with ScreenshotAPI
Use ScreenshotAPI’s render endpoint to turn a website URL or HTML into a PDF. Configure page size, orientation, page ranges, and loading controls.
To capture a website as a PDF with ScreenshotAPI, send a GET or POST request to its v3 render endpoint with your API token, the target URL, and file_type=pdf. Add PDF options to choose a standard page format, orientation, and optional page range. For pages that load content after navigation, the documentation describes delay and lazy-loading controls. These are rendering controls, not a guarantee that every site will produce a complete or perfectly paginated PDF.
ScreenshotAPI documents URL-to-PDF and raw-HTML-to-PDF workflows. Its PDF options and endpoint are described in the PDF rendering guide and render endpoint documentation. The examples below use the documented endpoint pattern; check the current docs for the latest parameter syntax before putting a request into production.
1. Get an API token and choose your input
- Create or sign in to a ScreenshotAPI account and get an API token from the dashboard, as described in its getting-started documentation.
- Choose a publicly fetchable URL, or use the custom HTML option when you already have markup to render.
- Keep the token in server-side configuration or a secret manager. Do not put a long-lived API token in browser JavaScript, a public repository, or a URL that will be shared. This is standard API-key handling advice; it is not a claim about ScreenshotAPI’s implementation.
The documented v3 endpoint pattern is https://shot.screenshotapi.net/v3/screenshot. The response for file_type=pdf is a PDF file, so save the response body as a .pdf rather than printing it as text. See the endpoint reference.
2. Make a basic PDF request
Here is a cURL request for a Letter-sized, portrait PDF with printed backgrounds enabled. Replace YOUR_TOKEN and the example URL. The PDF option parameter names are shown in ScreenshotAPI’s PDF documentation.
curl --get 'https://shot.screenshotapi.net/v3/screenshot' \
--data-urlencode 'token=YOUR_TOKEN' \
--data-urlencode 'url=https://example.com' \
--data-urlencode 'file_type=pdf' \
--data-urlencode 'pdf_options[format]=Letter' \
--data-urlencode 'pdf_options[landscape]=false' \
--data-urlencode 'pdf_options[print_background]=true' \
--output page.pdf
Using --data-urlencode matters: URLs and nested option values can contain characters that otherwise change the query string. The documentation’s endpoint examples use the v3 render route and token, URL, and output type. Confirm the accepted format names in the live PDF options reference when selecting a format other than Letter.
3. Configure paper size, orientation, and page range
| Need | Option | What it does |
|---|---|---|
| Conventional pagination | pdf_options[format] |
Choose a standard paper format such as A4, A3, or Letter. The PDF guide describes standard formats. |
| Wide tables or dashboards | pdf_options[landscape]=true |
Switches the selected format to landscape. The documented default is portrait (false). |
| Include page backgrounds | pdf_options[print_background]=true |
Requests printing of page backgrounds. Check the resulting PDF for site-specific print styling. |
| Export only selected pages | pdf_options[page_range]=2-6 |
Keeps pages 2 through 6 after rendering. The range uses a start-end string. |
If you omit a page format and explicit dimensions, ScreenshotAPI documents that the web page can render as one long PDF page. That can be useful for archiving a long article, but it is often awkward to print or browse as a conventional document. Setting a paper format paginates the output. Landscape can help when a table is too wide for portrait orientation; it does not guarantee that every column will fit without scaling or wrapping.
Page ranges are applied after the full document has been rendered. If the end page is higher than the rendered page count, the documentation says the range is clipped to the available pages. A page range has no effect on a single-page PDF. Use a range only after choosing a paginated layout, and remember that it does not reduce the work needed to render the whole page. Source: PDF rendering options.
4. Python example
This example streams the response to disk and checks for an HTTP error before saving it. Install requests with python -m pip install requests. Keep the token in an environment variable in real deployments.
import os
import requests
TOKEN = os.environ["SCREENSHOTAPI_TOKEN"]
params = {
"token": TOKEN,
"url": "https://example.com",
"file_type": "pdf",
"pdf_options[format]": "A4",
"pdf_options[landscape]": "false",
"pdf_options[print_background]": "true",
"pdf_options[page_range]": "1-5",
}
with requests.get(
"https://shot.screenshotapi.net/v3/screenshot",
params=params,
stream=True,
timeout=(10, 180),
) as response:
response.raise_for_status()
content_type = response.headers.get("content-type", "")
if "pdf" not in content_type.lower():
raise RuntimeError(f"Expected a PDF response, got {content_type!r}")
with open("page.pdf", "wb") as pdf_file:
for chunk in response.iter_content(chunk_size=64 * 1024):
if chunk:
pdf_file.write(chunk)
print("Saved page.pdf")
The timeout values are client-side examples, not ScreenshotAPI service limits. Set them for your own workload and the maximum render time you can tolerate. The service may return an error response; check the status and content type before treating a response body as a PDF.
5. Node.js example
This example uses the built-in fetch available in current Node.js releases. It writes the response bytes to a file and rejects unsuccessful responses.
import { writeFile } from "node:fs/promises";
const token = process.env.SCREENSHOTAPI_TOKEN;
if (!token) throw new Error("Set SCREENSHOTAPI_TOKEN first");
const params = new URLSearchParams({
token,
url: "https://example.com",
file_type: "pdf",
"pdf_options[format]": "A4",
"pdf_options[landscape]": "false",
"pdf_options[print_background]": "true",
"pdf_options[page_range]": "1-5",
});
const response = await fetch(
`https://shot.screenshotapi.net/v3/screenshot?${params}`,
{ signal: AbortSignal.timeout(180_000) },
);
if (!response.ok) {
const detail = await response.text();
throw new Error(`ScreenshotAPI returned HTTP ${response.status}: ${detail}`);
}
const contentType = response.headers.get("content-type") ?? "";
if (!contentType.toLowerCase().includes("pdf")) {
throw new Error(`Expected PDF response, got ${contentType}`);
}
await writeFile("page.pdf", Buffer.from(await response.arrayBuffer()));
console.log("Saved page.pdf");
6. cURL with selected pages and landscape layout
For a wide report where only pages 2–6 are needed, change the relevant options:
curl --get 'https://shot.screenshotapi.net/v3/screenshot' \
--data-urlencode 'token=YOUR_TOKEN' \
--data-urlencode 'url=https://example.com/report' \
--data-urlencode 'file_type=pdf' \
--data-urlencode 'pdf_options[format]=A4' \
--data-urlencode 'pdf_options[landscape]=true' \
--data-urlencode 'pdf_options[print_background]=true' \
--data-urlencode 'pdf_options[page_range]=2-6' \
--output report-pages-2-to-6.pdf
Do not assume a page range makes capture faster: the documented operation renders the pages first and trims afterward. For large HTML inputs, use the documented POST approach rather than putting the full markup into a GET URL, which has URL length limits. See the PDF guide and endpoint docs.
7. Handle dynamic content and page styling
Some sites load content after the initial document response, defer images until they approach the viewport, or need a print-specific layout. ScreenshotAPI documents these relevant controls:
- Delay: wait before rendering to give delayed content time to appear. A fixed delay adds time to every request and cannot guarantee that a variable or failed request has completed.
- Lazy loading: use the documented lazy-load option to help load deferred content and images. Verify that the target page’s specific lazy-loading behavior appears in the PDF.
- CSS and JavaScript injection: apply page-specific styling or behavior before capture when needed. The docs describe inline or externally supplied CSS/JavaScript; injected code can change what is rendered, so keep it narrow and review the result.
For example, the PDF guide documents combining PDF output with delay, lazy loading, and CSS/JavaScript injection. Use the parameter names and accepted values from the current PDF rendering documentation, delay and lazy-loading reference, and injection reference. The research for this article did not execute requests or independently verify output quality; rendering depends on the target site.
8. Render raw HTML instead of a URL
When you have generated markup and do not want the renderer to fetch a public page, ScreenshotAPI documents a custom HTML input option. Use POST for large HTML because GET URLs have length limits. The endpoint docs describe custom HTML, and the PDF guide covers HTML-to-PDF output: render endpoint and PDF guide.
Check the current endpoint reference for the exact request body and HTML parameter name before implementing this variant; do not place substantial markup in a query string. Treat the HTML as untrusted input if it comes from users, and avoid injecting secrets or privileged internal content into a rendering request.
9. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| Saved file is an error page or not a PDF | The request failed, or the client saved an error response as if it were the PDF. | Check the HTTP status and response content type before writing the file. Read the error body for diagnostics; do not publish it as a PDF. |
| Unauthorized response | Missing, invalid, or incorrectly named token parameter; token may also have been copied incorrectly. | Confirm the token from the account dashboard and the current endpoint’s parameter name. Keep it out of public client code. |
| The target page is missing or redirects unexpectedly | The renderer cannot access the URL as requested, or the page requires a login, consent, or network access that the request does not provide. | Check the URL in a normal browser, redirect behavior, and the current API documentation for supported authentication and request options. Do not assume a private page is accessible without supplying the required credentials. |
| Images or below-the-fold content are absent | Content may load lazily or after the initial render. | Try the documented lazy-load option or a suitable delay, then inspect the output. Increasing delay alone may not fix failed resources. |
| Content is cut off or hard to read | A single long page, an unsuitable paper format, portrait orientation for wide content, or site-specific print styles. | Choose a standard format for pagination, try landscape for wide content, and use documented CSS injection only when the layout needs adjustment. |
| Requested page range contains fewer pages than expected | The range is applied after rendering and its end is clipped to the actual page count; the PDF may also be a single page. | Render without a range once to inspect pagination, then set a range within the available pages. A range does not affect a single-page output. |
| GET request is too long | The URL or raw HTML creates an oversized query string. | Use the documented POST method for large HTML or requests that exceed practical URL limits. |
| Background colors are missing | Background printing was not enabled or the page’s print styles omit them. | Try pdf_options[print_background]=true and inspect the result; site CSS can still affect print output. |
10. Performance, reliability, and cost considerations
- Rendering time: each added delay increases end-to-end latency. Lazy loading and scripts may also require more rendering work. Choose only the controls the target page needs.
- PDF size: large pages, many images, and high-detail assets can produce larger files. If you distribute PDFs, account for storage and transfer separately from API usage.
- Page ranges: because the range is applied after full rendering, it limits the final document but does not avoid rendering earlier or later pages.
- Reliability: handle non-success HTTP responses, timeouts, and non-PDF bodies. For repeatable documents, use stable page URLs and validate that important sections appear in output. The documentation describes controls but does not guarantee identical results across changing sites.
- Freshness: the getting-started documentation describes
fresh=truefor requesting a current capture where a prior screenshot may be cached. Consult the current getting-started docs for its exact behavior and use it when stale output is a concern. - Cost: the research sources reviewed for this guide do not establish current ScreenshotAPI pricing or per-render charges. Check the vendor’s current account or pricing information before estimating production cost; do not assume a page range or a failed render is free.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It can return a screenshot or PDF from one GET request. Its clean-shot flow accepts consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. See the ScreenshotNeo site and API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Use the documented PDF output option when you need a PDF; the example above shows the required one-call request shape. ScreenshotNeo includes every feature on every plan: 1,000 screenshots a month free with no card, then paid plans start at $5 for 3,000 screenshots. Sign up for the free plan.
FAQ
Can I turn a private, login-protected page into a PDF?
The cited endpoint documentation establishes URL and HTML rendering, but this guide’s research did not verify a particular authentication flow. Consult the current endpoint options and provide credentials only through supported, secure request parameters.
Can I use a custom page width and height?
The PDF documentation covers standard page formats and notes that explicit dimensions can affect single-page output. Check the current PDF options reference for accepted dimension parameters and units.
Does selecting pages 2–6 make the capture faster?
No. The documented page range is applied after the full document has been rendered.
Will a delay guarantee that every animation or API request finishes?
No. A delay is a timing control, not a guarantee. Pages with variable load behavior need output validation and may require different page-specific handling.


