Free tools Windows power users keep installed

One-click scans. No signup required.

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

Add the watermark before calling page.pdf(). Puppeteer prints with the print media type by default, so a print-only, fixed CSS layer is the most flexible way to place a diagonal or centered mark on every page. Inject the CSS with page.addStyleTag(), enable printBackground: true when the design depends on backgrounds, and inspect the resulting PDF for page breaks, clipping, stacking, and contrast.

Does Puppeteer have a watermark option?

Puppeteer’s documented PDF API does not provide a dedicated watermark option. The reliable approach is to make the watermark part of the document that Chromium prints, then generate the file with page.pdf(). The method works for text marks such as “DRAFT”, “CONFIDENTIAL”, or a company name and can be adapted for an image or other CSS content.

The examples below target Puppeteer documentation versions 25.12.0 (PDF APIs and guide) and 25.11.0 (Page.addStyleTag()), documented on September 29, 2026. Check the API in the version installed by your project because defaults can change.

Use print CSS for a page-content watermark

This complete Node.js example loads a local HTML file, injects a centered diagonal watermark, and writes the PDF to disk.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.goto('file:///absolute/path/to/document.html', {
      waitUntil: 'networkidle0'
    });

    await page.addStyleTag({
      content: `
        @media print {
          body {
            position: relative;
          }
          body::before {
            content: "DRAFT";
            position: fixed;
            inset: 0;
            display: grid;
            place-items: center;
            color: rgba(100, 100, 100, 0.18);
            font: 700 64px sans-serif;
            transform: rotate(-35deg);
            pointer-events: none;
            z-index: 9999;
          }
        }
      `
    });

    await page.pdf({
      path: 'document-watermarked.pdf',
      format: 'A4',
      printBackground: true
    });
  } finally {
    await browser.close();
  }
})();

page.pdf() returns a Uint8Array when no path is supplied; the path option saves the bytes directly. The CSS in this example is an implementation pattern, not a guarantee that every arbitrary layout will repeat or layer identically. Open the actual PDF and verify it.

Why the CSS is print-only

The @media print rule keeps the watermark out of the normal browser view while making it available to page.pdf(). Puppeteer uses print media for PDF generation. A fixed pseudo-element covers the printable viewport and does not consume normal document flow, so it will not push headings or paragraphs down. pointer-events: none prevents it from interfering with interaction if the page is also used in a browser.

Change the text, appearance, and location

  • Replace content: "DRAFT" with your label. CSS generated content is a string, so escape quotes appropriately.
  • Use a smaller font, lower opacity, or a lighter color when the mark competes with body text.
  • For a corner label, replace the centering grid with top: 24px; right: 24px; left: auto; bottom: auto; and remove the grid alignment.
  • For a repeated mark at a specific page position, test the fixed element with your target paper size and margins. CSS pagination and stacking can vary with complex positioned content.

Make backgrounds and print colors appear

printBackground is false by default. Set it to true when the watermark or its supporting design uses CSS background colors or images. A text-only pseudo-element may still render without this option, but enabling it is prudent for designs that rely on backgrounds.

await page.pdf({
  path: 'output.pdf',
  format: 'Letter',
  printBackground: true
});

Chromium may adjust colors for printing. If exact authored colors matter, add -webkit-print-color-adjust: exact; to the relevant elements and check the output rather than assuming screen colors will be identical.

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

Wait for content before applying the watermark

Inject the style only after the page has loaded the content you intend to print. For remote pages, use an appropriate navigation condition and explicitly wait for application data, images, or a font-loading signal when needed.

await page.goto('https://example.com/report', { waitUntil: 'networkidle0' });
await page.waitForSelector('#report-ready');
await page.evaluate(() => document.fonts.ready);
await page.addStyleTag({ content: watermarkCss });
const pdf = await page.pdf({
  path: 'report.pdf',
  preferCSSPageSize: true,
  printBackground: true,
  waitForFonts: true
});

Puppeteer’s PDF guide and PDFOptions expose waitForFonts, which defaults to true. Waiting for fonts reduces layout shifts that can move content beneath a watermark, but it does not replace waits for your application’s data or images.

Choose page size, margins, and media deliberately

Honor the document’s CSS page size

If the page declares an @page size, preferCSSPageSize: true gives that size priority over format, width, or height. This is useful when the document controls its own paper dimensions.

await page.pdf({
  path: 'custom-size.pdf',
  preferCSSPageSize: true,
  printBackground: true
});

Use a named format or explicit dimensions

format defaults to Letter. Select A4, Letter, or another supported format for predictable output, or provide explicit width and height. Keep the watermark’s font size and rotation in proportion to that choice.

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

Use screen styles only when you need them

PDF generation uses print CSS. If your page is designed around screen rules, call await page.emulateMediaType('screen') before page.pdf(). This changes which media rules apply; it does not turn off PDF pagination. Compare the output with print media before choosing this route.

Use headers and footers for repeated labels

A header or footer is often better than a page-content overlay for a simple “Internal” label, document title, or page counter. Enable displayHeaderFooter and provide an HTML template.

await page.pdf({
  path: 'labeled.pdf',
  displayHeaderFooter: true,
  headerTemplate: '
INTERNAL
', footerTemplate: '
Page of
', margin: { top: '48px', bottom: '48px' }, printBackground: true });

Puppeteer documents special template classes including pageNumber and totalPages. Header and footer templates have layout constraints and require enough margin space; verify that they do not overlap the document or disappear at the chosen paper size. They are not a substitute for a diagonal, centered watermark.

Watermark images and custom CSS

For a logo or scanned stamp, add an absolutely or fixed-position element rather than relying on generated text.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.addStyleTag({
  content: `
    @media print {
      .watermark-image {
        position: fixed;
        inset: 0;
        width: 100%;
        height: 100%;
        object-fit: contain;
        opacity: .12;
        transform: rotate(-25deg);
        z-index: 9999;
        pointer-events: none;
      }
    }
  `
});
await page.evaluate(() => {
  const image = document.createElement('img');
  image.className = 'watermark-image';
  image.src = 'data:image/png;base64,REPLACE_WITH_YOUR_IMAGE';
  document.body.appendChild(image);
});

Use a data URL or a resource that the browser can access. If the image loads asynchronously, wait for its load event before creating the PDF. Confirm that opacity, clipping, and the stacking order remain acceptable on every page.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common failures and fixes

Symptom Likely cause Fix
No watermark The style was injected after PDF generation, the selector did not match, or the rule was not inside an applicable media context. Call addStyleTag() before page.pdf(); inspect the page with page.evaluate(); test the rule under @media print.
Background or logo missing printBackground remained at its default of false. Set printBackground: true and verify that the asset URL is reachable.
Watermark appears once or is clipped Fixed positioning interacts with pagination, transforms, page margins, or a containing stacking context. Try a simpler fixed element, remove conflicting transforms, adjust margins and z-index, and inspect every page at the target format.
Watermark covers important text Opacity, font size, or placement is too aggressive. Lower opacity, move the mark, reduce its size, or use a header/footer label.
Content shifts or is cut off Fonts, images, or application data were not ready when printing began. Wait for the required selector, image loads, network activity, and document.fonts.ready; then generate the PDF.
Header/footer overlaps content Margins are too small for the template. Increase the top or bottom margin and retest with the longest header/footer text.
Colors differ from the browser Print color adjustment changed them. Use -webkit-print-color-adjust: exact where appropriate and validate the resulting file.

Test the generated PDF, not just the HTML

  • Open pages at the beginning, middle, and end of a multi-page document.
  • Check the requested paper size, margins, page breaks, and orientation.
  • Confirm that the mark is behind readable text and above the intended background.
  • Test long headings, tables, images, missing assets, and pages with unusual content.
  • Verify that PDFs generated in production use the same Chromium and Puppeteer versions as local tests.

CSS watermarking is presentation-layer work. It does not cryptographically prove authorship or prevent removal by a determined PDF editor; use a separate signing or rights-management system when that is the requirement.

Or skip the browser setup

If your goal is simply to capture a clean, watermarked-ready PDF or image from a URL, ScreenshotNeo provides a one-request website screenshot API and MCP server. Its capture options include PDF paper size, margins, landscape mode, page ranges, custom CSS and JavaScript, waiting for a selector or network idle, and blocking unwanted requests. You can supply CSS that creates the watermark before capture.

cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo documentation for PDF and custom-CSS parameters. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

What’s actually slowing this PC down?

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

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

Frequently Asked Questions

Can I watermark an existing PDF with Puppeteer?

Puppeteer is primarily a browser renderer. Load the source content in a page, add the print CSS, and generate a new PDF; use a PDF-specific processing library when you must edit an already-generated PDF without re-rendering.

Will a fixed CSS watermark always appear on every page?

It is intended to repeat during printing, but pagination, transforms, stacking contexts, and browser layout can affect arbitrary documents. Validate the actual multi-page PDF for your layout and Puppeteer version.

Should I use a header, footer, or page-content watermark?

Use page-content CSS for diagonal or centered marks, and header/footer templates for simple repeated labels or page metadata with predictable margins.

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

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