Passing data around in Chrome extensions

We were working on a simple Chrome extension when we got stuck on something that didn't seem clear in Google's documentation. We wanted to get data from the current web page and then use it to populate a form that appears in a new window.

It was easy to create a context menu item that triggered an event, but sending data based on the current page to the new window wasn't obvious.

Chrome extensions run JavaScript files in different contexts. Sometimes you need to communicate between contexts -- for example, between a background page and a popup window.

To get around this, Chrome provides an API for sending messages between different parts of an extension, using the sendMessage and sendResponse methods. This article is a brief explanation of how these methods work.

There's a full example on GitHub that you can try out in Chrome: mekentosj / sample-chrome-extension. The end result uses a context menu that communicates with a popup window.

Right click on context menu

Main files

This is our app's tree:

le tree

background.js is where the context menu is defined. It sets up an onclick handler so a function runs when the relevant item is selected from Chrome's right-click menu.

The onclick handler creates the popup window, then sends the data that will be used to populate the new window by using sendMessage.

window.js is where the message is received by using a callback passed to addEventListener(). We wanted to get the data passed from background.js and populate a form.

window.html is the popup window's markup -- it's just a simple form that will be populated with the incoming data.

Creating a context menu

First, you need to allow a context menu to be created. A context menu is the menu that appears once you right click anywhere on a web page.

Add the following to your manifest.json file:

"permissions": ["contextMenus"]  

You will also need to register the background script:

"background": {  
  "scripts": [
  "js/background.js"
  ]
}

onClick Handler

This is how context menus are actually created (in background.js):

chrome.contextMenus.create({  
  'title': 'Get Metadata',
  'contexts': ['link'],
  'onclick': onClickHandler
});

The onClickHandler function just grabs bits of metadata from the current web page and sends it with sendMessage:

function onClickHandler(info) {  
    var details = {}
    details.title = info.selectionText;
    [...]
    chrome.windows.create[...]
    chrome.runtime.sendMessage[...]
}

See the full code at lines 7 - 30 of our live example.

Info about... info

When we looked at Chrome's documentation we struggled to figure out how to use the info argument that is passed to onClickHandler.

We ended up inspecting all of the key/value pairs in info. The first thing we tried was to iterate over each item in the object:

var information;  
for (var key in info) {  
  if (info.hasOwnProperty(key)) {
    information += ' ' + key;
  }
}

console.log(information);

(You can see this in context here: background.js)

This displayed undefined editable linkUrl menuItemId pageUrl selectionText.

Here's what it looks like in the Chrome debugger:

chrome debugger

Summary

Sending and receiving messages in a Chrome extension provides a way to communicate between different execution contexts. This is done using a simple event-based API, with chrome.runtime.sendMessage and chrome.runtime.onMessage.addListener.

A few good resources to get started are this Tutsplus tutorial, this bootstrapped template and this directory of sample extensions at Chrome's official documentation.