• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<div id="pageData-name" class="pageData">Message Passing</div>
2<div id="pageData-showTOC" class="pageData">true</div>
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<a href="extension.html#method-sendRequest">chrome.extension.sendRequest()</a>
31or
32<a href="tabs.html#method-sendRequest">chrome.tabs.sendRequest()</a>
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>
41contentscript.js
42================
43chrome.extension.sendRequest({greeting: "hello"}, function(response) {
44  console.log(response.farewell);
45});
46</pre>
47
48<p>
49Sending a request from the extension to a content script looks very similar,
50except that you need to specify which tab to send it to. This example
51demonstrates sending a message to the content script in the selected tab.
52<pre>
53background.html
54===============
55chrome.tabs.getSelected(null, function(tab) {
56  chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
57    console.log(response.farewell);
58  });
59});
60</pre>
61
62<p>
63On the receiving end, you need to set up an
64<a href="extension.html#event-onRequest">chrome.extension.onRequest</a>
65event listener to handle the message. This looks the same from a content
66script or extension page. The request will remain open until you call
67sendResponse, so it is good practice to call sendResponse with an empty
68object to allow the request to be cleaned up.
69<pre>
70chrome.extension.onRequest.addListener(
71  function(request, sender, sendResponse) {
72    console.log(sender.tab ?
73                "from a content script:" + sender.tab.url :
74                "from the extension");
75    if (request.greeting == "hello")
76      sendResponse({farewell: "goodbye"});
77    else
78      sendResponse({}); // snub them.
79  });
80</pre>
81
82<p class="note">
83<b>Note:</b> If multiple pages are listening for onRequest events, only the
84first to call sendResponse() for a particular event will succeed in sending the
85response. All other responses to that event will be ignored.
86</p>
87
88
89<h2 id="connect">Long-lived connections</h2>
90<p>
91Sometimes it's useful to have a conversation that lasts longer than a single
92request and response. In this case, you can open a long-lived channel from
93your content script to an extension page, or vice versa, using
94<a href="extension.html#method-connect">chrome.extension.connect()</a>
95or
96<a href="tabs.html#method-connect">chrome.tabs.connect()</a> respectively. The
97channel can optionally have a name, allowing you to distinguish between
98different types of connections.
99
100<p>
101One use case might be an automatic form fill extension. The content script
102could open a channel to the extension page for a particular login, and send a
103message to the extension for each input element on the page to request the
104form data to fill in. The shared connection allows the extension to keep
105shared state linking the several messages coming from the content script.
106
107<p>
108When establishing a connection, each end is given a
109<a href="extension.html#type-Port">Port</a>
110object which is used for sending and receiving messages through that
111connection.
112
113<p>
114Here is how you open a channel from a content script, and send and listen for
115messages:
116<pre>
117contentscript.js
118================
119var port = chrome.extension.connect({name: "knockknock"});
120port.postMessage({joke: "Knock knock"});
121port.onMessage.addListener(function(msg) {
122  if (msg.question == "Who's there?")
123    port.postMessage({answer: "Madame"});
124  else if (msg.question == "Madame who?")
125    port.postMessage({answer: "Madame... Bovary"});
126});
127</pre>
128
129<p>
130Sending a request from the extension to a content script looks very similar,
131except that you need to specify which tab to connect to. Simply replace the
132call to connect in the above example with
133<a href="tabs.html#method-connect">chrome.tabs.connect(tabId, {name:
134"knockknock"})</a>.
135
136<p>
137In order to handle incoming connections, you need to set up a
138<a href="extension.html#event-onConnect">chrome.extension.onConnect</a>
139event listener. This looks the same from a content script or an extension
140page. When another part of your extension calls "connect()", this event is
141fired, along with the
142<a href="extension.html#type-Port">Port</a>
143object you can use to send and receive messages through the connection. Here's
144what it looks like to respond to incoming connections:
145<pre>
146chrome.extension.onConnect.addListener(function(port) {
147  console.assert(port.name == "knockknock");
148  port.onMessage.addListener(function(msg) {
149    if (msg.joke == "Knock knock")
150      port.postMessage({question: "Who's there?"});
151    else if (msg.answer == "Madame")
152      port.postMessage({question: "Madame who?"});
153    else if (msg.answer == "Madame... Bovary")
154      port.postMessage({question: "I don't get it."});
155  });
156});
157</pre>
158
159<p>
160You may want to find out when a connection is closed, for example if you are
161maintaining separate state for each open port. For this you can listen to the
162<a href="extension.html#type-Port">Port.onDisconnect</a>
163event. This event is fired either when the other side of the channel manually
164calls
165<a href="extension.html#type-Port">Port.disconnect()</a>, or when the page
166containing the port is unloaded (for example if the tab is navigated).
167onDisconnect is guaranteed to be fired only once for any given port.
168
169
170<h2 id="external">Cross-extension messaging</h2>
171<p>
172In addition to sending messages between different components in your
173extension, you can use the messaging API to communicate with other extensions.
174This lets you expose a public API that other extensions can take advantage of.
175
176<p>
177Listening for incoming requests and connections is similar to the internal
178case, except you use the
179<a href="extension.html#event-onRequestExternal">chrome.extension.onRequestExternal</a>
180or
181<a href="extension.html#event-onConnectExternal">chrome.extension.onConnectExternal</a>
182methods. Here's an example of each:
183<pre>
184// For simple requests:
185chrome.extension.onRequestExternal.addListener(
186  function(request, sender, sendResponse) {
187    if (sender.id == blacklistedExtension)
188      sendResponse({});  // don't allow this extension access
189    else if (request.getTargetData)
190      sendResponse({targetData: targetData});
191    else if (request.activateLasers) {
192      var success = activateLasers();
193      sendResponse({activateLasers: success});
194    }
195  });
196
197// For long-lived connections:
198chrome.extension.onConnectExternal.addListener(function(port) {
199  port.onMessage.addListener(function(msg) {
200    // See other examples for sample onMessage handlers.
201  });
202});
203</pre>
204
205<p>
206Likewise, sending a message to another extension is similar to sending one
207within your extension. The only difference is that you must pass the ID of the
208extension you want to communicate with. For example:
209<pre>
210// The ID of the extension we want to talk to.
211var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";
212
213// Make a simple request:
214chrome.extension.sendRequest(laserExtensionId, {getTargetData: true},
215  function(response) {
216    if (targetInRange(response.targetData))
217      chrome.extension.sendRequest(laserExtensionId, {activateLasers: true});
218  });
219
220// Start a long-running conversation:
221var port = chrome.extension.connect(laserExtensionId);
222port.postMessage(...);
223</pre>
224
225<h2 id="security-considerations">Security considerations</h2>
226
227<p>
228When receiving a message from a content script or another extension, your
229background page should be careful not to fall victim to <a
230href="http://en.wikipedia.org/wiki/Cross-site_scripting">cross-site
231scripting</a>.  Specifically, avoid using dangerous APIs such as the
232below:
233</p>
234<pre>background.html
235===============
236chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
237  // WARNING! Might be evaluating an evil script!
238  var resp = eval("(" + response.farewell + ")");
239});
240
241background.html
242===============
243chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
244  // WARNING! Might be injecting a malicious script!
245  document.getElementById("resp").innerHTML = response.farewell;
246});
247</pre>
248<p>
249Instead, prefer safer APIs that do not run scripts:
250</p>
251<pre>background.html
252===============
253chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
254  // JSON.parse does not evaluate the attacker's scripts.
255  var resp = JSON.parse(response.farewell);
256});
257
258background.html
259===============
260chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
261  // innerText does not let the attacker inject HTML elements.
262  document.getElementById("resp").innerText = response.farewell;
263});
264</pre>
265
266<h2 id="examples">Examples</h2>
267
268<p>
269You can find simple examples of communication via messages in the
270<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/messaging/">examples/api/messaging</a>
271directory.
272Also see the
273<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/howto/contentscript_xhr">contentscript_xhr</a> example,
274in which a content script and its parent extension exchange messages,
275so that the parent extension can perform
276cross-site requests on behalf of the content script.
277For more examples and for help in viewing the source code, see
278<a href="samples.html">Samples</a>.
279</p>
280