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

Use Puppeteer’s Firefox browser, turn the HTML file’s absolute filesystem path into a properly encoded file: URL with Node.js pathToFileURL, and navigate to that URL with page.goto. This makes the HTML file the document the browser opens, so references such as ./report.css and ../images/chart.png are resolved from its location. Avoid building a file URL by joining file: to a raw path.

Open the HTML file as a file URL

For current Puppeteer, select Firefox with browser: 'firefox'. Resolve the HTML path, convert it with Node’s pathToFileURL, then pass the resulting URL to page.goto. The following is a complete ES module example:

import puppeteer from 'puppeteer';
import path from 'node:path';
import { pathToFileURL } from 'node:url';

const browser = await puppeteer.launch({ browser: 'firefox' });

try {
  const page = await browser.newPage();
  const htmlPath = path.resolve('fixtures/report/index.html');
  const fileUrl = pathToFileURL(htmlPath).href;

  console.log(fileUrl);
  await page.goto(fileUrl);

  // Interact with the page or capture output after its required assets are ready.
} finally {
  await browser.close();
}

Run it from a project configured to use ES modules, with Puppeteer and its Firefox browser available in that environment. The example assumes the file is at fixtures/report/index.html relative to the directory from which you run the script. Change that path to match your project. The finally block closes the browser even if navigation or later work throws an error.

Puppeteer’s Page.goto method navigates to a URL, not a bare operating-system path, and its documentation says the URL should include a scheme. Node’s pathToFileURL resolves a filesystem path to an absolute path and encodes characters that have special meaning in URLs. Mozilla announced first-class Puppeteer support for Firefox beginning with Puppeteer 23 in 2024, using this launch form: puppeteer.launch({ browser: 'firefox' }).

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

Why the document’s location matters

Suppose index.html contains these references:

<link rel="stylesheet" href="./report.css">
<img src="../images/chart.png" alt="Chart">
<script src="./report.js"></script>

When Firefox opens index.html through its file URL, the references are interpreted relative to the HTML document’s location. Check that the stylesheet and script are beside the HTML file and that the image is in the expected parent directory’s images folder. A correctly formed URL does not fix a reference that points to the wrong directory or a file that does not exist.

Build the file URL safely

Do not construct a URL by concatenating file:// and a path string. Characters such as spaces, # and % can be interpreted as URL syntax instead of as parts of a filename. Node’s URL documentation demonstrates that direct construction can produce incorrect URLs; pathToFileURL handles this conversion for you.

const htmlPath = path.resolve('fixtures/report/index.html');
const fileUrl = pathToFileURL(htmlPath).href;

console.log(fileUrl); // Inspect the actual URL passed to page.goto
await page.goto(fileUrl);

Use an absolute path as the input to the conversion. Calling path.resolve makes the example’s intended starting point explicit; pathToFileURL also resolves the filesystem path and produces an absolute file URL. This is particularly useful when paths contain spaces, punctuation, non-ASCII characters or Windows drive letters. Inspect the printed result if the browser opens the wrong file or reports a navigation problem.

Use a real document navigation, not just injected markup

page.setContent(html) supplies markup to a page; it is not the same operation as navigating to an HTML file on disk. If you read a file into a string and inject it, do not assume relative references will use that file’s directory as their base. For a local fixture with neighboring assets, navigate to the fixture’s file URL instead.

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.

If you must inject markup, give its resources an intentional base or rewrite references as explicit file URLs, then verify the result in the specific Puppeteer and Firefox versions you run. Treat that as an approach to test, not as a documented guarantee that injected markup will inherit a local file’s location. Puppeteer’s official files guide describes uploading a local file through an HTML file input; that is a different operation from opening a local HTML document and does not establish a base URL for setContent.

Wait for the output your task needs

Successful navigation does not necessarily mean every asset or application task is finished. If you are taking a screenshot or reading content that depends on images or scripts, wait for the relevant page state before using the result. For example, wait for an element your task needs to appear, or check that a particular image has loaded. Inspect failed requests and browser console errors if the rendered page differs from what you expect. These are practical checks; the cited API guidance does not promise that every relative local resource will load under every Firefox version or security configuration.

For lazy-loaded images, the page may need additional interaction or scrolling before those images are requested. The right wait condition depends on the page: waiting for a document navigation alone may not establish that a particular image, client-side update or delayed component is ready. Prefer checking for the specific output your automation relies on over adding an arbitrary delay when you can.

Common failures and fixes

Symptom Likely cause What to check
Puppeteer launches a different browser or rejects the browser option. The installed setup does not support the requested Firefox launch mode, or the option is not set. Use a Puppeteer version with Firefox support and select it with browser: 'firefox'. Mozilla announced first-class support starting in Puppeteer 23; confirm the version and browser configuration used by the script.
page.goto rejects the path or cannot navigate to it. A raw filesystem path was supplied instead of a URL, or the URL has no scheme. Resolve the path and pass pathToFileURL(htmlPath).href. Log the final URL and confirm it starts with file:.
The HTML opens, but an image, stylesheet or script is missing. The reference resolves to a different directory than expected, the file is absent, or the browser did not load that local resource. Check the reference against the HTML file’s directory, confirm the target exists, and inspect failed requests and console errors. A correct conversion of the HTML path does not correct a broken asset path.
Paths with spaces or punctuation open incorrectly. A raw path was manually prefixed with file:, leaving URL-sensitive characters unencoded. Use pathToFileURL and inspect the resulting URL, especially when the filename contains #, %, spaces or non-ASCII characters.
Markup injected with setContent has broken relative references. The injected document was not navigated to at the local HTML file’s URL, so its filesystem base should not be assumed. Navigate to the actual file URL, or define explicit resource locations and test the exact browser and Puppeteer versions.
The page looks incomplete even though navigation returned. A required image, script or delayed page element was not ready when the automation continued. Wait for the specific element or output needed and inspect failed requests. If the issue persists, reduce it to one HTML file and one relative asset.

A 2019 Stack Overflow question reported relative local assets failing with the legacy puppeteer-firefox package, and said that using setContent did not solve the issue. That is a historical user report, not evidence that the same failure occurs in current Puppeteer Firefox. If a minimal case still fails, record the Puppeteer version, Firefox version, operating system, generated file URL and one relative asset reference; those details help distinguish a path error from a browser-specific local-file restriction.

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

When to serve the files over HTTP instead

If navigating to the correctly formed file URL still does not provide the local-resource behavior your task requires, serve the fixture files over HTTP and navigate to the resulting HTTP URL. That gives the document an ordinary web URL and makes its relative references resolve from that URL’s path. This is an alternative to test when the browser’s local-file policies or the project’s test setup make file URLs unsuitable; it is not necessary to replace the file-URL method when that method works for your fixture.

Keep the choice aligned with what you are testing. A file URL exercises a local document opened from disk. A page served over HTTP exercises the document in a web-server context. If the production page runs behind a server, using the same kind of URL context can make the automated setup more representative, but it will not be identical unless the relevant server behavior and assets are also present.

Or skip the browser setup

For a publicly reachable website, ScreenshotNeo can return a screenshot or PDF through a single GET request. It is not a replacement for the local-file steps above: an API request cannot reach a file on your computer merely because you pass a file: URL or a local-only address. Use it for a page the service can reach, not as a way to upload this local fixture.

For example, this cURL request captures a public page as WebP:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo documentation for API options. Before capture, it accepts cookie or consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and each response reports the page verdict and billing status in headers. An MCP server offers take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month with no card.

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.