Skip to main content

Convert URL to PDF

Converts a target URL to PDF using Headless Chromium.

This route works by simulating a standard browser navigation: it connects to the URL, executes the necessary JavaScript, loads assets (CSS, images, fonts), and captures the final state of the DOM as a PDF. It supports Single Page Applications (SPAs) and dynamic content rendering.

Configuration

You can configure the Chromium module behavior. See the Chromium module configuration for details.

Basics

POST/forms/chromium/convert/url
Gotenberg-Output-Filenamestring
The filename of the resulting file - Gotenberg automatically appends the file extension. Defaults to a random UUID filename.
Gotenberg-Tracestring
A custom request ID to identify the request in the logs; overrides the default UUID.
urlstringrequired
URL of the page to convert into PDF.
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
-o my.pdf
The PDF file has been successfully created.
Content-Disposition: attachment; filename={output-filename.pdf}
Content-Type: {content-type}
Content-Length: {content-length}
Gotenberg-Trace: {trace}
Body: {output-file}

Rendering Behavior

paperWidthstring
Paper width (e.g. 8.5in). Standard units supported (in, pt, cm). Default is inches.
Default:8.5
paperHeightstring
Paper height (e.g. 11in). Standard units supported (in, pt, cm). Default is inches.
Default:11
marginTopstring
Top margin (e.g. 0.39in). Standard units supported (in, pt, cm). Default is inches.
Default:0.39
marginBottomstring
Bottom margin (e.g. 0.39in). Standard units supported (in, pt, cm). Default is inches.
Default:0.39
marginLeftstring
Left margin (e.g. 0.39in). Standard units supported (in, pt, cm). Default is inches.
Default:0.39
marginRightstring
Right margin (e.g. 0.39in). Standard units supported (in, pt, cm). Default is inches.
Default:0.39
landscapeboolean
Sets the paper orientation to landscape
Default:false
scalenumber
The scale of the page rendering (zoom factor).
Default:1.0
printBackgroundboolean
Includes background graphics/colors from the HTML.
Default:false
omitBackgroundboolean
Hides the default white background (allows transparency).
Default:false
singlePageboolean
Forces the entire content to fit on one very long page.
Default:false
preferCssPageSizeboolean
Uses page sizes defined in CSS (@page) instead of API parameters.
Default:false
emulatedMediaTypeenum
Media type to emulate ('screen' or 'print').
Default:print
waitDelaystring
Duration to wait before converting (e.g. '5s').
Default:None
waitForExpressionstring
Waits until this JavaScript expression returns true.
Default:None
waitForSelectorstring
Waits until the given selector (e.g., '#id') is visible on the page.
Default:None
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form paperWidth=8.27 \
--form paperHeight=11.7 \
--form marginTop=1 \
--form marginBottom=1 \
--form marginLeft=1 \
--form marginRight=1 \
--form landscape=true \
--form scale=2.0 \
--form printBackground=true \
--form omitBackground=true \
--form singlePage=true \
--form preferCssPageSize=false \
--form emulatedMediaType=screen \
-o my.pdf

Standard Paper Sizes

The following standard paper sizes are in inches (width x height), ordered from smallest to largest:

FormatDimensionsFormat (US)Dimensions
A64.13 x 5.83Letter8.5 x 11 (Default)
A55.83 x 8.27Legal8.5 x 14
A48.27 x 11.7Tabloid11 x 17
A311.7 x 16.54Ledger17 x 11
A216.54 x 23.4
A123.4 x 33.1
A033.1 x 46.8

Single Page

If singlePage is set to true, it automatically overrides the values from paperHeight and nativePageRanges.

CSS & Print Media

Chromium uses the print media type. By default, browsers optimize pages for printing by removing background colors/images and adjusting the layout to save ink.

If your generated PDF looks different from what you see in a browser viewport, it is likely because print media styles are being applied or background graphics are disabled.

Cheatsheets
  • Use @media print in your CSS to define specific styles for the PDF (e.g., hiding navigation bars or buttons).
  • Alternatively, use the emulatedMediaType form field to force the media type to screen.
  • To force background colors and images to appear, enable the printBackground form field in your request.
  • You can control paper size and margins via CSS using the @page rule. Note that for Gotenberg to respect these rules, you must enable the preferCssPageSize form field.

Background Logic

The final background depends on printBackground, omitBackground, and your document's CSS:

Print Background?Omit Background?HTML CSS has BG?Resulting Output
false(Any)(Any)No Background
true(Any)YesUses HTML CSS Background
truetrueNoTransparent
truefalseNoWhite (Default)

JavaScript & Dynamic Content

Chromium captures what is currently visible. If the page relies on JavaScript to render data, charts, or external content, the conversion might trigger before the rendering is complete, resulting in blank or incomplete sections.

Cheatsheets

If the content is generated dynamically:

  1. Use the waitDelay form field to add a fixed pause before conversion.
  2. For more precision, use the waitForExpression form field to trigger the conversion only when a specific JavaScript condition (e.g., window.status === 'ready') is met.

Wait Delay

Use this as a fallback when you cannot modify the target page's code. It forces Gotenberg to wait for a fixed duration before rendering, giving JavaScript time to finish execution.

Reliability Note

This method is "brute force". If the page loads faster, time is wasted. If it loads slower, the PDF will be incomplete. Use explicit waits (Expression or Selector) whenever possible.

cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form waitDelay=5s \
-o my.pdf

Wait For Expression

This is the most robust method for synchronization. It pauses the conversion process until a specific JavaScript expression evaluates to true within the page context. This ensures the PDF is generated exactly when your data is ready.

Example: Client-side logic

// Inside your HTML page.
window.status = "loading";

fetchData().then(() => {
renderCharts();
// Signal to Gotenberg that the page is ready.
window.status = "ready";
});
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
-- form 'waitForExpression=window.status === '\''ready'\''' \
-o my.pdf

Wait For Selector

Ideally suited for Single Page Applications (SPAs) or frameworks like React/Vue. This method delays the conversion until a specific HTML element - identified by a CSS selector - appears in the DOM.

Example: Dynamic Element Injection

// Inside your HTML page.
await heavyCalculation();

const completionMarker = document.createElement("div");
completionMarker.id = "app-ready"; // The selector we wait for.
document.body.appendChild(completionMarker);
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form 'waitForSelector=#app-ready' \
-o my.pdf

HTTP & Networking

cookiesjson
Array of cookies to add to the request.
Default:None
extraHttpHeadersjson
Custom HTTP headers for the request.
Default:None
userAgentstring
Overrides the default User-Agent header.
Default:None
skipNetworkIdleEventboolean
Does not wait for Chromium network to be idle.
Default:true
failOnHttpStatusCodesjson
Returns a 409 Conflict if Gotenberg receives these codes for the main URL.
Default:[499,599]
failOnResourceHttpStatusCodesjson
Returns a 409 Conflict if Gotenberg receives these codes for at least one resource (images/css/etc.).
Default:None
ignoreResourceHttpStatusDomainsjson
Excludes resources from failOnResourceHttpStatusCodes checks based on their hostname.
Default:None
failOnResourceLoadingFailedboolean
Returns a 400 Bad Request if assets (images/css/etc.) fail to load due to network errors.
Default:false
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form 'userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)"' \
--form skipNetworkIdleEvent=false \
--form failOnResourceLoadingFailed=true \
-o my.pdf

Cookies

The cookies form field accepts a JSON-formatted array of cookie objects. It allows you to authenticate requests or maintain session state during the conversion process.

Cookie Object Schema

KeyDescriptionDefault
nameThe name of the cookie.Required
valueThe value of the cookie.Required
domainThe domain the cookie applies to (e.g., example.com).Required
pathThe URL path the cookie applies to.None
secureIf true, the cookie is only sent over HTTPS.None
httpOnlyIf true, the cookie is inaccessible to JavaScript (document.cookie).None
sameSiteControls cross-site behavior. Values: "Strict", "Lax", "None".None

Session Lifecycle

Cookies are transient and automatically expire when the request reaches its time limit.

To ensure strict isolation between conversions (preventing data leakage), you can configure the API to explicitly clear the cookie jar after every request. See API Configuration for details.

cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form 'cookies=[{"name":"yummy_cookie","value":"choco","domain":"theyummycookie.com"}]' \
-o my.pdf

HTTP Headers

The extraHttpHeaders form field accepts a JSON-formatted object representing the HTTP headers to send with every request.

Schema

This is a key-value map where:

  • Key: The header name (e.g., Authorization, X-Custom-Header).
  • Value: The header value (string).
Scoped Headers

By default, headers are sent with every request made by the browser (including images, stylesheets, and scripts).

To restrict a header to specific URLs, append a ;scope= token containing a Regular Expression. Gotenberg will process this token and only send the header if the target URL matches the regex.

Example: "X-Internal-Token": "secret-123;scope=.*\\.internal\\.api"

  • Matches: https://data.internal.api/v1 (Header sent)
  • Ignores: https://google.com/fonts (Header NOT sent)

Note: The scope token is stripped before the header is sent to the server.

cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form-string 'extraHttpHeaders={"X-Header":"value","X-Scoped-Header":"value;scope=https?:\/\/([a-zA-Z0-9-]+\.)*domain\.com\/.*"}' \
-o my.pdf

Invalid HTTP Status Codes

You can configure Gotenberg to return a 409 Conflict error if the main page or its resources return specific HTTP status codes.

These fields accept a JSON-formatted array of integers.

FieldDescription
failOnHttpStatusCodesFails if the main page URL returns a matching code.
failOnResourceHttpStatusCodesFails if any asset (image, CSS, script) returns a matching code.

Status Code Ranges

You can define ranges using the X99 notation:

  • 499 matches every code from 400 to 499.
  • 599 matches every code from 500 to 599.

Domain Exclusions

Use ignoreResourceHttpStatusDomains to prevent failures for specific third-party assets (e.g., analytics or tracking scripts that might fail without affecting the PDF).

Matching Rules: Gotenberg matches if the asset's hostname equals or is a subdomain of the entry.

Input values are automatically normalized (trimmed, lowercased, port/scheme removed):

  • example.com
  • *.example.com or .example.com
  • example.com:443 (port is ignored)
  • https://example.com/path (scheme/path are ignored)
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form 'failOnHttpStatusCodes=[499,599]' \
--form 'failOnResourceHttpStatusCodes=[499,599]' \
--form 'ignoreResourceHttpStatusDomains=["sentry-cdn.com","analytics.example.com"]' \
-o my.pdf
The main page or one of its resources returned an invalid status code.
Content-Type: text/plain; charset=UTF-8
Gotenberg-Trace: {trace}
Body: Invalid HTTP status code from the main page: 400: Bad Request

Network Errors

Gotenberg automatically validates the connection to the main page URL. If the browser encounters any of the following critical network errors, the API immediately returns 400 Bad Request to indicate the page could not be reached.

Critical Error List

  • net::ERR_CONNECTION_CLOSED
  • net::ERR_CONNECTION_RESET
  • net::ERR_CONNECTION_REFUSED
  • net::ERR_CONNECTION_ABORTED
  • net::ERR_CONNECTION_FAILED
  • net::ERR_NAME_NOT_RESOLVED
  • net::ERR_INTERNET_DISCONNECTED
  • net::ERR_ADDRESS_UNREACHABLE
  • net::ERR_BLOCKED_BY_CLIENT
  • net::ERR_BLOCKED_BY_RESPONSE
  • net::ERR_FILE_NOT_FOUND
  • net::ERR_HTTP2_PROTOCOL_ERROR
Strict Resource Validation

By default, if an image or stylesheet fails to load (e.g., a broken 404 image link), the PDF is still generated with a missing asset icon.

To force the conversion to fail completely when any resource encounters a network error, set the failOnResourceLoadingFailed form field to true.

Console

failOnConsoleExceptionsboolean
Returns a 409 Conflict response if there are exceptions in the Chromium console.
Default:false
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form failOnConsoleExceptions=true \
-o my.pdf
Exceptions in the Chromium console.
Content-Type: text/plain; charset=UTF-8
Gotenberg-Trace: {trace}
Body:

Chromium console exceptions:

exception "Uncaught" (17:10): Error: Exception 1
at file:///tmp/db09d2c8-31e3-4058-9923-c2705350f2b3/index.html:18:11;
exception "Uncaught" (20:10): Error: Exception 2
at file:///tmp/db09d2c8-31e3-4058-9923-c2705350f2b3/index.html:21:11:

You can inject a custom header and footer into every page of the generated PDF.

These must be provided as separate, complete HTML files (header.html and footer.html).

Chromium Print Feature

This feature uses the native Chromium printing engine. It operates in a separate context from your main document, which means:

  1. Styles are isolated: Your main page's CSS does not apply here.
  2. No JavaScript: Scripts inside headers/footers will not execute.
  3. No External Requests: You cannot link to external images, fonts, or stylesheets.
header.htmlfile
Complete HTML document for the header.
Default:None
footer.htmlfile
Complete HTML document for the footer.
Default:None
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form files=@/path/to/header.html \
--form files=@/path/to/footer.html \
-o my.pdf

HTML Structure

Each file must be a full HTML document with its own <html>, <head>, and <body> tags.

<html>
<head>
<style>
body {
/* Recommended: Use a larger font-size than normal */
font-size: 16px;
/* Recommended: Use margins to align with the page edge */
margin: 0 20px;
/* Required for background colors to show */
-webkit-print-color-adjust: exact;
}
</style>
</head>
<body>
<p>
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
</p>
</body>
</html>

Dynamic Content Injection

Chromium automatically injects values into elements with specific class names:

Class NameInjected Value
dateThe formatted print date.
titleThe document title.
urlThe document location.
pageNumberThe current page number.
totalPagesThe total number of pages.

Styling & Asset Limitations

The Chromium header/footer engine operates in a restricted environment. Follow these rules to ensure correct rendering:

ComponentLimitation & Solution
ImagesMust be Base64 encoded inline (e.g., <img src="data:image/png;base64,...">). External URLs (HTTP) will not load.
FontsOnly fonts installed in the Docker image are available. See Fonts Configuration.
ColorsTo force background/text colors to print, you must explicitly add -webkit-print-color-adjust: exact; to your CSS.
MarginsContent taller than the marginTop / marginBottom form fields will be clipped.
CSSfooter.html styles may override header.html styles. Use unique class names to prevent conflicts.

Performance Impact

Do not attempt to load external assets (CSS, images, scripts) in headers or footers. They will likely time out, slowing down the rendering process significantly or causing the request to fail entirely.

Structure & Metadata

generateDocumentOutlineboolean
Chromium feature. Embeds the document outline (bookmarks) into the PDF.
Default:false
metadatajson
Writes metadata (Author, Title, etc.).
Default:None
flattenboolean
Converts form fields into static content, preventing further editing.
Default:false
embedsfile[]
Embeds files into the PDF.
Default:None

Document Outline (Chromium)

Use the generateDocumentOutline form field to automatically create a PDF bookmark pane (sidebar) based on your HTML headings (<h1> to <h6>).

  • Process: Happens during the HTML-to-PDF conversion.
  • Requirement: Your HTML must use proper heading tags to generate the hierarchy.
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form generateDocumentOutline=true \
-o my.pdf

Metadata (PDF Engines)

Use the metadata form field to inject XMP metadata into the generated PDF. This allows you to set properties like Author, Title, Copyright, and Keywords by passing a JSON-formatted object.

Valid Keys

Not all metadata tags are writable. Gotenberg relies on ExifTool for this operation. See the XMP Tag Name documentation for a list of potential keys.

Compliance Warning

Writing metadata involves modifying the PDF structure and usually breaks PDF/A compliance.

cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form 'metadata={"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreationDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"}' \
-o my.pdf

Attachments (PDF Engines)

Use the embeds form field to attach external files directly inside the PDF container.

Common Use Case: This is essential for e-invoicing standards like ZUGFeRD / Factur-X, which require a human-readable PDF to carry a machine-readable XML invoice as an attachment.

cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form embeds=@invoice.xml \
--form embeds=@logo.png \
-o my.pdf

Flatten (PDF Engines)

Use the flatten form field to make the PDF non-interactive.

This process merges all interactive form fields (text inputs, checkboxes, etc.) directly into the page content. The resulting PDF cannot be modified by the end-user.

cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form flatten=true \
-o my.pdf

Split & Page Ranges

nativePageRangesstring
Chromium feature. Define ranges to print (e.g., '1-5, 8, 11-13').
Default:None
splitModeenum
Activates the splitting engine. Options: 'intervals' or 'pages'.
Default:None
splitSpanstring
The rule for splitting. If mode is 'intervals', defines the chunk size (e.g. '2'). If mode is 'pages', defines the page ranges.
Default:None
splitUnifyboolean
Only for 'pages' mode. If true, puts all extracted pages into a single PDF file. If false, creates a separate file for each range.
Default:false

Native Printing (Chromium)

Use the nativePageRanges form field to instruct Chromium which pages to print.

  • Process: Happens during the HTML-to-PDF conversion.
  • Output: A single PDF file containing only the selected pages.
  • Performance: Faster, as unused pages are never rendered.
Page Breaks

Unlike word processors, HTML has no intrinsic concept of "pages" until it is printed. To prevent awkward breaks (like a table header being separated from its rows or an image being cut in half), use standard CSS fragmentation properties:

  • break-inside: avoid; (prevents an element from being split across two pages).
  • break-before: always; or break-after: always; (forces a new page).
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form nativePageRanges=1-5 \
-o my.pdf

Post-Processing (PDF Engines)

Use the splitMode, splitSpan, and splitUnify form fields to manipulate the PDF after it has been generated.

  • Process: Gotenberg generates the full PDF, then uses a PDF Engine (like pdfcpu) to split or extract pages.
  • Output: A single PDF or a ZIP archive containing PDF files.
  • Use Case: Creating separate files for every page, or extracting intervals into separate documents.
Syntax Validation

When splitMode is set to pages, Gotenberg does not validate the splitSpan syntax.

The value is passed directly to the underlying PDF Engine, and the valid syntax depends on which engine you have configured:

EngineSyntax Reference
pdfcpu (Default)See pdfcpu /trim documentation
QPDFSee QPDF page-ranges documentation
PDFtkSee PDFtk cat operation

Check the PDF Engines Configuration to see which engine is active.

cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form splitMode=intervals \
--form splitSpan=1 \
-o my.zip

PDF/A & PDF/UA

generateTaggedPdfboolean
Chromium feature. Embeds logical structure tags for accessibility during generation.
Default:false
pdfaenum
Converts to a specific PDF/A archival standard. Options includes: 'PDF/A-1b', 'PDF/A-2b', 'PDF/A-3b'
Default:None
pdfuaboolean
Enables PDF/UA (Universal Accessibility) compliance.
Default:false

Native Accessibility (Chromium)

Use the generateTaggedPdf form field to instruct Chromium to structure the PDF for accessibility (tagging).

  • Process: Happens during the initial HTML-to-PDF conversion.
  • Performance: High (negligible overhead).
  • Result: A logical structure tree (headings, paragraphs) embedded in the PDF, essential for screen readers.
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form generateTaggedPdf=true \
-o my.pdf

Post-Processing (PDF Engines)

Use the pdfa and pdfua form fields to convert the result into a standardized PDF format during post-processing.

  • Process: Gotenberg generates the result, then re-processes it using LibreOffice (the only engine supporting these standards).
  • Performance: Slower (requires a second conversion pass).
  • Result: A compliant PDF/A (Archival) or PDF/UA (Universal Accessibility) document.
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form userPassword=my_user_password \
--form ownerPassword=my_owner_password \
-o my.pdf

Encryption (PDF Engines)

Secure your PDF by setting passwords that control access and permissions.

  • User Password: Required to open and view the PDF.
  • Owner Password: Required to modify permissions (e.g., printing, copying text, extracting pages).
PDF Engine Dependency

The encryption strength (e.g., AES-256) depends on the configured PDF Engine (QPDF, pdfcpu, or PDFtk).

Check the PDF Engines Configuration to see which engine is active.

userPasswordstring
The password required to open the PDF.
Default:None
ownerPasswordstring
The password required to change permissions or edit the PDF.
Default:None
cURL
curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form userPassword=my_user_password \
--form ownerPassword=my_owner_password \
-o my.pdf