• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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