ScreenshotNeo

BlogHTML to image & PDF

How to Convert a Full Webpage to PDF with the Html2Pdf.app API

Convert a public webpage or raw HTML to PDF with Html2Pdf.app. Learn the request, binary response handling, rendering options, callbacks, and fixes for common output issues.

By the ScreenshotNeo team4 October 20269 min read

To convert a full webpage to PDF with Html2Pdf.app, send a server-side POST request to https://api.html2pdf.app/v1/generate, put the publicly reachable page URL in the required html field, and authenticate with your API key in the X-API-Key header. A successful synchronous response is PDF bytes, so check the HTTP status and save or stream the response as binary data rather than trying to parse it as JSON.

The same html field accepts raw HTML when you want to render application-generated markup. The API documentation describes its renderer as headless Chromium with support for modern HTML, CSS, and JavaScript. See the Html2Pdf.app API documentation for current parameters and limits.

1. Choose URL input or raw HTML

Use a URL when the source is a public webpage and its stylesheets, fonts, images, and scripts can be reached by the renderer. Use raw HTML when your application already has the markup to render or when you need to generate a document from application data. With raw HTML, include or otherwise make available the CSS and assets that the document needs.

Input Use it when Check
Public URL The page is already hosted and accessible to the conversion service. The URL works without a private login or network access unavailable to the service; page assets are reachable.
Raw HTML Your server builds the document markup or report. Include required styles and ensure linked assets can load. Treat submitted markup and data according to your privacy requirements.

The endpoint and authentication shape are the same for both. A minimal JSON request is:

POST https://api.html2pdf.app/v1/generate
Content-Type: application/json
X-API-Key: YOUR_API_KEY

{"html":"https://example.com"}

2. Make the request and preserve the PDF bytes

Keep the API key in a backend, trusted server-side script, or protected job. Do not put it in browser JavaScript, public repositories, or client-side templates. The examples below check for an HTTP error before writing the response body.

cURL

curl --fail-with-body \
  --request POST \
  --url https://api.html2pdf.app/v1/generate \
  --header "Content-Type: application/json" \
  --header "X-API-Key: ${HTML2PDF_API_KEY}" \
  --data '{"html":"https://example.com"}' \
  --output webpage.pdf

Set HTML2PDF_API_KEY in the shell environment before running this command. --output writes the response bytes directly to a file. If your cURL version does not support --fail-with-body, use --fail or check the exit status and HTTP response before treating the output as a PDF.

Python

import os
import requests

api_key = os.environ["HTML2PDF_API_KEY"]
response = requests.post(
    "https://api.html2pdf.app/v1/generate",
    headers={
        "X-API-Key": api_key,
        "Content-Type": "application/json",
    },
    json={"html": "https://example.com"},
    timeout=120,
)
response.raise_for_status()

with open("webpage.pdf", "wb") as pdf_file:
    pdf_file.write(response.content)

Use wb so Python writes the response unchanged as bytes. For large documents, use stream=True and write iter_content() chunks to avoid holding the entire file in memory.

Node.js

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

const response = await fetch("https://api.html2pdf.app/v1/generate", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": apiKey,
  },
  body: JSON.stringify({ html: "https://example.com" }),
});

if (!response.ok) {
  const detail = await response.text();
  throw new Error(`Html2Pdf.app returned ${response.status}: ${detail}`);
}

const pdfBytes = new Uint8Array(await response.arrayBuffer());
const { writeFile } = await import("node:fs/promises");
await writeFile("webpage.pdf", pdfBytes);

Use arrayBuffer() for the successful response. Calling response.json() or converting the body to a text string corrupts a binary PDF. In a web server, you can send the bytes to the caller with a PDF content type and an attachment filename instead of writing a local file.

3. Tune page size, pagination, and rendering

Rendering settings affect pagination and appearance. Start with defaults, then adjust the options that correspond to the desired printed document. The vendor documents these relevant settings:

Option What it controls Practical guidance
orientation Portrait or landscape layout. Choose landscape for wide tables or dashboards; verify page breaks after changing it.
format Paper format: Letter, Legal, Tabloid, Ledger, and A0 through A6. Choose the page standard expected by the reader or printer.
width, height Custom page dimensions in pixels. Use custom dimensions when the listed paper formats do not fit. Confirm units and supported combinations in the current docs.
Margins Top, right, bottom, and left page margins. Leave enough top or bottom space for header and footer templates.
printBackground / print styling The documentation exposes print or screen CSS media selection. Use the media mode that matches the source design; print styles may intentionally hide navigation or change colors.
scale Rendering scale, documented range 0.1–2. Adjust modestly if content clips or is too small; scale can also change page breaks.
waitFor Wait time for JavaScript or asynchronous resources, documented range 0–10 seconds. Increase when client-rendered content is absent at capture time. It cannot make an inaccessible asset reachable.
Header and footer templates Repeated page header or footer content. Reserve enough corresponding margin so the template does not overlap page content.
Filename Output document filename metadata or naming option. Use a safe, meaningful name; verify exact parameter spelling in the current docs.

Exact JSON property names for some layout settings can change or differ from the labels used in prose. Use the current parameter reference when adding them; do not assume an HTML attribute or a similarly named option is accepted. Keep a representative test page for each layout pattern in your own integration and review the resulting PDF when changing media, fonts, resources, or wait settings.

4. Use a callback for background generation

Use the synchronous response when the caller can wait and consume the PDF immediately. For background work, the documentation describes a callBackUrl workflow: the completed PDF is POSTed to your callback URL as base64 data in a document field. An optional state value is returned unchanged so you can correlate the result to the originating job.

Callback handling outline:

  1. Expose an HTTPS callback endpoint that can accept the vendor’s completion POST.
  2. Include a correlation value in state and persist the originating job identifier.
  3. Decode the received document base64 value to bytes before storing or serving the PDF.
  4. Validate the callback according to the authentication or verification mechanism documented for your account before trusting the payload.
  5. Make processing idempotent so a retried callback cannot create duplicate downstream work.

Callbacks trade direct response handling for an application endpoint and job lifecycle. Confirm callback payload details and any delivery or verification guarantees in the current vendor documentation before production use; this dossier does not establish those guarantees.

5. Troubleshoot blank, incomplete, or incorrectly paginated PDFs

Symptom Likely cause What to check or change
Authentication or request error Missing/invalid API key, wrong header, malformed JSON, or unsupported option value. Confirm the key is sent as X-API-Key, the body is valid JSON, and option names and ranges match the current API docs. Keep secrets out of logs.
The saved file is not a PDF An HTTP error response was written as if it were successful PDF output, or the client decoded binary as text. Check status before saving; inspect error text only on failure. Write response bytes unchanged.
Blank PDF or navigation/error page The source is not publicly reachable by the conversion service, or it redirects to an access challenge/login. Check public accessibility and redirect behavior. A URL available only inside your private network may not be fetchable by a hosted service.
Missing CSS, fonts, or images Assets are blocked, private, relative to an unexpected base, or otherwise unreachable. Make required resources reachable to the renderer, use valid absolute asset URLs where appropriate, and inspect the page’s network dependencies.
JavaScript content is missing The page renders content after the capture starts. Use waitFor within its documented 0–10 second range. If the application controls the page, make the required content render deterministically before conversion.
Colors or layout differ from the browser Print versus screen CSS, available fonts, media queries, or viewport-related layout differs. Try the other documented CSS media mode, ensure fonts load, and adjust the layout for printing where needed.
Content is clipped or page breaks are poor Paper format, orientation, margins, or scale do not suit the page. Try landscape or a larger format, adjust margins and scale, and use print CSS to control breaks for long sections or tables.
Header or footer overlaps content Insufficient top or bottom margin. Increase the matching margin to reserve room for the template.

6. Security, reliability, performance, and cost considerations

Protect credentials and source data

Call the API from a trusted backend and load the key from a secret store or environment configuration. Avoid logging the key or placing sensitive values in public URLs. Html2Pdf.app states that generated PDFs are processed temporarily and are not permanently stored on its servers; its docs also say raw HTML or text in the html parameter is not stored in conversion logs, while selected request metadata and a source URL supplied in html may be retained. These are vendor statements, not an independent audit. Review the vendor’s privacy policy and data processing agreement for sensitive or regulated workloads.

Plan for variable page behavior

JavaScript timing, external resources, font availability, and page-specific print styles can change output. Use a finite client timeout appropriate to your application, handle non-success HTTP statuses, and keep failed jobs observable with a correlation ID. Retry only errors that are plausibly transient, with bounded backoff; repeated retries will not fix a private URL, invalid request, or missing asset.

Manage response size and expense

A PDF response occupies memory if buffered in full. Stream to storage for large files, or return it incrementally from your own server where supported. The dossier establishes the API request and rendering settings but does not provide pricing, quotas, rate limits, or comparative performance data, so check current vendor terms and your account before estimating cost or throughput. Do not assume that adding wait time makes conversion more reliable; it only gives delayed page work more time to finish.

7. Or skip the browser setup

If your goal is a clean website capture or a PDF capture through a screenshot API, ScreenshotNeo accepts a URL in one API call and can return a PDF. The code below uses the documented endpoint and options. See the ScreenshotNeo API documentation for supported parameters.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://example.com \
  -o shot.pdf

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com", "format": "pdf"},
    timeout=90,
)
r.raise_for_status()
open("shot.pdf", "wb").write(r.content)

Node.js

const q = new URLSearchParams({
  access_key: process.env.SCREENSHOTNEO_API_KEY,
  url: 'https://example.com',
  format: 'pdf',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo returned ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
const { writeFile } = await import('node:fs/promises');
await writeFile('shot.pdf', bytes);

ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up free for ScreenshotNeo.

8. Frequently asked questions

Can the API convert a page that requires my browser login?

The documented URL workflow is for a publicly reachable webpage. The research does not establish a supported authenticated-page workflow; check current documentation for supported access mechanisms, and do not send credentials in a URL.

Can I use the result directly in an HTTP response?

Yes. Treat a successful synchronous response as binary PDF data and stream or send those bytes with an appropriate PDF content type and a download filename. Do not JSON-decode the body.

Does waitFor guarantee all page work has completed?

No such guarantee is established in the reviewed documentation. It is a bounded wait setting for JavaScript or asynchronous resources; verify the output for pages with delayed content.

Does the API support HTML I generate myself?

Yes. The required html field accepts raw HTML as well as a public URL.