As you correctly noted, you cannot send data directly to the popup when it closes. So, you are sending data to the background image.
Then, when you open the popup, you need the data. So what are the options?
Please note: this answer will first give bad advice and then improve it. As an OP learns, it is important to show the thought process and road cramps.
The first solution that comes to mind is this: ask for the help page using Messaging again. Early warning: this will not work or works poorly
First of all, make sure there can be different types of messages. Change the current messaging code:
// content.js chrome.runtime.sendMessage({type: "setCount", count: count}); // background.js chrome.runtime.onMessage.addListener( function(message, sender, sendResponse) { switch(message.type) { case "setCount": temp = message.count; break; default: console.error("Unrecognised message: ", message); } } );
And now, theoretically, you can ask that in the popup:
// popup.js chrome.runtime.sendMessage({type: "getCount"}, function(count) { if(typeof count == "undefined") { // That kind of bad } else { // Use count } }); // background.js chrome.runtime.onMessage.addListener( function(message, sender, sendResponse) { switch(message.type) { case "setCount": temp = message.count; break; case "getCount": sendResponse(temp); break; default: console.error("Unrecognised message: ", message); } } );
Now what are the problems with this?
What is the temp life time? You explicitly indicated "persistent": false in your manifest . As a result, the background page can be unloaded at any time by wiping state, such as temp .
You can fix it with "persistent": true , but keep reading.
What tab do you expect to see? temp will have the latest data recorded on it, which may well be not the current tab.
You can fix this by saving the tabs (see what I did there?) On which the tab sent the data, for example. using:
// background.js /* ... */ case "setCount": temp[sender.tab.id] = message.count; break; case "getCount": sendResponse(temp[message.id]); break; // popup.js chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { // tabs is a single-element array after this filtering chrome.runtime.sendMessage({type: "getCount", id: tabs[0].id}, function(count) { /* ... */ }); });
This is a lot of work, right? This solution works fine, although for non-tab data after commit 1.
The following improvement to consider: Do we need a help page to store the results for us? After all, chrome.storage is a thing ; it is a persistent store available for all extension scripts (including content scripts).
This reduces the background (and messages) outside the image:
// content.js chrome.storage.local.set({count: count}); // popup.js chrome.storage.local.get("count", function(data) { if(typeof data.count == "undefined") { // That kind of bad } else { // Use data.count } });
This looks cleaner and completely bypasses problem 1 from above, but problem 2 is getting harder. You cannot directly set / read something like count[id] in the repository, you will need to read count , change it and write. It can become slow and messy.
Add to this that the content scripts are not aware of their tab identifier; you need to tell the message background in order to recognize it. Ugh. Not pretty. Again, this is a great solution for non-tab data.
Then we ask the following question: why do we even need a central place to store the result (for tabulation)? The lifetime of a script is the lifetime of the page. You can directly request the contents of the script at any point. Including from a popup.
Wait, wait, you didn’t say that at the very top you can’t send data to a popup? Well, yes, curious: when you don’t know if it is listening. But if a popup asks, then it should be ready to get an answer, no?
So, cancel the logic of the content of the script. Instead of sending data immediately, wait and listen for requests:
chrome.runtime.onMessage.addListener( function(message, sender, sendResponse) { switch(message.type) { case "getCount": sendResponse(count); break; default: console.error("Unrecognised message: ", message); } } );
Then in the popup we need to request a tab containing the content of the script. This is another messaging feature, and we must provide a tab identifier.
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { chrome.tabs.sendMessage(tabs[0].id, {type: "getCount"}, function(count) { }); });
Now that much cleaner. Problem 2 resolved: we request the tab we want to hear. Problem 1 seems to be solved: while the script has calculated what we need, it can respond.
Please note that as a final complication, content scripts are not always entered when you expect them: they only start to be activated when navigating after the extension has been downloaded. Here's an answer explaining this in great detail. You can get around it if you want, but at the moment this is just the code for it:
function(count) { if(typeof count == "undefined") {