Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To make CasperJS render a custom font, do four things in order: declare the font with @font-face, make the font URL reachable from the page, wait for that font resource (or a page condition that proves readiness), and only then call CasperJS’s capture method. CasperJS delegates rendering to PhantomJS, so installing a font on the machine is not enough when the page’s CSS points to an inaccessible or incorrect URL.

The workflow below covers remote and local pages, reliable waits, PhantomJS runtime requirements, diagnostics, and a browser-free alternative when you would rather use an API.

The rendering chain you must satisfy

A screenshot contains the font only if every link in this chain works:

  1. The page’s CSS defines an @font-face family.
  2. The target element actually uses that family.
  3. PhantomJS can request the referenced font file from the page’s URL context.
  4. CasperJS waits until the request and relevant page work are complete.
  5. The PhantomJS build and operating system can render the font format correctly.

A valid CSS declaration does not prove that the file loaded. Inspect the request and wait for a condition tied to the real page before capturing.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Declare the font correctly

Remote page example

Put the declaration in the page’s stylesheet and use the same family name on the element being captured:

@font-face {
  font-family: "Acme Sans";
  src: url("https://cdn.example.com/fonts/acme-sans.woff2") format("woff2"),
       url("https://cdn.example.com/fonts/acme-sans.woff") format("woff");
  font-weight: 400;
  font-style: normal;
}

.hero-title {
  font-family: "Acme Sans", sans-serif;
  font-weight: 400;
}

Check the spelling and capitalization of the family name. The URL must be reachable from the page that PhantomJS opens; a file that exists on your development computer is irrelevant if the rendered page cannot request it.

Local HTML with a remote font

When CasperJS opens a file:// page that references an HTTP(S) font, PhantomJS’s localToRemoteUrlAccessEnabled setting matters. PhantomJS documents this setting as false by default. Enable it explicitly for a controlled local test, then verify the request rather than assuming it succeeded.

var casper = require('casper').create({
  pageSettings: {
    localToRemoteUrlAccessEnabled: true
  }
});

casper.start('file:///absolute/path/to/test.html');

For production captures, serving the HTML and font from an appropriate HTTP(S) origin usually makes the loading context easier to reason about. Keep the font URL in the page’s own CSS and test that exact URL in the PhantomJS job.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A complete CasperJS capture that waits for the font

The following script watches for the specific font request, logs resource failures, and captures only after the request has completed. Replace the URL and filename pattern with your own values.

var casper = require('casper').create({
  verbose: true,
  logLevel: 'debug',
  pageSettings: {
    localToRemoteUrlAccessEnabled: true
  }
});

casper.on('resource.error', function (resourceError) {
  this.echo(
    'Resource error ' + resourceError.errorCode +
    ': ' + resourceError.errorString +
    ' (' + resourceError.url + ')',
    'ERROR'
  );
});

casper.start('https://your-site.example/page', function () {
  this.viewport(1440, 900);
});

casper.waitForResource(
  function (resource) {
    return //fonts/acme-sans.(woff2?|ttf|otf)(?|$)/i.test(resource.url);
  },
  function () {
    this.echo('Custom font resource loaded.');
  },
  function () {
    this.die('The custom font was not loaded before the timeout.');
  },
  15000
);

casper.then(function () {
  this.capture('casper-custom-font.png');
});

casper.run(function () {
  this.echo('Capture complete.').exit();
});

waitForResource() is useful when the font URL is predictable. The success callback runs after CasperJS observes a matching resource; the failure callback prevents a misleading screenshot when the request never arrives. A regular expression that accepts a query string handles cache-busting URLs.

When the font URL is generated dynamically

If your application constructs the URL at runtime, wait for a page condition that your application sets only after its font-loading work is complete. For example, application code can add an element with an agreed identifier after it has finished loading the typeface:

casper.waitFor(
  function () {
    return this.exists('#font-ready');
  },
  function () {
    this.capture('casper-custom-font.png');
  },
  function () {
    this.die('The page never reported font readiness.');
  },
  15000
);

Use a condition tied to the page’s actual readiness. An arbitrary sleep can hide a slow or failed request and is not evidence that the font loaded. If the page can expose both a readiness marker and a predictable resource URL, use the resource wait first and the marker as a second check.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Verify that PhantomJS requested the file

Use CasperJS resource events while diagnosing a missing font. The error handler in the complete script prints the HTTP or network failure details that PhantomJS reports. You can also log every received resource temporarily:

casper.on('resource.received', function (resource) {
  if (/.(woff2?|ttf|otf)(?|$)/i.test(resource.url)) {
    this.echo('Font response: ' + resource.status + ' ' + resource.url);
  }
});

A successful CSS response followed by no font request usually means the URL is wrong, the family is not used by any element, or the page has not reached the code path that applies the style. A request that returns an error or never completes points to the URL, access context, or network policy rather than to CasperJS’s capture call.

Remote versus local font delivery

Delivery setup What must be true Best diagnostic
Remote HTML and remote font The page can retrieve the font URL from its normal origin. Match the exact font request with waitForResource() and inspect resource errors.
Local HTML and remote font PhantomJS permits local-to-remote access; the font URL is reachable. Set localToRemoteUrlAccessEnabled: true, then confirm a received font response.
Local HTML and local font The file URL is correct from the HTML file’s directory and readable by the PhantomJS process. Open the page with its real file:// URL and log resource errors.
Stylesheet supplied by a font service The stylesheet response points to a font file that this PhantomJS user agent can request. Log both the stylesheet and subsequent font-file request; do not assume the CSS response is sufficient.

Font-service stylesheets can vary by user agent and may lead to a separate font-file request. Test the response seen by the PhantomJS build you actually run.

Capture only after the page is ready

CasperJS provides two complementary wait mechanisms:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • waitForResource(): matches a network resource, such as a known WOFF, WOFF2, TTF, or OTF URL.
  • waitFor(): evaluates a condition in the page, such as an application readiness marker or a selector that appears only after the typeface setup completes.

Choose the narrowest reliable signal. Waiting for every network request can leave a job open because analytics, streaming connections, or third-party widgets may never become idle. Waiting for a fixed number of milliseconds can capture a fallback font on a slow run. A targeted resource or page condition gives you a meaningful timeout and a clear failure reason.

PhantomJS and operating-system requirements

Linux Fontconfig

PhantomJS’s Linux binary depends on Fontconfig. Ensure the runtime environment contains the dependency and that the job uses the same container, VM, or host configuration you use for validation. A missing or incomplete Fontconfig environment can change whether text renders correctly even when the HTTP request succeeds.

Build and platform differences

PhantomJS warns that feature support varies and recommends feature detection and testing. Do not assume that a screenshot produced by one WebKit build, operating system, or PhantomJS binary will match another. Validate the actual output in the same PhantomJS build and operating system used by your capture job.

Rank #4
The SQL Programming Language: .
  • Used Book in Good Condition

Project status

PhantomJS development is suspended. The official release history dates PhantomJS 2.1 to January 23, 2016. CasperJS/PhantomJS remains relevant when you are maintaining an existing system, but a new production workflow should also assess a currently maintained browser-automation option against your compatibility, deployment, and rendering requirements.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting missing custom fonts

Symptom Likely cause Fix
Screenshot uses a fallback font immediately Capture runs before the font request finishes. Add a matching waitForResource() or page readiness condition before capture().
No font request appears in the log The selector does not use the declared family, the CSS rule is not active, or the URL is malformed. Compare the font-family value with the @font-face name and inspect the rendered element’s active styles.
Local page cannot retrieve an HTTP font PhantomJS local-to-remote access is disabled. Set localToRemoteUrlAccessEnabled: true in pageSettings and test the exact URL from the local page context.
Resource error or non-success response Wrong path, unavailable host, blocked request, or a server response the runtime cannot use. Log resource.error, verify the URL and response, and confirm the page is allowed to load that resource.
Font loads but text still looks wrong Family, weight, or style does not match the rule that loaded; the runtime may not support the chosen feature. Check the requested family and weight, provide an appropriate fallback, and test the same PhantomJS build and OS used in production.
Intermittent pass/fail results Timing varies between runs or the page starts before resources are ready. Replace arbitrary delays with a resource or condition wait and give the wait a bounded timeout with a useful error.
Works on a developer laptop but not Linux The Linux runtime lacks the required Fontconfig environment or differs from the tested build. Install and verify the required runtime dependency, then compare output on the deployment host.
Font-service CSS differs from browser testing The stylesheet response varies by user agent. Log the stylesheet and font-file URLs returned to PhantomJS and test those exact resources.

Performance and reliability practices

  • Match the specific font URL instead of waiting for a broad page event.
  • Use a finite timeout and fail loudly; a blank or fallback-font image is harder to detect later.
  • Keep a diagnostic mode that logs font responses and resource errors, then reduce logging once the job is stable.
  • Reuse a consistent PhantomJS binary and operating-system image so font behavior does not vary between workers.
  • When a page uses several weights or styles, wait for each resource that affects the captured element, or expose one application-level readiness condition that covers them.
  • Retain the captured output from failed jobs while diagnosing; visual comparison in the target runtime is the final check.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. It can capture a reachable page without you maintaining CasperJS or PhantomJS. Before capture, it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the result in X-Page-Verdict and X-Billed headers.

For a one-request capture, see the ScreenshotNeo API documentation:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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 also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Its options include full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper and margin controls, custom CSS and JavaScript, clicks, selector waits, delay or network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, configurable caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work.

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan, and yearly billing provides two months free. If you want to remove the CasperJS browser setup, create a free ScreenshotNeo account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can I prove which font PhantomJS used from the PNG alone?

A PNG does not contain a dependable CSS font-family record. Keep the resource logs and compare the output in the exact PhantomJS build and operating system that produced it.

Should I wait for network idle instead of the font request?

Only when your page has no long-lived or third-party connections. A specific font resource or application readiness condition normally gives a more deterministic completion point.

Is CasperJS a good starting point for a new capture service?

Because PhantomJS development is suspended, evaluate a currently maintained browser-automation option for new production work; retain CasperJS when compatibility with an existing suite is the deciding requirement.

Quick Recap

Bestseller No. 2
SaleBestseller No. 3
Bestseller No. 4
The SQL Programming Language: .
The SQL Programming Language: .
Used Book in Good Condition
$4.23

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.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.