To run a legacy PhantomJS test in GitLab CI, use a pinned Node container image, install dependencies from a committed lockfile with npm ci, and invoke the project’s PhantomJS script in the job’s script. On Linux, make sure Fontconfig is installed. This setup can keep existing tests running, but PhantomJS is a legacy choice: GitLab reported switching its own tests to headless Chrome in 2017.
What the GitLab CI job needs
A GitLab CI job runs commands inside the environment selected for it. With the Docker executor, the image must include a working shell, and the job’s script lists the commands to execute. For a Node project using the npm phantomjs package, the package downloads a prebuilt binary for the detected operating system; on Linux, Fontconfig is also required.
The example below uses node:20-bookworm as a pinned-major Node image pattern. Adapt the image to the Node version and runner environment your project supports, and verify it on the target runner before relying on it. The job commands assume your test runner is at test/runner.js; replace that path with your project’s actual entry point.
Install PhantomJS and run it in GitLab CI
1. Add the npm dependency and commit the lockfile
From the project root, add the phantomjs package as a development dependency using npm. Commit both package.json and the generated package-lock.json. The lockfile records the dependency tree so the CI job can install the project’s declared versions rather than resolving a fresh tree on each run.
#1 Best Overall
Use npm ci in CI. It performs a clean install from the lockfile and is intended for automated builds. If the lockfile was created with flags that change dependency-tree shape, use the same relevant flags with npm ci; otherwise installation may fail because the package manifest and lockfile do not agree.
2. Add a CI job
image: node:20-bookworm
stages:
- test
phantomjs_test:
stage: test
before_script:
- npm ci
script:
- ./node_modules/.bin/phantomjs test/runner.js
Save this as .gitlab-ci.yml in the repository root. The job installs dependencies before running the PhantomJS binary installed under node_modules/.bin. Calling that local executable directly makes it clear that the job uses the project dependency, rather than an unrelated binary that might happen to be installed globally.
If your package scripts already define the test command, you can invoke the script instead—for example, use npm test if that is the project’s configured test command. Make sure that script actually runs PhantomJS and points to the correct test file. The sample runner path is illustrative, not a built-in PhantomJS or GitLab path.
3. Install Fontconfig when the image lacks it
The npm package documentation identifies Fontconfig as a Linux requirement. If the selected image does not already provide it, install it before running the test. In a Debian-based image such as the example, an apt-based installation step can be added before npm ci:
Free tools Windows power users keep installed
One-click scans. No signup required.
before_script:
- apt-get update
- apt-get install -y fontconfig
- npm ci
This assumes the job’s container user has permission to install system packages. If your runner uses a restricted image or non-root user, use an image where Fontconfig is already installed or arrange an approved image build instead. Do not add system-package installation blindly to every job: first check whether the image already has the library.
Make installation repeatable across CI runs
- Pin the container image deliberately. A stable image selection reduces unexpected changes to the Node runtime and operating-system environment. Change it intentionally and verify the job after an upgrade.
- Commit the npm lockfile. Without it, the resolved dependency tree can change over time. Keep the lockfile aligned with
package.json. - Use
npm ci, not an unconstrained install, for the CI job. It starts from a clean dependency installation and follows the committed lockfile. - Keep the executable and test path explicit. The sample uses
./node_modules/.bin/phantomjs; changetest/runner.jsto the file your project actually runs. - Account for platform differences. The npm package selects a binary for the detected operating system. It also accepts
PHANTOMJS_PLATFORMandPHANTOMJS_ARCHto control platform and architecture selection. Use those only when you intentionally need to override detection and know which binary matches the runner.
If dependencies were installed on a different platform from the CI runner, the package documentation describes running npm rebuild to rebuild platform-dependent dependencies. Prefer installing in the target environment with npm ci when possible, rather than carrying a platform-specific node_modules directory between machines.
Rank #3
Troubleshoot common installation and startup failures
| Symptom | Likely cause | What to check or change |
|---|---|---|
spawn ENOENT |
A required executable cannot be found, commonly node or tar. |
Check that the selected image provides the executable and that it is on PATH. Confirm the job is running in the image you expect. |
| Permission error during install | The CI user cannot write to the npm cache or installation directory. | Check the ownership and write permissions of those directories. Use a writable cache and project directory, or an image configured for the runner’s user. |
ECONNRESET or ETIMEDOUT while installing |
The installer could not download the platform binary, often because of network access, a proxy, or a mirror issue. | Check runner connectivity and approved proxy or mirror settings. The package can use a PhantomJS binary already on PATH, so an approved internal binary is another option. |
| PhantomJS starts with a Linux library or font-related error | Fontconfig may be missing from the image. | Install Fontconfig in the image or use a compatible image that includes it, then rerun the job. |
| Install works locally but fails in CI on another platform | The installed dependency artifacts may have been produced for a different operating system or architecture. | Install in the CI environment with npm ci; if necessary, follow the package guidance to run npm rebuild for the target platform. Check PHANTOMJS_PLATFORM and PHANTOMJS_ARCH if they are set. |
| TLS or certificate failure on binary download | The runner may not trust a proxy’s certificate chain or the configured download endpoint. | Configure a properly trusted certificate chain or use an approved internal mirror. Do not casually set strict-ssl=false: the package documentation warns that this is a risky workaround for intercepting proxies. |
When a job fails, inspect the first failing command in its log. A failure in npm ci points toward the lockfile, permissions, or download path; a failure in the PhantomJS command after installation points more toward the executable path, platform compatibility, Fontconfig, or the test runner itself.
Understand PhantomJS’s legacy status before extending it
PhantomJS may still be practical when a project has existing scripts that depend on its API and needs a short-term CI path. It should not be treated as a current browser-compatibility target without checking the project’s requirements. In a 2017 post, GitLab said it had switched from PhantomJS to headless Chrome for both frontend tests and RSpec feature tests. The post described PhantomJS as having been part of its test framework for almost five years at that point; that is historical context, not a present-day support guarantee.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
If you are deciding whether to preserve or migrate a test suite, assess the actual page features and test needs rather than assuming the runners are interchangeable. Compare:
Rank #4
- JavaScript and web-platform compatibility: whether the browser engine supports the APIs and behavior your application uses.
- Binary and image availability: whether you can obtain and maintain a compatible binary or container image for the operating systems and architectures your runners use.
- Debugging and failure diagnostics: what logs and inspection tools are available when an assertion or page load fails.
- CI startup and reproducibility: how the job obtains its browser and dependencies, and whether those inputs can be pinned and installed consistently.
- Migration effort: how much existing page code, selectors, and test APIs need to change for a different runner.
Or skip the browser setup
If you need a website screenshot rather than a PhantomJS-driven test suite, ScreenshotNeo is a screenshot API and MCP server for developers. It does not run PhantomJS tests or replace browser assertions; it provides an endpoint for capturing a page as an image or PDF. One GET request can return a screenshot, and its options cover cases such as full-page capture, a CSS-selected element, viewport and device settings, custom CSS or JavaScript, and waiting for a selector or network idle. See the API documentation for parameters and response details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each of those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for AI agents and MCP clients.
The Free plan includes 1,000 screenshots per month with no card required; paid plans start at $5 for 3,000 shots. Try it by signing up for the free plan.
Choose the right next step
For an existing PhantomJS suite, first get a reproducible job running with the project lockfile, a compatible image, a reachable binary, and Fontconfig on Linux. Then decide whether maintaining the legacy runner still fits the application’s browser requirements. If the need is only to produce screenshots—not to execute the project’s PhantomJS tests—a screenshot API is a different, simpler tool for that narrower task.
Frequently Asked Questions
Does GitLab CI require a special PhantomJS runner?
No special PhantomJS runner is shown in this setup. The job needs a compatible image with a working shell, its script commands, the npm-installed binary, and Linux Fontconfig where required.
Can I use a PhantomJS binary already installed in the image?
Yes. The npm package can use a PhantomJS executable on PATH. Make sure it matches the runner’s operating system and architecture, and that the CI job can execute it.
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.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problems

