I have an options page where the user can define certain options and it saves it in localStorage: options.html
Now, I also have a content script that needs to get the options that were defined in the options.html page, but when I try to access localStorage from the content script, it doesn't return the value from the options page.
How do I make my content script get values from localStorage, from the options page or even the background page?
Update 2016:
Google Chrome released the storage API: https://developer.chrome.com/docs/extensions/reference/storage/
It is pretty easy to use like the other Chrome APIs and you can use it from any page context within Chrome.
// Save it using the Chrome extension storage API.
chrome.storage.sync.set({'foo': 'hello', 'bar': 'hi'}, function() {
console.log('Settings saved');
});
// Read it using the storage API
chrome.storage.sync.get(['foo', 'bar'], function(items) {
message('Settings retrieved', items);
});
To use it, make sure you define it in the manifest:
"permissions": [
"storage"
],
There are methods to "remove", "clear", "getBytesInUse", and an event listener to listen for changed storage "onChanged"
Using native localStorage (old reply from 2011)
Content scripts run in the context of webpages, not extension pages. Therefore, if you're accessing localStorage from your contentscript, it will be the storage from that webpage, not the extension page storage.
Now, to let your content script to read your extension storage (where you set them from your options page), you need to use extension message passing.
The first thing you do is tell your content script to send a request to your extension to fetch some data, and that data can be your extension localStorage:
contentscript.js
chrome.runtime.sendMessage({method: "getStatus"}, function(response) {
console.log(response.status);
});
background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.method == "getStatus")
sendResponse({status: localStorage['status']});
else
sendResponse({}); // snub them.
});
You can do an API around that to get generic localStorage data to your content script, or perhaps, get the whole localStorage array.
I hope that helped solve your problem.
To be fancy and generic ...
contentscript.js
chrome.runtime.sendMessage({method: "getLocalStorage", key: "status"}, function(response) {
console.log(response.data);
});
background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.method == "getLocalStorage")
sendResponse({data: localStorage[request.key]});
else
sendResponse({}); // snub them.
});
Sometimes it may be better to use chrome.storage API. It's better then localStorage because you can:
store information from your content script without the need for
message passing between content script and extension;
store your data as JavaScript objects without serializing them to JSON (localStorage only stores strings).
Here's a simple code demonstrating the use of chrome.storage. Content script gets the url of visited page and timestamp and stores it, popup.js gets it from storage area.
content_script.js
(function () {
var visited = window.location.href;
var time = +new Date();
chrome.storage.sync.set({'visitedPages':{pageUrl:visited,time:time}}, function () {
console.log("Just visited",visited)
});
})();
popup.js
(function () {
chrome.storage.onChanged.addListener(function (changes,areaName) {
console.log("New item in storage",changes.visitedPages.newValue);
})
})();
"Changes" here is an object that contains old and new value for a given key. "AreaName" argument refers to name of storage area, either 'local', 'sync' or 'managed'.
Remember to declare storage permission in manifest.json.
manifest.json
...
"permissions": [
"storage"
],
...
Another option would be to use the chromestorage API. This allows storage of user data with optional syncing across sessions.
One downside is that it is asynchronous.
https://developer.chrome.com/extensions/storage.html
[For manifest v3]
You can execute a script that returns localstorage items from the webpage. This script can be executed from popup or background service worker.
Add this line in manifest.json:
"permissions": ["scripting"]
let [tab] = await chrome.tabs.query({ active: true, currentWindow: true })
// Execute script in the current tab
const fromPageLocalStore = await chrome.scripting.executeScript({
target: { tabId: tabId },
func: () => {
return JSON.stringify(localStorage)
}
})
const localStorageItems = JSON.parse(fromPageLocalStore[0].result)
Related
i'm newbie on developping chrome extension and i'm facing a problem.
I need to get user input data and store it in some ways. I tryed with local.storage and sync.storage but they should work only with same domain since i cannot get data while i'm trying to inject javascript by using script in content.js file. It works on same domain (i suppose that in this case, when i open tab of chrome extension, local.storage save data only for that "domain").
How can solve it?
Thank you
You can try the message passing.
// popup.js
function submit(data) {
chrome.tabs.query({active: true}, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, data);
});
}
// content.js
chrome.runtime.onMessage.addListener(function (message) {
// do sth
});
I'm struggling to find the best way to communicate with my web app, which I'm opening with chrome.windows.create in my extension.
I've got the wiring between content script and background script right. I can right click an element and send it's value to the background script, and the background script creates a window containing my webapp. But from there I can't figure out how to access and use that value in my webapp (it needs to load the value into an editor).
I've tried setting fns and vars on the window and tab objects, but somehow they go missing from the window object once the web app is loaded.
With chrome.tabs.executeScript I can fiddle with the dom, but not set global variables or anything on 'window' either.
If there isn't a better way, I guess I'm forced to add to the DOM and pick that up once my web app is loaded, but it seems messy. I was hoping for a cleaner method, like setting an onLoadFromExtension fn which my web app can execute to get the value it needs.
I found a method that works after much trial and error, though it still seems error prone. And it also depends on the extension ID matching the installed one, so if that can't be hard-coded it'll be another message that needs passing through another channel (after reading up, looks like that can be hard-coded since it's a hash of the public key, so problem solved)... Starting to think manipulating the DOM is less messy...
background.js:
var selectedContent = null;
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
console.info("------------------------------- Got request", request);
if (request.getSelectedContent) {
sendResponse(selectedContent);
}
});
web app:
var extensionId = "naonkagfcedpnnhdhjahadkghagenjnc";
chrome.runtime.sendMessage(extensionId, {getSelectedContent: "true"},
response => {
console.info("----------------- Got response", response);
if(response) {
this.text = response;
}
});
manifest.json:
"externally_connectable": {
"ids": ["naonkagfcedpnnhdhjahadkghagenjnc"],
"matches": ["http://localhost:1338/*"]
},
Within the popup, do the following:
const parentWindow = window.opener
parentWindow.postMessage({ action: 'opened' })
window.onmessage = msg => {
alert(JSON.stringify(msg.data)) // Alerts you with {"your":"data"}
}
Within the script that will call chrome.windows.create, do the following:
window.onmessage = msg => {
if (msg.data.action == 'opened') {
msg.source.postMessage({ your: 'data' })
}
}
Set setSelfAsOpener: true when calling chrome.windows.create
How does this work?
Due to limitations of the Chrome extension windows API, the created window needs to post a message to its creator (aka window.opener) or else the creator won't have access to a WindowProxy (useful for posting messages to the created window).
I'm making an extension and while I can delete all the cookies of a specified domain, I can't delete its local storage.
So for example, if I visited The Telegraph's website, it keeps a local storage in my machine:
Origin: http://www.telegraph.co.uk/
Size on disk: 6.0 KB
I have tried using the remove() method from the storage api:
StorageArea.remove("http://www.telegraph.co.uk/");
and I'm getting the following error:
Error in event handler for browserAction.onClicked: StorageArea is not defined
Stack trace: ReferenceError: StorageArea is not defined
How can I programmatically make this work?
chrome.storage is a completely different API compared to localStorage. The former is only available to extensions, while the latter is specific to the domain of the website.
If you want to modify or clear the data in localStorage for a specific domain, then just insert a content script in the page that invokes localStorage.clear().
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id, {code: 'localStorage.clear()'});
});
If you want to clear the localStorage of a different origin, you have to load a page from that origin in a tab or frame and insert a content script in it. For example:
// background.js
var f = document.createElement('iframe');
f.sandbox = ''; // Sandboxed = disable scripts, etc.
f.src = 'http://example.com/#someuniqueid';
f.onloadend = function() {
f.remove();
};
// content script, declared in manifest file (read the documentation)
if (location.hash === '#someuniqueid') {
localStorage.clear();
}
try using
StorageArea.clear(function callback)
.remove accepts key string or array of keys to remove specific items.
Also i'm not sure if it will access storage of specific domains.
Try to check url before clearing
I have a chrome extension that sets a string value in JavaScript localStorage in a content script. I have tested that it is being set by grabbing it and displaying it. While on the same page after it has loaded I can still access the stored string in the javascript console. If I go to any other tabs js console or when I try to access it in my other extensions background page(After the browser action has been clicked) it is returning null.
extension 1 contentscript.js
embeded.addEventListener
(
"message",
function(message)
{
localStorage.setItem("pdf", message.data);
loadPDF(message.data);
},
false
);
extension 2 background.js
chrome.browserAction.onClicked.addListener(function(tab) {
if (tab.url.substr(tab.url.length - 4) === ".pdf")
{
if (localStorage.getItem("pdf") !== null)
{
alert("boomy");
}
}
});
localStorage is shared among extension pages (background, options, popup), but not content scripts. And most certainly not shared between 2 extensions!
You have two-and-a-half options. With 2 separate extensions, only one option.
Option one: rely on messaging.
When you need to pass some value between background and content script, you can do so with messaging. Works especially well if you only need to pass it in one direction.
contentscript.js:
embeded.addEventListener(
"message",
function(message)
{
chrome.runtime.sendMessage(extensionTwoId, {pdf: message.data});
loadPDF(message.data);
},
false
);
background.js:
chrome.runtime.onMessageExternal.addListener(
function(message, sender, sendResponse) {
if(sender.id !== extenstionOneId) return;
if(message.pdf) localStorage.setItem("pdf", message.pdf);
}
);
/* ... */
Option two: chrome.storage. Not applicable between 2 extensions.
I try to create a communication channel between specific webpage (per example : www.website.dev) and a chrome extension I created.
By using postMessage it's work from webpage to extension but I can't do that from extension to webpage.
I tried Google example but it uses background page
Thanks for your help
EDIT : sorry I don't understand the difference between content_script and background.js
In my manifest I have content script = test.js
What's about "background" ?
Following the documentation you can pass messages to your extension if you know the extension id:
https://developer.chrome.com/extensions/messaging#external-webpage
manifest.json
"externally_connectable": {
"matches": ["*://*.example.com/*"]
}
website:
// 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);
});
extension:
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (sender.url == blocklistedWebsite)
return; // don't allow this web page access
if (request.openUrlInEditor)
openUrl(request.openUrlInEditor);
});
You will find all the details in the documentation https://developer.chrome.com/extensions/messaging
You would have one piece use sendMessage function while the other piece is listening for the event, which could be either a webpage or content script.
either the webpage's content script should initiate the communication (so you would get the tab id) or you can have the background query for tabs with specific url and then use sendMessage. Notice two separate functions chrome.extension.sendMessage and chrome.tabs.sendMessage used here.
the following code works for me:
content_script.js:
chrome.extension.sendMessage({"msg":"hello"});
background.js:
chrome.extension.onMessage.addListener(function (request, sender, sendResponse) {
if (request.msg == "hello"){
senderTab = sender.tab.id;
chrome.tabs.sendMessage(senderTab, {"msg": "ehlo"});
};
})