71

I want to send message from the console of the random web page to my chrome extension. chrome.extension.sendMessage doesn't seem to work.

Nakilon
  • 34,866
  • 14
  • 107
  • 142
dilpreet023
  • 855
  • 1
  • 7
  • 5

6 Answers6

88

According to the official docs you should use postMessage in the sender and message event listener in the receiver.

Here is an example:

Your website's page.html

var data = { type: "FROM_PAGE", text: "Hello from the webpage!" };
window.postMessage(data, "*");

Content script: (injected using chrome.tabs.executeScript(tabid, {code:...)

window.addEventListener("message", function(event) {
    // We only accept messages from ourselves
    if (event.source != window)
        return;

    if (event.data.type && (event.data.type == "FROM_PAGE")) {
        console.log("Content script received message: " + event.data.text);
    }
});

Here page.html (which is not a part of the extension) posts messages to itself, which are intercepted and inspected by the content script. The reverse is possible through similar means.

To pass from content script to extension, you will have to use one of the available message-passing techniques.

It looks complicated and it is somewhat complicated but all this mumbo-jumbo is very secure.

Mike Frysinger
  • 2,827
  • 1
  • 21
  • 26
Silviu-Marian
  • 10,565
  • 6
  • 50
  • 72
  • can I try to insert the code in the Website's html for dispatching event along through the 'chrome.tabs.executeScript()' command? I tired that and it isn't working... it says, "Port Error: could not establish connection: receiving end does not exist: – dilpreet023 Jul 11 '12 at 13:16
  • Thanks for this. I was wondering how to do this more securely than just window.postMessage. This would definitely have fewer side effects, but still unfortunately could be tampered with by a malicious web page. I'm looking forward to [chrome.runtime.onMessageExternal](http://developer.chrome.com/extensions/messaging.html) which will allow a somewhat more secure (hopefully) channel of communication – kzahel Aug 17 '13 at 13:23
  • 1
    @kzahel Content scripts are ran within their own context, so it's isolated from webpage context. Content scripts have access to the DOM (the HTML elements), basically you can attach listeners if you want to pass data between contexts, you can do that via events. Just note there are 3 different contexts: Extension, Custom script, and webpage scripts. – Silviu-Marian Feb 05 '14 at 15:01
  • 2
    That first link mentions using `windows.postMessage(...)` so apparently you don't even need a custom myCustomEventDiv, as it were... – rogerdpack Jan 24 '17 at 18:18
  • Glad to find this after an hour of searching. Thanks for the writeup! – Dan Abramov Apr 28 '17 at 14:53
  • Still helping in 2019! – Jay Dadhania Nov 01 '19 at 00:21
63

Here's a quote from the latest https://developer.chrome.com/docs/extensions/mv3/messaging/, It's much simpler to support this kind of feature now, here's how:

###Sending messages from web pages

Similar to cross-extension messaging, your app or extension can receive and respond to messages from regular web pages. To use this feature, you must first specify in your manifest.json which web sites you want to communicate with. For example:

"externally_connectable": {
  "matches": ["*://*.example.com/*"]
}

This will expose the messaging API to any page which matches the URL patterns you specify. The URL pattern must contain at least a second-level domain - that is, hostname patterns like "", ".com", ".co.uk", and ".appspot.com" and <all_urls> are prohibited. From the web page, use the runtime.sendMessage or runtime.connect APIs to send a message to a specific app or extension. For example:

// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
  function(response) {
    if (!response.success)
      handleError(url);
  });

From your app or extension, you may listen to messages from web pages via the runtime.onMessageExternal or runtime.onConnectExternal APIs, similar to cross-extension messaging. Only the web page can initiate a connection. Here is an example:

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.url == blacklistedWebsite)
      return;  // don't allow this web page access
    if (request.openUrlInEditor)
      openUrl(request.openUrlInEditor);
  });
Mike Frysinger
  • 2,827
  • 1
  • 21
  • 26
hewigovens
  • 1,190
  • 11
  • 9
  • This works for me. However, I have one question. How do people find the ID of their extension? At the moment I just hard code it. – dooderson Feb 19 '14 at 17:57
  • how to see that message is received by extension, I'm using unpacked extension. I'm currently developing it. – pavan Sep 24 '14 at 13:43
  • 2
    @user1311069 the extension ID generation mechanism is explained here: http://stackoverflow.com/a/21500707/258772 – mrts Jan 02 '15 at 18:01
  • @pavan I just add an `alert` in the event handler in the extension. – Potassium Ion Apr 01 '15 at 22:42
  • this would be the best method if it weren't by; 1- you must specify all the externally connactable web sites with at least 2 level domain (its a problem for me) and 2- you must know app/extension id upfront – Renato Gama May 05 '15 at 20:37
  • 5
    Listen to events with `chrome.runtime.onMessageExternal.addListener()` – Stas Bichenko Jun 12 '15 at 13:59
  • 1
    Note that this method does not currently work in Firefox, as of FF 54. See this for a possible solution: https://stackoverflow.com/questions/44592605/firefox-webextension-check-if-my-extension-exists – Haydentech Aug 01 '17 at 19:41
  • 1
    It won't possible to send message from script from unknown domain as it must defined in manifest.json – Sarjan Desai Aug 03 '18 at 07:09
  • 4
    horrible documentation, really – JBarros35 Jul 29 '21 at 16:18
  • Does this also work when sending a message from localhost? Doesn't seem to work for me. – Mathijs Jul 20 '22 at 09:21
  • It works in localhost, you need to mention it `http://localhost:3000/*` in `externally_connectable`. Also, onMessageExternal works from BGSW not Content Script – GorvGoyl Mar 19 '23 at 07:46
12

So to elaborate, a more concreate example: An issue with chrome.runtime.sendMessage(...) style is that you have to specify the pag you're on as externally_connectable which doesn't take a global wildcard like "https:///". So if you want that ability, you have to use the postMessage style communication. Capture the message from the window into the contentscript, then from the contentscript, you can send it elsewhere (if desired, like to the background.js etc.)

So in the normal web page, or in injected source that you embed into the normal page, from your contentscript.js, send a message like this:

window.postMessage({ type: "FROM_PAGE_TO_CONTENT_SCRIPT", 
     text: "Hello from the webpage!" }, "*");

ex, you could add it to a button like this:

document.getElementById("theButton").addEventListener("click",
    function() {
       window.postMessage({ type: "FROM_PAGE_TO_CONTENT_SCRIPT", 
                            text: "Hello from the webpage!" }, "*");
}, false);

Then to capture it in the contentscript.js and "send it on" to the rest of the extension, the only caveat is that you only want to "select" messages that seem to be ones that you care about:

window.addEventListener("message", function(event) {
  // We only accept messages from this window to itself [i.e. not from any iframes]
  if (event.source != window)
    return;

  if (event.data.type && (event.data.type == "FROM_PAGE_TO_CONTENT_SCRIPT")) {        
    chrome.runtime.sendMessage(event.data); // broadcasts it to rest of extension, or could just broadcast event.data.payload...
  } // else ignore messages seemingly not sent to yourself
}, false);
rogerdpack
  • 62,887
  • 36
  • 269
  • 388
5

You can switch to the JS execution context of your content script using the <page context> menu at the bottom of a page’s developer JS console, then use chrome.runtime.sendMessage and other chrome.* APIs just as you would within the content script.

enter image description here

jaredjacobs
  • 5,625
  • 2
  • 27
  • 23
  • 1
    What can be the reason if the execution context switching menu shown in your screenshot does not appear (Chrome v 39.0.2171.95 m, Windows 7)? – mrts Jan 02 '15 at 19:36
  • Just for reference - I can access the extension context console by opening the extensions page (`chrome://extensions`) and clicking the *Inspect views: background page* link, so the missing context switching menu is not a big problem really. – mrts Jan 02 '15 at 19:43
  • 1
    In a recent release, Chrome combined the execution context menu with the frame menu. If your extension has a content script in the page, you should now see it listed under ``. – jaredjacobs Jan 03 '15 at 21:28
  • Thanks for the tip. Unfortunately I only see `` when I click on the drop-down, even though the page script is able to communicate with the extension with no problems. But as I can use the background page link from the extensions page, it's just a cosmetic issue. – mrts Jan 04 '15 at 17:44
  • @mrts Background script != Content script. There are 3 separate JS execution contexts here: page script (what you see in your console by default), background script (what you see when you inspect the background page and is universal [one instance] for all Chrome tabs), and content script, which runs inside a given tab + given url as defined in manifest.json. If you put `window.foo = 'bar';` in a content script, you won't see it in the background-page-inspection console. afaics it's only viewable via the dropdown that jaredjacobs points out here (which is now under 'top'). – jdunk Mar 28 '17 at 07:58
4

In addition to @hewigovens , I don't have enough points to comment... I'm explaining @renatoargh and @sbichenko If sending message from a default web page -

1) the webpage needs to be quoted in the manifest. e.g.:

"externally_connectable": {
  "matches": ["http://abcde/abcde/main.aspx*"]
}

2) the background.js (background page) excepts the call with onMessageExternal e.g. (calling an extension):

var host_name = "com.my_chrome_extension.com";
 chrome.runtime.onMessageExternal.addListener(function(message, sender, sendResponse) {
    chrome.runtime.sendNativeMessage(host_name, {"run":message});
    sendResponse({"success": "success"});
    return true;
});
AJ AJ
  • 187
  • 2
  • 12
-1

Here it shows how to send messages from chrome extension to web page https://developer.chrome.com/docs/extensions/mv3/messaging/#external-webpage

Add externally connectible resources in manifest.json that matches your web page URL or localhost, if you testing locally.

"externally_connectable": {
  "matches": ["https://*.example.com/*"]
}

From the web page, use the runtime.sendMessage or runtime.connect APIs to send a message to a specific app or extension. For example:

// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
  function(response) {
    if (!response.success)
      handleError(url);
  });

From your extension, you may listen to messages from web pages via the runtime.onMessageExternal or runtime.onConnectExternal APIs, similar to cross-extension messaging. Only the web page can initiate a connection. Here is an example:

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (request.openUrlInEditor)
      openUrl(request.openUrlInEditor);
  });
akshay_sushir
  • 1,483
  • 11
  • 9