October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
Chromium

How to Fix Emoji Rendering in Firebase Cloud Functions With Puppeteer

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

When emoji appear as empty boxes, blank space, or replacement characters in a Puppeteer screenshot or PDF generated by Firebase Cloud Functions, the cause is usually a missing emoji-capable font or a font that Chromium cannot load—not an emoji setting in Puppeteer. First separate a browser-launch failure from a glyph-rendering failure, then verify fonts and the page’s ability to fetch them in the deployed Linux runtime. There is no single Firebase change that is proven to fix every runtime, generation, browser, and output format.

Start by identifying the failure

Run the same render path locally and in the deployed function with a short page containing representative characters such as 😀, 😁, ❤️, 👍🏽 and flags. Record whether Chromium starts, whether ordinary text is visible, and whether the defect occurs in screenshots, PDFs, or both.

Observed result Most likely branch
The function cannot launch Chromium Browser installation, executable discovery, permissions, memory, or deployment caching. Fix this before investigating fonts.
Normal text renders but emoji are boxes or blank Chromium has no usable emoji glyph coverage in the deployed Linux environment, or the selected font lacks those glyphs.
Only a custom web font fails The browser cannot resolve, fetch, decode, or is blocked from reading the font URL.
Screenshot works but PDF does not Font readiness, print layout, page timing, or PDF-specific font loading may differ from the screenshot path.

Do not treat a blank glyph as proof that Firebase removed emoji. A Linux image can launch Chrome successfully while still lacking the font needed for color emoji.

Make sure Puppeteer’s browser is installed after deployment

Puppeteer’s Cloud Functions troubleshooting guidance addresses browser installation rather than emoji specifically. The Node.js Cloud Functions runtime supplies the system packages needed by headless Chrome, but Puppeteer must be a package dependency and its cache must be configured inside node_modules. Cloud Functions can cache node_modules; if the install step is skipped or the cache contains an incomplete installation, the browser executable may be absent.

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

Package and cache checklist

  • Declare puppeteer in the deployed function’s dependencies, not only in a development-only section.
  • Use the Puppeteer package and Node.js runtime versions supported by your current Functions environment.
  • Configure Puppeteer’s browser cache directory under node_modules as described in its Cloud Functions troubleshooting documentation.
  • Deploy from a clean, reproducible install when diagnosing a stale cache; do not assume a locally downloaded browser is present in the cloud image.
  • Log the executable path and catch launch errors so a browser problem is not mistaken for a font problem.

Minimal launch diagnostic

The following diagnostic is intentionally independent of any particular Firebase generation or trigger. Adapt the import and export to your project, and use the executable configuration required by your installed Puppeteer version.

const puppeteer = require('puppeteer');

exports.renderTest = async (req, res) => {
  let browser;
  try {
    browser = await puppeteer.launch({headless: true});
    const page = await browser.newPage();
    await page.setContent('<h1>Chrome started</h1>');
    res.status(200).send(await page.title());
  } catch (err) {
    console.error('Puppeteer launch/render failure', err);
    res.status(500).send('Puppeteer failed; inspect the function log');
  } finally {
    if (browser) await browser.close();
  }
};

If this fails, resolve deployment and launch errors first. If it succeeds and ordinary text renders, continue with font diagnostics.

Check emoji font coverage in the deployed Linux runtime

Emoji are rendered from glyphs supplied by fonts available to Chromium. The browser does not create missing glyphs. An Azure Functions Linux report described an image without a bundled emoji font and proposed Noto Color Emoji. That report is an analogous Linux case, not proof that every Firebase image lacks the font or that a particular package is approved for your deployment.

Inspect the actual output

Render a matrix containing monochrome symbols, color emoji, skin-tone modifiers, joined sequences, and flags. A font may cover basic faces but not newer Unicode characters or complex sequences. Compare the same HTML in the exact deployed function, not only in your workstation’s Chrome.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const sample = `
  <meta charset="utf-8">
  <style>body{font-family:sans-serif;font-size:40px}</style>
  <p>😀 😁 😂 ❤️ 👍🏽 👩‍💻 🏳️‍🌈 🇺🇳</p>`;
await page.setContent(sample, {waitUntil: 'networkidle0'});
await page.screenshot({path: '/tmp/emoji.png', fullPage: true});

Use a temporary file or your normal storage path appropriate to Functions. Do not infer success from the HTTP response alone; open the generated image or PDF.

Supply a font only through a deployment method you can verify

If the deployed image has no suitable emoji font, make one available using a method supported by your chosen Functions runtime: for example, a deployment-managed system font, a bundled asset, or a remote font endpoint. Confirm the font’s license, package availability, URL, and compatibility before adopting it. The Noto Color Emoji suggestion comes from the Azure report; it is a lead to investigate, not a Firebase-specific, copy-and-paste prescription.

Keep the font file in a deterministic location and make the page reference that location. Merely placing a file on the function’s filesystem does not make it visible to Chromium’s page context.

Verify that Chromium can load a custom font

A Puppeteer PDF issue involving a local Noto font showed that the browser appeared to block the font. The reporter found that navigating to a file:// page behaved differently from using page.setContent(), which had created an about:blank document. That observation belongs to that reported case; changing the page origin is not a universal Firebase fix.

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

Use an explicit origin and wait for fonts

Prefer an HTTP(S) page or a deliberate local origin whose resource permissions you understand. Resolve URLs relative to the document, not the server process’s current directory. Then wait for the browser’s font promises before capturing.

await page.goto('https://your-render-origin.example/emoji-test', {
  waitUntil: 'networkidle0'
});
await page.evaluate(async () => {
  await document.fonts.ready;
});
await page.screenshot({fullPage: true});

For HTML assembled in the function, use a data URL or a controlled local server only when you have verified that the font URL resolves from that origin. A relative URL that works in a browser tab may resolve differently from an about:blank document.

Log console, page errors, and failed requests

page.on('console', msg => console.log('browser console:', msg.text()));
page.on('pageerror', err => console.error('page error:', err));
page.on('requestfailed', request => {
  console.error('request failed:', request.url(), request.failure());
});
page.on('response', response => {
  const type = response.request().resourceType();
  if (type === 'font') console.log('font response', response.status(), response.url());
});

Look for blocked requests, 404 responses, certificate failures, unsupported formats, redirects to authentication, and content-type or decoding errors. A successful HTTP status alone does not prove that Chromium accepted the font.

Use a deployment-safe render sequence

  1. Launch and log. Confirm the browser executable is present and that Chromium starts in the deployed function.
  2. Create a page with a known origin. Avoid relying on implicit about:blank URL resolution for external font files.
  3. Load the document. Use an appropriate navigation wait condition; do not assume the initial DOM means web fonts are ready.
  4. Wait for fonts. Await document.fonts.ready and, when useful, test document.fonts.check() for the family you selected.
  5. Capture the target format. Test the exact screenshot or PDF code used in production. PDF output can expose timing or font-embedding problems not visible in a screenshot.
  6. Compare local and cloud logs. Keep browser version, font URL, page origin, network messages, and output files for both environments.

Common errors and fixes

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

This is an installation or cache problem, not an emoji-glyph problem. Check that Puppeteer is a production dependency, that its cache directory is inside node_modules, and that deployment actually ran the install step. Rebuild from a clean dependency state and redeploy before changing page CSS.

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

Chromium starts, but every emoji is a square

Inspect emoji font coverage in the deployed image. Provide an emoji-capable font through a verified deployment method, then wait for it to load. Do not claim that installing one named package will work until its current availability and licensing are confirmed for your runtime.

Only emoji from @font-face are missing

Check the resolved URL from the page origin, request failures, redirects, permissions, certificate validation, and font decoding. A file existing on the server is not evidence that the page can read it.

Font works in a browser but not with setContent()

Inspect the document origin and relative URLs. The reported Puppeteer case behaved differently between a file:// page and an about:blank page. Reproduce the font request in the deployed path and choose an origin that your security model permits.

Screenshot is correct but PDF is not

Wait for document.fonts.ready immediately before PDF generation, verify print CSS and page ranges, and test the same font resource under the PDF path. Do not assume a screenshot proves that the PDF pipeline embedded the same glyphs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
The SQL Programming Language: .
  • Used Book in Good Condition

Some newer emoji remain blank

Check the Unicode characters and variation selectors in your test set. Emoji support is not binary: a font can contain common faces while lacking newer symbols, flags, modifiers, or joined sequences. Test the exact characters your application emits.

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

Performance, reliability, and cost considerations

  • Cold starts: browser startup and font loading add latency. Reuse a browser carefully within a warm invocation, while closing pages and handling crashes.
  • Memory: large pages, PDFs, multiple tabs, and high-resolution screenshots increase memory pressure. Keep concurrency and page size appropriate for your function limits.
  • Network dependence: remote fonts add DNS, TLS, and availability failure modes. A deployment-controlled asset can be more predictable, but only if the runtime and license permit it.
  • Caching: dependency and browser caches can preserve a broken installation. Make builds reproducible and log the versions and paths used.
  • Evidence: capture representative output from the deployed runtime after each change. Local success is not production verification.

Or skip the browser setup

If your requirement is simply a clean website screenshot or PDF rather than running Puppeteer inside your own Firebase function, ScreenshotNeo provides a single API request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the page verdict and billing status in X-Page-Verdict and X-Billed headers. It also offers an MCP server for AI agents, including Claude and Cursor, with take_screenshot, get_page_info, and capture_pdf.

Example using cURL (see the ScreenshotNeo API documentation):

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

The same request in 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)

And 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}`);

ScreenshotNeo includes full-page and element capture, device presets and custom viewports, retina scale, dark mode, PDF controls, custom CSS and JavaScript, clicks, selector or network-idle waits, request and resource blocking, headers, cookies, user agents, timezone and geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous webhooks, bulk capture for up to 100 URLs per call, usage reporting, and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs, which can simplify migration.

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.

The Free plan includes 1,000 screenshots per month without a card. Paid plans start at $5 for 3,000 shots; yearly billing provides two months free, and every feature is available on every plan. Create a free ScreenshotNeo account to try it.

FAQ

Is this definitely a Firebase bug?

No. The available evidence does not establish one Firebase-wide defect. The runtime, browser, font source, page origin, and output format determine the diagnosis.

Should I switch from Puppeteer to a different browser library?

Not as a first response. Determine whether the failure is browser installation, font coverage, or font loading; changing libraries can leave the underlying Linux font issue unchanged.

Can a CSS fallback guarantee color emoji?

No. CSS chooses among fonts that exist and can be loaded. It cannot supply glyph data missing from the runtime.

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

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

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

Read next

Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.