| skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 1 | # Headless Chromium |
| 2 | |
| skyostil | 4c9d164c | 2016-12-23 11:15:52 | [diff] [blame] | 3 | Headless Chromium allows running Chromium in a headless/server environment. |
| 4 | Expected use cases include loading web pages, extracting metadata (e.g., the |
| 5 | DOM) and generating bitmaps from page contents -- using all the modern web |
| 6 | platform features provided by Chromium and Blink. |
| skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 7 | |
| Mathias Bynens | 31eceb2 | 2023-08-17 04:52:41 | [diff] [blame] | 8 | As of M118, precompiled `headless_shell` binaries are available for download |
| 9 | under the name `chrome-headless-shell` via [Chrome for Testing |
| 10 | infrastructure](https://googlechromelabs.github.io/chrome-for-testing/). |
| skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 11 | |
| Nikolay Vitkov | 5a48c624 | 2025-01-20 08:58:31 | [diff] [blame] | 12 | As of M132, headless shell functionality is no longer part of |
| 13 | the Chrome binary, so --headless=old has no effect. |
| 14 | If you are using old Headless functionality you should |
| 15 | now migrate to `chrome-headless-shell`. |
| 16 | [Read more](https://developer.chrome.com/blog/removing-headless-old-from-chrome). |
| 17 | |
| Peter Kvitek | 0cf1c8e0 | 2024-10-01 23:41:23 | [diff] [blame] | 18 | There are two ways to use Headless Chromium: |
| skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 19 | |
| Peter Kvitek | 0cf1c8e0 | 2024-10-01 23:41:23 | [diff] [blame] | 20 | ## Usage via the DevTools remote debugging protocol |
| skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 21 | |
| Nikolay Vitkov | 5a48c624 | 2025-01-20 08:58:31 | [diff] [blame] | 22 | 1. Start Chrome in headless mode using the `--headless` command line flag: |
| skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 23 | |
| Peter Kvitek | 0cf1c8e0 | 2024-10-01 23:41:23 | [diff] [blame] | 24 | ```sh |
| Nikolay Vitkov | 5a48c624 | 2025-01-20 08:58:31 | [diff] [blame] | 25 | $ chrome --headless --remote-debugging-port=9222 https://chromium.org/ |
| Peter Kvitek | 0cf1c8e0 | 2024-10-01 23:41:23 | [diff] [blame] | 26 | ``` |
| skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 27 | |
| Peter Kvitek | 0cf1c8e0 | 2024-10-01 23:41:23 | [diff] [blame] | 28 | 2. Navigate to `chrome://inspect/` in another instance of Chrome. |
| skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 29 | |
| Peter Kvitek | 0cf1c8e0 | 2024-10-01 23:41:23 | [diff] [blame] | 30 | ## Usage from Node.js |
| skyostil | fe11616 | 2016-02-26 20:53:33 | [diff] [blame] | 31 | |
| Peter Kvitek | 0cf1c8e0 | 2024-10-01 23:41:23 | [diff] [blame] | 32 | For example, the [chrome-remote-interface](https://github.com/cyrus-and/chrome-remote-interface) Node.js package can be used to |
| 33 | extract a page's DOM like this: |
| 34 | |
| 35 | ```js |
| 36 | const CDP = require('chrome-remote-interface'); |
| 37 | |
| 38 | (async () => { |
| 39 | let client; |
| 40 | try { |
| 41 | // Connect to browser |
| 42 | client = await CDP(); |
| 43 | |
| 44 | // Extract used DevTools domains. |
| 45 | const {Page, Runtime} = client; |
| 46 | |
| 47 | // Enable events on domains we are interested in. |
| 48 | await Page.enable(); |
| 49 | await Page.navigate({url: 'https://example.com'}); |
| 50 | await Page.loadEventFired(); |
| 51 | |
| 52 | // Evaluate outerHTML after page has loaded. |
| 53 | const expression = {expression: 'document.body.outerHTML'}; |
| 54 | const { result } = await Runtime.evaluate(expression); |
| 55 | console.log(result.value); |
| 56 | |
| 57 | } catch (err) { |
| 58 | console.error('Cannot connect to browser:', err); |
| 59 | |
| 60 | } finally { |
| 61 | if (client) { |
| 62 | await client.close(); |
| 63 | } |
| 64 | } |
| 65 | })(); |
| 66 | ``` |
| 67 | |
| 68 | Alternatvely, the [Puppeteer](https://pptr.dev/guides/what-is-puppeteer) Node.js package can be used to communicate |
| 69 | with headless, for example: |
| 70 | ```js |
| 71 | import puppeteer from 'puppeteer'; |
| 72 | |
| 73 | (async () => { |
| 74 | const browser = await puppeteer.launch({headless: 'shell'}); |
| 75 | |
| 76 | const page = await browser.newPage(); |
| 77 | await page.goto('https://example.com'); |
| 78 | |
| 79 | const title = await page.evaluate(() => document.title); |
| 80 | console.log(title); |
| 81 | |
| 82 | await browser.close(); |
| 83 | })(); |
| 84 | ``` |
| skyostil | 6db3da67 | 2016-10-11 02:52:19 | [diff] [blame] | 85 | |
| skyostil | 4c9d164c | 2016-12-23 11:15:52 | [diff] [blame] | 86 | ## Resources and Documentation |
| 87 | |
| 88 | Mailing list: [[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/headless-dev) |
| skyostil | 120e542 | 2017-02-21 13:21:55 | [diff] [blame] | 89 | |
| Sami Kyostila | a80b77b | 2017-05-15 15:20:29 | [diff] [blame] | 90 | Bug tracker: [Internals>Headless](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=component%3AInternals%3EHeadless) |
| skyostil | 6db3da67 | 2016-10-11 02:52:19 | [diff] [blame] | 91 | |
| Sami Kyostila | a80b77b | 2017-05-15 15:20:29 | [diff] [blame] | 92 | [File a new bug](https://bugs.chromium.org/p/chromium/issues/entry?components=Internals%3EHeadless) ([bit.ly/2pP6SBb](https://bit.ly/2pP6SBb)) |
| skyostil | 120e542 | 2017-02-21 13:21:55 | [diff] [blame] | 93 | |
| Sami Kyostila | 40e4469f | 2017-05-26 16:06:57 | [diff] [blame] | 94 | * [Runtime headless mode on Windows OS](https://docs.google.com/document/d/12c3bSEbmpeGevuyFHcvEKw9br6CkFJSS2saQynBjIzE) |
| skyostil | ffe5b07 | 2017-02-28 17:03:35 | [diff] [blame] | 95 | * [BeginFrame sequence numbers + acknowledgements](https://docs.google.com/document/d/1nxaunQ0cYWxhtS6Zzfwa99nae74F7gxanbuT5JRpI6Y/edit#) |
| 96 | * [Deterministic page loading for Blink](https://docs.google.com/document/d/19s2g4fPP9p9qmMZvwPX8uDGbb-39rgR9k56B4B-ueG8/edit#) |
| 97 | * [Crash dumps for Headless Chrome](https://docs.google.com/document/d/1l6AGOOBLk99PaAKoZQW_DVhM8FQ6Fut27lD938CRbTM/edit) |
| skyostil | b354f88 | 2016-12-13 18:42:45 | [diff] [blame] | 98 | * [Runtime headless mode for Chrome](https://docs.google.com/document/d/1aIJUzQr3eougZQp90bp4mqGr5gY6hdUice8UPa-Ys90/edit#) |
| Eric Seckler | 3a991f1 | 2017-12-05 15:21:05 | [diff] [blame] | 99 | * [Virtual Time in |
| 100 | Blink](https://docs.google.com/document/d/1y9KDT_ZEzT7pBeY6uzVt1dgKlwc1OB_vY4NZO1zBQmo/edit?usp=sharing) |
| Tiago Vignatti | f205adf | 2023-03-30 13:23:19 | [diff] [blame] | 101 | * [Headless Chrome architecture (Design Doc)](https://docs.google.com/document/d/11zIkKkLBocofGgoTeeyibB2TZ_k7nR78v7kNelCatUE) |
| skyostil | 6db3da67 | 2016-10-11 02:52:19 | [diff] [blame] | 102 | * [Session isolation in Headless Chrome](https://docs.google.com/document/d/1XAKvrxtSEoe65vNghSWC5S3kJ--z2Zpt2UWW1Fi8GiM/edit) |
| 103 | * [Headless Chrome mojo service](https://docs.google.com/document/d/1Fr6_DJH6OK9rG3-ibMvRPTNnHsAXPk0VzxxiuJDSK3M/edit#heading=h.qh0udvlk963d) |
| 104 | * [Controlling BeginFrame through DevTools](https://docs.google.com/document/d/1LVMYDkfjrrX9PNkrD8pJH5-Np_XUTQHIuJ8IEOirQH4/edit?ts=57d96dbd#heading=h.ndv831lc9uf0) |
| 105 | * [Viewport bounds and scale for screenshots](https://docs.google.com/document/d/1VTcYz4q_x0f1O5IVrvRX4u1DVd_K34IVUl1VULLTCWw/edit#heading=h.ndv831lc9uf0) |
| 106 | * [BlinkOn 6 presentation slides](https://docs.google.com/presentation/d/1gqK9F4lGAY3TZudAtdcxzMQNEE7PcuQrGu83No3l0lw/edit#slide=id.p) |