phantomas: a headless Chromium metrics collector that emits events, not just scores
Headless Chromium-based web performance metrics collector and monitoring tool
At a glance
- What is it?
- phantomas is a Node.js CommonJS module and CLI that drives headless Chromium through puppeteer and reports dozens of page metrics as JSON. It suits engineers who want raw numbers they can assert on, not a single performance score.
- Who is it for?
- Adopt phantomas if you want per-page metrics and offender lists in JSON that you can assert on inside Node.js or a CI job, and if you are willing to pin the Chromium that puppeteer downloads. Do not adopt it if you need a single headline score, a hosted dashboard, or if you cannot run a Chromium binary in your build environment.
- Can I use it commercially?
- Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What phantomas measures that a Lighthouse score hides
The README describes phantomas as a "modular web performance metrics collector" built on headless Chromium, and the module layout in the repository backs that up: core/ holds the event emitter, modules/ holds the individual metric producers, reporters/ holds the output formats. Each metric comes from its own module rather than from one monolithic audit pass.
The feature list names things a generic audit rarely surfaces: the number of events bound via jQuery, calls to window.write, and complex or duplicated CSS selectors, the last handled through the analyze-css dependency. Those are specific to how a page is built, not to how fast it loaded. A team maintaining a large jQuery codebase or a stylesheet that has grown by accretion gets a number it can act on rather than a colour-coded dial.
Because results come back as a CommonJS module, the intended consumer is a test or a build step. results.getMetrics() and results.getAllOffenders() are the two calls the README shows, and the second is the interesting one: offenders name the concrete resources or selectors behind a metric, which is what you need in a failure message.
Events, modules and the window.__phantomas scope
The architecture is an event bus. The README states that phantomas "core" acts as an events emitter that each module can hook into, so a module subscribes to page lifecycle events and accumulates its own counters. The example in the README listens for recv, which carries method, url and contentType for every response, and for domQuery, a custom event emitted by one of the phantomas modules with a type and a query.
That second listener is the part worth understanding. The README says metrics can be emitted from JavaScript running in the page under test, through helper functions exposed on window.__phantomas. So instrumentation is two-way: the collector observes the browser, and the page can report back into the collector. If you control the application code, you can push custom measurements into the same result set as the built-in metrics.
The output format is JSON, and reporters/ is a separate directory from modules/, which means the collection step and the presentation step are decoupled. Device profiles are also part of the feature list: phantomas can emulate mobile or tablet by setting a user agent and a viewport. The README does not document the exact profile names, so check docs/ before relying on one.
Installing phantomas via npm and running a first measurement
The README requires Node.js 16 or newer, and package.json sets the engine field to >=16.0. Installing from npm also pulls a recent Chromium build, because puppeteer is a direct dependency and the README notes that npm install will install a recent version of Chromium supported by the puppeteer module.
npm install phantomasAfter installation the package exposes a bin entry named phantomas, so the CLI is on your PATH inside the project. The README says to run phantomas -h for the full option list; this article does not reproduce flags that the README does not state.
The shortest real use is the module API. Create a file and point it at a URL, then print both the metrics and the offenders behind them.
const phantomas = require('phantomas'),
promise = phantomas('http://example.com/');
promise.
then(results => {
console.log('Metrics', results.getMetrics());
console.log('Offenders', results.getAllOffenders());
}).
catch(res => {
console.error(res);
});You should see two objects logged. Metrics is the flat map of counters and timings; Offenders groups the entries that explain a metric, such as the individual responses behind a request count. The README also points at ./examples/index.js, and the examples/ directory ships config.json.example, config.yaml and screenshot.js, so a YAML config path exists even though the README does not spell out its keys.
If you would rather not manage a Chromium download, the README gives two image sources. The Dockerfile installs the shared libraries Chromium needs, runs npm ci, symlinks the downloaded chrome-linux64/chrome binary onto the PATH, and switches to the nobody user before copying the rest of the repository.
docker pull macbre/phantomas:latestThe README also lists the GitHub Container Registry as an alternative source, ghcr.io/macbre/phantomas:latest. The Dockerfile sets DOCKERIZED=yes in the environment, which is the marker the code uses to know it is running in a container.
Where phantomas gets in your way
The dependency on puppeteer is the biggest practical constraint. Installing phantomas downloads a Chromium build, and the release tags track it directly: v2.25.0 is labelled HeadlessChrome/149, v2.24.0 HeadlessChrome/146, v2.23.0 HeadlessChrome/145. A browser upgrade therefore arrives with a phantomas upgrade, and metrics that depend on rendering or on network behaviour can shift between those versions. If you gate a build on a threshold, pin the phantomas version and re-baseline when you move it.
Running Chromium in CI is the second constraint. The Dockerfile exists precisely because the binary needs a long list of shared libraries, including libnss3, libatk-bridge2.0-0, libgbm1 and libxkbcommon0, plus fonts-liberation for text rendering. The image also drops to the nobody user, which is good practice but means anything your measurement depends on must be reachable without root.
The README points to a separate Troubleshooting.md rather than covering failures inline, which tells you the maintainers expect environment problems to be common. It also does not document rollback of a configuration change, so if you tune a device profile or a module list there is no described way to revert it beyond version control.
phantomas is also the wrong tool when you want one number for a dashboard. It produces a metric map and offender lists. Turning that into a score, a trend line or an alert is left to whatever consumes the JSON.
phantomas against Lighthouse
Lighthouse is the obvious comparison and the difference is in the shape of the output. Lighthouse runs a fixed set of audits and reduces them to category scores, which is why it works well as a browser devtools panel and as a one-off report. phantomas emits individual metrics from independently loadable modules and hands you the offenders behind each one.
That changes what you can do with the result. A Lighthouse score of 74 is hard to assert on without a tolerance band; a phantomas metric such as a count of jQuery-bound events or a set of duplicated CSS selectors is a discrete value you can compare against a number you chose. The trade-off runs the other way too: phantomas gives you no opinion about which metrics matter for your site, and no built-in scoring model. You supply the judgement.
There is a second difference in integration surface. Lighthouse is primarily a browser and CLI experience with a Node API layered on. phantomas is described in its own README as coming as a CommonJS module first, with the CLI as an additional entry point. If your performance check lives inside a Jest or Node build script rather than in a browser session, that orientation fits better.
Maintenance, licensing and the cost of upgrading Chromium
The repository is not archived, and the last push was on 2026-08-31. Releases in 2026 have arrived roughly every one to three months, each tagged with the Chromium version it bundles. That cadence is set by puppeteer more than by phantomas itself, so expect the upgrade cost to be dominated by re-validating thresholds after a browser bump rather than by API churn.
The licence is BSD-2-Clause, which is permissive and short. It is a permissive licence, so redistribution and modification are allowed provided the copyright notice and licence text are kept; the repository ships AUTHORS and LICENSE at the top level. Two dependencies carry their own terms and are worth reading before you ship the tool inside a product: analyze-css and analyze-image are separate projects pulled in by package.json, and puppeteer brings Chromium, which has its own licensing. This is not legal advice; check those licences against your distribution model.
Support is not free. The README links to xs:code for commercial support, and FUNDING.yml is present at the top level. For an internal CI tool that is usually irrelevant, but it matters if you plan to depend on response times for a fix.
Editorial conclusion
Adopt phantomas if you want per-page metrics and offender lists in JSON that you can assert on inside Node.js or a CI job, and if you are willing to pin the Chromium that puppeteer downloads. Do not adopt it if you need a single headline score, a hosted dashboard, or if you cannot run a Chromium binary in your build environment. Before wiring it into a pipeline, verify that your Node.js version satisfies the >=16.0 engine field, that the Docker image's non-root user can still reach the pages you want to measure, and that the metrics you plan to gate on are listed in docs/metrics.md.
Frequently asked questions
What Node.js version does phantomas need?
The README lists NodeJS 16+, and package.json sets the engines field to >=16.0. Installing the package also pulls a Chromium build through puppeteer.
Can I run phantomas without installing Chromium myself?
Yes. The README documents two Docker images, macbre/phantomas:latest on Docker Hub and ghcr.io/macbre/phantomas:latest on the GitHub Container Registry. The Dockerfile installs the shared libraries Chromium needs, runs npm ci, and symlinks the downloaded chrome-linux64/chrome binary onto the PATH.
What output format does phantomas produce?
JSON. The feature list names JSON as the output format, and the module API returns a results object with getMetrics() and getAllOffenders() methods. Reporters live in their own directory, separate from the metric modules.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/macbre-phantomas)