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

Generate the PDF inside an HTTP-triggered Firebase Function, then return Puppeteer’s Uint8Array as an HTTP attachment. The essential sequence is: validate the request, launch a Chromium binary available in the deployed function, render trusted content, call page.pdf(), send the bytes with PDF headers, and close the browser in a finally block.

Architecture: render, return, and download

An HTTP function is a good fit when a user or application needs a PDF immediately. The function receives parameters, renders a page, and sends the resulting bytes. Firebase requires every HTTP handler to finish with send(), redirect(), or end(); an unended response can leave clients waiting.

The example below uses Firebase Functions v2 and Node.js. Firebase currently lists Node.js 20 and 22 as supported and Node.js 18 as deprecated. Node.js 14 and 16 deployments are disabled after their decommissioning in early 2025. Confirm the runtime selected in your project before deploying.

1. Create the function project

Install the required packages

In an initialized Firebase project, install the Functions SDK and Puppeteer:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Brother Compact Monochrome Laser Printer, HLL2395DW, Flatbed Copy & Scan, Wireless Printing, NFC with Refresh Subscription Free Trial and Amazon Dash Replenishment Ready
  • Engineered for convenience – This new Brother Monochrome Laser Printer is conveniently equipped with a flatbed scan glass for quick copying and scanning. Mobile Device Compatibility AirPrint, Google Cloud Print 2.0, Brother iPrint and Scan, Mopria, Cortado Workplace
  • Optimized for efficiency – Engineered with new features, the HL L2395DW laser printer (replacement for the HLL2380DW) and has been optimized for efficiency, allowing you to print up to 36 pages per minute(1)
  • Faster, high quality prints: This monochrome laser printer is built with a 250 sheet paper capacity that helps improve efficiency due to less time spent refilling trays. It also handles both letter and legal sized paper. Power Source AC 120V 50/60Hz.Machine Noise (Ready/Printing): 30dB / 50dB
  • Cloud based print & scan – Print from and scan to popular Cloud services directly from the 2.7" color touchscreen, including Dropbox, Google Drive, Evernote, OneNote, and more(4)
  • Wireless printing & exceptional support – This printer’s simple to connect wireless technology allows you to submit print jobs from your laptop, smartphone, desktop, and tablets(2). The "Touch to connect" printing with NFC delivers added convenience(3).
npm install firebase-functions puppeteer

The standard puppeteer package downloads a compatible Chrome for Testing browser during installation. Your build must run the install step and preserve Puppeteer’s browser cache in the deployed artifact. If your package manager blocks install scripts, the browser may not be present.

Choose a supported runtime

Set the Functions runtime in functions/package.json, for example:

{
  "engines": {
    "node": "20"
  }
}

Use source-code runtime options for memory, timeout, and CORS. The values in the complete example are starting points, not performance guarantees. Firebase documents HTTP and callable function timeouts up to 3,600 seconds; that is a ceiling, not an expected PDF-generation time.

2. Implement a PDF download endpoint

This handler renders a small HTML document supplied by the function itself. In production, authenticate callers and use an allowlist or trusted data source rather than accepting unrestricted URLs or HTML. A renderer that can fetch arbitrary addresses can be abused for server-side request forgery.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const { onRequest } = require('firebase-functions/v2/https');
const puppeteer = require('puppeteer');

exports.downloadPdf = onRequest({
  memory: '1GiB',
  timeoutSeconds: 120,
  cors: ['https://your-frontend.example'],
}, async (req, res) => {
  let browser;
  try {
    if (req.method !== 'GET' && req.method !== 'POST') {
      res.status(405).set('Allow', 'GET, POST').send('Method not allowed');
      return;
    }

    const title = typeof req.query.title === 'string'
      ? req.query.title.slice(0, 200)
      : 'Example document';

    browser = await puppeteer.launch({
      // Add project-specific flags only when your deployed runtime requires them.
    });
    const page = await browser.newPage();

    const html = `<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>${title.replace(/[&<>"']/g, '')}</title>
    <style>
      @page { size: A4; margin: 18mm; }
      body { font-family: Arial, sans-serif; color: #222; }
      h1 { font-size: 24px; }
    </style>
  </head>
  <body>
    <h1>${title.replace(/[&<>"']/g, '')}</h1>
    <p>Generated by a Firebase HTTP function.</p>
  </body>
</html>`;

    await page.setContent(html, { waitUntil: 'networkidle0' });
    const pdf = await page.pdf({
      format: 'A4',
      printBackground: true,
    });

    res.status(200)
      .set('Content-Type', 'application/pdf')
      .set('Content-Disposition', 'attachment; filename="document.pdf"')
      .send(Buffer.from(pdf));
  } catch (error) {
    console.error('PDF generation failed', error);
    if (!res.headersSent) res.status(500).send('PDF generation failed');
  } finally {
    if (browser) await browser.close();
  }
});

page.pdf() returns a Promise<Uint8Array>. Converting it to a Node.js Buffer lets Express, which underlies the Firebase response object, send the binary body. Content-Type identifies the format, while Content-Disposition: attachment gives browsers a download filename.

3. Render real pages reliably

Navigate to a URL

For a page you control, replace setContent() with navigation and wait for the state your application needs:

await page.goto('https://your-site.example/report/123', {
  waitUntil: 'networkidle0',
  timeout: 60000,
});
await page.waitForSelector('#report-ready', { timeout: 30000 });
const pdf = await page.pdf({ format: 'A4', printBackground: true });

Do not treat networkidle0 as proof that asynchronous data is ready. A page can continue rendering after network activity settles; a specific readiness selector is more reliable. Keep outbound destinations restricted and validate every identifier used to construct a URL.

Rank #2
Brother MFC-L3710CW Compact Digital Color All-in-One Printer Providing Laser Printer Quality Results with Wireless, Amazon Dash Replenishment Ready
  • FAST PRINT AND SCAN: The Brother MFC-L3710CW lets you get things done with up to 19 ppm print speed and scans up to 29 ipm in black and 22 ipm in color
  • AFFORDABLE AND FLEXIBLE COLOR PRINTING: Affordably print professional quality, rich, vivid color documents with laser printer quality. The 250 sheet adjustable paper tray helps minimize refills and the manual feed slot handles varied printing needs
  • 3.7” COLOR TOUCHSCREEN: Print from and scan to popular cloud apps directly from the 3.7" color touchscreen including Dropbox, Google Drive, Evernote, OneNote and more. Save time by creating custom shortcuts on the touchscreen for your most used features.
  • PRINT AND CONNECT YOUR WAY: Print wirelessly from your desktop, laptop, smartphone and tablet with built-in wireless, and Wi-Fi Direct or connect locally to a single computer via USB interface.
  • UNIT DIMENSIONS (WxDxH): 16.1” W x 18.7” D x 16.3” H

Control print and screen styles

Puppeteer’s API states that page.pdf() “Generates a PDF of the page with the print CSS media type.” If your design uses screen styles, call this before generating the PDF:

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.
await page.emulateMediaType('screen');
const pdf = await page.pdf({ printBackground: true });

Print rendering can alter colors. For color-sensitive documents, CSS using -webkit-print-color-adjust can request exact colors, although the final result still depends on the page and browser.

Useful PDF options

  • format: 'A4', 'Letter', or explicit width and height controls paper dimensions.
  • margin sets top, right, bottom, and left margins.
  • landscape: true rotates the page.
  • printBackground: true includes background colors and images.
  • displayHeaderFooter, headerTemplate, and footerTemplate add repeating page furniture.
  • pageRanges limits output to selected pages.
  • preferCSSPageSize: true honors a document’s CSS @page size.

4. Select a Chromium packaging strategy

Approach Browser delivery Advantages Risks and maintenance
puppeteer Downloads Chrome for Testing during installation Simplest API and version pairing Build scripts must run; cache and artifact size must be preserved
puppeteer-core No browser download Use a browser you manage or a remote endpoint You must configure an executable path or connection and maintain compatibility
@sparticuz/chromium plus puppeteer-core Packages a serverless Chromium binary; the README describes a binary over 50 MB and a chromium-min option with separately hosted assets Explicit packaging and launch control Check Chromium/Puppeteer pairing, Linux architecture, permissions, and Firebase behavior; its turnkey compatibility statement covers supported AWS Lambda Node.js runtimes, not an official Firebase certification

There is no single Firebase-certified Puppeteer/Chromium version pair established for every project. Validate the deployed artifact, architecture, executable permissions, fonts, browser launch, and generated output in the actual Firebase environment. Local success does not prove deployment success.

Google Cloud Functions cache behavior

Puppeteer’s troubleshooting guidance says the Google Cloud Functions Node.js runtime has system packages needed for headless Chrome and recommends placing Puppeteer’s browser cache under node_modules when a cached build prevents the install process from running. Treat this as deployment troubleshooting, and verify the result with your current build pipeline.

5. Deploy and call the endpoint

  1. From the project root, run firebase deploy --only functions:downloadPdf.
  2. Copy the deployed HTTPS URL shown by the Firebase CLI.
  3. Open the URL in a browser, or request it with a client that saves binary data.
curl -L "https://REGION-PROJECT.cloudfunctions.net/downloadPdf?title=Invoice" 
  -o invoice.pdf

For a frontend using fetch, read the response as a Blob and create an object URL. Cross-origin browser calls require an explicit CORS allowlist; Firebase HTTP functions have no CORS policy by default. A command-line request can work while a browser request fails because of CORS.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const response = await fetch(functionUrl + '?title=Invoice');
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const blob = await response.blob();
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'invoice.pdf';
link.click();
URL.revokeObjectURL(link.href);

6. Decide between direct bytes and stored files

Pattern Best when Trade-offs
Send bytes directly The caller needs one immediate download Caller waits for rendering; retries repeat generation; very large responses increase request and memory pressure
Generate and store a file A PDF must be reused, shared, or downloaded later Requires storage permissions, cleanup, access control, a durable-link design, and a separate status/retry path

The reviewed APIs do not define a universal PDF-size threshold for switching to storage. Base that decision on observed document size, generation latency, concurrency, retry behavior, and whether a reusable link is required.

7. Resource, concurrency, and security considerations

  • Memory and CPU: Chromium is resource-intensive. A 1 GiB allocation and 120-second timeout are illustrative starting values; tune them from your deployed workload. Firebase’s second-generation CPU defaults vary with memory, which can affect cost.
  • Browser lifecycle: Always close the browser in finally. Leaked processes consume memory and can exhaust concurrent instances.
  • Authentication: Verify Firebase Auth, signed tokens, or another authorization mechanism before generating sensitive documents.
  • Input controls: Limit HTML size, URL schemes, redirects, navigation time, and destination hosts. Block access to internal services when accepting any caller-controlled address.
  • Fonts and assets: Install or package fonts required by the document and make external assets reachable from the runtime; missing fonts change pagination.
  • Observability: Log request IDs, rendering duration, browser-launch failures, and page errors without logging secrets or full private document contents.

8. Troubleshooting deployed PDFs

“Could not find Chrome” or an executable-path error

Cause: the install script did not run, the cache was omitted, or puppeteer-core has no configured browser. Fix: confirm the package is installed during the Firebase build, inspect the deployed artifact, keep the browser cache under node_modules when appropriate, or provide an explicit executable path/remote browser for puppeteer-core.

Rank #3
MixPad Free Multitrack Recording Studio and Music Mixing Software [Download]
  • Create a mix using audio, music and voice tracks and recordings.
  • Customize your tracks with amazing effects and helpful editing tools.
  • Use tools like the Beat Maker and Midi Creator.
  • Work efficiently by using Bookmarks and tools like Effect Chain, which allow you to apply multiple effects at a time
  • Use one of the many other NCH multimedia applications that are integrated with MixPad.

Launch fails only after deployment

Cause: local and deployed Linux architecture, permissions, libraries, or browser versions differ. Fix: log the deployed runtime, verify the executable is present and executable, and test the exact package pairing in a deployed function. Do not assume an AWS Lambda-oriented Chromium package is Firebase-certified.

The function times out

Cause: slow navigation, never-ending requests, blocked assets, or insufficient resources. Fix: set explicit navigation and selector timeouts, wait for a deterministic readiness marker, remove unnecessary third-party requests, and increase timeout or memory based on measured behavior. The 3,600-second Firebase maximum is not a target.

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.

The PDF is blank or missing data

Cause: capture occurred before client-side rendering completed, or the page required authentication/assets unavailable to Chromium. Fix: wait for a content selector, set cookies or headers deliberately, inspect page console and request failures, and ensure the data endpoint is reachable from the function.

Colors, backgrounds, or page breaks differ

Cause: print media CSS, omitted backgrounds, missing fonts, or unconstrained content. Fix: choose emulateMediaType('screen') when appropriate, set printBackground: true, define @page and break rules, and package the required fonts.

Browser download works with curl but not in the web app

Cause: CORS is disabled by default. Fix: configure cors with only the exact frontend origins, then handle non-2xx responses before reading the Blob.

Requests hang or consume all instances

Cause: browsers are not closed after exceptions, or unbounded concurrent jobs are accepted. Fix: retain the finally close path, authenticate and rate-limit callers, cap document complexity, and consider a queued generation-and-storage workflow for bursty workloads.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server when you need an image or PDF of a URL without packaging Chromium in Firebase. Its clean-shot workflow accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

For a direct PDF or screenshot request, see the ScreenshotNeo API documentation:

Rank #4
Corel PDF Fusion Software
  • Save money by using PDF Fusion to view over 100 file formats without having to purchase additional software
  • Merge incompatible files quickly and easily by dragging and dropping in PDF Fusion to create a new PDF documents
  • Save time with PDF Fusion's editing tools to reuse the content from existing documents without starting from scratch
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Every plan includes the features, including full-page capture, element selection, device and retina settings, PDF paper controls, custom CSS and JavaScript, waits, request blocking, headers, cookies, geolocation, caching, signed links, webhooks, bulk capture, usage reporting, and an OpenAPI specification. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

FAQ

Does Puppeteer return a file path from page.pdf()?

No. It returns PDF bytes as a Uint8Array; write those bytes to storage or send them in the HTTP response.

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

Can I use screen CSS without changing the page?

Yes. Call page.emulateMediaType('screen') immediately before page.pdf().

Is a 3,600-second timeout necessary for PDF generation?

No. It is Firebase’s documented HTTP-function ceiling. Set a timeout appropriate to your document and fail predictably when navigation or rendering exceeds it.

Frequently Asked Questions

Does Puppeteer return a file path from page.pdf()?

No. It returns PDF bytes as a Uint8Array; write those bytes to storage or send them in the HTTP response.

Can I use screen CSS without changing the page?

Yes. Call page.emulateMediaType(‘screen’) immediately before page.pdf().

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

Is a 3,600-second timeout necessary for PDF generation?

No. It is Firebase’s documented HTTP-function ceiling. Set a timeout appropriate to your document and fail predictably when navigation or rendering exceeds it.

Quick Recap

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.