chrome-remote-interface
[Chrome Debugging Protocol] interface that helps to instrument Chrome (or any other suitable implementation) by providing a simple abstraction of commands and notifications using a straightforward JavaScript API.
Sample API usage
The following snippet loads https://github.com and dumps every request made:
const CDP = require('chrome-remote-interface');
async function example() {
let client;
try {
// connect to endpoint
client = await CDP();
// extract domains
const {Network, Page} = client;
// setup handlers
Network.requestWillBeSent((params) => {
console.log(params.request.url);
});
// enable events then start!
await Network.enable();
await Page.enable();
await Page.navigate({url: 'https://github.com'});
await Page.loadEventFired();
} catch (err) {
console.error(err);
} finally {
if (client) {
await client.close();
}
}
}
example();
Find more examples in the wiki. You may also want to take a look at the FAQ.
Installation
npm install chrome-remote-interface
Install globally (-g) to just use the bundled client.
Implementations
This module should work with every application implementing the [Chrome Debugging Protocol]. In particular, it has been tested against the following implementations:
| Implementation | Protocol version | Protocol | List | New | Activate | Close | Version |
|---|---|---|---|---|---|---|---|
| Chrome | tip-of-tree | yes¹ | yes | yes | yes | yes | yes |
| Opera | tip-of-tree | yes | yes | yes | yes | yes | yes |
| Node.js (v6.3.0+) | node | yes | no | no | no | no | yes |
| Safari (iOS) | partial | no | yes | no | no | no | no |
| Edge | partial | yes | yes | no | no | no | yes |
| Firefox (Nightly) | partial | yes | yes | no | yes | yes | yes |
¹ Not available on Chrome for Android, hence a local version of the protocol must be used.
The meaning of target varies according to the implementation, for example, each Chrome tab represents a target whereas for Node.js a target is the currently inspected script.
Setup
An instance of either Chrome itself or another implementation needs to be
running on a known port in order to use this module (defaults to
localhost:9222).
Chrome/Chromium
Desktop
Start Chrome with the --remote-debugging-port option, for example:
google-chrome --remote-debugging-port=9222
Headless
Since version 59, additionally use the --headless option, for example:
google-chrome --headless --remote-debugging-port=9222
Android
Plug the device and make sure to authorize the connection from the device itself. Then enable the port forwarding, for example:
adb -d forward tcp:9222 localabstract:chrome_devtools_remote
After that you should be able to use http://127.0.0.1:9222 as usual, but note that in
Android, Chrome does not have its own protocol available, so a local version must be used.
See here for more information.
WebView
In order to be inspectable, a WebView must be configured for debugging and the corresponding process ID must be known. There are several ways to obtain it, for example:
adb shell grep -a webview_devtools_remote /proc/net/unix
Finally, port forwarding can be enabled as follows:
adb forward tcp:9222 localabstract:webview_devtools_remote_
Opera
Start Opera with the --remote-debugging-port option, for example:
opera --remote-debugging-port=9222
Node.js
Start Node.js with the --inspect option, for example:
node --inspect=9222 script.js
Safari (iOS)
Install and run the iOS WebKit Debug Proxy. Then use it with the local
option set to true to use the local version of the protocol or pass a custom
descriptor upon connection (protocol option).
Edge
Start Edge with the --devtools-server-port option, for example:
MicrosoftEdge.exe --devtools-server-port 9222 about:blank
Please find more information here.
Firefox (Nightly)
Start Firefox with the --remote-debugging-port option, for example:
firefox --remote-debugging-port 9222
Bear in mind that this is an experimental feature of Firefox.
Bundled client
This module comes with a bundled client application that can be used to interactively control a remote instance.
Target management
The bundled client exposes subcommands to interact with the HTTP frontend
(e.g., List, New, etc.),
run with --help to display the list of available options.
Here are some examples:
$ chrome-remote-interface new 'http://example.com'
{
"description": "",
"devtoolsFrontendUrl": "/devtools/inspector.html?ws=localhost:9222/devtools/page/b049bb56-de7d-424c-a331-6ae44cf7ae01",
"id": "b049bb56-de7d-424c-a331-6ae44cf7ae01",
"thumbnailUrl": "/thumb/b049bb56-de7d-424c-a331-6ae44cf7ae01",
"title": "",
"type": "page",
"url": "http://example.com/",
"webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/b049bb56-de7d-424c-a331-6ae44cf7ae01"
}
$ chrome-remote-interface close 'b049bb56-de7d-424c-a331-6ae44cf7ae01'
Inspection
Using the inspect subcommand it is possible to perform command execution
and event binding in a REPL fashion that provides completion.
Here is a sample session:
$ chrome-remote-interface inspect
>>> Runtime.evaluate({expression: 'window.location.toString()'})
{ result: { type: 'string', value: 'about:blank' } }
>>> Page.enable()
{}
>>> Page.loadEventFired(console.log)
[Function]
>>> Page.navigate({url: 'https://github.com'})
{ frameId: 'E1657E22F06E6E0BE13DFA8130C20298',
loaderId: '439236ADE39978F98C20E8939A32D3A5' }
>>> { timestamp: 7454.721299 } // from Page.loadEventFired
>>> Runtime.evaluate({expression: 'window.location.toString()'})
{ result: { type: 'string', value: 'https://github.com/' } }
Additionally there are some custom commands available:
>>> .help
[...]
.reset Remove all the registered event handlers
.target Display the current target
Embedded documentation
In both the REPL and the regular API every object of the protocol is decorated
with the meta information found within the descriptor. In addition The
category field is added, which determines if the member is a command, an
event or a type.
For example to learn how to call Page.navigate:
>>> Page.navigate
{ [Function]
category: 'command',
parameters: { url: { type: 'string', description: 'URL to navigate the page to.' } },
returns:
[ { name: 'frameId',
'$ref': 'FrameId',
hidden: true,
description: 'Frame id that will be navigated.' } ],
description: 'Navigates current page to