Explain Codes LogoExplain Codes Logo

Chrome Extension how to send data from content script to popup.html

javascript
async-programming
callbacks
local-storage
Alex KataevbyAlex Kataev·Jan 10, 2025
TLDR

Employ chrome.runtime.sendMessage in your content script to send data, and leverage chrome.runtime.onMessage in the popup script to receive it.

Content Script:

// Sending a love letter to popup script chrome.runtime.sendMessage({data: "yourData"});

Popup Script:

// Catching the love letter from content script chrome.runtime.onMessage.addListener((message) => { // Process message.data });

A closer look at asynchronous message passing

Understanding the asynchronous nature of message passing is essential to building a robust extension. Prepare for callbacks to handle responses when the message has been delivered.

Handling Responses:

// In your content script // SendMessage is the new email chrome.runtime.sendMessage({data: "yourData"}, function(response) { console.log("Incoming... got a response:", response); }); // In your popup script chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { // Process message.data // Responding back 'cause communication is a two-way street sendResponse({status: "Roger, data received!"}); return true; // keeps the messaging channel open for longer conversations });

Strategies for smooth messaging

Local storage - your data warehouse

localStorage is an efficient way to create a semi-persistent bridge between the content script and the popup. It is invaluable for maintaining data between popup window lifecycles.

// In your content script // Counting stars... I mean DOM elements const totalElements = document.querySelectorAll('*').length; localStorage.setItem('total_elements', totalElements); // In your popup script // Retrieve the data treasure const totalElements = localStorage.getItem('total_elements'); console.log(`Number of DOM elements: ${totalElements}`);

Messaging with a secret handshake

Incorporate a "type" field in your messages to distinguish between different kinds of messages, like a secret handshake.

Content Script:

// Passing secret message, like we are in a spy movie! chrome.runtime.sendMessage({type: "DOM_COUNT", data: "yourData"});

Popup Script:

// Listening to all secret messages like a pro! chrome.runtime.onMessage.addListener((message) => { if(message.type === "DOM_COUNT") { // Lol, secret message found! Process message.data } });

Active tab - your target for messages

Aim your messages at the right tab. Use chrome.tabs.query to accurately target message sending from the popup to the content script.

// We are going tab fishing chrome.tabs.query({active: true, currentWindow: true}, function(tabs){ // Gotcha, look what I found! chrome.tabs.sendMessage(tabs[0].id, {data: "yourData"}); });

Watch out! Here’s what could go wrong

Sequencing scripts - The order of knights

In your extension's manifest.json, the order of scripts affects their execution. Ensure content scripts start the dance before popups scripts to prevent one stepping on the other's toes.

Local storage - A rocky boat

In modern browsers, with localStorage access from the content script, you might feel empowered. However, avoid this rocky boat due to isolated worlds of content scripts and consider proper message passing routines for safe sailing.

Asynchronous messaging – the time traveler

Messaging APIs are asynchronous, time is a trippy concept in the async world. Code your scripts to handle this time-travel by properly waiting for message responses with callbacks or promises.