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 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 Opera tip-of-tree yes Node.js (v6.3.0+) node yes no yes Safari (iOS) partial no yes no Edge partial yes no yes Firefox (Nightly) partial yes no 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_<pid> 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 the given URL.', handlers: [ 'browser', 'renderer' ] } To learn about the parameters returned by the Network.requestWillBeSent event: >>> Network.requestWillBeSent { [Function] category: 'event', description: 'Fired when page is about to send HTTP request.', parameters: { requestId: { '$ref': 'RequestId', description: 'Request identifier.' }, frameId: { '$ref': 'Page.FrameId', description: 'Frame identifier.', hidden: true }, loaderId: { '$ref': 'LoaderId', description: 'Loader identifier.' }, documentURL: { type: 'string', description: 'URL of the document this request is loaded for.' }, request: { '$ref': 'Request', description: 'Request data.' }, timestamp: { '$ref': 'Timestamp', description: 'Timestamp.' }, wallTime: { '$ref': 'Timestamp', hidden: true, description: 'UTC Timestamp.' }, initiator: { '$ref': 'Initiator', description: 'Request initiator.' }, redirectResponse: { optional: true, '$ref': 'Response', description: 'Redirect response data.' }, type: { '$ref': 'Page.ResourceType', optional: true, hidden: true, description: 'Type of this resource.' } To inspect the Network.Request (note that unlike commands and events, types are named in upper camel case) type: >>> Network.Request { category: 'type', id: 'Request', type: 'object', description: 'HTTP request data.', properties: { url: { type: 'string', description: 'Request URL.' }, method: { type: 'string', description: 'HTTP request method.' }, headers: { '$ref': 'Headers', description: 'HTTP request headers.' }, postData: { type: 'string', optional: true, description: 'HTTP POST request data.' }, mixedContentType: { optional: true, type: 'string', enum: [Object], description: 'The mixed content status of the request, as defined in http://www.w3.org/TR/mixed-content/' }, initialPriority: { '$ref': 'ResourcePriority', description: 'Priority of the resource request at the time request is sent.' } Chrome Debugging Protocol versions By default chrome-remote-interface asks the remote instance to provide its own protocol. This behavior can be changed by setting the local option to true upon connection, in which case the local version of the protocol descriptor is used. This file is manually updated from time to time using scripts/update-protocol.sh and pushed to this repository. To further override the above behavior there are basically two options: pass a custom protocol descriptor upon connection (protocol option); use the raw version of the commands and events interface to use bleeding-edge features that do not appear in the local version of the protocol descriptor; Browser usage This module is able to run within a web context, with obvious limitations though, namely external HTTP requests (List, New, etc.) cannot be performed directly, for this reason the user must provide a global criRequest in order to use them: function criRequest(options, callback) {} options is the same object used by the Node.js http module and callback is a function taking two arguments: err (JavaScript Error object or null) and data (string result). Using webpack It just works, simply require this module: const CDP = require('chrome-remote-interface'); Using vanilla JavaScript To generate a JavaScript file that can be used with a <script> element: run npm install from the root directory; manually run webpack with: TARGET=var npm run webpack use as: <script> function criRequest(options, callback) { /*...*/ } </script> <script src="chrome-remote-interface.js"></script> TypeScript Support TypeScript definitions are kindly provided by DefinitelyTyped: npm install --save-dev @types/chrome-remote-interface Note that the TypeScript definitions are automatically generated from the npm package [email protected]. For other versions of devtools-protocol: Install patch-package using the instructions given. Copy the contents of the corresponding API