Manipulate a page from a chrome extension

In the last days I experimented with a small chrome extension and I ran into trouble to manipulate a website which was currently active in the browser. The use case was that a user can right click into an input field, select an entry from the context menu (which was extended by my extension) and then the input field should be filled with some text. First, I thought this would be very easy, but because of Chrome’s security restrictions, it’s not that easy. I would like to explain how I’ve come to a solution:

If you add a context menu to the right click, you have to add some lines to your manifest.json (click here if you don’t know how a Chrome extension is created):

{
  "manifest_version": 2,
  "name": "MyExtension",
  "description": "Can create a context menu!",
  "version": "1.0",
  "browser_action": {
    "default_popup": "popup.html"
  },
  "permissions": [
    "tabs",
    "contextMenus"
  ],
  "background": {
    "scripts": [
      "js/contextMenus.js"
    ]
  }
}

What does this manifest.json do? Beside the regular attributes like name or description, you set the permission and background files. Both are self-explaining: with the permissions flag you request rights to the specified modules etc. from the Chrome browser. This documentation page explains the permissions in general and differences between required and optional permissions. In my case I needed explicit permissions to tabs and contextMenus: with tabs I can communicate to any other tab and that will be important later when I want to manipulate the page from the current active tab. With contextMenus my chrome extension will be granted access to the context menu (right click) so that I can add a custom context entry. Click here if you need other permissions. The next declaration is the background: It basically defines a background page which is always running after your extension has been installed. So you can define scripts and pages which are always available. In some cases this is not necessary and thus the Chrome documentation proposes to use the “persistent”:false flag. In my case it wasn’t an option because the contextMenu had to react to dynamic changes in the background. However, these are the basics to get you context menu up and running. Let’s see how to add an entry:

chrome.contextMenus.create({
    "id": "yourId",
    "title": "Context Menu Entry",
    "contexts": ["editable"],
    "parentId": parentId,
    "onclick": onContextClick
});

This is quite simple. You set an ID for your menu item, a title, a context where the item is applied to (for me input fields, so I define editable as the context element), a parent id (if you have a parent item) and a callback function which is fired if the menu item is clicked (another option is to add a listener and click here to find out other options for contextMenus.create). Simple as that! Now comes the tricky part: You can’t directly manipulate the site where the context menu click was fired, because the background script is like another page in your Chrome which has some limitations. To get it done, this StackOverflow answer explains the way to go very nice. There is one exception: The referenced API is deprecated. But it’s quite simple to get it running with the proposed alternatives in the documentation.

function onContextClick(info, tab) {
    var message = info.menuItemId + " was clicked.";
    chrome.tabs.sendMessage(tab.id, message);
}

The info and tab parameters give you a lot information which can be used by your scripts. The magic happens in line 3: it sends a message to the tab with the given id (= the one where the context menu was clicked) and hands over your message. For this case you need the tabs permission from above 😉 Now the content script from this tab can listen to that message. Wait… You may wonder “Which content script?”. And you’re right! You need to add something more to you manifest.json:

"permissions": [...],
"background": {...},
"content_scripts": [ {
  "matches" : ["https://*/*"],
  "js" : [
    "js/content.js"
  ]
}],
// ...

From the Chrome extension documentation: “Content scripts are JavaScript files that run in the context of web pages.” And with this extended manifest, you tell Chrome that you want to run the given scripts on all pages which match the matches value. You can also add other scripts, for example jQuery, but consider that they must be in the correct order in terms of loading (jQuery before your content scripts). And now you can listen to your message in content.js:

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
   // do something with your message object
});

It’s as simple as that!

Conclusion: The way to go for your Chrome extension is to define one or more content scripts which have the permission to manipulate a web page within Chrome. And if you need information from other scripts of your extension, you should use the Chrome API message events.