Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Run Gotenberg in Docker, then send a multipart POST request to /forms/chromium/convert/html with a file named index.html. Upload every stylesheet, image, font, or script the document needs in the same request, save the successful response body as a PDF, and reference those assets by filename. If the source is already a reachable website, use /forms/chromium/convert/url instead; that route does not accept file:// addresses.

This guide covers local files, remote URLs, asset paths, dynamic pages, Python and Node.js clients, failure handling, and an option that avoids maintaining a browser container when you only need a rendered capture.

Choose the Gotenberg route that matches your input

Gotenberg uses headless Chromium to render HTML and return a file. The two relevant routes differ by where Chromium obtains the document:

Input Route Request field Important constraint
Local HTML plus uploaded assets /forms/chromium/convert/html Multipart files, including index.html Uploads are placed in one flat directory; use filename references.
Web page available at a URL /forms/chromium/convert/url Multipart url file:// URLs return HTTP 400.

Use the HTML route when the source is on disk or must remain private. Use the URL route when the page is publicly or internally reachable by the Gotenberg container and its JavaScript needs to run in a browser context.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Canon Canoscan Lide 300 Scanner (PDF, AUTOSCAN, Copy, Send)
  • Scanner type: Document
  • Connectivity technology: USB
  • With Auto Scan Mode, the scanner automatically detects what you're scanning
  • Digitize documents and images

Start Gotenberg with Docker

Gotenberg is documented as a Docker-based conversion API. Publish port 3000 and run the container:

docker run --rm -p "3000:3000" gotenberg/gotenberg:8

Leave that process running. The API is then available at http://localhost:3000 from the host. In a deployed setup, put the container on a private network and expose the API only to trusted callers; the conversion service can fetch URLs and process uploaded content, so it should not be treated as an unauthenticated public endpoint.

Convert a local HTML file

  1. Prepare the entry file. Name the uploaded document index.html. The HTML route requires that filename; a file called report.html should be copied or renamed before submission.
  2. Collect dependencies. Put images, CSS, fonts, and scripts beside the document for the upload. Every dependency that is not available from a reachable URL must be sent as another multipart files part.
  3. Use filename-based references. If you upload logo.png, reference logo.png in the HTML. Do not use /logo.png, ./assets/logo.png, or an absolute path from your workstation: Gotenberg stores uploaded files in a flat directory.
  4. POST the form and write the response. A successful conversion is HTTP 200 and the response body is the PDF.

A minimal document might look like this:

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <img src="logo.png" alt="Company logo">
    <h1>Invoice</h1>
  </body>
</html>

Submit it with cURL:

curl 
  --request POST http://localhost:3000/forms/chromium/convert/html 
  --form files=@/path/to/index.html 
  --form files=@/path/to/styles.css 
  --form files=@/path/to/logo.png 
  -o invoice.pdf

For a document with no external assets, the shorter request is sufficient:

curl 
  --request POST http://localhost:3000/forms/chromium/convert/html 
  --form files=@/path/to/index.html 
  -o my.pdf

Do not print the binary response to a terminal. The -o option writes the PDF exactly as returned by Gotenberg.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Call the same endpoint from Python

The following example uploads the entry file and an image, checks the HTTP result, and writes the PDF:

Rank #2
Sale
Brother DS-640 Compact Mobile Document Scanner, (Model: DS640)
  • FAST SPEEDS - Scans color and black and white documents a blazing speed up to 16ppm (1). Color scanning won’t slow you down as the color scan speed is the same as the black and white scan speed.
  • ULTRA COMPACT – At less than 1 foot in length and only about 1. 5lbs in weight you can fit this device virtually anywhere (a bag, a purse, even a pocket).
  • READY WHENEVER YOU ARE – The DS-640 mobile scanner is powered via an included micro USB 3. 0 cable allowing you to use it even where there is no outlet available. Plug it into you PC or laptop and you are ready to scan.
  • WORKS YOUR WAY – Use the Brother free iPrint&Scan desktop app for scanning to multiple “Scan-to” destinations like PC, Network, cloud services, Email and OCR. (2) Supports Windows, Mac and Linux and TWAIN/WIA for PC/ICA for Mac/SANE drivers. (3)
  • OPTIMIZE IMAGES AND TEXT – Automatic color detection/adjustment, image rotation (PC only), bleed through prevention/background removal, text enhancement, color drop to enhance scans. Software suite includes document management and OCR software. (4)
import requests

url = "http://localhost:3000/forms/chromium/convert/html"
with open("index.html", "rb") as html_file, open("logo.png", "rb") as image_file:
    files = [
        ("files", ("index.html", html_file, "text/html")),
        ("files", ("logo.png", image_file, "image/png")),
    ]
    response = requests.post(url, files=files, timeout=90)

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

The tuple filename for the first part is deliberately index.html. If your local path has another name, setting the multipart filename to index.html satisfies the route’s requirement.

Call it from Node.js

Node.js versions with built-in fetch, FormData, and Blob can submit the files without an additional HTTP library:

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

const form = new FormData();
form.append("files", new Blob([await readFile("index.html")], { type: "text/html" }), "index.html");
form.append("files", new Blob([await readFile("styles.css")], { type: "text/css" }), "styles.css");
form.append("files", new Blob([await readFile("logo.png")], { type: "image/png" }), "logo.png");

const response = await fetch("http://localhost:3000/forms/chromium/convert/html", {
  method: "POST",
  body: form
});

if (!response.ok) {
  throw new Error(`Gotenberg returned ${response.status}: ${await response.text()}`);
}

const pdf = Buffer.from(await response.arrayBuffer());
await import("node:fs/promises").then(({ writeFile }) => writeFile("output.pdf", pdf));

Do not set a manual Content-Type header for a FormData request. The runtime adds the multipart boundary; overriding it can make Gotenberg reject an otherwise valid upload.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make asset paths work in a flat upload directory

The HTML route does not preserve your local directory tree. Uploading assets/logo.png does not create an assets directory inside the conversion workspace. Either upload the file with the flat filename and change the document to logo.png, or generate a self-contained HTML document with data URLs.

  • Use relative filename references such as styles.css and logo.png.
  • Upload each referenced local file as its own files part.
  • Keep names unique; two files with the same basename can collide in the flat workspace.
  • For remote fonts, images, or stylesheets, verify that Chromium in the container can reach the host and that the server returns them without an interactive login.

A missing asset often produces a valid-looking PDF with blank areas rather than an HTTP error, so inspect the output visually and check the browser-facing URLs independently.

Rank #3
Plustek PS186 Desktop Document Scanner, with 50-Pages Auto Document Feeder (ADF). for Windows 7/8 / 10/11 (Intel/AMD only)
  • Up to 255 customize favorite scan file setting with "Single Touch" , Support Windows 7/8/10
  • Turn paper documents into searchable, editable files - save scans as searchable PDF files; OCR function included
  • Info Barcode function - automatic categorization of complicate documentation and data with 1D or 2D Barcode page.
  • Intelligent color and image adjustments — Auto Rotate, Crop, Deskew and blank page remove with Plustek Image Processing Technology
  • Easy send scanned files to FTP server or personal NAS (FTP) with PDFs , Jpeg , TIFF or Png format. User can download scanner driver from Plustek website

Convert a page that already has a URL

For a web page, submit the address in the url form field to the URL route:

curl 
  --request POST http://localhost:3000/forms/chromium/convert/url 
  --form url=https://example.com 
  -o page.pdf

The URL must be reachable from the Gotenberg container, not merely from your laptop. A hostname available only through a host-machine shortcut may fail from inside Docker. The URL route supports JavaScript execution and waiting controls, which makes it suitable for applications that build their content after the initial response.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do not pass a local path as file://. That input returns HTTP 400. Serve the document over an HTTP endpoint that the container can reach, or use the HTML route and upload the files directly.

Wait for dynamic content before rendering

Chromium can execute page JavaScript, but conversion can begin before an asynchronous chart, API response, image, or font has finished. The route documentation provides request controls for waiting:

  • Fixed delay: pause for a known number of milliseconds when the page has a predictable startup time.
  • DOM selector or expression: continue only after a marker element or condition indicates that rendering is complete.
  • Failed-asset behavior: configure how conversion reacts when a resource fails instead of silently accepting an incomplete page.

Choose the smallest wait that reliably produces complete output. A long fixed delay increases latency without guaranteeing correctness when an upstream request is slow. A selector that your application adds after data binding is usually more deterministic. Treat these as request controls, not a promise that every third-party page will finish successfully.

Rank #4
Hczrc Portable Scanner, Photo Scanner for A4 Documents, Handheld Scanner for Business, Photo, Picture, Receipts, Books, JPG/PDF Format Selection, UP to 900 DPI, with 16G SD Car
  • Note: No software installation is required. You need 2 AA batteries ( not included) and a memory card ( included) to use it directly. Scan mode: Press and hold "Scan" for 2 seconds to turn on the device, and then press "Scan", the green light is on. The scanner moves to scan the file until the green light turns off automatically (or press the "Scan" key and the green light goes out). The number shown on the display increases by 1 to indicate that the scan is complete.
  • Portable Scanner scans images or pictures quickly: Store JPEG/PDF files within seconds, scan images or pictures quickly, plug and play, no need any software preinstalled. Compatible with Windows XP/7/Vista/Mac OS 10.4 or above version.
  • Lightweight and travel-friendly: Stored in Micro SD card directly, support read data on your computer or phone with USB connected. Powered by 2pcs AA batteries, Compact Design, it is convenient to carry outside.
  • 3 Image Resolution: 3 modes of resolution for your options: 300dpi/600dpi/900dpi, you can save it at the clearest way, picture and document are showed clear as it is. Freely choose your favorite resolution.File Format: JPEG/PDF format is all available, Great storage capacity as it supports 32G Micro SD card(Included 16GB Card),total meet your need for business trip or daily use.
  • Widely Used: It is applicable in bank, insurance business, real estate agency,home, office, library or outdoors. suitable for lawyer, businessmen, students, travelers and amateur archivists. Scan your important files and save them immediately, no struggling in finding a printing shop, keep it confidential.

Understand responses and failure modes

HTTP result Meaning What to check
200 PDF created; the response body contains the file. Save the binary body and verify the PDF opens.
400 Invalid form input, including an unsupported field or a file:// URL on the URL route. Check the route, field names, and required index.html filename.
503 Conversion did not complete within the configured maximum duration. Inspect page reachability, asset waits, JavaScript work, and resource availability; then adjust the request or deployment limits.

All conversion routes use a multipart/form-data POST and return a file. Have clients check the status before writing the body as a PDF; otherwise an error message can be saved with a .pdf extension.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot the common problems

“Required file index.html is missing”

The multipart filename is not index.html. Rename the local file or set the upload filename explicitly, as shown in the Python and Node.js examples.

The PDF has no logo or styles

Upload every local dependency and replace directory or absolute paths with flat filenames. For remote dependencies, test reachability from the container and confirm the server does not require a browser-only session.

The URL conversion returns 400

Confirm that you used /forms/chromium/convert/url with a url field and an HTTP(S) address. Local file:// addresses are not accepted; use the HTML upload route instead.

The page is cut off before data appears

Add a selector-based or delay-based wait for the asynchronous work, and configure failed-asset handling where appropriate. A wait cannot repair an API that never responds, so inspect the page’s network dependencies as well.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
Sale
Epson Workforce ES-50 Compact & Lightweight Mobile Document Scanner
  • PORTABLE SCANNER FOR USE ON-THE-GO — The fastest and lightest mobile single-sheet-fed compact document scanner in its class¹
  • QUICK DOCUMENT SCANNING ― This Epson ultra-fast scanner scans a single page as quickly as 5.5 seconds²; Windows and Mac compatible
  • VERSATILE PAPER HANDLING ― Portable scanner scans documents up to 8.5 x 72 in; Also easily digitizes receipts and ID cards to make accounting, bookkeeping, and organizing simpler
  • INTUITIVE, HIGH-SPEED SOFTWARE — Epson ScanSmart Software³ is a smart tool allowing you to easily scan, review, and save; Stay organized easily with the help of this Epson scanner
  • EASY SETUP — USB-powered connect to your computer for quick and simple scanning; No batteries or external power supply required to operate portable document scanner; Standard Connectivity: USB 2.0

The request ends with 503

Look for a slow remote host, infinite JavaScript activity, an overly ambitious wait, or a resource that never loads. Reduce unnecessary work, make the completion condition explicit, and ensure the container can reach every required host.

The PDF opens as an error document

Check the HTTP status before saving. A 400 or 503 response is not a PDF even if your script writes it to output.pdf.

Operational notes for reliable conversions

  • Keep the input deterministic. Bundle critical CSS, images, and fonts when possible instead of relying on third-party hosts.
  • Use bounded waits. Selector-based completion avoids an arbitrary long sleep, while a fixed delay is useful only when the page’s timing is stable.
  • Validate output. Record the status code, preserve the response headers and size, and perform a PDF-open or page-count check in your own pipeline.
  • Plan for transient failures. Retry only failures that are plausibly temporary, with a limit and backoff; repeatedly retrying a page that always times out increases load without improving the result.
  • Do not infer a benchmark. Conversion time depends on HTML complexity, asset size, JavaScript, network conditions, and the container’s resources. The route documentation does not establish a universal throughput or latency figure.

Or skip the browser setup

If your requirement is a rendered image or PDF of a reachable web page rather than a self-hosted HTML-to-PDF pipeline, ScreenshotNeo provides a single request. Its API can return PNG, JPEG, WebP, or PDF; the example below captures a page and saves the response:

ScreenshotNeo 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

Before capture, ScreenshotNeo accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing result in X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create a free ScreenshotNeo account to try it without a card.

Which approach should you use?

  • Choose Gotenberg’s HTML route when your application owns local HTML and must upload its exact assets.
  • Choose Gotenberg’s URL route when a reachable page must be rendered with browser JavaScript and explicit waits.
  • Choose ScreenshotNeo when you want a managed capture endpoint, cleaned pages, billing only for clean shots, or MCP tools instead of operating the browser container yourself.

Frequently Asked Questions

Can I submit several HTML documents in one Gotenberg request?

The documented HTML workflow requires one uploaded entry file named index.html. Generate separate requests when you need separate documents.

Does Gotenberg preserve my local assets directory?

No. Uploaded files share a flat directory, so directory-based paths are not preserved; use uploaded basenames or embed the assets.

What should a client do with a non-200 response?

Read and log the status and error body, then stop before writing the response as a PDF. The documented HTML route uses 400 for invalid input and 503 for a conversion that exceeds its maximum duration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.