1<h1>Message Passing</h1> 2 3 4<p> 5Since content scripts run in the context of a web page and not the extension, 6they often need some way of communicating with the rest of the extension. For 7example, an RSS reader extension might use content scripts to detect the 8presence of an RSS feed on a page, then notify the background page in order to 9display a page action icon for that page. 10 11<p> 12Communication between extensions and their content scripts works by using 13message passing. Either side can listen for messages sent from the other end, 14and respond on the same channel. A message can contain any valid JSON object 15(null, boolean, number, string, array, or object). There is a simple API for 16<a href="#simple">one-time requests</a> 17and a more complex API that allows you to have 18<a href="#connect">long-lived connections</a> 19for exchanging multiple messages with a shared context. It is also possible to 20send a message to another extension if you know its ID, which is covered in 21the 22<a href="#external">cross-extension messages</a> 23section. 24 25 26<h2 id="simple">Simple one-time requests</h2> 27<p> 28If you only need to send a single message to another part of your extension 29(and optionally get a response back), you should use the simplified 30$(ref:runtime.sendMessage) 31or 32$(ref:tabs.sendMessage) 33methods. This lets you send a one-time JSON-serializable message from a 34content script to extension, or vice versa, respectively. An optional 35callback parameter allows you handle the response from the other side, if 36there is one. 37 38<p> 39Sending a request from a content script looks like this: 40<pre data-filename="contentscript.js"> 41chrome.runtime.sendMessage({greeting: "hello"}, function(response) { 42 console.log(response.farewell); 43}); 44</pre> 45 46<p> 47Sending a request from the extension to a content script looks very similar, 48except that you need to specify which tab to send it to. This example 49demonstrates sending a message to the content script in the selected tab. 50<pre data-filename="background.html"> 51chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { 52 chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) { 53 console.log(response.farewell); 54 }); 55}); 56</pre> 57 58<p> 59On the receiving end, you need to set up an 60$(ref:runtime.onMessage) 61event listener to handle the message. This looks the same from a content 62script or extension page. 63<pre> 64chrome.runtime.onMessage.addListener( 65 function(request, sender, sendResponse) { 66 console.log(sender.tab ? 67 "from a content script:" + sender.tab.url : 68 "from the extension"); 69 if (request.greeting == "hello") 70 sendResponse({farewell: "goodbye"}); 71 }); 72</pre> 73 74<p class="note"> 75<b>Note:</b> If multiple pages are listening for onMessage events, only the 76first to call sendResponse() for a particular event will succeed in sending the 77response. All other responses to that event will be ignored. 78</p> 79 80 81<h2 id="connect">Long-lived connections</h2> 82<p> 83Sometimes it's useful to have a conversation that lasts longer than a single 84request and response. In this case, you can open a long-lived channel from 85your content script to an extension page, or vice versa, using 86$(ref:runtime.connect) 87or 88$(ref:tabs.connect) respectively. The 89channel can optionally have a name, allowing you to distinguish between 90different types of connections. 91 92<p> 93One use case might be an automatic form fill extension. The content script 94could open a channel to the extension page for a particular login, and send a 95message to the extension for each input element on the page to request the 96form data to fill in. The shared connection allows the extension to keep 97shared state linking the several messages coming from the content script. 98 99<p> 100When establishing a connection, each end is given a 101$(ref:runtime.Port) 102object which is used for sending and receiving messages through that 103connection. 104 105<p> 106Here is how you open a channel from a content script, and send and listen for 107messages: 108<pre data-filename="contentscript.js"> 109var port = chrome.runtime.connect({name: "knockknock"}); 110port.postMessage({joke: "Knock knock"}); 111port.onMessage.addListener(function(msg) { 112 if (msg.question == "Who's there?") 113 port.postMessage({answer: "Madame"}); 114 else if (msg.question == "Madame who?") 115 port.postMessage({answer: "Madame... Bovary"}); 116}); 117</pre> 118 119<p> 120Sending a request from the extension to a content script looks very similar, 121except that you need to specify which tab to connect to. Simply replace the 122call to connect in the above example with 123$(ref:tabs.connect). 124 125<p> 126In order to handle incoming connections, you need to set up a 127$(ref:runtime.onConnect) 128event listener. This looks the same from a content script or an extension 129page. When another part of your extension calls "connect()", this event is 130fired, along with the 131$(ref:runtime.Port) 132object you can use to send and receive messages through the connection. Here's 133what it looks like to respond to incoming connections: 134<pre> 135chrome.runtime.onConnect.addListener(function(port) { 136 console.assert(port.name == "knockknock"); 137 port.onMessage.addListener(function(msg) { 138 if (msg.joke == "Knock knock") 139 port.postMessage({question: "Who's there?"}); 140 else if (msg.answer == "Madame") 141 port.postMessage({question: "Madame who?"}); 142 else if (msg.answer == "Madame... Bovary") 143 port.postMessage({question: "I don't get it."}); 144 }); 145}); 146</pre> 147 148<p> 149You may want to find out when a connection is closed, for example if you are 150maintaining separate state for each open port. For this you can listen to the 151$(ref:runtime.Port.onDisconnect) 152event. This event is fired either when the other side of the channel manually 153calls 154$(ref:runtime.Port.disconnect), or when the page 155containing the port is unloaded (for example if the tab is navigated). 156onDisconnect is guaranteed to be fired only once for any given port. 157 158 159<h2 id="external">Cross-extension messaging</h2> 160<p> 161In addition to sending messages between different components in your 162extension, you can use the messaging API to communicate with other extensions. 163This lets you expose a public API that other extensions can take advantage of. 164 165<p> 166Listening for incoming requests and connections is similar to the internal 167case, except you use the 168$(ref:runtime.onMessageExternal) 169or 170$(ref:runtime.onConnectExternal) 171methods. Here's an example of each: 172<pre> 173// For simple requests: 174chrome.runtime.onMessageExternal.addListener( 175 function(request, sender, sendResponse) { 176 if (sender.id == blacklistedExtension) 177 return; // don't allow this extension access 178 else if (request.getTargetData) 179 sendResponse({targetData: targetData}); 180 else if (request.activateLasers) { 181 var success = activateLasers(); 182 sendResponse({activateLasers: success}); 183 } 184 }); 185 186// For long-lived connections: 187chrome.runtime.onConnectExternal.addListener(function(port) { 188 port.onMessage.addListener(function(msg) { 189 // See other examples for sample onMessage handlers. 190 }); 191}); 192</pre> 193 194<p> 195Likewise, sending a message to another extension is similar to sending one 196within your extension. The only difference is that you must pass the ID of the 197extension you want to communicate with. For example: 198<pre> 199// The ID of the extension we want to talk to. 200var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc"; 201 202// Make a simple request: 203chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true}, 204 function(response) { 205 if (targetInRange(response.targetData)) 206 chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true}); 207 }); 208 209// Start a long-running conversation: 210var port = chrome.runtime.connect(laserExtensionId); 211port.postMessage(...); 212</pre> 213 214 215<h2 id="external-webpage">Sending messages from web pages</h2> 216<p> 217Similar to <a href="#external">cross-extension messaging</a>, 218your app or extension can receive and 219respond to messages from regular web pages. 220To use this feature, you must first 221specify in your manifest.json which web sites you want to communicate with. For 222example: 223 224<pre data-filename="manifest.json"> 225"externally_connectable": { 226 "matches": ["*://*.example.com/*"] 227} 228</pre> 229 230<p> 231This will expose the messaging API to any page which matches the URL patterns 232you specify. The URL pattern must contain at least a 233<a href="http://en.wikipedia.org/wiki/Second-level_domain">second-level domain</a> 234- that is, hostname 235patterns like "*", "*.com", "*.co.uk", and "*.appspot.com" are prohibited. 236From the web page, use the 237$(ref:runtime.sendMessage) 238or 239$(ref:runtime.connect) 240APIs to send a message to a specific app or extension. For example: 241<pre> 242// The ID of the extension we want to talk to. 243var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc"; 244 245// Make a simple request: 246chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url}, 247 function(response) { 248 if (!response.success) 249 handleError(url); 250 }); 251</pre> 252 253<p> 254From your app or extension, you may listen to messages from web pages via the 255$(ref:runtime.onMessageExternal) 256or 257$(ref:runtime.onConnectExternal) 258APIs, similar to <a href="#external">cross-extension messaging</a>. 259Only the web page can initiate a connection. 260Here is an example: 261 262<pre> 263chrome.runtime.onMessageExternal.addListener( 264 function(request, sender, sendResponse) { 265 if (sender.url == blacklistedWebsite) 266 return; // don't allow this web page access 267 if (request.openUrlInEditor) 268 openUrl(request.openUrlInEditor); 269 }); 270</pre> 271 272 273<h2 id="native-messaging">Native messaging</h2> 274<p> 275Extensions can exchange messages with native applications. Native 276applications that support this feature must register a <em>native messaging 277host</em> that knows how to communicate with the extension. Chrome starts the 278host in a separate process and communicates with it using standard input and 279standard output streams. 280 281<h3 id="native-messaging-host">Native messaging host</h3> 282<p> 283In order to register a native messaging host the application must install a 284manifest file that defines the native messaging host configuration. Below is an 285example of the manifest file: 286<pre data-filename="manifest.json"> 287{ 288 "name": "com.my_company.my_application", 289 "description": "My Application", 290 "path": "C:\\Program Files\\My Application\\chrome_native_messaging_host.exe", 291 "type": "stdio", 292 "allowed_origins": [ 293 "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/" 294 ] 295} 296</pre> 297 298<p>Native messaging host manifest file contains the following fields: 299<table class="simple"> 300 <tr> 301 <th>Name</th> 302 <th>Description</th> 303 </tr> 304 <tr> 305 <td><code>name</code></td> 306 <td>Name of the native messaging host. Clients pass this string to 307 $(ref:runtime.connectNative) or $(ref:runtime.sendNativeMessage).</td> 308 </tr> 309 <tr> 310 <td><code>description</code></td> 311 <td>Short application description.</td> 312 </tr> 313 <tr> 314 <td><code>path</code></td> 315 <td>Path to the native messaging host binary. On Linux and OSX the path must 316 be absolute. On Windows it can be relative to the directory in which the 317 manifest file is located.</td> 318 </tr> 319 <tr> 320 <td><code>type</code></td> 321 <td>Type of the interface used to communicate with the native messaging 322 host. Currently there is only one possible value for this parameter: 323 <code>stdio</code>. It indicates that Chrome should use <code>stdin</code> 324 and <code>stdout</code> to communicate with the host.</td> 325 </tr> 326 <tr> 327 <td><code>allowed_origins</code></td> 328 <td>List of extensions that should have access to the native messaging host.</td> 329 </tr> 330</table> 331 332<p>Location of the manifest file depends on the platform: 333 334<dl> 335 <dt>Windows:</dt> 336 <dd>The manifest file can be located anywhere in the file system. 337 The application installer must create registry key 338 <code>HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\<em>com.my_company.my_application</em></code> 339 or 340 <code>HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\<em>com.my_company.my_application</em></code>, 341 and set default value of that key to the full path to the manifest file. 342 </dd> 343 344 <dt>OSX:</dt> 345 <dd>The manifest file must be placed at 346 <code>/Library/Google/Chrome/NativeMessagingHosts/<em>com.my_company.my_application</em>.json</code>, 347 or, for applications installed on user level, 348 <code>~/Library/Application Support/Google/Chrome/NativeMessagingHosts/<em>com.my_company.my_application</em>.json</code>. 349 </dd> 350 351 <dt>Linux:</dt> 352 <dd>The manifest file must be placed at 353 <code>/etc/opt/chrome/native-messaging-hosts/<em>com.my_company.my_application</em>.json</code>, 354 or, for applications installed on user level, 355 <code>~/.config/google-chrome/NativeMessagingHosts/<em>com.my_company.my_application</em>.json</code>. 356 </dd> 357</dl> 358 359<p> 360Chrome starts each native messaging host in a separate process and communicates 361with it using standard input (<code>stdin</code>) and standard output 362(<code>stdout</code>). The same format is used to send messages in both 363directions: each message is serialized using JSON, UTF-8 encoded 364and is preceded with 32-bit message length in native byte order. 365 366<p> 367When a messaging port is created using $(ref:runtime.connectNative) Chrome 368starts native messaging host process and keeps it running until the port is 369destroyed. On the other hand, when a message is sent using 370$(ref:runtime.sendNativeMessage), without creating a messaging port, Chrome starts 371a new native messaging host process for each message. In that case the first 372message generated by the host process is handled as a response to the original 373request, i.e. Chrome will pass it to the response callback specified when 374$(ref:runtime.sendNativeMessage) is called. All other messages generated by the 375native messaging host in that case are ignored. 376 377<h3 id="native-messaging-client">Connecting to a native application</h3> 378<p> 379Sending and receiving messages to and from a native application is very similar 380to cross-extension messaging. The main difference is that 381$(ref:runtime.connectNative) is used instead of $(ref:runtime.connect), 382and $(ref:runtime.sendNativeMessage) is used instead of $(ref:runtime.sendMessage). 383 384<p> 385The Following example creates a $(ref:runtime.Port) object that's connected to native 386messaging host <code>com.my_company.my_application</code>, starts listening for 387messages from that port and sends one outgoing message: 388<pre> 389var port = chrome.runtime.connectNative('com.my_company.my_application'); 390port.onMessage.addListener(function(msg) { 391 console.log("Received" + msg); 392}); 393port.onDisconnect.addListener(function() { 394 console.log("Disconnected"); 395}); 396port.postMessage({ text: "Hello, my_application" }); 397</pre> 398 399<p> 400$(ref:runtime.sendNativeMessage) can be used to send a message to native 401application without creating a port, e.g.: 402<pre> 403chrome.runtime.sendNativeMessage('com.my_company.my_application', 404 { text: "Hello" }, 405 function(response) { 406 console.log("Received " + response); 407 }); 408</pre> 409 410<h2 id="security-considerations">Security considerations</h2> 411 412<p> 413When receiving a message from a content script or another extension, your 414background page should be careful not to fall victim to <a 415href="http://en.wikipedia.org/wiki/Cross-site_scripting">cross-site 416scripting</a>. Specifically, avoid using dangerous APIs such as the 417below: 418</p> 419<pre data-filename="background.js"> 420chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { 421 // WARNING! Might be evaluating an evil script! 422 var resp = eval("(" + response.farewell + ")"); 423}); 424</pre> 425<pre data-filename="background.js"> 426chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { 427 // WARNING! Might be injecting a malicious script! 428 document.getElementById("resp").innerHTML = response.farewell; 429}); 430</pre> 431<p> 432Instead, prefer safer APIs that do not run scripts: 433</p> 434<pre data-filename="background.js"> 435chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { 436 // JSON.parse does not evaluate the attacker's scripts. 437 var resp = JSON.parse(response.farewell); 438}); 439</pre> 440<pre data-filename="background.js"> 441chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { 442 // innerText does not let the attacker inject HTML elements. 443 document.getElementById("resp").innerText = response.farewell; 444}); 445</pre> 446 447<h2 id="examples">Examples</h2> 448 449<p> 450You can find simple examples of communication via messages in the 451<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/messaging/">examples/api/messaging</a> 452directory. 453<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/nativeMessaging/">examples/api/nativeMessaging</a> 454contains an example application that uses native messaging. 455Also see the 456<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/howto/contentscript_xhr">contentscript_xhr</a> example, 457in which a content script and its parent extension exchange messages, 458so that the parent extension can perform 459cross-site requests on behalf of the content script. 460For more examples and for help in viewing the source code, see 461<a href="samples">Samples</a>. 462</p> 463