If a PhantomJS screenshot shows fallback text instead of your web font, do not assume that page.open() succeeded completely. The HTML navigation can finish while the font request is still pending, has timed out, was blocked, or cannot be used by that PhantomJS/QtWebKit build. Log the font request, verify the @font-face declaration and runtime errors, then wait for a supported readiness signal (or a bounded timeout) before calling page.render(). If the request succeeds but the font still fails, check the host environment and consider moving new work to a maintained renderer because PhantomJS development is suspended.
Why a successful page load can still produce the wrong font
PhantomJS uses WebKit to render pages. The usual screen-capture example calls page.render() from the page.open() callback, as shown in the official screen-capture guide. That callback means the document navigation completed; it does not prove that every stylesheet, font request, font decode, and resulting layout operation has completed.
A web-font failure generally falls into one of four categories:
- Timing: the screenshot is taken before the remote font finishes loading and layout switches from the fallback face.
- Request failure: the URL is wrong, inaccessible, blocked, denied by the server, incompatible with the TLS stack, or timed out.
- CSS mismatch: the captured element requests a family, weight, style, or format that the
@font-facerule does not provide. - Runtime or host limitations: the particular PhantomJS/QtWebKit build cannot decode the supplied format, or the required local font is not installed in the execution environment.
Treat the image as an output symptom, not as proof of the cause. Instrument the page first, then change the wait or environment based on what the logs show.
Recommended Free Tools
#1 Best Overall
1. Verify the font request and CSS face
Inspect the declaration
Check the exact stylesheet used by the page and the element you capture. Confirm the family name is identical in font-family and @font-face, and that the requested font-weight and font-style have matching faces. Verify every URL and declared format:
@font-face {
font-family: "Report Sans";
src: url("https://static.example.com/fonts/report-sans.woff2") format("woff2"),
url("https://static.example.com/fonts/report-sans.woff") format("woff");
font-weight: 400;
font-style: normal;
}
.report { font-family: "Report Sans", sans-serif; }
A missing network request usually indicates CSS, selector, font matching, or page-logic trouble. A request that appears and then fails points toward networking, access control, TLS, server response, or resource configuration. A successful request with fallback output requires format/build and host checks.
Log requests, responses, and timeouts
PhantomJS exposes resource callbacks and a configurable timeout. The WebPage settings API documents resourceTimeout and onResourceTimeout; the troubleshooting guide recommends sniffing requests while diagnosing pages.
var page = require('webpage').create();
var system = require('system');
page.settings.resourceTimeout = 30000;
page.onResourceRequested = function (request) {
console.log('REQUEST ' + request.id + ' ' + request.url);
};
page.onResourceReceived = function (response) {
if (response.stage === 'end') {
console.log('RESPONSE ' + response.status + ' ' + response.url);
}
};
page.onResourceError = function (error) {
console.log('RESOURCE ERROR ' + error.errorCode + ' ' + error.url + ' ' + error.errorString);
};
page.onResourceTimeout = function (request) {
console.log('RESOURCE TIMEOUT ' + request.id + ' ' + request.url);
};
page.onError = function (message, trace) {
console.log('PAGE ERROR ' + message);
trace.forEach(function (item) {
console.log(' ' + item.file + ':' + item.line + ' ' + item.function);
});
};
Run this against the same URL used in production and look specifically for the font URL. Do not infer success from a 200 HTML response: the font is a separate resource with its own status and timeout.
2. Wait for the font before rendering
Use a bounded delay when you need a compatible fallback
Once navigation completes, delay rendering long enough for the page’s remote assets to settle, but keep the delay bounded so a broken font cannot hang your job forever. For example:
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
page.open('https://example.com/report', function (status) {
if (status !== 'success') {
console.log('OPEN FAILED: ' + status);
phantom.exit(1);
return;
}
window.setTimeout(function () {
page.render('/tmp/report.png');
phantom.exit();
}, 2000);
});
A fixed delay is only a safety net. It can be too short on a slow CI runner and wasteful on a fast one. Prefer a page-side readiness signal when the deployed PhantomJS executable supports it.
Feature-check the modern FontFaceSet API
Modern browsers expose document.fonts; MDN says document.fonts.ready fulfills after loading and layout operations for used fonts complete (MDN: Document.fonts). PhantomJS ships an older QtWebKit runtime, and support is not established for every build. Feature-check the actual executable instead of assuming this API exists:
page.open('https://example.com/report', function (status) {
if (status !== 'success') {
phantom.exit(1);
return;
}
page.evaluate(function () {
if (document.fonts && document.fonts.ready) {
return document.fonts.ready.then(function () { return 'fonts-ready'; });
}
return 'fonts-api-unavailable';
}).then(function (result) {
// Promise handling may itself be unavailable in older PhantomJS builds;
// use the bounded timer fallback when this call cannot be evaluated.
page.render('/tmp/report.png');
phantom.exit();
});
});
Older PhantomJS versions may not support promises or the FontFaceSet API at all. If the feature check fails, use a timer plus request logs, or expose a simple page variable that your application sets after its own font-loading logic completes. Always retain a maximum wait and record whether the readiness signal or timeout ended the wait.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →3. Separate network problems from rendering problems
When the request is missing
- Inspect the computed style of the captured element and confirm it actually uses the intended family and weight.
- Check that the stylesheet containing
@font-faceloaded in PhantomJS, not just in your desktop browser. - Verify relative URLs resolve from the stylesheet’s location, not the document URL.
- Look for conditional CSS or JavaScript that selects a different face at the PhantomJS viewport or user agent.
When the request fails or times out
- Open the exact font URL from the same machine or container and inspect DNS, TLS, redirects, authentication, and HTTP status.
- Check server rules that reject PhantomJS’s user agent, omit CORS headers, or require cookies or authorization.
- Increase
resourceTimeoutonly after confirming the request is progressing; a longer timeout does not repair a blocked URL. - Capture the resource error and timeout lines with the screenshot so intermittent failures can be correlated.
When the request succeeds but text remains a fallback
Check whether the supplied format is supported by the exact PhantomJS/QtWebKit build. Confirm that the face’s internal naming, weight, and style match the CSS. Reproduce on the same operating system and container as production; a local desktop test can hide missing libraries or fonts.
4. Check fonts installed on the host
Some workflows depend on fonts installed in the operating system rather than on a downloadable web font. Verify that the intended face is installed and discoverable by the user running PhantomJS, including inside a CI container. A PhantomJS issue discussion records a Linux-specific report in which installing the font’s TTF files under /usr/share/fonts/truetype and running fc-cache -fv allowed PhantomJS to use the face (issue discussion). Another commenter reported that upgrading dependencies solved their case.
Rank #3
These are environment-specific reports, not a universal repair. Treat installation as an infrastructure change: pin the font files, install them in the image used by CI, rebuild the font cache, and verify the effective user can read them. If your CSS is intended to use a remote font, installing a similarly named local face can mask a broken URL, so keep the network diagnosis in place.
5. Capture useful diagnostics with every failure
Save the PhantomJS version, executable path, URL, viewport, resource logs, page errors, and the final image (even when it is wrong). Run phantomjs --version and confirm which binary your job invokes; the official troubleshooting guide warns that multiple installed versions can cause confusing results. A minimal failure record should answer:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
- Did the font URL appear in
onResourceRequested? - What response status or resource error did it produce?
- Did the page report a JavaScript exception?
- Did the readiness check complete, or did the bounded timeout expire?
- Which PhantomJS build, OS, container image, and font files were used?
6. Choose a durable path
| Remedy | Best when | Main trade-off |
|---|---|---|
| Instrument requests and add a bounded wait | The font is valid but capture races loading or layout. | Requires timing controls and ongoing diagnostics. |
| Install/configure host fonts | The deployed stack relies on local fonts and the host lacks them. | Changes images or servers and may not address a remote-font failure. |
| Move to a maintained renderer | You need current CSS/font support, reproducible deployment, and active fixes. | Requires migration and a new compatibility check. |
The PhantomJS project home states that development is suspended (PhantomJS). For new or actively maintained screenshot systems, compare maintained browser automation options against your site’s font formats, explicit font/resource waiting, OS setup, container reproducibility, and debugging output. Do not choose a replacement solely because it renders one test page correctly; validate the fonts and CSS used by your production pages.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report X-Page-Verdict and X-Billed. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—work with Claude, Cursor, and other MCP clients.
One GET request returns PNG, JPEG, WebP, or PDF. See the ScreenshotNeo documentation for all options.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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 supports full-page and element captures, device presets and custom viewports, retina scale, dark mode, custom CSS and JavaScript, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage reporting, and PDF controls. Every feature is on every plan: 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000, with yearly billing giving two months free.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Create a free ScreenshotNeo account to use the 1,000 included screenshots without a card.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting checklist
Fallback text appears intermittently
Log the font request and replace an unbounded or very short delay with a feature-checked readiness signal plus a maximum timeout. Compare slow and fast CI runs.
The font URL never appears
Inspect computed styles, stylesheet loading, URL resolution, and conditional rules. The issue is likely CSS or page logic rather than capture timing.
The request times out
Test DNS, TLS, redirects, access controls, and server behavior from the capture host. Increase the timeout only after confirming the endpoint is reachable.
Free tools Windows power users keep installed
One-click scans. No signup required.
The request is 200 but the font is ignored
Check format support, internal face metadata, weight/style matching, and host libraries. Test the exact PhantomJS binary in the production image.
Best Value
It works locally but not in CI
Compare OS, container image, installed fonts, font cache, effective user, PhantomJS version, and network policy. Pin these inputs before changing application code.
Frequently Asked Questions
Does page.open() guarantee that web fonts are ready?
No. It reports navigation status; a font can still be downloading, decoding, or waiting for layout when the callback runs.
Should I always install the font on the server?
No. Install host fonts only when your rendering stack depends on local faces or the evidence shows an environment-specific discovery problem; it is not a general fix for a failed web-font request.
Can I rely on document.fonts.ready in PhantomJS?
Only after feature-checking the exact executable. It is a modern browser API, while PhantomJS uses an older QtWebKit runtime with build-dependent support.
What should a migration test include?
Use production font formats, weights, CSS, viewport sizes, and authentication paths, then compare readiness behavior, host setup, reproducibility, and diagnostics in the target CI environment.
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.

