PHPackages                             fagundes/chrome - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [PDF &amp; Document Generation](/categories/documents)
4. /
5. fagundes/chrome

ActiveLibrary[PDF &amp; Document Generation](/categories/documents)

fagundes/chrome
===============

Instrument headless chrome/chromium instances from php

v0.8.1(6y ago)05FairPHPPHP &gt;=7.0

Since Apr 7Pushed 5y agoCompare

[ Source](https://github.com/fagundes/headless-chromium-php)[ Packagist](https://packagist.org/packages/fagundes/chrome)[ Docs](https://github.com/gsouf/headless-chromium-php)[ RSS](/packages/fagundes-chrome/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (9)Versions (21)Used By (0)

Chrome PHP
==========

[](#chrome-php)

[![Build Status](https://camo.githubusercontent.com/12377dc0fa83d19b8a08c1f33c69891bbcf523c10b7b4f2eee621b263a20cf29/68747470733a2f2f7472617669732d63692e6f72672f6368726f6d652d7068702f686561646c6573732d6368726f6d69756d2d7068702e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/chrome-php/headless-chromium-php)[![Latest Stable Version](https://camo.githubusercontent.com/dbab9f61c8115cdab272534cc2566f25ec6ed5dfb4be51c235978667fe5c4b86/68747470733a2f2f706f7365722e707567782e6f72672f6368726f6d652d7068702f6368726f6d652f76657273696f6e)](https://packagist.org/packages/chrome-php/chrome)[![License](https://camo.githubusercontent.com/dad2bb40420f8bc53de31fdee90b00c553ce280aa6053beb02ecc88f2957bb99/68747470733a2f2f706f7365722e707567782e6f72672f6368726f6d652d7068702f6368726f6d652f6c6963656e7365)](https://packagist.org/packages/chrome-php/chrome)

This library lets you start playing with chrome/chromium in headless mode from PHP.

> **/!\\** The library is still young and some features you need might be missing. We add feature as feature requests are submitted, feel free to rise an issue if you want to see a new feature to be supported by the library. Additionally the library follows semver. That means that until version 1.0.0 a lot of changes might occur.

⚠️Loking for maintainers⚠️
--------------------------

[](#️loking-for-maintainers️)

Many people are showing interest in the library but I don't have much time to maintain it. I'm looking for some permanent maintainers to help with it.

It can be for handling issues, adding documentation, adding new features, fixing bugs, etc...

Features
--------

[](#features)

- Open chrome or chromium browser from php
- Create pages and navigate to pages
- Take screenshots
- Evaluate javascript in the page
- Make PDF
- Emulate mouse
- *TODO* Emulate keyboard
- Always IDE friendly

Happy browsing!

Requirements
------------

[](#requirements)

Requires php 7 and a chrome/chromium executable.

As of version 65 of chrome/chromium the library proved to work correctly. Please try to keep using latest version of chrome.

Note that the library is only tested on linux but is compatible with osX and windows.

Install
-------

[](#install)

The library can be installed with composer and is available on packagist under [chrome-php/chrome](https://packagist.org/packages/chrome-php/chrome)

`composer require chrome-php/chrome`

Usage
-----

[](#usage)

It uses a simple and understandable API to start chrome, to open pages, to take screenshots, to crawl websites... and almost everything that you can do with chrome as a human.

```
    use HeadlessChromium\BrowserFactory;

    $browserFactory = new BrowserFactory();

    // starts headless chrome
    $browser = $browserFactory->createBrowser();

    // creates a new page and navigate to an url
    $page = $browser->createPage();
    $page->navigate('http://example.com')->waitForNavigation();

    // get page title
    $pageTitle = $page->evaluate('document.title')->getReturnValue();

    // screenshot - Say "Cheese"! 😄
    $page->screenshot()->saveToFile('/foo/bar.png');

    // pdf
    $page->pdf(['printBackground'=>false])->saveToFile('/foo/bar.pdf');

    // bye
    $browser->close();
```

### Using different chrome executable

[](#using-different-chrome-executable)

When starting the factory will look for the environment variable `"CHROME_PATH"` to find the chrome executable. If the variable is not found then it will use `"chrome"` as the executable.

You can use any executable of your choice. For instance `"chromium-browser"`:

```
    use HeadlessChromium\BrowserFactory;

    // replace default 'chrome' with 'chromium-browser'
    $browserFactory = new BrowserFactory('chromium-browser');
```

### Debugging

[](#debugging)

The following example adds some development-oriented features to help debugging

```
    use HeadlessChromium\BrowserFactory;

    $browserFactory = new BrowserFactory();

    $browser = $browserFactory->createBrowser([
        'headless'        => false,         // disable headless mode
        'connectionDelay' => 0.8,           // add 0.8 second of delay between each instruction sent to chrome,
        'debugLogger'     => 'php://stdout' // will enable verbose mode
    ]);
```

About `debugLogger`: this can be any of a resource string, a resource or an object implementing `LoggerInterface` from Psr\\Log (such as [monolog](https://github.com/Seldaek/monolog)or [apix/log](https://github.com/apix/log)).

---

API
---

[](#api)

### Browser Factory

[](#browser-factory)

```
    use \HeadlessChromium\BrowserFactory;

    $browserFactory = new BrowserFactory();
    $browser = $browserFactory->createBrowser([
        'windowSize' => [1920, 1000],
        'enableImages' => false
    ]);
```

#### Options

[](#options)

Here are the options available for the browser factory:

Option nameDefaultDescriptionconnectionDelay0Delay to apply between each operation for debugging purposescustomFlagsnoneArray of flags to pass to the command line. Eg: `['--option1', '--option2=someValue']`debugLoggernullA string (e.g "php://stdout"), or resource, or PSR-3 logger instance to print debug messagesenableImagestrueToggles loading of imagesheadlesstrueEnable or disable headless modeignoreCertificateErrorsfalseSet chrome to ignore ssl errorskeepAlivetruetrue to keep alive the chrome instance when the script terminatesnoSandboxfalseUseful to run in a docker containersendSyncDefaultTimeout3000Default timeout (ms) for sending sync messagesstartupTimeout30Maximum time in seconds to wait for chrome to startuserAgentnoneUser agent to use for the whole browser (see page api for alternative)userDataDirnonechrome user data dir (default: a new empty dir is generated temporarily)windowSizenoneSize of the window. usage: `[$width, $height]` - see also Page::setViewport### Browser API

[](#browser-api)

#### Create a new page (tab)

[](#create-a-new-page-tab)

```
    $page = $browser->createPage();

    // destination can be specified
    $uri = 'http://example.com';
    $page = $browser->createPage($uri);
```

#### Close the browser

[](#close-the-browser)

```
    $browser->close();
```

### Set a script to evaluate before every page created by this browser will navigate

[](#set-a-script-to-evaluate-before-every-page-created-by-this-browser-will-navigate)

```
    $script =
     '// Simulate navigator permissions;
      const originalQuery = window.navigator.permissions.query;
      window.navigator.permissions.query = (parameters) => (
          parameters.name === 'notifications' ?
              Promise.resolve({ state: Notification.permission }) :
              originalQuery(parameters)
      );'

    $browser->setPagePreScript($script);
```

### Page API

[](#page-api)

#### Navigate to an url

[](#navigate-to-an-url)

```
    // navigate
    $navigation = $page->navigate('http://example.com');

    // wait for the page to be loaded
    $navigation->waitForNavigation();
```

When Using `$navigation->waitForNavigation()` you will wait for 30sec until the page event "loaded" is triggered. You can change the timeout or the event to listen for:

```
    // wait 10secs for the event "DOMContentLoaded" to be triggered
    $navigation->waitForNavigation(Page::DOM_CONTENT_LOADED, 10000)
```

Available events (in the order they trigger):

- `Page::DOM_CONTENT_LOADED`: dom has completely loaded
- `Page::LOAD`: (default) page and all resources are loaded
- `Page::NETWORK_IDLE`: page has loaded, and no network activity has occurred for at least 500ms

When you want to wait for the page to navigate there are 2 main issues that may occur. First the page is too long to load and second the page you were waiting to be loaded has been replaced. The good news is that you can handle those issues using a good old try catch:

```
  use HeadlessChromium\Exception\OperationTimedOut;
  use HeadlessChromium\Exception\NavigationExpired;

  try {
    $navigation->waitForNavigation()
  } catch (OperationTimedOut $e) {
    // too long to load
  } catch (NavigationExpired $e) {
    // An other page was loaded
  }
```

#### Evaluate script on the page

[](#evaluate-script-on-the-page)

Once the page has completed the navigation you can evaluate arbitrary script on this page:

```
    // navigate
    $navigation = $page->navigate('http://example.com');

    // wait for the page to be loaded
    $navigation->waitForNavigation();

    // evaluate script in the browser
    $evaluation = $page->evaluate('document.documentElement.innerHTML');

    // wait for the value to return and get it
    $value = $evaluation->getReturnValue();
```

Sometime the script you evaluate will click a link or submit a form, in this case the page will reload and you will want to wait for the new page to reload.

You can achieve this by using `$page->evaluate('some js that will reload the page')->waitForPageReload()`. An example is available in [form-submit.php](./examples/form-submit.php)

#### Call a function

[](#call-a-function)

This is an alternative to `evaluate` that allows to call a given function with the given arguments in the page context:

```
    $evaluation = $page->callFunction(
      'function(a, b) {
          window.foo = a + b;
       }',
      [1, 2]
    );

    $value = $evaluation->getReturnValue();
```

#### Add a script tag

[](#add-a-script-tag)

That's useful if you want to add jQuery (or anything else) to the page:

```
    $page->addScriptTag([
        'content' => file_get_contents('path/to/jquery.js')
    ])->waitForResponse();

    $page->evaluate('$(".my.element").html()');
```

You can also use an url to feed the src attribute:

```
    $page->addScriptTag([
        'url' => 'https://code.jquery.com/jquery-3.3.1.min.js'
    ])->waitForResponse();

    $page->evaluate('$(".my.element").html()');
```

### Add a script to evaluate upon page navigation

[](#add-a-script-to-evaluate-upon-page-navigation)

```
    $script =
     '// Simulate navigator permissions;
      const originalQuery = window.navigator.permissions.query;
      window.navigator.permissions.query = (parameters) => (
          parameters.name === 'notifications' ?
              Promise.resolve({ state: Notification.permission }) :
              originalQuery(parameters)
      );'

    $page->addPreScript($script);
```

If your script needs the dom to be fully populated before it runs then you can use the option "onLoad":

```
    $page->addPreScript($script, ['onLoad' => true]);
```

#### Set viewport size

[](#set-viewport-size)

This features allows to change the size of the viewport (emulation) for the current page without affecting the size of all the browser's pages (see also option `"windowSize"` of [BrowserFactory::createBrowser](#options)).

```
    $width = 600;
    $height = 300;
    $page->setViewport($width, $height)
        ->await(); // wait for operation to complete
```

#### Make a screenshot

[](#make-a-screenshot)

```
    // navigate
    $navigation = $page->navigate('http://example.com');

    // wait for the page to be loaded
    $navigation->waitForNavigation();

    // take a screenshot
    $screenshot = $page->screenshot([
        'format'  => 'jpeg',  // default to 'png' - possible values: 'png', 'jpeg',
        'quality' => 80       // only if format is 'jpeg' - default 100
    ]);

    // save the screenshot
    $screenshot->saveToFile('/some/place/file.jpg');
```

**choose an area**

You can use the option "clip" in order to choose an area for the screenshot (TODO exemple)

**take a full page screenshot**

You can also take a screenshot for the full layout (not only the layout) using `$page->getFullPageClip` (TODO exemple)

TODO `Page.getFullPageClip();`

```
    use HeadlessChromium\Clip;

    // navigate
    $navigation = $page->navigate('http://example.com');

    // wait for the page to be loaded
    $navigation->waitForNavigation();

    // create a rectangle by specifying to left corner coordinates + width and height
    $x = 10;
    $y = 10;
    $width = 100;
    $height = 100;
    $clip = new Clip($x, $y, $width, $height);

    // take the screenshot (in memory binaries)
    $screenshot = $page->screenshot([
        'clip'  => $clip'
    ]);

    // save the screenshot
    $screenshot->saveToFile('/some/place/file.jpg');
```

#### Print as PDF

[](#print-as-pdf)

```
    // navigate
    $navigation = $page->navigate('http://example.com');

    // wait for the page to be loaded
    $navigation->waitForNavigation();

    $options = [
                  'landscape'       => true,  // default to false
                  'printBackground' => true,   // default to false
                  'displayHeaderFooter' => true, // default to false
                  'preferCSSPageSize' => true, // default to false ( reads parameters directly from @page )
                  'marginTop' => 0.0, // defaults to ~0.4 (must be float, value in inches)
                  'marginBottom' => 1.4, // defaults to ~0.4 (must be float, value in inches)
                  'marginLeft' => 5.0, // defaults to ~0.4 (must be float, value in inches)
                  'marginRight' => 1.0 // defaults to ~0.4 (must be float, value in inches)
                  'paperWidth' => 6 // defaults to 8.5 (must be float, value in inches)
                  'paperHeight' => 6 // defaults to 8.5 (must be float, value in inches)
                  'headerTemplate' => "foo", // see details bellow
                  'footerTemplate' => "foo", // see details bellow
                  'scale' => 1.2, // defaults to 1
               ];

    // print as pdf (in memory binaries)
    $pdf = $page->pdf($options);

    // save the pdf
    $pdf->saveToFile('/some/place/file.pdf');

    // or directly output pdf without saving
    header('Content-Description: File Transfer');
    header('Content-Type: application/pdf');
    header('Content-Disposition: inline; filename=filename.pdf');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');

    echo base64_decode($pdf->getBase64());
```

Options `headerTempalte` and `footerTempalte`:

Should be valid HTML markup with following classes used to inject printing values into them:

- date: formatted print date
- title: document title
- url: document location
- pageNumber: current page number
- totalPages: total pages in the document

### Mouse API

[](#mouse-api)

The mouse API is dependent on the page instance and allows you to control the mouse's moves and clicks.

```
    $page->mouse()
        ->move(10, 20)                              // Moves mouse to position x=10;y=20
        ->click()                                   // left click on position set above
        ->move(100, 200, ['steps' => 5])            // move mouse to x=100;y=200 in 5 equal steps
        ->click(['button' => Mouse::BUTTON_RIGHT];  // right click on position set above

    // given the last click was on a link, the next step will wait for the page to load after the link was clicked
    $page->waitForReload();
```

### Cookie API

[](#cookie-api)

You can set and get cookies for a page:

#### Set Cookie

[](#set-cookie)

```
    use HeadlessChromium\Cookies\Cookie;

    $page = $browser->createPage();

    // example 1: set cookies for a given domain

    $page->setCookies([
        Cookie::create('name', 'value', [
            'domain' => 'example.com',
            'expires' => time() + 3600 // expires in 1 day
        ])
    ])->await();

    // example 2: set cookies for the current page

    $page->navigate('http://example.com')->waitForNavigation();

    $page->setCookies([
        Cookie::create('name', 'value', ['expires'])
    ])->await();

```

#### Get Cookies

[](#get-cookies)

```
    use HeadlessChromium\Cookies\Cookie;

    $page = $browser->createPage();

    // example 1: get all cookies for the browser

    $cookies = $page->getAllCookies();

    // example 2: get cookies for the current page

    $page->navigate('http://example.com')->waitForNavigation();
    $cookies = $page->getCookies();

    // filter cookies with name == 'foo'
    $cookiesFoo = $cookies->filterBy('name', 'foo');

    // find first cookie with name == 'bar'
    $cookieBar = $cookies->findOneBy('name', 'bar');
    if ($cookieBar) {
        // do something
    }

```

### Set user agent

[](#set-user-agent)

You can set an user agent per page :

```
$page->setUserAgent('my user agent');
```

See also BrowserFactory option `userAgent` to set it for the whole browser.

---

Advanced usage
--------------

[](#advanced-usage)

The library ships with tools that hide all the communication logic but you can use the tools used internally to communicate directly with chrome debug protocol.

Example:

```
  use HeadlessChromium\Communication\Connection;
  use HeadlessChromium\Communication\Message;

  // chrome devtools uri
  $webSocketUri = 'ws://127.0.0.1:9222/devtools/browser/xxx';

  // create a connection
  $connection = new Connection($webSocketUri);
  $connection->connect();

  // send method "Target.activateTarget"
  $responseReader = $connection->sendMessage(new Message('Target.activateTarget', ['targetId' => 'xxx']));

  // wait up to 1000ms for a response
  $response = $responseReader->waitForResponse(1000);

  if ($response) {
    // ok
  }else {
    // not ok
  }
```

### Create a session and send message to the target

[](#create-a-session-and-send-message-to-the-target)

```
  // given a target id
  $targetId = 'yyy';

  // create a session for this target (attachToTarget)
  $session = $connection->createSession($targetId);

  // send message to this target (Target.sendMessageToTarget)
  $response = $session->sendMessageSync(new Message('Page.reload'));
```

### Debugging

[](#debugging-1)

You can ease the debugging by setting a delay before each operation is made:

```
  $connection->setConnectionDelay(500); // wait for 500 ms between each operation to ease debugging
```

### Browser (standalone)

[](#browser-standalone)

```
    use HeadlessChromium\Communication\Connection;
    use HeadlessChromium\Browser;

    // chrome devtools uri
    $webSocketUri = 'ws://127.0.0.1:9222/devtools/browser/xxx';

    // create connection given a web socket uri
    $connection = new Connection($webSocketUri);
    $connection->connect();

    // create browser
    $browser = new Browser($connection);
```

Contributing
------------

[](#contributing)

See [CONTRIBUTING.md](./CONTRIBUTING.md) for contribution details.

Credits
-------

[](#credits)

Thanks to [puppeteer](https://github.com/GoogleChrome/puppeteer) that served as an inspiration.

Roadmap
-------

[](#roadmap)

- Make pdf
- Create a DOM manipulation framework
- Inspect network traces
- Emulate keyboard
- Adding api documentation ()

Authors
-------

[](#authors)

- **Soufiane Ghzal** - *Initial work* - [gsouf](https://github.com/gsouf)

See also the list of [contributors](https://github.com/gsouf/headless-chromium-php/contributors) who participated in this project.

License
-------

[](#license)

This project is licensed under the [Fair License](./LICENSE).

###  Health Score

26

—

LowBetter than 43% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity4

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 80% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~42 days

Recently: every ~116 days

Total

17

Last Release

2278d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/2a488c4d3cfa2f8b3759d907c04cd7da9d347a25090424efbd7b8f1b57937543?d=identicon)[fagundes](/maintainers/fagundes)

---

Top Contributors

[![gsouf](https://avatars.githubusercontent.com/u/3215399?v=4)](https://github.com/gsouf "gsouf (160 commits)")[![tigris-berlin-mx](https://avatars.githubusercontent.com/u/180308638?v=4)](https://github.com/tigris-berlin-mx "tigris-berlin-mx (10 commits)")[![tanasecosminromeo](https://avatars.githubusercontent.com/u/808587?v=4)](https://github.com/tanasecosminromeo "tanasecosminromeo (9 commits)")[![andrew-s](https://avatars.githubusercontent.com/u/479306?v=4)](https://github.com/andrew-s "andrew-s (5 commits)")[![sergiosusa](https://avatars.githubusercontent.com/u/5395597?v=4)](https://github.com/sergiosusa "sergiosusa (3 commits)")[![TimIgoe](https://avatars.githubusercontent.com/u/1212502?v=4)](https://github.com/TimIgoe "TimIgoe (2 commits)")[![dogawaf](https://avatars.githubusercontent.com/u/381969?v=4)](https://github.com/dogawaf "dogawaf (2 commits)")[![fagundes](https://avatars.githubusercontent.com/u/169477?v=4)](https://github.com/fagundes "fagundes (2 commits)")[![kaero598](https://avatars.githubusercontent.com/u/9202326?v=4)](https://github.com/kaero598 "kaero598 (2 commits)")[![marios88](https://avatars.githubusercontent.com/u/302688?v=4)](https://github.com/marios88 "marios88 (1 commits)")[![svbackend](https://avatars.githubusercontent.com/u/19356345?v=4)](https://github.com/svbackend "svbackend (1 commits)")[![johnanthonyeletto](https://avatars.githubusercontent.com/u/18408818?v=4)](https://github.com/johnanthonyeletto "johnanthonyeletto (1 commits)")[![hamidzr](https://avatars.githubusercontent.com/u/12127420?v=4)](https://github.com/hamidzr "hamidzr (1 commits)")[![ArseniyShestakov](https://avatars.githubusercontent.com/u/9513350?v=4)](https://github.com/ArseniyShestakov "ArseniyShestakov (1 commits)")

---

Tags

browserpdfheadlesschromescreenshotcrawlchromium

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/fagundes-chrome/health.svg)

```
[![Health](https://phpackages.com/badges/fagundes-chrome/health.svg)](https://phpackages.com/packages/fagundes-chrome)
```

###  Alternatives

[chrome-php/chrome

Instrument headless chrome/chromium instances from PHP

2.6k4.5M64](/packages/chrome-php-chrome)[spatie/browsershot

Convert a webpage to an image or pdf using headless Chrome

5.2k32.1M102](/packages/spatie-browsershot)[gotenberg/gotenberg-php

A PHP client for interacting with Gotenberg, a developer-friendly API for converting numerous document formats into PDF files, and more!

3685.2M19](/packages/gotenberg-gotenberg-php)[sensiolabs/gotenberg-bundle

A Symfony bundle that provides seamless integration with Gotenberg for generating PDFs and screenshots from various sources (HTML, Markdown, Office documents, URLs) with a clean, builder-based API.

210210.4k2](/packages/sensiolabs-gotenberg-bundle)[spiritix/php-chrome-html2pdf

A PHP library for converting HTML to PDF using Google Chrome

153472.0k3](/packages/spiritix-php-chrome-html2pdf)[daandesmedt/phpheadlesschrome

A PHP wrapper for using Google Chrome Headless mode. Convert URL or HTML to a PDF / screenshot. Easy to use and OOP interfaced.

92233.1k](/packages/daandesmedt-phpheadlesschrome)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
