NewConnect Claude, Gemini, ChatGPT, and other AI agents to API Ninjas via our MCP server →

HTML to PDF API

The HTML to PDF API turns HTML, or any public web page, into a PDF. Pages are rendered the way a modern web browser shows them, so CSS layouts, web fonts, SVG, images and charts drawn with JavaScript all come out right, and the text in the PDF stays selectable and searchable.

Generate invoices, receipts, reports, certificates and tickets from one HTML template: put {{tags}} in the HTML and send the values as JSON in data. Add headers and footers with page numbers, choose the paper size, orientation and margins, and set the PDF's title, author, watermark and password in the same call.

Converting a web page waits for it to load, runs its JavaScript and scrolls through it so lazy-loaded images appear. Cookies, headers and basic authentication reach pages that need a login.

Each page of the PDF uses one of your plan's monthly document pages, not API calls: Free 50, Developer 10,000, Business 100,000, Professional 500,000. Your dashboard shows the pages you've used this month. See pricing.

Going the other way? The PDF to HTML API turns PDFs into HTML. The Word to PDF API converts Word documents, and the PDF to Image API turns PDF pages into images.

At a Glance

InputHTML (up to 4 MB) as text, a file or the raw body, or a web page url
OutputA PDF, as base64 in JSON or as a PDF file; large PDFs as a download link
Pages per PDFUp to 500
Templates{{tags}} filled from JSON data
Plan usage1 document page per page of the PDF
Free planPDFs up to 5 pages, from HTML up to 1 MB

Related APIs

https://api.api-ninjas.com/v1/htmltopdf

Converts HTML, or a web page, to PDF. Returns the PDF as base64 in JSON, or as a PDF file. Accepts GET or POST: use POST to send HTML, or GET with url.

Parameters

Send one of html, file or url. All other parameters are optional. In a POST, put the parameters in a JSON body (where data, headers and cookies can be JSON objects), or send them as form fields or query parameters.

  • html  optional

    The HTML to convert: a full document or a fragment, up to 4 MB (1 MB on the Free plan). Send it in a JSON body, as a form field, or as the raw request body with Content-Type: text/html. Images, stylesheets and fonts it links to are loaded from the internet; use base_url for relative links.

  • file  optional

    An .html file as a multipart form upload, instead of html.

  • url  optional

    A public http:// or https:// web page to convert, instead of html. The page is loaded like in a browser: its JavaScript runs and lazy-loaded images are scrolled into view before the PDF is made.

  • data  optional

    A JSON object that fills the template tags in html, header and footer: {{name}} inserts a value (HTML-escaped), {{#items}}...{{/items}} repeats a block for each item of a list, and {{{html}}} inserts a value as HTML. Up to 1 MB. Works with html, not url.

  • base_url  optional

    The address that relative links in html are resolved against, for example https://example.com/invoices/ for <img src="logo.png">.

  • page_size  optional

    Paper size: A4 (default), Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A5 or A6. A size set by the page's own CSS (@page { size: ... }) takes precedence.

  • width  optional

    Custom page width with a unit, for example 210mm, 8.5in, 20cm or 800px. Send it with height, instead of page_size.

  • height  optional

    Custom page height with a unit, for example 297mm. Send it with width.

  • orientation  optional

    portrait (default) or landscape.

  • margin  optional

    Page margins in CSS shorthand: one to four lengths with units, for example 1cm or 20mm 15mm. Default 1cm, or 2 cm at the top and bottom when there is a header or footer. Margins set by the page's own @page CSS take precedence.

  • scale  optional

    Zoom from 0.1 to 2. Default 1; 0.8 fits more on each page.

  • print_background  optional

    Include background colors and images: true (default) or false.

  • media  optional

    Which CSS styles apply: print (default, the page's print styles) or screen (the page as it looks on screen).

  • header  optional

    HTML printed at the top of every page, up to 50,000 characters. It can use {{page}}, {{pages}}, {{date}}, {{title}} and {{url}}, and the values in data. It is styled on its own: page styles do not apply, so put any CSS inline.

  • footer  optional

    HTML printed at the bottom of every page, with the same tags as header, for example Page {{page}} of {{pages}}.

  • page_numbers  optional

    true adds a centered "Page 1 of 3" footer when you don't send a footer. Default false.

  • page_ranges  optional

    Pages to keep, for example 1-3, 1,4 or 2- (page 2 to the end). Default: all pages.

  • css  optional

    Extra CSS added to the page before it is converted, up to 200 KB, for example to hide a cookie banner.

  • javascript  optional

    Run the page's JavaScript: true (default) or false.

  • wait_until  optional

    When the page counts as loaded: load (default, after images and stylesheets), domcontentloaded (as soon as the HTML is read) or networkidle (once the network has been quiet for half a second; best for pages that load data with JavaScript).

  • wait_for  optional

    A CSS selector to wait for before converting, for example #chart or .report-ready, so content drawn by JavaScript is in the PDF.

  • delay  optional

    Extra milliseconds to wait before converting, up to 10000, for animations or charts.

  • lazy_load  optional

    Scroll through the page first so lazy-loaded images appear: true by default for url, false for html.

  • viewport_width  optional

    Browser window width in pixels, from 320 to 3840. Default 1280. Responsive pages lay out for this width; use 390 for the mobile layout.

  • user_agent  optional

    The User-Agent header sent when loading url. Works with url only.

  • headers  optional

    Extra HTTP headers for url as a JSON object, for example {"Authorization": "Bearer ..."}. They are sent to the page's own host only, never to other sites the page loads from. Works with url only.

  • cookies  optional

    Cookies for url, as a JSON object or as name=value pairs separated by semicolons, for example session=abc123; theme=dark. Works with url only.

  • url_username  optional

    User name for pages behind HTTP basic authentication. Works with url only.

  • url_password  optional

    Password for pages behind HTTP basic authentication. Works with url only.

  • timezone  optional

    Time zone the page sees, for dates its JavaScript shows, for example America/New_York.

  • locale  optional

    Language and region the page sees, for example de-DE, for pages that adapt to the browser's language.

  • title  optional

    Title stored in the PDF's document properties, shown by most PDF viewers. Default: the page's own <title>.

  • author  optional

    Author stored in the PDF's document properties.

  • subject  optional

    Subject stored in the PDF's document properties.

  • keywords  optional

    Keywords stored in the PDF's document properties.

  • password  optional

    Encrypts the PDF (AES-256) so it opens only with this password. Up to 128 characters.

  • watermark  optional

    Text printed diagonally across every page, for example DRAFT or COPY. Up to 100 characters.

  • tagged  optional

    true (default) makes an accessible tagged PDF, with the structure screen readers use. Set false for a slightly smaller file.

  • outline  optional

    true (default) adds bookmarks for the page's headings, shown in a PDF viewer's sidebar.

  • filename  optional

    File name for the PDF when it is returned as a file (Accept: application/pdf). Default document.pdf.

Headers

  • X-Api-Key  required

    API Key associated with your account.

  • Accept  optional

    application/pdf returns the raw PDF file instead of JSON.

  • Content-Type  optional

    application/json for a JSON body, or text/html when the request body is the HTML itself. Multipart uploads set their own content type.

Response

The /v1/htmltopdf endpoint returns a JSON object with the following fields, or an error if the request is unsuccessful (see errors).

  • page_count

    Number of pages in the PDF.

  • size

    Size of the PDF in bytes.

  • warnings

    Images, stylesheets, fonts and other resources the page could not load, as messages. The PDF is made without them; an empty list means everything loaded.

  • pdf

    The PDF file, base64-encoded.

  • pdf_url

    Paid plans: for a PDF larger than about 4 MB, a link to download it instead of pdf. The link works for one hour.

  • expires_at

    When pdf_url stops working (UTC, ISO 8601).

With Accept: application/pdf, the response body is the PDF file itself (Content-Type: application/pdf), or for a PDF larger than about 4 MB, a redirect (HTTP 303) to its download link.

Limits

  • HTML up to 4 MB. PDFs up to 500 pages.
  • PDFs up to about 4 MB come back in the response; larger ones, up to 100 MB, as a download link that works for one hour.
  • Each request has about 20 seconds to load and convert. For very long documents, send them in parts with page_ranges.
  • Web pages must be on the public internet, on port 80, 443, 8080 or 8443. Pages that need a login can be reached with cookies, headers or url_username and url_password.
  • Free plan: PDFs up to 5 pages and 4 MB, from HTML up to 1 MB.

Document pages

This API uses your plan's monthly document pages, not API calls. Each page of the PDF uses one: a 10-page PDF uses 10. With page_ranges, only the pages you keep are counted.

Live Demo

Live demo · no API key required
Form data and query parameters
file
Converts this sample invoice until you enter a url or choose an HTML file.
url
page_size

Get a free API key to get started — no credit card required.

Headers
X-Api-KeyLog in or sign up to get your API key
POST
https://api.api-ninjas.com/v1/htmltopdf
Sample response

Press Send to convert the sample invoice and preview the PDF here.

{
"page_count": 1,
"size": 53245,
"warnings": [],
"pdf": "JVBERi0xLjUKJb/3ov4KMSAwIG9iago8PCAvVHlwZSAvT2JqU3Rt..."
}

The live demo converts the first page, from HTML up to 100 KB. No API key is needed to try it.

Code Examples

# Fill an HTML template and save the PDF curl -X POST "https://api.api-ninjas.com/v1/htmltopdf" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/pdf" \ -d '{"html": "<h1>Invoice {{number}}</h1><p>Bill to: {{customer}}</p><p>Total due: {{total}}</p>", "data": {"number": "INV-2026-0042", "customer": "Jane Doe", "total": "$348.00"}, "page_size": "Letter", "page_numbers": true}' \ --output invoice.pdf # Convert a web page curl "https://api.api-ninjas.com/v1/htmltopdf?url=https://example.com" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Accept: application/pdf" \ --output page.pdf

Errors

An invalid request returns HTTP 400 with a JSON body holding a readable error message. If too many PDFs are being made at once, the API returns HTTP 503: retry after a few seconds. Authentication and quota errors use the standard format described in error codes.

CauseExample error
No HTML or url in the requestSend the HTML as html (or upload an .html file) or a web page as url.
Both html and urlSend either html or url, not both.
A url that is not a web addressurl must be a full http:// or https:// link.
A private or local address in urlurl must point to a public internet address.
The web page returns an errorurl returned HTTP 404.
The page keeps loading past the time limitThe page did not finish loading in time. Try wait_until=domcontentloaded, or check that the page loads without logging in.
Nothing matches wait_for in timeNo element matched wait_for (#chart) before the time limit.
An unknown page_sizepage_size must be one of: Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6.
A length without a unit, e.g. margin=10margin must be a length with a unit, for example 10mm, 1cm, 0.5in or 40px.
data with urldata fills an HTML template, so it needs html instead of url.
More than 500 pagesThis PDF would have 620 pages. The most per request is 500 pages; use page_ranges to convert part of it.
A PDF over 100 MBThe PDF is larger than 100 MB. Use page_ranges to convert part of the document.
No document pages left this monthYou have used all 50 document pages included in your Free plan this month. They renew on December 1, 2026. Upgrade at https://api-ninjas.com/pricing for more.
Free plan: more than 5 pagesThis PDF would have 8 pages. The Free plan converts documents of up to 5 pages. Upgrade at https://api-ninjas.com/pricing for documents up to 500 pages.
Free plan: HTML over 1 MBHTML on the Free plan can be up to 1 MB. Upgrade at https://api-ninjas.com/pricing for up to 4 MB.
Free plan: a PDF over 4 MBThe PDF is larger than 4 MB. Upgrade at https://api-ninjas.com/pricing for PDFs up to 100 MB.

Frequently Asked Questions

  • Yes, but you must have a premium subscription. Commercial use of the HTML to PDF API is not permitted on the free tier. See our pricing page to choose a plan that fits your needs.
  • Sign up for a free account to instantly get your API key, then pass it in the X-Api-Key header on every request. The documentation above includes ready-to-run examples in cURL, Python, JavaScript, Node.js, and more.
  • Your API requests will simply be denied once you hit your monthly quota — you will never be charged more than the plan you signed up for. To increase your quota, you can upgrade your plan any time on our pricing page.
  • The API responds with a standard HTTP status code and a JSON error message describing the problem. See our error codes reference for the full list of codes and how to resolve each one, or contact support if you need help.
  • POST the HTML to /v1/htmltopdf in a JSON body, e.g. curl -X POST "https://api.api-ninjas.com/v1/htmltopdf" -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" -H "Accept: application/pdf" -d '{"html": "<h1>Hello</h1>"}' --output hello.pdf. Without the Accept header the response is JSON with the PDF base64-encoded in pdf. You can also upload an .html file or send the HTML as the raw request body with Content-Type: text/html.
  • Yes: pass url instead of html, e.g. /v1/htmltopdf?url=https://example.com. The page loads like in a browser: its JavaScript runs and it is scrolled through so lazy-loaded images appear. For pages that draw content late, add wait_until=networkidle, wait_for with a CSS selector, or delay. Pages behind a login can be reached with cookies, headers or url_username and url_password.
  • Write the template once in HTML with {{tags}}, and send the values for each document in data: {"html": "<h1>Invoice {{number}}</h1>{{#items}}<p>{{name}}: {{price}}</p>{{/items}}", "data": {"number": "INV-0042", "items": [{"name": "Plan", "price": "$149"}]}}. {{#items}}...{{/items}} repeats a block for each item in a list, values are HTML-escaped, and {{{value}}} inserts HTML as is. The same tags work in header and footer.
  • Set page_numbers=true for a centered "Page 1 of 3" footer, or send your own footer and header HTML with the tags {{page}}, {{pages}}, {{date}}, {{title}} and {{url}}, e.g. <div style="text-align:right">{{page}} / {{pages}}</div>. Headers and footers are styled on their own, so put their CSS inline. The page margins grow to 2 cm at the top and bottom to make room, unless you set margin.
  • No API calls. Each page of the PDF uses one of your plan's monthly document pages, so a 3-page PDF uses 3. With page_ranges, only the pages you keep count. Your dashboard shows the pages you've used this month. See pricing for the document pages in each plan.
  • Yes: the Free plan includes 50 document pages a month, for PDFs up to 5 pages and 4 MB made from HTML up to 1 MB or from a web page. Paid plans make PDFs up to 500 pages from HTML up to 4 MB, and return PDFs over 4 MB as a download link, up to 100 MB. See pricing.