Custom fonts
Browser Run uses a managed Chromium environment that includes a standard set of pre-installed fonts. When you generate a screenshot or PDF, text is rendered using the fonts available in this environment. If your page specifies a font that is not pre-installed, Chromium will automatically fall back to a similar supported font.
If you need a specific font that is not pre-installed, you can inject it into the page at render time. You can load fonts from an external URL or embed them directly as a Base64 string.
How you add a custom font depends on how you are using Browser Run:
- If you are using Puppeteer, Playwright, or CDP, refer to the Browser sessions section.
- If you are using Quick Actions, refer to the Quick Actions section.
Use addStyleTag to inject a @font-face rule into the page before capturing your screenshot or PDF. You can load the font file from a CDN URL or embed it as a Base64-encoded string.
The examples below use Puppeteer with Workers Bindings. If you are connecting via CDP, the only difference is how you connect to the browser. Once connected, page.addStyleTag() works the same way. Refer to CDP connection example for details.
Example with Puppeteer and a CDN source:
const browser = await puppeteer.launch(env.MYBROWSER);const page = await browser.newPage();await page.addStyleTag({ content: ` @font-face { font-family: 'CustomFont'; src: url('https://your-cdn.com/fonts/MyFont.woff2') format('woff2'); font-weight: normal; font-style: normal; }
body { font-family: 'CustomFont', sans-serif; } `,});Example with Puppeteer and a CDN source:
const browser = await puppeteer.launch(env.MYBROWSER);const page = await browser.newPage();await page.addStyleTag({ content: ` @font-face { font-family: 'CustomFont'; src: url('https://your-cdn.com/fonts/MyFont.woff2') format('woff2'); font-weight: normal; font-style: normal; }
body { font-family: 'CustomFont', sans-serif; } `,});The following examples use Playwright, but this method works the same way with Puppeteer.
Example with a Base64-encoded data source:
const browser = await playwright.launch(env.MYBROWSER);const page = await browser.newPage();await page.addStyleTag({ content: ` @font-face { font-family: 'CustomFont'; src: url('data:font/woff2;base64,<BASE64_STRING>') format('woff2'); font-weight: normal; font-style: normal; }
body { font-family: 'CustomFont', sans-serif; } `,});Example with a Base64-encoded data source:
const browser = await playwright.launch(env.MYBROWSER);const page = await browser.newPage();await page.addStyleTag({ content: ` @font-face { font-family: 'CustomFont'; src: url('data:font/woff2;base64,<BASE64_STRING>') format('woff2'); font-weight: normal; font-style: normal; }
body { font-family: 'CustomFont', sans-serif; } `,});When connecting via CDP, you connect to the browser using a WebSocket endpoint instead of a Workers Binding. Once connected, you use page.addStyleTag() the same way as the examples above.
import puppeteer from "puppeteer-core";
const ACCOUNT_ID = "your-account-id";const API_TOKEN = "your-api-token";
// Create a browser session via CDPconst response = await fetch( `https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/browser-rendering/devtools/browser`, { method: "POST", headers: { Authorization: `Bearer ${API_TOKEN}` }, },);const { webSocketDebuggerUrl } = await response.json();
// Connect Puppeteer to the sessionconst browser = await puppeteer.connect({ browserWSEndpoint: webSocketDebuggerUrl, headers: { Authorization: `Bearer ${API_TOKEN}` },});
const page = await browser.newPage();
// Add a custom font — same as with Workers Bindingsawait page.addStyleTag({ content: ` @font-face { font-family: 'CustomFont'; src: url('https://your-cdn.com/fonts/MyFont.woff2') format('woff2'); font-weight: normal; font-style: normal; }
body { font-family: 'CustomFont', sans-serif; } `,});
// Take a screenshot, generate a PDF, etc.await page.goto("https://example.com");
browser.disconnect();When using Quick Actions, you can load custom fonts by including the addStyleTag parameter in your request body. This works with both the screenshot and PDF endpoints.
curl -X POST 'https://api.cloudflare.com/client/v4/accounts/<accountId>/browser-rendering/screenshot' \ -H 'Authorization: Bearer <apiToken>' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com/", "addStyleTag": [ { "content": "@font-face { font-family: '\''CustomFont'\''; src: url('\''https://your-cdn.com/fonts/MyFont.woff2'\'') format('\''woff2'\''); font-weight: normal; font-style: normal; } body { font-family: '\''CustomFont'\'', sans-serif; }" } ] }' \ --output "screenshot.png"curl -X POST 'https://api.cloudflare.com/client/v4/accounts/<accountId>/browser-rendering/screenshot' \ -H 'Authorization: Bearer <apiToken>' \ -H 'Content-Type: application/json' \ -d '{ "url": "https://example.com/", "addStyleTag": [ { "content": "@font-face { font-family: '\''CustomFont'\''; src: url('\''data:font/woff2;base64,<BASE64_STRING>'\'') format('\''woff2'\''); font-weight: normal; font-style: normal; } body { font-family: '\''CustomFont'\'', sans-serif; }" } ] }' \ --output "screenshot.png"For more details on using addStyleTag with Quick Actions, refer to Customize CSS and embed custom JavaScript.