You print a page to PDF with Puppeteer, Playwright or headless Chrome, and the colored header, the table stripes and the badges are gone: plain black text on white. We built two test pages (a custom invoice and a Bootstrap 4 report) and printed them both with Chromium 156 in each configuration, then measured the pixels with poppler. Only four things cause this, and each has a one-line fix.
| Symptom | Cause and fix |
|---|---|
| Every background is gone: header, badges, gradients, page color (0% of the indigo header left) | page.pdf() defaults to printBackground: false in Puppeteer and Playwright, like Chrome's unticked "Background graphics" box.Fix: printBackground: true, or the CSS below |
| Backgrounds print, but a white frame runs round every page | The margin passed to page.pdf() is never painted: page color coverage fell from 78% to 65% with 10mm margins.Fix: @page { margin: 0 } and padding on the body |
| Bootstrap 4 tables print white, the navbar vanishes, text is 29% smaller | Bootstrap 4's own @media print block, even with printBackground: true.Fix: print with screen CSS, or override 4 rules |
This is the cause nine times out of ten. Chrome treats backgrounds as "ink saving" material when printing and drops them unless asked. In Playwright (Node):
import { chromium } from 'playwright';
import { readFile } from 'node:fs/promises';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.setContent(await readFile('report.html', 'utf8'), { waitUntil: 'networkidle' });
// await page.emulateMedia({ media: 'screen' }); // optional: skip @media print rules
await page.pdf({
path: 'report.pdf',
format: 'A4',
printBackground: true, // default false: every background color and image is dropped
});
await browser.close();
Puppeteer takes the same printBackground: true option in page.pdf(), and its screen-CSS call is page.emulateMediaType('screen'). Python's Playwright uses print_background=True.
If you can't change the renderer options (a third-party service, the browser's own print dialog, a CLI), put this in the page. With printBackground left at false, our test page then printed exactly like the true version (6.5% indigo header, 78% page color, same as with the option):
/* prints backgrounds even when printBackground / "Background graphics" is off */
* { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
Scope it to the elements that need it (.header, .badge) if you'd rather let other backgrounds drop. Older Chrome versions only read the -webkit- name, so keep both.
Margins set in page.pdf({ margin }) sit outside the page box, and Chrome never paints them, so a page background stops 10mm short of the paper edge. A CSS @page margin wins over the option (we checked with a 10mm option and @page { margin: 0 }: the color reached the corners). Move the white space inside the page instead:
@page { margin: 0; } /* overrides the margin passed to page.pdf() */
html { background: #eef2ff; } /* now reaches the paper edge on every page */
body { margin: 0; padding: 15mm; }
The body padding only pads the top of page 1 and the bottom of the last page. If text on later pages runs too close to the edge, keep a small margin and accept the frame, or give each page its own padded section with a page break after it.
Bootstrap 4.6's CSS ends with an @media print block. With printBackground: true, our report still lost the dark navbar, the striped rows, the table-success row and the dark table head, and the text came out 29% smaller. The rules responsible, from bootstrap.min.css:
@media print {
*,::after,::before{text-shadow:none!important;box-shadow:none!important}
@page{size:a3}
body{min-width:992px!important}
.container{min-width:992px!important}
.navbar{display:none}
.table td,.table th{background-color:#fff!important}
/* ...and more */
}
The @page{size:a3} is the sneaky one: Chrome lays the page out on A3 and scales it down onto your A4 sheet (unless you pass preferCSSPageSize: true, which gives you an A3 PDF instead). Bootstrap 5 dropped all of this and only keeps its .d-print-* display utilities, which is why the same markup prints fine after an upgrade. Two ways out:
page.emulateMedia({ media: 'screen' }) before page.pdf() skips every @media print rule. Our report then printed with all its colors (dark navbar 8.3% of the page, stripes 7.6%, green row 3.5%, same as on screen). You lose any print rules you wrote yourself, too.@page { size: A4; } /* Bootstrap 4 sets size: a3, so Chrome shrinks everything onto A4 */
@media print {
/* Bootstrap 4 paints every table cell white, hiding row colors and stripes */
.table td, .table th { background-color: transparent !important; }
.table .thead-dark th { background-color: #343a40 !important; color: #fff !important; }
.table-success > td, .table-success > th { background-color: #c3e6cb !important; } /* one line per row color you use */
/* it also hides the navbar and forces a 992px minimum layout width */
.navbar { display: flex !important; }
body, .container { min-width: 0 !important; }
}
Older themes built on Bootstrap 3 and the HTML5 Boilerplate print styles go further (Bootstrap 3 sets * { background: transparent !important; color: #000 !important }); for those, screen CSS is the only practical route. To find the culprit on any site, search its CSS for @media print and for !important near background.
/v1/pdf has print_background on by default, so cause 1 can't happen. Pass "screen_media": true to print with screen CSS, and "margin": "0mm" for full-bleed pages. This prints the Bootstrap 4.6 tables documentation:
curl -s -X POST https://shotmint.creasework.com/v1/pdf \
-H "X-API-Key: $SHOTMINT_KEY" -H "Content-Type: application/json" \
-d '{"url": "https://getbootstrap.com/docs/4.6/content/tables/", "screen_media": true}' \
-o tables.pdf
Run against the live API: 20 A4 pages, 1 credit, with the table-dark examples dark as on screen. Without screen_media the same call gives 19 pages of white tables in smaller text. (Writing this guide is how we found that our own screen_media option had stopped working for PDFs, because page.pdf() switches to print CSS unless screen media is set explicitly. It's fixed and re-tested above.)
printBackground: true, or print-color-adjust: exact in the page.@page { margin: 0 } plus body padding.@media print rules that reset backgrounds, shadows or page size.pdftoppm -r 50 -png out.pdf p), not just by opening it in a viewer that may add its own background.Related: Tailwind print classes, CSS page breaks, page numbers and footers, custom fonts in PDFs.
One PDF = one credit, however many pages it has. €5 buys 2,000 renders, credits never expire and there's no subscription.
No signup, no card. Get a key in one click, then buy credits only if you need more (from €5 for 2,000, never expire). From a script, an AI agent, Make or Zapier, POST /v1/keys/free (no body) returns a key as JSON (openapi.json, no-code recipes).
All guides: guides · integrations · comparisons