I've been attempting to capture a screenshot of a web page using Puppeteer in Node.js, running on a Digital Ocean Droplet (Ubuntu 20.04 / Ubuntu 22.04 / Debian 12). However, I've encountered an issue where the page fails to load a font (Quicksand) from Google Fonts. I've experimented with Puppeteer using both the bundled Chrome and a manually installed Chrome with the executablePath set. I've tested different versions of Ubuntu and Debian, but unfortunately, the font fails to load. Additionally, the website incorporates emojis, and they also appear to be missing in the captured text.
Has anyone successfully configured Puppeteer to load fonts correctly? For reference, here's an example page that utilizes the Quicksand font and doesn't render properly for me: https://jshzdf.csb.app. The font doesn't load even on the font page https://fonts.google.com/specimen/Quicksand.
When I run the code locally on a Macbook, the fonts look all right. Am I missing something?
I also tried a javascript library that watches if a font is loaded and adding a <div data-font-loaded="true" /> element to the DOM and then using await page.waitForSelector("[data-font-loaded=true]") but the promise never resolves, because the font doesn't load.
Here's a minimal example, where the font loading doesn't work for me:
import express, { Request, Response, Application, NextFunction } from 'express';
import asyncHandler from 'express-async-handler';
import puppeteer from 'puppeteer';
const app: Application = express();
app.post('/capture', bodyParser.json(), asyncHandler(async (req: Request, res: Response) => {
const url = req.body.url;
const browser = await puppeteer.launch({
args: ['--no-sandbox'],
headless: "new",
defaultViewport: {
width: 1200,
height: 630,
deviceScaleFactor: 2,
},
});
const page = await browser.newPage();
await page.goto(url, { waitUntil: "networkidle0" });
const buffer = await page.screenshot({ type: "jpeg", quality: 70 });
await browser.close();
// send the buffer back to the client
res.set("Content-Type", "image/jpeg");
res.send(buffer);
}));
app.listen(process.env.PORT, () => {
console.log(`Server is Fire at http://localhost:${process.env.PORT}`);
});
Any help is greatly appreciated, thanks
So I found out that it was caused by CORS errors, although I'm not sure why they occur because they don't manifest on my browser. So to fix this I'm running the headless Chrome with disabled security, like so:
This hasn't fixed the emojis issue. For that, I had to install
fonts-noto-color-emojipackage:Don't forget to restart the system after installing the package for the new emojis to take effect.
I hope this helps someone else too.