ScreenshotNeo

BlogHow-to

Urlbox Screenshots Show the Wrong Font: How to Fix Font Loading

Fix fallback fonts in Urlbox screenshots by checking font requests, choosing the right wait condition, and waiting for the page’s actual ready state.

By the ScreenshotNeo team4 October 20269 min read

If an Urlbox screenshot shows a fallback or unexpected font, check two things first: whether the page’s font file can load, and whether capture happens before the page applies it. Make sure block_fonts is not enabled. Then choose a wait condition that fits the page, preferably a page-specific ready state when the page loads content or fonts asynchronously. Add a measured delay only if work still finishes after that condition.

Urlbox documents web-font rendering, but that capability does not guarantee that every target page’s font URL is reachable or that an arbitrary capture time will include the final font. [Urlbox render options] [Urlbox web-font support]

1. Check whether the font can load

A screenshot can use a fallback font because the browser never received the intended font, or because the screenshot was taken before it finished loading. Begin with the font request and the capture configuration.

  1. Open the target page in a browser and inspect its font requests in the developer tools Network panel. Look for failed requests, blocked requests, or a URL that requires authentication.
  2. Check the page’s CSS for the active @font-face declaration and confirm the expected family is actually applied to the element you are capturing.
  3. Check the Urlbox request for block_fonts. This option blocks font requests; remove it or set it to false if the page needs web fonts. [Urlbox blocking options]
  4. Check whether the font host, page policy, or cross-origin setup prevents the browser from obtaining the font. A delay cannot repair a failed font request.

Urlbox’s web-font documentation demonstrates rendering a page that uses Google Fonts. Treat this as support for web-font rendering generally, not a promise that a particular website’s font host or configuration is healthy. [Urlbox web-font support]

2. Choose a wait condition that matches the page

The wait condition determines what Urlbox waits for before capture. Current Urlbox options list loaded as the default, along with domloaded, mostrequestsfinished, and requestsfinished. The request-based conditions wait until there are at most two or zero network connections, respectively, for at least 500 ms. [Urlbox wait options]

Condition What it indicates Use it when Font-loading caveat
domloaded The DOMContentLoaded event fired. You need an early DOM-ready signal and provide another readiness check if needed. It does not wait for stylesheets, images, fonts, or subframes. Do not assume the font is applied yet. [Urlbox loading guide]
loaded The window load event fired; this is the documented default. Ordinary pages whose key resources load with the document. A JavaScript-heavy application can still add content and make requests after load.
mostrequestsfinished No more than two network connections for at least 500 ms. The page makes follow-up requests and a short quiet period is sufficient. Continuous traffic can delay the condition; a quiet network does not prove the desired font was applied.
requestsfinished No network connections for at least 500 ms. You need a stricter network-quiet signal and the page eventually becomes quiet. Analytics, polling, or streaming requests may keep the page active.

Urlbox’s September 14, 2026 changelog says domloaded and turbo capture as soon as the DOM is ready, without a hidden network-settle period. It describes smart as allowing the network to settle after DOMContentLoaded, excluding media playback requests from that settle condition. The options documentation lists the four values above; check the current docs for the values and defaults available to your account. If using domloaded, add a page-specific condition or explicit delay when the page needs more time. [Urlbox changelog] [Urlbox options]

3. Prefer a page-specific ready state

A meaningful selector is often a better signal than a guessed global delay. Use wait_for for an element that appears when the relevant content is ready, or wait_to_leave when a loading indicator remains visible until the page is ready. Configure wait_timeout for the page’s expected behavior. By default, Urlbox can continue with the capture if a wait_for selector is not found; set fail_if_selector_missing=true when capturing without that state should count as a failed render. [Urlbox selector waits]

Choose a selector that represents the finished content. A static heading that is present before the application applies its font does not establish font readiness. When you control the page, expose a reliable ready marker only after the page has initialized the content and typography you need.

4. Configure Urlbox and add delay only if needed

Urlbox render options are request parameters. The following examples show the relevant configuration; provide your own Urlbox render URL or signing logic using the account setup documented by Urlbox. Do not publish secrets in client-side code. [Urlbox options] [Urlbox quickstart]

{
  "url": "https://example.com/page",
  "block_fonts": false,
  "wait_until": "loaded",
  "wait_for": "main .content-ready",
  "wait_timeout": 10000,
  "fail_if_selector_missing": true,
  "delay": 0
}

Replace the selector with one that exists on the target page and signals the desired state. If the page has no useful marker, first choose the closest wait condition, then increase delay in small increments and compare captures. Urlbox defines delay in milliseconds and its default is zero. Delay gives late asynchronous work more time; it does not prove the font loaded successfully. [Urlbox delay option]

Python: pass the capture options to your configured Urlbox endpoint

import os
import requests

# Set URLBOX_RENDER_URL to the signed render URL generated for your Urlbox account.
render_url = os.environ["URLBOX_RENDER_URL"]
params = {
    "url": "https://example.com/page",
    "block_fonts": "false",
    "wait_until": "loaded",
    "wait_for": "main .content-ready",
    "wait_timeout": 10000,
    "fail_if_selector_missing": "true",
    "delay": 0,
}
response = requests.get(render_url, params=params, timeout=90)
response.raise_for_status()
with open("capture.png", "wb") as image:
    image.write(response.content)

Use the authentication and render URL format from your Urlbox account. If your account’s signed URL already includes the target URL or options, generate a new signature after changing those values.

Node.js: pass the same options to your configured render URL

const renderUrl = process.env.URLBOX_RENDER_URL;
if (!renderUrl) throw new Error("Set URLBOX_RENDER_URL to your configured Urlbox render URL");

const url = new URL(renderUrl);
const options = {
  url: "https://example.com/page",
  block_fonts: "false",
  wait_until: "loaded",
  wait_for: "main .content-ready",
  wait_timeout: "10000",
  fail_if_selector_missing: "true",
  delay: "0",
};
for (const [key, value] of Object.entries(options)) {
  url.searchParams.set(key, value);
}

const response = await fetch(url);
if (!response.ok) throw new Error(`Urlbox returned ${response.status}`);
const image = Buffer.from(await response.arrayBuffer());
await import("node:fs/promises").then(fs => fs.writeFile("capture.png", image));

For a signed request, use Urlbox’s signing instructions and sign the final option set. These snippets illustrate the render options; they do not replace account-specific authentication. [Urlbox quickstart and secure render links]

5. Diagnose the result, not just the wait time

  1. Capture once with the default loaded wait. If the font is correct, the earlier wait condition was likely too early.
  2. Try the page’s ready selector. If this fixes the mismatch consistently, keep the selector and remove unnecessary delay.
  3. Try a small delay after readiness. Increase it incrementally and compare output. Avoid adopting one delay as universal; font hosts, cache state, and page behavior vary.
  4. Check a direct font request failure. If the font URL fails, fix reachability, access, or page configuration. Waiting longer will only postpone the same fallback.
  5. Compare the affected area and glyphs. If only content lower on a full-page shot differs, inspect how the page behaves during scrolling.

6. Check full-page captures separately

Urlbox’s default full-page stitch mode scrolls through page sections and may trigger lazy-loaded elements and animations; scroll_delay controls the time between scrolls. If the wrong font appears only in lower sections, determine whether scrolling changes page styles or content and whether the scroll timing affects those sections. This is separate from whether the initial font request succeeded. [Urlbox full-page screenshots]

7. Troubleshooting common failures

Symptom Likely cause What to change
Fallback font with domloaded Capture starts before stylesheets or fonts finish. Use loaded, a suitable request-based wait, or a page-specific selector.
Fallback font with loaded The font request failed, or client-side work applies the font after load. Inspect the font URL and CSS; wait for the application’s ready marker or add a measured delay.
Font never appears, even with a long delay Font requests are blocked, unreachable, or inaccessible. Disable block_fonts; fix the target site’s font URL or access configuration.
Selector wait times out but a screenshot is returned Urlbox’s default behavior can continue if the selector is missing. Correct the selector and set fail_if_selector_missing=true when missing readiness must invalidate the render.
Network wait takes too long Long polling, analytics, or streaming keeps requests active. Use a page-specific selector or the less strict mostrequestsfinished condition if suitable.
Only the lower page has a mismatch Full-page scrolling triggers late content, animation, or style changes. Review stitch behavior and scroll_delay; compare against a viewport capture.
Only dotted glyphs such as i, j, periods, or colons look wrong A renderer-specific glyph issue is possible. Compare the current engine/version and release notes. Urlbox’s changelog records a January 9, 2026 Helvetica glyph fix; that does not explain unrelated font mismatches. [Urlbox changelog]

8. Performance, reliability, and cost trade-offs

  • Wait only for what the capture needs. Longer delays and stricter network-quiet conditions increase render time. A targeted selector can finish sooner and more reliably when it represents the actual page state.
  • Do not use a delay as a font health check. A failed or blocked request remains failed no matter how long the renderer waits.
  • Account for variable page behavior. Network conditions and application timing vary. A selector with explicit failure behavior helps distinguish a ready capture from a timed-out one.
  • Be cautious with network idle. It is useful for pages that make follow-up requests, but recurring background traffic may prevent it from completing promptly.
  • Check current service and plan details separately. The cited render documentation establishes option behavior, not pricing or a guaranteed render duration. Choose settings based on the page’s correctness requirements and the service terms for your account.

9. Or skip the browser setup

If you need a screenshot without maintaining browser-wait logic, ScreenshotNeo is a website screenshot API and MCP server. It accepts one GET request for a URL and returns a screenshot or PDF. The API options include waiting for a selector, delay, and network idle, along with custom CSS and JavaScript. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/page -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com/page"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com/page' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo returned ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up for free and get 1,000 screenshots a month with no card.

10. Frequently asked questions

Does Urlbox support web fonts?

Urlbox documents web-font rendering. A particular font still depends on the target page’s CSS, font URL, access, and capture timing. [Urlbox web-font support]

Is loaded always enough?

No. It waits for the load event, but an application can add content and make requests afterward. Use a page-specific condition when the final state comes later.

Should I use a fixed delay or network idle?

Use the condition that reflects the page’s behavior. Network quiet can be useful but may be delayed by ongoing traffic; a fixed delay is simple but cannot confirm readiness. A meaningful selector is often more precise.

Can I fix a font URL that requires login by waiting longer?

No. Resolve access or configure the target page so the renderer can request the font. A wait condition only affects capture timing.