Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
CasperJS renders pages through PhantomJS, so custom fonts work only when the page can load the font file and the capture waits until the relevant resources are ready. Declare the font with CSS @font-face, verify its URL is accessible from the page, wait for the font request to finish, and then capture. Installing a font on the machine running PhantomJS is not enough if the page’s CSS points to a missing or inaccessible file.
This workflow is mainly for maintaining existing CasperJS projects: PhantomJS development is suspended, and its 2.1 release dates to January 23, 2016. Test against the same PhantomJS build and operating system that run your job.
How font rendering works in CasperJS
CasperJS controls PhantomJS, whose page renderer lays out the document using the CSS and resources it can access. A custom font therefore has two separate requirements: CSS must assign the intended font family to the text, and the browser must successfully retrieve the font file named by the CSS.
Recommended Free Tools
A declaration can be syntactically valid while the font still fails to appear. A wrong relative path, blocked request, unsupported font format, or capture taken before loading completes can leave the page using a fallback. The screenshot may still look plausible, which makes checking the actual request and output important.
#1 Best Overall
Declare the custom font in CSS
Define a family with @font-face, point its src at a font file, and use that exact family name on the element you want to render. For example, the page being captured could contain:
@font-face {
font-family: "Report Sans";
src: url("https://static.example.com/fonts/report-sans.woff2") format("woff2");
font-weight: 400;
font-style: normal;
}
.report-title {
font-family: "Report Sans", sans-serif;
}
Replace the example host and path with a real font URL you control. The font-family value in the rule and the one used by the target element must match. If the design uses multiple weights or styles, declare each available face with its corresponding font-weight and font-style; otherwise the browser may synthesize a style or choose another face.
Google Fonts documents the same general delivery pattern: a stylesheet declares @font-face, then the browser requests the font file. That means both stylesheet access and the file request matter. For a page you do not control, inspect its existing CSS first; adding a second font rule does not help if the selector that matters continues to use another family.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Check where the font URL is resolved
The browser resolves a relative font path in the context of the page and stylesheet that reference it, not in the working directory of the CasperJS script. A URL such as fonts/site.woff may work on one page and point somewhere else on another. Prefer an absolute URL while diagnosing, then use a deliberate relative path if that is how the site is deployed.
- Remote page, remote font: confirm that the font URL can be retrieved by the page and is not blocked by access controls or the serving configuration.
- Local HTML, remote font: PhantomJS documents
localToRemoteUrlAccessEnabledas false by default. Check this setting when a local file attempts to load a remote resource; do not assume a successful local page load implies remote fonts are permitted. - Local HTML, local font: ensure the URL is valid from the file page’s context and that the file is readable by the process. Installing the font system-wide is a separate matter from serving a font file to the page.
Check the actual font request and response in the running job. A CSS rule alone is not proof that the font arrived or was accepted. Google Fonts notes that its stylesheet response can vary by user agent, followed by a request for the resulting font file, so the runtime making the request is relevant.
Wait for the font before capturing
CasperJS provides waitForResource() to wait for a matching resource and waitFor() to wait for a condition evaluated in the page. A wait should match the font or a meaningful page-ready condition. An arbitrary delay can make a race less frequent, but it cannot establish that the font loaded successfully.
Rank #3
For a page whose font URL is known, a resource wait can be used after navigation:
Free tools Windows power users keep installed
One-click scans. No signup required.
var casper = require('casper').create();
var targetUrl = 'https://example.com/report';
var fontUrl = 'https://static.example.com/fonts/report-sans.woff2';
casper.start(targetUrl, function () {
this.waitForResource(fontUrl, function () {
this.capture('report.png');
}, function () {
this.echo('Timed out waiting for the custom font: ' + fontUrl, 'error');
this.exit(1);
}, 10000);
});
casper.run();
Use the URL that the page actually requests. A substring or regular expression can be useful when the site adds query parameters or uses a changing URL, but make the match specific enough not to accept an unrelated asset. Adjust the timeout for the network and page involved; reaching the timeout handler means this script did not observe the matching resource in time, not that it can diagnose why.
Resource completion is a useful synchronization signal, but it is not a complete visual guarantee. The request could fail, CSS could use a different family, or the font file could be unusable. When the page’s own ready state is more meaningful, wait for a specific selector or other condition using CasperJS’s waitFor(), and separately inspect whether the font request succeeded. Avoid relying on modern browser font-loading APIs unless they have been confirmed in the particular PhantomJS build you run.
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
Capture and validate the result
CasperJS proxies PhantomJS’s WebPage rendering API. In the example, capture('report.png') writes the screenshot after the wait succeeds. Save to an explicit path and ensure the process has permission to write there. Open the output and check distinctive letter shapes, line breaks, and element dimensions; a fallback font can alter wrapping even when the text remains readable.
For repeatable validation, run the same page, font URL, CasperJS script, PhantomJS binary, and operating system used in production. PhantomJS’s Linux binary depends on Fontconfig. Its project also cautions that feature support varies, so results from another WebKit build or operating system do not prove identical behavior in the target runtime.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Make a local test page when the target site is ambiguous
If you control the capture input, reduce the problem to a small HTML page that loads only the stylesheet, font and text in question. This separates a bad font path or environment issue from unrelated scripts, consent overlays, and page-specific logic. Use a reachable test URL in the same network context as the capture job, and check whether the font request completes before adding more wait time.
Best Value
For a target site you do not control, avoid changing the site’s CSS or injecting assumptions into the page as a first fix. Establish whether the page already declares the intended family, whether its font URL succeeds, and whether capture starts too early. CasperJS timing bugs can appear intermittent because a fast local request and a slower production request complete at different times.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshoot fonts that still look wrong
- The screenshot uses a fallback family: compare the element’s computed CSS family with the name in
@font-face. Verify the face’s declared weight and style match the element’s requested weight and style. - The font file request is missing: inspect the resolved URL from the page context. Correct the CSS path or permissions, and confirm the page is allowed to request the resource.
- The request occurs but capture is inconsistent: ensure the wait is registered and matches the actual resource, then render only from the success path. CasperJS’s FAQ recommends waiting for resources or page content where a test begins before readiness.
- A local page cannot retrieve a remote font: check PhantomJS’s
localToRemoteUrlAccessEnabledconfiguration, which is documented as disabled by default. Also verify that the remote host itself is reachable. - It fails only on Linux: verify the Fontconfig dependency and runtime environment for the PhantomJS binary used by the job.
- It works elsewhere but not in this job: test with the same operating system and PhantomJS build. PhantomJS feature support can vary between builds, so do not infer parity from a different renderer.
- The CSS seems correct but the appearance is still off: verify the font response and inspect the resulting image, including line wrapping. The available evidence does not establish one universal supported font-format matrix for every PhantomJS build, so test the format and build combination you deploy.
Or skip the browser setup
If the goal is to obtain a screenshot of a page that already renders its font in a browser, ScreenshotNeo provides a screenshot API and MCP server. It does not fix a font declaration or make an inaccessible font file load; it captures the page as rendered by its service.
One GET request returns an image or PDF. For example, using cURL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/report -o shot.webp
See the ScreenshotNeo API documentation for request options and setup. ScreenshotNeo accepts cookie/consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses include X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.
Learn more about ScreenshotNeo, or sign up free for 1,000 screenshots a month with no card.
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.

