Skip to content

cherfia/chromiumly

Repository files navigation

Chromiumly Logo

build coverage vulnerabilities Maintainability npm downloads licence

A lightweight TypeScript client for Gotenberg’s HTTP API. Use it against your own Gotenberg container or against the Chromiumly hosted API—same client, different backend.

Self‑hosted Gotenberg Chromiumly hosted API
What it is Official open‑source PDF stack (Docker image) Managed service at https://api.chromiumly.dev
What Chromiumly calls Documented Gotenberg routes (Chromium, LibreOffice, PDF engines, …) Those same routes, plus Templates (not in open‑source Gotenberg)
Configuration GOTENBERG_ENDPOINT CHROMIUMLY_API_KEY (no endpoint)

Everything in this README that maps to gotenberg.dev applies to both backends unless a section says otherwise. Templates are Chromiumly hosted API only—they are not a Gotenberg feature and do not work with a self‑hosted instance.

API Key Authentication (Hosted API)

Chromiumly provides a managed API at https://api.chromiumly.dev. Hosted API support was introduced in chromiumly@5.0.0 and is available only in Chromiumly 5.0.0+. If you prefer not to run Gotenberg yourself, you avoid Docker and server ops. Sign up at https://chromiumly.dev, get an API key, and call the same conversion routes as with self‑hosting. The hosted API also exposes Templates (invoice PDFs from structured data), which are not available on self‑hosted Gotenberg.

When using the hosted API, you do not need to set GOTENBERG_ENDPOINT. Just provide your API key:

CHROMIUMLY_API_KEY=your-api-key

Once the environment variable is set, Chromiumly will automatically send all requests to the hosted API using your key.

You can also configure the hosted API programmatically without an endpoint:

import { Chromiumly } from "chromiumly";

Chromiumly.configure({
  apiKey: "your-api-key",
});

Minimal usage example (hosted API)

import { UrlConverter } from "chromiumly";

async function run() {
  const urlConverter = new UrlConverter();

  const buffer = await urlConverter.convert({
    url: "https://www.example.com/",
  });

  // Write the buffer to disk, send it over HTTP, etc.
}

run();

Table of Contents

  1. API Key Authentication (Hosted API)
  2. Getting Started
  3. Authentication
  4. Core Features
  5. Usage Example

Getting Started

Installation

Using npm:

npm install chromiumly

Using yarn:

yarn add chromiumly

Prerequisites

If you are using the hosted API key option at https://api.chromiumly.dev, you do not need Docker or a local Gotenberg instance — the service is fully managed for you.

If you prefer to self‑host Gotenberg, be sure you install Docker if you have not already done so.

After that, you can start a default Docker container of Gotenberg as follows:

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

Configuration

Chromiumly supports configurations via both dotenv and config configuration libraries or directly via code to add a Gotenberg endpoint to your project when you are self‑hosting.

dotenv

GOTENBERG_ENDPOINT=http://localhost:3000

config

{
  "gotenberg": {
    "endpoint": "http://localhost:3000"
  }
}

code

import { Chromiumly } from "chromiumly";

Chromiumly.configure({ endpoint: "http://localhost:3000" });

Authentication

Basic Authentication

Gotenberg introduces basic authentication support starting from version 8.4.0. Suppose you are running a Docker container using the command below:

docker run --rm -p 3000:3000 \
-e GOTENBERG_API_BASIC_AUTH_USERNAME=user \
-e GOTENBERG_API_BASIC_AUTH_PASSWORD=pass \
gotenberg/gotenberg:8.4.0 gotenberg --api-enable-basic-auth

To integrate this setup with Chromiumly, you need to update your configuration as outlined below:

GOTENBERG_ENDPOINT=http://localhost:3000
GOTENBERG_API_BASIC_AUTH_USERNAME=user
GOTENBERG_API_BASIC_AUTH_PASSWORD=pass

Or

{
  "gotenberg": {
    "endpoint": "http://localhost:3000",
    "api": {
      "basicAuth": {
        "username": "user",
        "password": "pass"
      }
    }
  }
}

Or

Chromiumly.configure({
  endpoint: "http://localhost:3000",
  username: "user",
  password: "pass",
});

API Key Authentication

API key authentication is primarily intended for the hosted Chromiumly API at https://api.chromiumly.dev. For setup and examples, see API Key Authentication (Hosted API). When both API key and basic auth are configured, the API key takes precedence.

Advanced Authentication

To implement advanced authentication or add custom HTTP headers to your requests, you can use the customHttpHeaders option within the configure method. This allows you to pass additional headers, such as authentication tokens or custom metadata, with each API call.

For example, you can include a Bearer token for authentication along with a custom header as follows:

const token = await generateToken();

Chromiumly.configure({
  endpoint: "http://localhost:3000",
  customHttpHeaders: {
    Authorization: `Bearer ${token}`,
    "X-Custom-Header": "value",
  },
});

Core Features

Chromiumly wraps Gotenberg’s HTTP API: classes mirror the routes described in Gotenberg’s docs. Methods that take files accept a path string, Buffer, or ReadStream (e.g. html, header, footer, markdown).

The Templates class is the exception—it talks only to the Chromiumly hosted API and is documented below.

Chromium

There are three different classes that come with a single method (i.e.convert) which calls one of Chromium's conversion routes to convert html and markdown files, or a url to a buffer which contains the converted PDF file content.

Similarly, a new set of classes have been added to harness the recently introduced Gotenberg screenshot routes. These classes include a single method called capture, which allows capturing full-page screenshots of html, markdown, and url.

URL

import { UrlConverter } from "chromiumly";

const urlConverter = new UrlConverter();
const buffer = await urlConverter.convert({
  url: "https://www.example.com/",
});
import { UrlScreenshot } from "chromiumly";

const screenshot = new UrlScreenshot();
const buffer = await screenshot.capture({
  url: "https://www.example.com/",
});

HTML

The only requirement is that the file name should be index.html.

import { HtmlConverter } from "chromiumly";

const htmlConverter = new HtmlConverter();
const buffer = await htmlConverter.convert({
  html: "path/to/index.html",
});
import { HtmlScreenshot } from "chromiumly";

const screenshot = new HtmlScreenshot();
const buffer = await screenshot.capture({
  html: "path/to/index.html",
});

Markdown

This route accepts an index.html file plus a markdown file.

import { MarkdownConverter } from "chromiumly";

const markdownConverter = new MarkdownConverter();
const buffer = await markdownConverter.convert({
  html: "path/to/index.html",
  markdown: "path/to/file.md",
});
import { MarkdownScreenshot } from "chromiumly";

const screenshot = new MarkdownScreenshot();
const buffer = await screenshot.capture({
  html: "path/to/index.html",
  markdown: "path/to/file.md",
});

Each convert() method takes an optional properties parameter of the following type which dictates how the PDF generated file will look like.

type PageProperties = {
  singlePage?: boolean; // Print the entire content in one single page (default false)
  size?: {
    width: number | string; // Paper width (number in inches or string with units: 72pt, 96px, 1in, 25.4mm, 2.54cm, 6pc, default 8.5)
    height: number | string; // Paper height (number in inches or string with units: 72pt, 96px, 1in, 25.4mm, 2.54cm, 6pc, default 11)
  };
  margins?: {
    top: number | string; // Top margin (number in inches or string with units: 72pt, 96px, 1in, 25.4mm, 2.54cm, 6pc, default 0.39)
    bottom: number | string; // Bottom margin (number in inches or string with units: 72pt, 96px, 1in, 25.4mm, 2.54cm, 6pc, default 0.39)
    left: number | string; // Left margin (number in inches or string with units: 72pt, 96px, 1in, 25.4mm, 2.54cm, 6pc, default 0.39)
    right: number | string; // Right margin (number in inches or string with units: 72pt, 96px, 1in, 25.4mm, 2.54cm, 6pc, default 0.39)
  };
  preferCssPageSize?: boolean; // Define whether to prefer page size as defined by CSS (default false)
  printBackground?: boolean; // Print the background graphics (default false)
  omitBackground?: boolean; // Hide the default white background and allow generating PDFs with transparency (default false)
  landscape?: boolean; // Set the paper orientation to landscape (default false)
  scale?: number; // The scale of the page rendering (default 1.0)
  nativePageRanges?: { from: number; to: number }; // Page ranges to print
};

Page Size and Margins Units

Both size and margins properties support two formats:

  1. Numeric values (in inches): For backward compatibility, you can continue using numbers which represent inches.
  2. String values with units: You can now specify explicit units using the following formats:
    • pt (points): e.g., "72pt"
    • px (pixels): e.g., "96px"
    • in (inches): e.g., "1in"
    • mm (millimeters): e.g., "25.4mm"
    • cm (centimeters): e.g., "2.54cm"
    • pc (picas): e.g., "6pc"

Examples:

// Using numeric values (inches)
properties: {
  size: { width: 8.5, height: 11 },
  margins: { top: 0.5, bottom: 0.5, left: 1, right: 1 }
}

// Using string values with units
properties: {
  size: { width: "210mm", height: "297mm" }, // A4 size
  margins: { top: "1cm", bottom: "1cm", left: "2cm", right: "2cm" }
}

// Mixing numeric and string values
properties: {
  size: { width: 8.5, height: "11in" },
  margins: { top: "10mm", bottom: 0.5, left: "72pt", right: 1 }
}

In addition to the PageProperties customization options, the convert() method also accepts a set of parameters to further enhance the versatility of the conversion process. Here's an overview of the full list of parameters:

type ConversionOptions = {
  properties?: PageProperties; // Customize the appearance of the generated PDF
  pdfFormat?: PdfFormat; // Define the PDF format for the conversion
  pdfUA?: boolean; // Enable PDF for Universal Access for optimal accessibility (default false)
  userAgent?: string; // Customize the user agent string sent during conversion
  header?: PathLikeOrReadStream; // Specify a custom header for the PDF
  footer?: PathLikeOrReadStream; // Specify a custom footer for the PDF
  emulatedMediaType?: EmulatedMediaType; // Specify the emulated media type for conversion
  emulatedMediaFeatures?: EmulatedMediaFeature[]; // Override CSS media features (e.g., prefers-color-scheme). Default: None.
  waitDelay?: string; // Duration (e.g., '5s') to wait when loading an HTML document before conversion
  waitForExpression?: string; // JavaScript expression to wait before converting an HTML document into PDF
  waitForSelector?: string; // CSS selector to wait for before converting an HTML document into PDF until it matches a node
  extraHttpHeaders?: Record<string, string>; // Include additional HTTP headers in the request
  failOnHttpStatusCodes?: number[]; // List of HTTP status codes triggering a 409 Conflict response (default [499, 599])
  failOnConsoleExceptions?: boolean; // Return a 409 Conflict response if there are exceptions in the Chromium console (default false)
  failOnResourceHttpStatusCodes?: number[]; // Return a 409 Conflict response if resource HTTP status code is in the list (default [499,599])
  ignoreResourceHttpStatusDomains?: string[]; // Domains to exclude from resource HTTP status code checks (matches exact domains or subdomains)
  failOnResourceLoadingFailed?: boolean; // Return a 409 Conflict response if resource loading failed (default false)
  skipNetworkIdleEvent?: boolean; // Do not wait for Chromium network to be idle (default true)
  skipNetworkAlmostIdleEvent?: boolean; // Do not wait for Chromium network to be almost idle (default true)
  metadata?: Metadata; // Metadata to be written.
  cookies?: Cookie[]; // Cookies to be written.
  downloadFrom?: DownloadFrom; //Download a file from a URL. It must return a Content-Disposition header with a filename parameter.
  split?: SplitOptions; // Split the PDF file into multiple files.
  userPassword?: string; // Password for opening the resulting PDF(s).
  ownerPassword?: string; // Password for full access on the resulting PDF(s).
  embeds?: PathLikeOrReadStream[]; // Files to embed in the generated PDF.
  watermark?: PdfEngineWatermark; // Optional PDF-engine post-processing watermark (behind page content).
  stamp?: PdfEngineStamp; // Optional PDF-engine post-processing stamp (on top of page content).
};

Optional watermark and stamp use the same multipart field names as Gotenberg’s PDF-engine watermark/stamp: text, image, or PDF sources, with JSON options depending on your configured engine (e.g. pdfcpu). See Watermark PDFs and Stamp PDFs in the official docs.

type PdfEngineWatermark = {
  source?: "text" | "image" | "pdf";
  expression?: string; // Text, or filename of the uploaded asset when source is image or pdf
  pages?: string; // Page ranges (e.g. "1-3"); omit for all pages
  options?: Record<string, unknown>; // Serialized as JSON (engine-specific)
  file?: PathLikeOrReadStream | Buffer; // Required when source is image or pdf
};

type PdfEngineStamp = {
  source?: "text" | "image" | "pdf";
  expression?: string;
  pages?: string;
  options?: Record<string, unknown>;
  file?: PathLikeOrReadStream | Buffer;
};

Screenshot

Similarly, the capture() method takes an optional properties parameter of the specified type, influencing the appearance of the captured screenshot file.

type ImageProperties = {
  format: "png" | "jpeg" | "webp"; //The image compression format, either "png", "jpeg" or "webp".
  quality?: number; // The compression quality from range 0 to 100 (jpeg only).
  omitBackground?: boolean; // Hide the default white background and allow generating screenshots with transparency.
  width?: number; // The device screen width in pixels (default 800).
  height?: number; // The device screen height in pixels (default 600).
  clip?: boolean; // Define whether to clip the screenshot according to the device dimensions (default false).
};

Furthermore, alongside the customization options offered by ImageProperties, the capture() method accommodates a variety of parameters to expand the versatility of the screenshot process. Below is a comprehensive overview of all parameters available:

type ScreenshotOptions = {
  properties?: ImageProperties;
  header?: PathLikeOrReadStream;
  footer?: PathLikeOrReadStream;
  emulatedMediaType?: EmulatedMediaType;
  emulatedMediaFeatures?: EmulatedMediaFeature[]; // Override CSS media features (e.g., prefers-color-scheme). Default: None.
  waitDelay?: string; // Duration (e.g, '5s') to wait when loading an HTML document before convertion.
  waitForExpression?: string; // JavaScript's expression to wait before converting an HTML document into PDF until it returns true.
  waitForSelector?: string; // CSS selector to wait for before converting an HTML document into PDF until it matches a node.
  extraHttpHeaders?: Record<string, string>;
  failOnHttpStatusCodes?: number[]; // Return a 409 Conflict response if the HTTP status code is in the list (default [499,599])
  failOnConsoleExceptions?: boolean; // Return a 409 Conflict response if there are exceptions in the Chromium console (default false)
  failOnResourceHttpStatusCodes?: number[]; // Return a 409 Conflict response if resource HTTP status code is in the list (default [499,599])
  ignoreResourceHttpStatusDomains?: string[]; // Domains to exclude from resource HTTP status code checks (matches exact domains or subdomains)
  failOnResourceLoadingFailed?: boolean; // Return a 409 Conflict response if resource loading failed (default false)
  skipNetworkIdleEvent?: boolean; // Do not wait for Chromium network to be idle (default true)
  skipNetworkAlmostIdleEvent?: boolean; // Do not wait for Chromium network to be almost idle (default true)
  optimizeForSpeed?: boolean; // Define whether to optimize image encoding for speed, not for resulting size.
  cookies?: Cookie[]; // Cookies to be written.
  downloadFrom?: DownloadFrom; // Download the file from a specific URL. It must return a Content-Disposition header with a filename parameter.
  userPassword?: string; // Password for opening the resulting PDF(s).
  ownerPassword?: string; // Password for full access on the resulting PDF(s).
  embeds?: PathLikeOrReadStream[]; // Files to embed in the generated PDF.
};

LibreOffice

The LibreOffice class comes with a single method convert. This method interacts with LibreOffice route to convert different documents to PDF files. You can find the file extensions accepted here.

import { LibreOffice } from "chromiumly";

const buffer = await LibreOffice.convert({
  files: [
    "path/to/file.docx",
    "path/to/file.png",
    { data: xlsxFileBuffer, ext: "xlsx" },
  ],
});

Similarly to Chromium's route convert method, this method takes the following optional parameters :

  • properties: changes how the PDF generated file will look like. It also includes a password parameter to open the source file.
  • pdfa: PDF format of the conversion resulting file (i.e. PDF/A-1a, PDF/A-2b, PDF/A-3b).
  • pdfUA: enables PDF for Universal Access for optimal accessibility.
  • merge: merges all the resulting files from the conversion into an individual PDF file.
  • metadata: writes metadata to the generated PDF file.
  • losslessImageCompression: allows turning lossless compression on or off to tweak image conversion performance.
  • reduceImageResolution: allows turning on or off image resolution reduction to tweak image conversion performance.
  • quality: specifies the quality of the JPG export. The value ranges from 1 to 100, with higher values producing higher-quality images and larger file sizes.
  • maxImageResolution: specifies if all images will be reduced to the specified DPI value. Possible values are: 75, 150, 300, 600, and 1200.
  • initialView: initial PDF view mode (0: none, 1: outline, 2: thumbnails).
  • initialPage: page number opened by default.
  • magnification: initial magnification mode (0: default, 1: fit page, 2: fit width, 3: fit visible, 4: explicit zoom).
  • zoom: initial zoom percentage when magnification is 4.
  • pageLayout: initial layout (0: default, 1: single page, 2: one column, 3: two columns).
  • firstPageOnLeft: place first page on the left when using two-column layout.
  • resizeWindowToInitialPage: resize the viewer window to the first page dimensions.
  • centerWindow: center the PDF viewer window on screen.
  • openInFullScreenMode: open the PDF in full-screen mode.
  • displayPDFDocumentTitle: display PDF title in viewer title bar instead of filename.
  • hideViewerMenubar: hide the viewer menu bar.
  • hideViewerToolbar: hide the viewer toolbar.
  • hideViewerWindowControls: hide viewer window controls.
  • useTransitionEffects: use transition effects for Impress slides.
  • openBookmarkLevels: number of bookmark levels opened on load (-1 opens all levels).
  • flatten: a boolean that, when set to true, flattens the split PDF files, making form fields and annotations uneditable.
  • userPassword: password for opening the resulting PDF(s).
  • ownerPassword: password for full access on the resulting PDF(s).
  • embeds: files to embed in the generated PDF (repeatable). This feature enables the creation of PDFs compatible with standards like ZUGFeRD / Factur-X, which require embedding XML invoices and other files within the PDF.
  • Native LibreOffice watermarks (applied during export): nativeWatermarkText, nativeWatermarkColor, nativeWatermarkFontHeight, nativeWatermarkRotateAngle, nativeWatermarkFontName, nativeTiledWatermarkText — see Convert to PDF.
  • PDF-engine watermark/stamp (post-processing after conversion): watermark and stamp — same shapes as in Chromium ConversionOptions (PdfEngineWatermark / PdfEngineStamp). For { data, ext } file objects, use the same pattern as in files.

PDF Engines

The PDFEngines class interacts with Gotenberg's PDF Engines routes to manipulate PDF files.

Format Conversion

This method interacts with PDF Engines convertion route to transform PDF files into the requested PDF/A format and/or PDF/UA.

import { PDFEngines } from "chromiumly";

const buffer = await PDFEngines.convert({
  files: ["path/to/file_1.pdf", "path/to/file_2.pdf"],
  pdfa: PdfFormat.A_2b,
  pdfUA: true,
});

Merging

This method interacts with PDF Engines merge route which gathers different engines that can manipulate and merge PDF files such as: PDFtk, PDFcpu, QPDF, and UNO.

import { PDFEngines } from "chromiumly";

const buffer = await PDFEngines.merge({
  files: ["path/to/file_1.pdf", "path/to/file_2.pdf"],
  pdfa: PdfFormat.A_2b,
  pdfUA: true,
});

Optional watermark and stamp (PdfEngineWatermark / PdfEngineStamp) apply PDF-engine post-processing to the merged output, matching Merge PDFs in the Gotenberg docs.

Optional rotate ({ angle: 90 | 180 | 270; pages?: string }) rotates pages after merge via the PDF engine; omit pages or leave it empty to rotate all pages.

PDF Rotation

PDFEngines.rotate() calls Gotenberg’s rotate route to rotate existing PDFs. The same post-processing is available on PDFEngines.merge(), PDFEngines.split(), and on Chromium and LibreOffice convert() through the optional rotate property (Gotenberg generates the PDF, then rotates selected pages—an extra pass).

import { PDFEngines } from "chromiumly";

const rotated = await PDFEngines.rotate({
  files: ["path/to/document.pdf"],
  angle: 90,
  pages: "1-3", // optional; omit for all pages
});

Watermark and stamp (dedicated routes)

These methods call /forms/pdfengines/watermark and /forms/pdfengines/stamp.

import { PDFEngines } from "chromiumly";

const watermarked = await PDFEngines.watermark({
  files: ["path/to/document.pdf"],
  watermark: {
    source: "text",
    expression: "CONFIDENTIAL",
    options: { opacity: 0.25, rotation: 45 },
  },
});

const stamped = await PDFEngines.stamp({
  files: ["path/to/document.pdf"],
  stamp: {
    source: "text",
    expression: "APPROVED",
    options: { opacity: 0.5, rotation: 0 },
  },
});

Metadata Management

readMetadata

This method reads metadata from the provided PDF files.

import { PDFEngines } from "chromiumly";

const metadataBuffer = await PDFEngines.readMetadata([
  "path/to/file_1.pdf",
  "path/to/file_2.pdf",
]);
writeMetadata

This method writes metadata to the provided PDF files.

import { PDFEngines } from "chromiumly";

const buffer = await PDFEngines.writeMetadata({
  files: ["path/to/file_1.pdf", "path/to/file_2.pdf"],
  metadata: {
    Author: "Taha Cherfia",
    Title: "Chromiumly",
    Keywords: ["pdf", "html", "gotenberg"],
  },
});

Please consider referring to ExifTool for a comprehensive list of accessible metadata options.

File Generation

It is just a generic complementary method that takes the buffer returned by the convert method, and a chosen filename to generate the PDF file.

Please note that all the PDF files can be found __generated__ folder in the root folder of your project.

PDF Splitting

Each Chromium and LibreOffice route has a split parameter that allows splitting the PDF file into multiple files. The split parameter is an object with the following properties:

  • mode: the mode of the split. It can be pages or intervals.
  • span: the span of the split. It is a string that represents the range of pages to split.
  • unify: a boolean that allows unifying the split files. Only works when mode is pages.
  • flatten: a boolean that, when set to true, flattens the split PDF files, making form fields and annotations uneditable.
import { UrlConverter } from "chromiumly";
const buffer = await UrlConverter.convert({
  url: "https://www.example.com/",
  split: {
    mode: "pages",
    span: "1-2",
    unify: true,
  },
});

On the other hand, PDFEngines' has a split method that interacts with PDF Engines split route which splits PDF files into multiple files.

import { PDFEngines } from "chromiumly";

const buffer = await PDFEngines.split({
  files: ["path/to/file_1.pdf", "path/to/file_2.pdf"],
  options: {
    mode: "pages",
    span: "1-2",
    unify: true,
  },
});

PDFEngines.split also accepts optional watermark, stamp, and rotate for the same PDF-engine post-processing as merge.

⚠️ Note: Gotenberg does not currently validate the span value when mode is set to pages, as the validation depends on the chosen engine for the split feature. See PDF Engines module configuration for more details.

PDF Flattening

PDF flattening converts interactive elements like forms and annotations into a static PDF. This ensures the document looks the same everywhere and prevents further edits.

import { PDFEngines } from "chromiumly";

const buffer = await PDFEngines.flatten({
  files: ["path/to/file_1.pdf", "path/to/file_2.pdf"],
});

PDF Encryption

Each Chromium and LibreOffice route supports PDF encryption through the userPassword and ownerPassword parameters. The userPassword is required to open the PDF, while the ownerPassword provides full access permissions.

import { UrlConverter } from "chromiumly";

const buffer = await UrlConverter.convert({
  url: "https://www.example.com/",
  userPassword: "my_user_password",
  ownerPassword: "my_owner_password",
});

Embedding Files

Each Chromium and LibreOffice route supports embedding files into the generated PDF through the embeds parameter. This feature enables the creation of PDFs compatible with standards like ZUGFeRD / Factur-X, which require embedding XML invoices and other files within the PDF.

You can embed multiple files by passing an array of file paths, buffers, or read streams:

import { HtmlConverter } from "chromiumly";

const htmlConverter = new HtmlConverter();
const buffer = await htmlConverter.convert({
  html: "path/to/index.html",
  embeds: [
    "path/to/invoice.xml",
    "path/to/logo.png",
    Buffer.from("additional data"),
  ],
});

All embedded files will be attached to the generated PDF and can be extracted using PDF readers that support file attachments.

Templates (hosted API only)

The Templates class is not part of open‑source Gotenberg. It generates PDFs from structured payloads on the Chromiumly hosted API and requires CHROMIUMLY_API_KEY. Hosted API features (including Templates) were introduced in chromiumly@5.0.0 and require Chromiumly 5.0.0+—pointing Chromiumly at GOTENBERG_ENDPOINT (self‑hosted Gotenberg) will not enable this feature.

The following template types are currently available:

Type Description
invoice_saas SaaS-style invoice
invoice_freelancer Freelancer invoice
invoice_classic Classic invoice
invoice_minimal Minimal invoice
invoice_modern Modern invoice

Basic Usage

import { Templates } from "chromiumly";

const templates = new Templates();
const buffer = await templates.generate({
  type: "invoice_saas",
  data: {
    invoiceNumber: "INV-319",
    createdDate: "2026-03-19",
    dueDate: "2026-04-02",
    companyLogo: "https://cdn.acmecloud.com/assets/logo-mark.png",
    sender: {
      name: "Acme Cloud LLC",
      addressLine1: "450 Madison Ave",
      addressLine2: "New York, NY 10022",
    },
    receiver: {
      name: "Northwind Health Inc.",
      addressLine1: "221 Harbor Blvd",
      addressLine2: "San Diego, CA 92101",
    },
    items: [
      {
        description: "Platform Subscription (Annual)",
        qty: 1,
        unitPrice: "1500.00",
        amount: "1500.00",
      },
      {
        description: "Onboarding",
        qty: 1,
        unitPrice: "300.00",
        amount: "300.00",
      },
    ],
    currency: "USD",
    subTotal: "1800.00",
    taxRate: 8.25,
    taxAmount: "148.50",
    total: "1948.50",
    footerNote: "Payment due in 14 days.",
    footerDisclaimer: "Late fees may apply.",
  },
});

Payload Validation

Pass { validate: true } to run runtime validation on the data before sending the request. An error is thrown if the payload does not match the expected structure for the given template type.

const buffer = await templates.generate(request, { validate: true });

Payload Shape

type TemplateRequest<TType extends TemplateType> = {
  type: TType;
  data: TemplateDataByType[TType];
};

interface InvoiceSaasTemplateData {
  invoiceNumber: string;
  createdDate: string;
  dueDate: string;
  companyLogo: string;
  sender: TemplateParty;
  receiver: TemplateParty;
  items: InvoiceItem[];
  currency: Currency;
  subTotal: string;
  taxRate: number;
  taxAmount: string;
  total: string;
  footerNote: string;
  footerDisclaimer: string;
}

interface TemplateParty {
  name: string;
  addressLine1: string;
  addressLine2: string;
  tax?: string;
  iban?: string;
  bic?: string;
}

interface InvoiceItem {
  description: string;
  qty: number;
  unitPrice: string;
  amount: string;
}

The currency field accepts any ISO 4217 currency code exported as the Currency type (e.g. "USD", "EUR", "GBP").

Watermark and stamp

Gotenberg can apply a watermark (behind content) and/or stamp (on top of content) using the configured PDF engine after the main conversion or PDF operation. Types PdfEngineWatermark and PdfEngineStamp are exported from chromiumly if you want them explicitly in your code. Chromiumly exposes this on:

API What to pass
UrlConverter / HtmlConverter / MarkdownConverter convert() watermark, stamp, rotate on the options object (see ConversionOptions above)
LibreOffice.convert() Native fields (nativeWatermarkText, …) and/or watermark, stamp, rotate
PDFEngines.merge() / PDFEngines.split() Optional watermark, stamp, rotate
PDFEngines.rotate() Dedicated endpoint; files, angle (90 | 180 | 270), optional pages
PDFEngines.watermark() / PDFEngines.stamp() Dedicated endpoints; watermark or stamp config is required

For image or PDF sources, set source to image or pdf, set expression to the filename of the uploaded asset, and pass the file in file. Chromium screenshot routes do not document these fields; use HTML/CSS overlays or convert-to-PDF flows instead.

Snippet

The following is a short snippet of how to use the library.

import { PDFEngines, UrlConverter } from "chromiumly";

async function run() {
  const urlConverter = new UrlConverter();
  const buffer = await urlConverter.convert({
    url: "https://gotenberg.dev/",
    properties: {
      singlePage: true,
      size: {
        width: 8.5,
        height: 11,
      },
    },
    emulatedMediaType: "screen",
    emulatedMediaFeatures: [
      { name: "prefers-color-scheme", value: "dark" },
      { name: "prefers-reduced-motion", value: "reduce" },
    ],
    failOnHttpStatusCodes: [404],
    failOnConsoleExceptions: true,
    skipNetworkIdleEvent: false,
    skipNetworkAlmostIdleEvent: false,
    optimizeForSpeed: true,
    split: {
      mode: "pages",
      span: "1-2",
      unify: true,
    },
  });

  await PDFEngines.generate("gotenberg.pdf", buffer);
}

run();

About

A lightweight Typescript library that interacts with Gotenberg's different modules to convert a variety of document formats to PDF files.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors