Convert HTML to PDF in Node.js

IronPDF's most powerful and most popular feature is the ability to create high-fidelity PDFs from raw HTML, CSS, and JavaScript. This tutorial walks Node.js developers through every practical method for turning HTML content into PDFs — from a one-liner string conversion all the way to dynamic template-driven document generation.

IronPDF is a high-level API library that helps developers implement powerful PDF processing capabilities into software applications quickly. IronPDF is available in multiple programming languages. For detailed coverage on creating PDFs in .NET, Java, and Python, consult the official documentation pages. This tutorial covers its usage as it applies to Node.js projects.

Quickstart: Convert HTML to PDF in Node.js

Table of Contents

How Do You Get Started with IronPDF for Node.js? {#getting-started}

Start using IronPDF in your project today with a free trial.

First Step:
green arrow pointer

Install the IronPDF Library

Install the IronPDF Node.js package by running the NPM command below in your chosen Node.js project:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/install.sh
npm install @ironsoftware/ironpdf
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/install.sh
npm install @ironsoftware/ironpdf
SHELL

You can also download and install the IronPDF package manually.

How Do You Install the IronPDF Engine?

IronPDF for Node.js requires an IronPDF Engine binary to function.

Please noteInstalling the IronPDF Engine is optional. The @ironsoftware/ironpdf package automatically downloads and installs the appropriate binary for your operating system on first execution. Explicit installation is recommended in environments where internet access is restricted or unavailable.

Install the IronPDF Engine binary by installing the appropriate package for your operating system.

How Do You Apply a License Key?

By default, IronPDF brands all documents it generates or modifies with a watermark. To remove the watermark, set the licenseKey property on the global IronPdfGlobalConfig object with a valid license key:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/config.js
import { IronPdfGlobalConfig } from "@ironsoftware/ironpdf";

// Retrieve the global configuration object
var config = IronPdfGlobalConfig.getConfig();

// Set a valid license key to remove watermarks
config.licenseKey = "{YOUR-LICENSE-KEY-HERE}";
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/config.js
import { IronPdfGlobalConfig } from "@ironsoftware/ironpdf";

// Retrieve the global configuration object
var config = IronPdfGlobalConfig.getConfig();

// Set a valid license key to remove watermarks
config.licenseKey = "{YOUR-LICENSE-KEY-HERE}";
JAVASCRIPT

Obtain a free trial license key or purchase a license key from the licensing page.

Please noteSet the license key and any other global configuration settings before calling other library functions. This ensures optimal performance and correct behavior throughout the application.

The remaining code examples in this tutorial assume that a license key has been applied in a separate config.js file, which is imported at the top of each script:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/config-import.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script
// ...
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/config-import.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script
// ...
JAVASCRIPT

IronPDF watermark displayed on a PDF document generated without a license key Obtain a license key at ironpdf.com/nodejs/licensing/ to generate PDF documents without watermarks.

How Do You Convert HTML to PDF in Node.js? {#convert-html-to-pdf}

The IronPDF Node.js library provides four approaches for creating PDF files from HTML content:

  1. From a string of HTML code
  2. From a local HTML file
  3. From an online URL
  4. From a compressed ZIP archive

Each approach uses the PdfDocument class as its foundation. A PdfDocument represents a PDF file produced from some source content and drives most of IronPDF's core creation and editing features.

How Do You Create a PDF from an HTML String? {#create-pdf-from-html-string}

PdfDocument.fromHtml generates PDFs from strings of raw HTML markup. This approach offers the most flexibility of the four methods because the HTML string can be sourced from virtually anywhere — text files, data streams, an HTML template engine, or dynamically constructed markup.

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/html-string-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Create a PDF from an HTML string
const pdf = await PdfDocument.fromHtml("<h1>Hello from IronPDF!</h1>");

// Save the PDF document to the file system
await pdf.saveAs("html-string-to-pdf.pdf");
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/html-string-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Create a PDF from an HTML string
const pdf = await PdfDocument.fromHtml("<h1>Hello from IronPDF!</h1>");

// Save the PDF document to the file system
await pdf.saveAs("html-string-to-pdf.pdf");
JAVASCRIPT

PdfDocument.fromHtml returns a Promise that resolves to an instance of the PdfDocument class. After obtaining the instance, call saveAs with a target file path to write the PDF to disk. The saved PDF file renders the HTML exactly as a standards-compliant browser would display it.

PDF document generated from the HTML string containing a level-one heading Hello from IronPDF! The PDF generated from the HTML string <h1>Hello from IronPDF!</h1>. The PDF files that PdfDocument.fromHtml generates appear just as web page content would appear.

How Do You Create a PDF from an HTML File? {#create-pdf-from-html-file}

PdfDocument.fromHtml also accepts a path to a local HTML document. Instead of a string of markup, pass a valid file path as the first argument. This is the preferred approach when working with saved web pages that reference local CSS, JavaScript, and image assets.

The following example converts a sample web page into a PDF:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/html-file-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Render a PDF from a local HTML file
const pdf = await PdfDocument.fromHtml("./sample2.html");

// Save the PDF document to the project directory
await pdf.saveAs("html-file-to-pdf-1.pdf");
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/html-file-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Render a PDF from a local HTML file
const pdf = await PdfDocument.fromHtml("./sample2.html");

// Save the PDF document to the project directory
await pdf.saveAs("html-file-to-pdf-1.pdf");
JAVASCRIPT

Sample HTML page displayed in Google Chrome before conversion to PDF The sample HTML page as it appears in Google Chrome. Download this and similar pages from the File Samples website: https://filesamples.com/samples/code/html/sample2.html

IronPDF preserves the appearance of the original HTML document and retains the functionality of links, forms, and other interactive elements. This fidelity extends to complex pages that include paragraphs, lists, images, hyperlinks, and client-side scripting.

PDF document generated from the sample HTML file, showing faithful reproduction of the original page layout This PDF was generated from the HTML file example above. Compare its appearance with the previous image — IronPDF preserves the layout with high fidelity.

IronPDF handles pages that go far beyond simple markup. The following example converts a feature-rich page that sources numerous external CSS files, images, and script assets:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/html-complex-file-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Render a PDF from a complex HTML page with external assets
PdfDocument.fromHtml("./sample4.html").then(async (pdf) => {
    return await pdf.saveAs("html-file-to-pdf-2.pdf");
});
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/html-complex-file-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Render a PDF from a complex HTML page with external assets
PdfDocument.fromHtml("./sample4.html").then(async (pdf) => {
    return await pdf.saveAs("html-file-to-pdf-2.pdf");
});
JAVASCRIPT

PDF generated from a complex HTML page containing rich CSS styling and JavaScript-rendered content If it looks good in Google Chrome, it will look good when converted to PDF. This includes CSS-heavy and JavaScript-rendered page designs.

TipsIf a page sources assets from local file paths, ensure all referenced CSS files, images, and scripts are present relative to the HTML file's location. IronPDF's Chrome rendering engine resolves these paths the same way a browser would.

How Do You Create a PDF from a URL? {#create-pdf-from-url}

PdfDocument.fromUrl fetches and renders a live web page as a PDF. Pass any publicly accessible URL as the argument. IronPDF's Chrome rendering engine retrieves the page, loads all assets, and produces a pixel-perfect PDF — no manual HTML download required.

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/url-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Convert a live web page to a PDF
const pdf = await PdfDocument.fromUrl("https://en.wikipedia.org/wiki/PDF");

// Save the document
await pdf.saveAs("url-to-pdf.pdf");
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/url-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Convert a live web page to a PDF
const pdf = await PdfDocument.fromUrl("https://en.wikipedia.org/wiki/PDF");

// Save the document
await pdf.saveAs("url-to-pdf.pdf");
JAVASCRIPT

Wikipedia article about the PDF format as it appears in a standards-compliant browser The Wikipedia article about the PDF format, as it appears in a standards-compliant web browser.

PDF document generated from calling PdfDocument.fromUrl on the Wikipedia PDF article page The PDF generated from calling PdfDocument.fromUrl on a Wikipedia article. Note its close resemblance to the original web page.

ImportantURL-based conversions require that the target server is accessible from the machine running IronPDF. Pages behind authentication, VPNs, or firewalls may require additional configuration through ChromePdfRenderOptions.

How Do You Create a PDF from a Zip Archive? {#create-pdf-from-zip}

PdfDocument.fromZip converts a specific HTML file contained in a ZIP archive into a PDF. This is particularly useful when distributing self-contained HTML projects that bundle their HTML, CSS, and image assets together.

For this example, assume the project directory contains a ZIP file with the following structure:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/zip-structure.txt
html-zip.zip
├─ index.html
├─ style.css
├─ logo.png

The index.html file contains:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Hello world!</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <h1>Hello from IronPDF!</h1>
    <a href="https://ironpdf.com/nodejs/">
      <img src="logo.png" alt="IronPDF for Node.js">
    </a>
  </body>
</html>
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Hello world!</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <h1>Hello from IronPDF!</h1>
    <a href="https://ironpdf.com/nodejs/">
      <img src="logo.png" alt="IronPDF for Node.js">
    </a>
  </body>
</html>
HTML

And style.css declares the page layout and font rules:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/style.css
@font-face {
  font-family: 'Gotham-Black';
  src: url('gotham-black-webfont.eot?') format('embedded-opentype'), 
       url('gotham-black-webfont.woff2') format('woff2'), 
       url('gotham-black-webfont.woff') format('woff'), 
       url('gotham-black-webfont.ttf') format('truetype'), 
       url('gotham-black-webfont.svg') format('svg');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin-left: auto;
  margin-right: auto;
  margin-top: 200px;
  margin-bottom: auto;
  color: white;
  background-color: black;
  text-align: center;
  font-family: "Helvetica"
}

h1 {
  font-family: "Gotham-Black";
  margin-bottom: 70px;
  font-size: 32pt;
}

img {
  width: 400px;
  height: auto;
}

p {
  text-decoration: underline;
  font-size: smaller;
}

Sample logo.png image contained inside the hypothetical HTML ZIP file The sample image inside the hypothetical HTML ZIP file.

When calling fromZip, specify the path to the ZIP file as the first argument and a configuration object as the second. Set the mainHtmlFile property to the name of the HTML file inside the archive that should be converted:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/zip-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Convert an HTML file from a ZIP archive to PDF
PdfDocument.fromZip("./html-zip.zip", {
  mainHtmlFile: "index.html"
}).then(async (pdf) => {
  return await pdf.saveAs("html-zip-to-pdf.pdf");
});
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/zip-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Convert an HTML file from a ZIP archive to PDF
PdfDocument.fromZip("./html-zip.zip", {
  mainHtmlFile: "index.html"
}).then(async (pdf) => {
  return await pdf.saveAs("html-zip-to-pdf.pdf");
});
JAVASCRIPT

PDF generated from the HTML ZIP archive, showing the IronPDF logo and styled heading on a black background PDF creation using PdfDocument.fromZip. The function successfully renders the HTML code from the ZIP file along with its bundled assets.

What Advanced Rendering Options Does IronPDF Support? {#advanced-rendering-options}

The ChromePdfRenderOptions interface exposes properties for granular customization of PDF rendering behavior. These settings apply before the PDF is generated and cover layout, visual appearance, and edge cases for dynamic content.

IronPDF applies default rendering settings to every conversion. Retrieve these default values with the defaultChromePdfRenderOptions function:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/default-options.js
import { defaultChromePdfRenderOptions } from "@ironsoftware/ironpdf";

// Retrieve a ChromePdfRenderOptions object with default settings
var options = defaultChromePdfRenderOptions();
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/default-options.js
import { defaultChromePdfRenderOptions } from "@ironsoftware/ironpdf";

// Retrieve a ChromePdfRenderOptions object with default settings
var options = defaultChromePdfRenderOptions();
JAVASCRIPT

Modify the returned object's properties as needed and pass it to the renderOptions parameter of any conversion method.

How Do You Add Headers and Footers? {#add-headers-footers}

The textHeader and textFooter properties affix custom text-based content to every page of a newly rendered PDF. The following example creates a PDF from the Google search homepage with a custom header and footer, each using a different font:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/custom-headers-footers.js
import { PdfDocument, defaultChromePdfRenderOptions, AffixFonts } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Start from default render options
var options = defaultChromePdfRenderOptions();

// Configure a text-based header
options.textHeader = {
  centerText: "https://www.adobe.com",
  dividerLine: true,
  font: AffixFonts.CourierNew,
  fontSize: 12,
  leftText: "URL to PDF"
};

// Configure a text-based footer
options.textFooter = {
  centerText: "IronPDF for Node.js",
  dividerLine: true,
  fontSize: 14,
  font: AffixFonts.Helvetica,
  rightText: "HTML to PDF in Node.js"
};

// Render the page with custom headers and footers applied
PdfDocument.fromUrl("https://www.google.com/", { renderOptions: options }).then(async (pdf) => {
  return await pdf.saveAs("add-custom-headers-footers-1.pdf");
});
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/custom-headers-footers.js
import { PdfDocument, defaultChromePdfRenderOptions, AffixFonts } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Start from default render options
var options = defaultChromePdfRenderOptions();

// Configure a text-based header
options.textHeader = {
  centerText: "https://www.adobe.com",
  dividerLine: true,
  font: AffixFonts.CourierNew,
  fontSize: 12,
  leftText: "URL to PDF"
};

// Configure a text-based footer
options.textFooter = {
  centerText: "IronPDF for Node.js",
  dividerLine: true,
  fontSize: 14,
  font: AffixFonts.Helvetica,
  rightText: "HTML to PDF in Node.js"
};

// Render the page with custom headers and footers applied
PdfDocument.fromUrl("https://www.google.com/", { renderOptions: options }).then(async (pdf) => {
  return await pdf.saveAs("add-custom-headers-footers-1.pdf");
});
JAVASCRIPT

PDF generated from the Google home page with a custom text header and footer added A PDF generated from the Google home page with a custom text header and footer applied using textHeader and textFooter.

For richer header and footer layouts, use the htmlHeader and htmlFooter properties instead. These accept raw HTML fragments, giving full control over typography, images, and alignment. The example below centers the page URL in bold in the header and embeds a logo image in the footer:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/html-headers-footers.js
import { PdfDocument, defaultChromePdfRenderOptions } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Start from default render options
var options = defaultChromePdfRenderOptions();

// Define a rich HTML header
options.htmlHeader = {
  htmlFragment: "<strong>https://www.google.com/</strong>",
  dividerLine: true,
  dividerLineColor: "blue",
  loadStylesAndCSSFromMainHtmlDocument: true,
};

// Define a rich HTML footer with a logo
options.htmlFooter = {
  htmlFragment: "<img src='logo.png' alt='IronPDF for Node.js' style='display: block; width: 150px; height: auto; margin-left: auto; margin-right: auto;'>",
  dividerLine: true,
  loadStylesAndCSSFromMainHtmlDocument: true
};

// Apply custom HTML headers and footers during rendering
await PdfDocument.fromUrl("https://www.google.com/", { renderOptions: options }).then(async (pdf) => {
  return await pdf.saveAs("add-html-headers-footers.pdf");
});
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/html-headers-footers.js
import { PdfDocument, defaultChromePdfRenderOptions } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Start from default render options
var options = defaultChromePdfRenderOptions();

// Define a rich HTML header
options.htmlHeader = {
  htmlFragment: "<strong>https://www.google.com/</strong>",
  dividerLine: true,
  dividerLineColor: "blue",
  loadStylesAndCSSFromMainHtmlDocument: true,
};

// Define a rich HTML footer with a logo
options.htmlFooter = {
  htmlFragment: "<img src='logo.png' alt='IronPDF for Node.js' style='display: block; width: 150px; height: auto; margin-left: auto; margin-right: auto;'>",
  dividerLine: true,
  loadStylesAndCSSFromMainHtmlDocument: true
};

// Apply custom HTML headers and footers during rendering
await PdfDocument.fromUrl("https://www.google.com/", { renderOptions: options }).then(async (pdf) => {
  return await pdf.saveAs("add-html-headers-footers.pdf");
});
JAVASCRIPT

PDF generated with an HTML-based header showing the page URL in bold and an HTML-based footer showing the IronPDF logo IronPDF supports HTML-based headers and footers, giving full control over branding and layout on every page.

How Do You Control Page Size, Orientation, and Margins? {#page-size-orientation-margins}

The margin, paperSize, fitToPaperMode, paperOrientation, and grayScale properties on ChromePdfRenderOptions control the physical layout of every rendered page. The following example converts the Google homepage with custom margins, A5 landscape orientation, and grayscale output:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/page-size-orientation.js
import { PdfDocument, defaultChromePdfRenderOptions, PaperSize, FitToPaperModes, PdfPaperOrientation } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Start from default render options
var options = defaultChromePdfRenderOptions();

// Set page margins in millimeters
options.margin = {
  top: 50,
  bottom: 50,
  left: 60,
  right: 60
};

// Configure paper size, fit mode, orientation, and color mode
options.paperSize = PaperSize.A5;
options.fitToPaperMode = FitToPaperModes.FitToPage;
options.paperOrientation = PdfPaperOrientation.Landscape;
options.grayScale = true;

// Render with the customized layout settings
PdfDocument.fromUrl("https://www.google.com/", { renderOptions: options }).then(async (pdf) => {
  return await pdf.saveAs("set-margins-and-page-size.pdf");
});
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/page-size-orientation.js
import { PdfDocument, defaultChromePdfRenderOptions, PaperSize, FitToPaperModes, PdfPaperOrientation } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Start from default render options
var options = defaultChromePdfRenderOptions();

// Set page margins in millimeters
options.margin = {
  top: 50,
  bottom: 50,
  left: 60,
  right: 60
};

// Configure paper size, fit mode, orientation, and color mode
options.paperSize = PaperSize.A5;
options.fitToPaperMode = FitToPaperModes.FitToPage;
options.paperOrientation = PdfPaperOrientation.Landscape;
options.grayScale = true;

// Render with the customized layout settings
PdfDocument.fromUrl("https://www.google.com/", { renderOptions: options }).then(async (pdf) => {
  return await pdf.saveAs("set-margins-and-page-size.pdf");
});
JAVASCRIPT

The PaperSize enumeration includes standard paper sizes such as A4, A5, Letter, and Legal. The PdfPaperOrientation enumeration supports Portrait and Landscape. These settings give precise control over output dimensions for print-ready documents.

TipsWhen generating PDFs for print workflows, always specify margins explicitly. Default margins may not match the requirements of your target printer or paper format.

How Do You Handle Dynamic Web Pages? {#dynamic-web-pages}

Pages that load content asynchronously — through JavaScript timers, lazy loading, or API calls — may not be fully rendered by the time IronPDF's engine captures them. The WaitFor mechanism, configured through the waitFor property on ChromePdfRenderOptions, instructs the Chrome renderer to pause until specified conditions are met before capturing the page.

The following code block sets IronPDF to wait 20 seconds before capturing the page content:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/waitfor-delay.js
import { PdfDocument, defaultChromePdfRenderOptions, WaitForType } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Configure the renderer to wait 20 seconds before capturing
var options = defaultChromePdfRenderOptions();
options.waitFor = {
  type: WaitForType.RenderDelay,
  delay: 20000
};

PdfDocument.fromUrl("https://ironpdf.com/nodejs/", { renderOptions: options }).then(async (pdf) => {
  return await pdf.saveAs("waitfor-renderdelay.pdf");
});
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/waitfor-delay.js
import { PdfDocument, defaultChromePdfRenderOptions, WaitForType } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Configure the renderer to wait 20 seconds before capturing
var options = defaultChromePdfRenderOptions();
options.waitFor = {
  type: WaitForType.RenderDelay,
  delay: 20000
};

PdfDocument.fromUrl("https://ironpdf.com/nodejs/", { renderOptions: options }).then(async (pdf) => {
  return await pdf.saveAs("waitfor-renderdelay.pdf");
});
JAVASCRIPT

Alternatively, configure IronPDF to wait until a specific DOM element appears before rendering. This is useful for pages where content is injected after a JavaScript framework finishes mounting:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/waitfor-element.js
import { PdfDocument, defaultChromePdfRenderOptions, WaitForType } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Configure the renderer to wait for a specific DOM element (up to 20 seconds)
var options = defaultChromePdfRenderOptions();
options.waitFor = {
  type: WaitForType.HtmlElement,
  htmlQueryStr: "div.ProseMirror",
  maxWaitTime: 20000,
};

PdfDocument.fromUrl("https://app.surferseo.com/drafts/s/V7VkcdfgFz-dpkldsfHDGFFYf4jjSvvjsdf", { renderOptions: options }).then(async (pdf) => {
  return await pdf.saveAs("waitfor-htmlelement.pdf");
});
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/waitfor-element.js
import { PdfDocument, defaultChromePdfRenderOptions, WaitForType } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

// Configure the renderer to wait for a specific DOM element (up to 20 seconds)
var options = defaultChromePdfRenderOptions();
options.waitFor = {
  type: WaitForType.HtmlElement,
  htmlQueryStr: "div.ProseMirror",
  maxWaitTime: 20000,
};

PdfDocument.fromUrl("https://app.surferseo.com/drafts/s/V7VkcdfgFz-dpkldsfHDGFFYf4jjSvvjsdf", { renderOptions: options }).then(async (pdf) => {
  return await pdf.saveAs("waitfor-htmlelement.pdf");
});
JAVASCRIPT

The WaitForType.HtmlElement strategy uses a standard CSS query selector. The renderer polls for the element's presence until maxWaitTime milliseconds elapse or the element is found — whichever comes first.

WarningSetting excessively long wait times can significantly increase PDF generation time in high-throughput applications. Use the minimum delay that reliably captures the content your use case requires.

How Do You Generate PDFs from an HTML Template? {#html-template-to-pdf}

A common real-world automation pattern is generating a batch of PDFs from a shared HTML template, substituting placeholder values with data from a database, API, or spreadsheet. IronPDF's replaceText method on PdfDocument handles this directly.

The sample invoice template below (adapted from a publicly accessible CodePen invoice template) uses curly-brace placeholders such as {COMPANY-NAME}, {FULL-NAME}, and {INVOICE-NUMBER} for substitutable content:

Sample invoice HTML template with placeholder tags for dynamic data substitution A sample invoice template with placeholder tags. JavaScript code will replace each tag with real data before the document is saved as a PDF.

The following code loads the template, replaces every placeholder with test data, and saves the result as a PDF:

//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/html-template-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

/**
 * Loads an HTML template from the file system as a PdfDocument.
 */
async function getTemplateHtml(fileLocation) {
  return PdfDocument.fromHtml(fileLocation);
}

/**
 * Saves a PdfDocument to the specified file path.
 */
async function generatePdf(pdf, location) {
  return pdf.saveAs(location);
}

/**
 * Replaces a named placeholder in the PdfDocument with a data value.
 */
async function addTemplateData(pdf, key, value) {
  return pdf.replaceText(key, value);
}

// Path to the HTML invoice template
const template = "./sample-invoice.html";

// Load the template, fill in all placeholder values, then save the PDF
getTemplateHtml(template).then(async (doc) => {
    await addTemplateData(doc, "{FULL-NAME}", "Lizbeth Presland");
    await addTemplateData(doc, "{ADDRESS}", "678 Manitowish Alley, Portland, OG");
    await addTemplateData(doc, "{PHONE-NUMBER}", "(763) 894-4345");
    await addTemplateData(doc, "{INVOICE-NUMBER}", "787");
    await addTemplateData(doc, "{INVOICE-DATE}", "August 28, 2023");
    await addTemplateData(doc, "{AMOUNT-DUE}", "13,760.13");
    await addTemplateData(doc, "{RECIPIENT}", "Celestyna Farmar");
    await addTemplateData(doc, "{COMPANY-NAME}", "BrainBook");
    await addTemplateData(doc, "{TOTAL}", "13,760.13");
    await addTemplateData(doc, "{AMOUNT-PAID}", "0.00");
    await addTemplateData(doc, "{BALANCE-DUE}", "13,760.13");
    await addTemplateData(doc, "{ITEM}", "Training Sessions");
    await addTemplateData(doc, "{DESCRIPTION}", "60 Minute instruction");
    await addTemplateData(doc, "{RATE}", "3,440.03");
    await addTemplateData(doc, "{QUANTITY}", "4");
    await addTemplateData(doc, "{PRICE}", "13,760.13");
    return doc;
}).then(async (doc) => await generatePdf(doc, "html-template-to-pdf.pdf"));
//:path=/static-assets/ironpdf-nodejs/content-code-examples/tutorials/html-to-pdf/html-template-to-pdf.js
import { PdfDocument } from "@ironsoftware/ironpdf";
import './config.js'; // Import the configuration script

/**
 * Loads an HTML template from the file system as a PdfDocument.
 */
async function getTemplateHtml(fileLocation) {
  return PdfDocument.fromHtml(fileLocation);
}

/**
 * Saves a PdfDocument to the specified file path.
 */
async function generatePdf(pdf, location) {
  return pdf.saveAs(location);
}

/**
 * Replaces a named placeholder in the PdfDocument with a data value.
 */
async function addTemplateData(pdf, key, value) {
  return pdf.replaceText(key, value);
}

// Path to the HTML invoice template
const template = "./sample-invoice.html";

// Load the template, fill in all placeholder values, then save the PDF
getTemplateHtml(template).then(async (doc) => {
    await addTemplateData(doc, "{FULL-NAME}", "Lizbeth Presland");
    await addTemplateData(doc, "{ADDRESS}", "678 Manitowish Alley, Portland, OG");
    await addTemplateData(doc, "{PHONE-NUMBER}", "(763) 894-4345");
    await addTemplateData(doc, "{INVOICE-NUMBER}", "787");
    await addTemplateData(doc, "{INVOICE-DATE}", "August 28, 2023");
    await addTemplateData(doc, "{AMOUNT-DUE}", "13,760.13");
    await addTemplateData(doc, "{RECIPIENT}", "Celestyna Farmar");
    await addTemplateData(doc, "{COMPANY-NAME}", "BrainBook");
    await addTemplateData(doc, "{TOTAL}", "13,760.13");
    await addTemplateData(doc, "{AMOUNT-PAID}", "0.00");
    await addTemplateData(doc, "{BALANCE-DUE}", "13,760.13");
    await addTemplateData(doc, "{ITEM}", "Training Sessions");
    await addTemplateData(doc, "{DESCRIPTION}", "60 Minute instruction");
    await addTemplateData(doc, "{RATE}", "3,440.03");
    await addTemplateData(doc, "{QUANTITY}", "4");
    await addTemplateData(doc, "{PRICE}", "13,760.13");
    return doc;
}).then(async (doc) => await generatePdf(doc, "html-template-to-pdf.pdf"));
JAVASCRIPT

The code above defines three async helper functions:

  • getTemplateHtml: Loads an HTML file into a PdfDocument object using PdfDocument.fromHtml.
  • addTemplateData: Calls PdfDocument.replaceText to substitute a placeholder key with its real data value.
  • generatePdf: Writes the completed PdfDocument to a target file path.

Each replaceText call operates directly on the in-memory PDF representation, so multiple replacements can be chained without reloading the document from disk. The resulting PDF retains all CSS styles, fonts, and layout from the original template.

PDF document generated from the invoice template after all placeholders have been replaced with real data The completed PDF invoice with placeholder values replaced by real data. The CSS styles and layout from the original template are preserved exactly.

This approach scales well for batch document generation. Call getTemplateHtml once per record to create a fresh PdfDocument for each output file, then chain the addTemplateData calls for that record's data before calling generatePdf.

What Are the Next Steps? {#next-steps}

This tutorial covers the core HTML-to-PDF conversion methods and the most frequently used rendering options in IronPDF for Node.js. The topics below extend what you have learned here into more specialized areas.

Frequently Asked Questions

How do you convert HTML to PDF in Node.js?

Use the IronPDF library. Install it with npm install @ironsoftware/ironpdf, then call PdfDocument.fromHtml with an HTML string or file path, or PdfDocument.fromUrl with a web address. Save the result with PdfDocument.saveAs.

How do you convert an HTML string to PDF in Node.js?

Call PdfDocument.fromHtml with the HTML string as the argument. The method returns a Promise that resolves to a PdfDocument instance. Chain saveAs on the result to write the PDF to disk.

How do you convert a local HTML file to PDF in Node.js?

Pass a valid file system path to PdfDocument.fromHtml instead of an HTML string. IronPDF resolves relative CSS, image, and script paths the same way a browser would when loading the file.

How do you convert a URL to PDF in Node.js?

Call PdfDocument.fromUrl with the target URL. IronPDF fetches the page using its Chrome rendering engine and produces a pixel-perfect PDF. The target URL must be publicly accessible from the host running IronPDF.

How do you add headers and footers to a PDF in Node.js?

Set the textHeader and textFooter properties on a ChromePdfRenderOptions object for simple text headers and footers. For richer layouts, use htmlHeader and htmlFooter with raw HTML fragments. Pass the options object to the renderOptions parameter of any conversion method.

How do you change the page size and orientation in IronPDF for Node.js?

Set options.paperSize to a value from the PaperSize enum (such as PaperSize.A4 or PaperSize.Letter) and set options.paperOrientation to PdfPaperOrientation.Portrait or PdfPaperOrientation.Landscape. Pass the configured options to the conversion method.

How do you handle dynamic JavaScript content when converting to PDF?

Use the waitFor property on ChromePdfRenderOptions. Set type to WaitForType.RenderDelay and provide a delay in milliseconds, or set type to WaitForType.HtmlElement and provide a CSS query selector. IronPDF will pause rendering until the condition is satisfied.

How do you convert an HTML file inside a ZIP archive to PDF?

Call PdfDocument.fromZip with the path to the ZIP file as the first argument and an options object as the second. Set the mainHtmlFile property to the name of the HTML file inside the archive that should be converted.

How do you remove the IronPDF watermark from generated PDFs?

Apply a valid license key to the global configuration before calling any conversion method. Retrieve the config object with IronPdfGlobalConfig.getConfig() and set config.licenseKey to your key. A free trial license is available at ironpdf.com.

How do you generate PDFs from an HTML template in Node.js?

Load the template with PdfDocument.fromHtml, then call PdfDocument.replaceText for each placeholder in the template, passing the placeholder string and its replacement value. After all substitutions are complete, call saveAs to write the final PDF.

Darrius Serrant
Full Stack Software Engineer (WebOps)

Darrius Serrant holds a Bachelor’s degree in Computer Science from the University of Miami and works as a Full Stack WebOps Marketing Engineer at Iron Software. Drawn to coding from a young age, he saw computing as both mysterious and accessible, making it the perfect medium for creativity ...

Read More
Ready to Get Started?
Version: 2026.4 just released
Still Scrolling Icon

Still Scrolling?

Want proof fast?
run a sample watch your HTML become a PDF.