chrome-php/chrome: Driving Headless Chrome from PHP
Instrument headless chrome/chromium instances from PHP
At a glance
- What is it?
- chrome-php/chrome wraps the Chrome DevTools Protocol in a PHP API so scripts can open pages, evaluate JavaScript, capture screenshots and render PDFs. It fits PHP backends that already shell out to a browser; it is not a general browser automation suite.
- Who is it for?
- Adopt chrome-php/chrome if you are already in PHP and need programmatic page loads, screenshots, PDFs or JavaScript evaluation without adding a Node or Python runtime to the deployment. Do not adopt it if you need cross-browser testing, a visual test runner with assertions, or a recorder that generates test code; this library provides a browser client, not a test framework.
- Can I use it commercially?
- Yes. MIT 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 86 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What chrome-php/chrome is for
The library exists to remove the shell-out step from PHP browser automation. Without it, a PHP application that needs a rendered page has to construct a Chrome command line, manage the process, parse its output, and clean up after a crash. chrome-php/chrome replaces that with a PHP object graph: a BrowserFactory starts a Chrome or Chromium process, the returned Browser creates pages, and each Page exposes navigation, JavaScript evaluation, screenshots and PDF generation.
The target user is a PHP developer working on a server-side task that needs a real browser engine. Rendering a page to PDF, capturing a screenshot of a dashboard, scraping content that only appears after JavaScript runs, or running a small script inside a page context are all in scope. The README describes the API as "simple and understandable" and lists the supported operations directly: open a browser, create pages, navigate, screenshot, evaluate JavaScript, make PDFs, and emulate mouse and keyboard input.
It is not a testing framework. There is no assertion layer, no test runner, no selector-driven wait-and-click DSL, and no reporting. If your goal is to verify that a checkout flow works, you want a test tool that happens to drive Chrome, not a Chrome client you build a test harness around.
How the library talks to Chrome
The architecture is a client process talking to a browser process. BrowserFactory locates a Chrome or Chromium executable, launches it, and hands back a Browser object that owns the connection. Pages are created from that Browser, and operations on a Page are messages sent to the browser and responses read back.
The README states that the library can be used "synchronously and asynchronously", which maps onto how callers consume results. Some operations return a value directly, as in the title example where evaluate('document.title')->getReturnValue() yields the string. Others return an object you act on, such as the screenshot and pdf calls, which expose saveToFile(). Navigation is a separate awaited step: navigate() returns an object with waitForNavigation(), so the caller decides when the page is considered loaded.
Process lifecycle is explicit. The README's example wraps the work in try/finally and calls $browser->close() in the finally block. The keepAlive option, defaulting to false, controls whether the Chrome instance survives the PHP script terminating. That default matters: a long-running worker that creates a browser per job will accumulate processes if close() is skipped.
Configuration flows through the factory. Options passed to createBrowser() apply to that single browser and, per the README, cause the factory's default options to be ignored for that call. Options set with setOptions() or addOptions() persist across subsequent createBrowser() calls, and addOptions() merges into the existing set rather than replacing it. The README illustrates this with a windowSize option set once and an enableImages option toggled true and then false across four browsers.
Installing chrome-php/chrome and taking a first screenshot
Installation is a single Composer command. The package is published on Packagist as chrome-php/chrome, and the README gives this line:
composer require chrome-php/chromeAfter that, the requirements are PHP 7.4 through 8.5 and a Chrome or Chromium executable at version 65 or higher. The README notes the library is only tested on Linux but states it is compatible with macOS and Windows.
The README's own starting example is the shortest path to a working result. It starts headless Chrome, opens a page, reads the title, writes a screenshot and a PDF, then closes the browser in a finally block:
use HeadlessChromium\BrowserFactory;
$browserFactory = new BrowserFactory();
$browser = $browserFactory->createBrowser();
try {
$page = $browser->createPage();
$page->navigate('http://example.com')->waitForNavigation();
$pageTitle = $page->evaluate('document.title')->getReturnValue();
$page->screenshot()->saveToFile('/foo/bar.png');
$page->pdf(['printBackground' => false])->saveToFile('/foo/bar.pdf');
} finally {
$browser->close();
}Two details in that snippet are worth noticing before you run it. First, the output paths are absolute; relative paths are not discussed in the README. Second, pdf() takes an options array, and printBackground is shown set to false, which drops background colours from the rendered document.
If the default executable lookup fails, the factory checks the CHROME_PATH environment variable and then guesses a path by operating system, falling back to "chrome". You can bypass that entirely by passing the binary name to the constructor, as the README shows with chromium-browser:
use HeadlessChromium\BrowserFactory;
$browserFactory = new BrowserFactory('chromium-browser');When something goes wrong, the README offers two debugging options. Setting headless to false opens a visible window, and connectionDelay adds a pause between instructions sent to Chrome. A debugLogger accepts a string such as php://stdout, a resource, or any PSR-3 logger instance.
Where the option table leaves you exposed
The browser factory option table is the most concrete documentation in the repository, and reading it closely reveals the boundaries. proxyServer is documented with the format 127.0.0.1:8080 and carries an explicit caveat: authorisation with credentials does not work. If your scraping target sits behind an authenticated proxy, this library cannot reach it through that option, and the README does not describe a workaround.
Several options are blunt instruments. enableImages is a boolean that toggles image loading for the whole browser, not per page. disableJavascript is described as applying to every page created via createPage(), so you cannot mix a JavaScript-enabled page and a JavaScript-disabled page in the same browser instance. noSandbox is documented as useful in a Docker container, which is accurate but also a security decision: disabling the sandbox removes a layer of process isolation, and the README does not discuss the trade-off.
Timeouts are global rather than per operation. sendSyncDefaultTimeout defaults to 5000 milliseconds and is described as the default timeout for sending sync messages. startupTimeout defaults to 30 seconds and caps how long the library waits for Chrome to start. A slow container or a cold start on a loaded host can exceed that, and the README does not describe retry behaviour.
The README also does not document rollback, version pinning strategy, or what happens to an in-flight page when the browser process dies. For a library that manages an external process, those are real gaps. The CHANGELOG.md file exists at the repository root, so release history is traceable, but the README itself does not walk through upgrade steps between minor versions.
chrome-php/chrome compared with Puppeteer and Playwright
The nearest alternatives are Puppeteer and Playwright. The difference is not capability so much as runtime. Puppeteer and Playwright are Node.js libraries, and Playwright additionally ships bindings for Python, Java and .NET. chrome-php/chrome is a PHP client for the same underlying browser protocol.
That distinction decides the choice in practice. A PHP application that already runs on a LAMP or PHP-FPM stack can add chrome-php/chrome with one Composer command and no new language runtime. Introducing Puppeteer or Playwright means introducing Node, a separate dependency tree, and a second process to supervise alongside the PHP application. For a team whose deployment pipeline is Composer and PHPUnit, that is a meaningful operational cost.
The trade runs the other way for testing. Playwright and Puppeteer ship test runners, assertion helpers, automatic waiting, trace viewers and code generation. chrome-php/chrome ships none of that. It gives you navigate, evaluate, screenshot, pdf, and input emulation, and leaves orchestration to you. If your task is a scheduled PDF render or a screenshot service, that is the right amount of library. If your task is a regression suite across three browsers, you will spend more time building the harness than using it.
Browser coverage is another split. The README describes starting Chrome or Chromium and does not mention Firefox or WebKit. Playwright and Puppeteer both target multiple engines. For cross-browser verification, chrome-php/chrome is the wrong tool by design.
Maintenance, upgrades and the MIT licence
The repository is not archived, and the last push was on 2026-07-06. The default branch is 1.16, and the most recent releases are v1.16.1, v1.16.0 and v1.15.1, all dated 2026-07-06. Three releases landing on the same day suggests a burst of patch activity rather than a steady cadence, so treat release frequency as uneven when planning upgrades.
Upgrade cost is partly visible in the repository layout. The project carries phpstan.neon.dist and a phpstan-baseline.neon, a .php-cs-fixer.dist.php, phpunit.xml.dist, and a Makefile whose targets run PHPUnit, PHPStan, php-cs-fixer and composer-normalize. That is a maintained static-analysis and code-style pipeline, which is a reasonable signal that changes are checked before release. For a consumer, the practical implication is that the maintainers enforce their own style and type rules, so contributions and patches have a defined bar.
Version constraints matter more than usual here because the library drives an external binary. The README states support for PHP 7.4 through 8.5 and Chrome or Chromium 65 or higher. A container image pinned to an old Chrome build will still satisfy the stated minimum, but the README does not enumerate which protocol features degrade at which Chrome version.
The licence is MIT, which is permissive and permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. If you fork the library or vendor it into a product, keep the LICENSE file intact. This is a description of the licence text, not legal advice; consult your own counsel for your distribution scenario.
Editorial conclusion
Adopt chrome-php/chrome if you are already in PHP and need programmatic page loads, screenshots, PDFs or JavaScript evaluation without adding a Node or Python runtime to the deployment. Do not adopt it if you need cross-browser testing, a visual test runner with assertions, or a recorder that generates test code; this library provides a browser client, not a test framework. Before committing, verify three things: that the PHP version on your host is inside the 7.4-8.5 range the README states, that a Chrome or Chromium 65+ binary is reachable either through the CHROME_PATH environment variable or the path you pass to BrowserFactory, and that your container can run Chrome with noSandbox enabled or with a proper sandbox configuration. The README notes the library is only tested on Linux, so treat macOS and Windows deployments as unverified territory and run your own smoke test on the target platform.
Frequently asked questions
What is chrome-php/chrome used for?
It lets a PHP script start Chrome or Chromium in headless mode and then create pages, navigate, evaluate JavaScript, take screenshots, generate PDFs, and emulate mouse and keyboard input. The README positions it for tasks like crawling websites and rendering pages from PHP.
How do I install chrome-php/chrome?
Install it with Composer using the package name chrome-php/chrome. You also need PHP 7.4 through 8.5 and a Chrome or Chromium executable at version 65 or higher; the README notes the library is only tested on Linux but states macOS and Windows compatibility.
Does chrome-php/chrome work on macOS and Windows?
The README states the library is compatible with macOS and Windows but that it is only tested on Linux. If you deploy on macOS or Windows, plan to run your own verification rather than relying on the tested platform.
Can chrome-php/chrome use a proxy server with credentials?
No. The browser factory option table documents proxyServer with the format 127.0.0.1:8080 and states explicitly that authorisation with credentials does not work. There is also a noProxyServer option that forces direct connections and overrides other proxy settings.
How does chrome-php/chrome find the Chrome executable?
The factory checks the CHROME_PATH environment variable first, then guesses a path based on the operating system, and falls back to "chrome". You can override the lookup by passing a binary name to the BrowserFactory constructor, as the README shows with chromium-browser.
Is chrome-php/chrome a replacement for Puppeteer or Playwright?
Only for the browser-control portion. It drives Chrome or Chromium from PHP, but it does not include a test runner, assertions, tracing or code generation, and the README does not mention Firefox or WebKit support. Cross-browser testing needs a different tool.
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/chrome-php-chrome)