Passing message from one listener to another


I'm developing an extension for Chrome, and here's the workflow I'm trying to achieve:

popup sends message -> content script 1 listens -> content script 1 sends message -> content script 2 listens -> content script 2 performs action

In concept it's fine and dandy; what I've done is set up 2 listeners: one in each content script:


chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { console.log('popup send request'); chrome.tabs.sendMessage(tabs[0].id, obj); });

Content script 1:

chrome.runtime.onMessage.addListener((function (request, sender) { this.log('wg got request', 'request', request, 'sender', sender); if (request.action == 'options-updated') { this.updateOptions(request, (function() { var obj = {action: 'refresh', WG: window.WG}; this.log('wg forwarded request'); chrome.runtime.sendMessage(obj); // attempting to forward another request return true; }).bind(this)); } return true; }).bind(window.WG));

Content script 2:

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { console.log('content script got request', 'request', request, 'sender', sender); if (request.WG) { request.WG.log('message', request.action); if (request.action == 'refresh') { WGRefresh(request.WG, request.options); } } return true; });

Problem is, content script 2 only receives the first message. So the output I'm getting is:

popup send request content script got request (first, to ignore) wg got request (same, first, don't ignore here) wg forward request

And then nothing. The content script should have fired it again, and in the request I always send "action", which I check for in the listener, but for the logs I don't differentiate (it should ALWAYS log, so this means the request never gets there).

I've tried returning true in all the listeners, according to the documentation it will keep the chain running and not stop after the first hit, but even so it's not working. What am I doing wrong?!


There are 2 sendMessage functions in Chrome API.

<ul><li><a href="https://developer.chrome.com/extensions/runtime#method-sendMessage" rel="nofollow">chrome.runtime.sendMessage</a> sends a message to <em>all</em> open <em>extension pages</em> (i.e. background, popup, etc.)</li> <li><a href="https://developer.chrome.com/extensions/tabs#method-sendMessage" rel="nofollow">chrome.tabs.sendMessage</a> sends a message to <em>all</em> content scripts from the extension <em>in a given tab</em></li> </ul>

So the call to chrome.runtime.sendMessage() in your first content script can't reach any other content script.

What's more, you can't call chrome.tabs directly from a content script.

To do what you want, you need to set up a background script that will act like a proxy between CS1 and CS2. Technically, you could use the popup, but it's unreliable, as the popup may be closed and then nobody would be listening. The background page (or better yet, an <a href="https://developer.chrome.com/extensions/event_pages" rel="nofollow">event page</a>) is designed specifically for that purpose.

So the scheme becomes: popup -(tabs.sendMessage)-> CS1 -(runtime.sendMessage)-> background -(tabs.sendMessage)-> CS2

Do note that background page will need to know the tab ID to send the message to. If it's the same tab for some reason, e.g. you're trying to message across frames, you can use the sender parameter in the callback.

See <a href="https://developer.chrome.com/extensions/messaging" rel="nofollow">Messaging docs</a> for more details.


  • Find start values for NLS function in R [duplicate]
  • Make client_id and secret mandatory in access token request with grant_type=password in rails+doorke
  • go routine deadlock with single channel
  • Webworker-threads in NodeJS
  • Why am I recieving a JMSBytesMessage when I'm sending an OBject message using Spring and MQ Que
  • How to implement collision detection on nodes which are in StackPane (in JavaFX)?
  • InfoWindow showing in wrong place
  • TypeError upon authenticating user using Google OAuth 2
  • Convert a plain string[] into a Observable and concat it to another Observable using RxJS 5
  • Websocket across pages JavaScript
  • Chrome extension update notification
  • Pubnub subscribe stops receiving messages after some time
  • runtime error when linking ffmpeg libraries in qt creator
  • Ruby on Rails App deployed to heroku showing “We're sorry, but something went wrong”
  • Click on button in another program - FindWindow, C#
  • How to load gif image while ajax content is loading and javascript [duplicate]
  • Detecting null parameter in preprocessor macro
  • C# program and C++ DLL compiled for 32-bit system crash on 64-bit system
  • c# open webrowser in many tab
  • D3 get axis values on zoom event
  • Using a canvas object in a thread to do simple animations - Java
  • Detect when Facebook like button is clicked
  • MonoTouch: How to download pdf incrementally as indicated in the Apple slides “Building Newsstand Ap
  • Needing to do .toArray() to get output of mongodb .find() on key name not value
  • How to Cache Real-time Data?
  • Make VS2015 use angular-cli ng at build time in a .NET project
  • C# - Is there a limit to the size of an httpWebRequest stream?
  • DotNetZip - Calculate final zip size before calling Save(stream)
  • Updating server-side rendering client-side
  • Can a Chrome extension content script make an jQuery AJAX request for an html file that is itself a
  • Upload files with Ajax and Jquery
  • Warning: Can't call setState (or forceUpdate) on an unmounted component
  • How to pass list parameters for each object using Spring MVC?
  • AT Commands to Send SMS not working in Windows 8.1
  • AngularJs get employee from factory
  • Proper way to use connect-multiparty with express.js?
  • Load html files in TinyMce
  • Free memory of cv::Mat loaded using FileStorage API
  • sending mail using smtp is too slow
  • Binding checkboxes to object values in AngularJs