Sebastian Gomez
Permissions in Chrome Extensions
In this post we will explore how to blur images on any web page using a Chrome extension. We will also see why permissions matter so much in Chrome extensions and how to configure them correctly. We will always work on Manifest V3, so let's get started.
Note: Manifest V2 is now fully retired from stable Chrome, the removal process completed during 2024 and 2025. Today Manifest V3 is the only valid target for publishing extensions, so everything we will see here starts from "manifest_version": 3.
How to blur images using a Chrome extension
Create the CSS file: First we need a CSS file that applies the blur effect. Create a file named content-style.css and add the following code:
img, video {
filter: blur(10px);
}Update the manifest: Make sure your manifest.json includes this CSS file as a content script:
{
"manifest_version": 3,
"name": "My Extension",
"version": "0.0.1",
"content_scripts": [
{
"matches": ["<all_urls>"],
"css": ["content-style.css"]
}
]
}Test the extension: Load your extension in Chrome and navigate to any website. You will see that all images and videos appear blurred.
Why permissions matter in Chrome extensions
As the manifest versions advanced (from V1 to V3), Chrome increased the restrictions on permission usage to improve security. It is now mandatory for extensions to declare the permissions they need in the manifest.json file.
Declaring permissions: Permissions let the extension access certain Chrome APIs and perform specific actions. Here is an example of how to declare them:
{
"manifest_version": 3,
"name": "My Extension",
"version": "0.0.1",
"permissions": [
"storage",
"tabs"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"css": ["content-style.css"]
}
]
}Host permissions: Host permissions let the extension interact with specific pages. You can specify URL patterns for these permissions:
"host_permissions": [
"https://*.example.com/*"
]Optional permissions: Optional permissions are requested from the user only when they are needed. This improves the user experience, since we do not ask for too many permissions up front.
Using the storage API in extensions
The storage API lets extensions save user specific data persistently.
Configure storage: Declare the storage permission in your manifest.json:
{
"permissions": ["storage"]
}Save and retrieve data: In Manifest V3 the service worker fully supports the promise form, so the idiomatic approach today is to use async/await:
// Save data
await chrome.storage.local.set({ key: "value" });
console.log("Data saved");
// Retrieve data
const result = await chrome.storage.local.get(["key"]);
console.log("Retrieved value:", result.key);If you prefer to keep the classic callback style, it still works too:
// Callback form (legacy, but valid)
chrome.storage.local.set({ key: "value" }, function () {
console.log("Data saved");
});
chrome.storage.local.get(["key"], function (result) {
console.log("Retrieved value:", result.key);
});Practical example of permissions and storage
Update the content script.js file: Create a file named content-script.js and add the following code. Notice that we guard response and check chrome.runtime.lastError, because if no listener responds, response arrives as undefined and reading response.farewell would throw an error in the console:
chrome.runtime.sendMessage({ greeting: "hello" }, function (response) {
if (chrome.runtime.lastError) {
console.warn("No response:", chrome.runtime.lastError.message);
return;
}
if (response) {
console.log(response.farewell);
}
});Update the background.js file: Create or update the background.js file to listen for and respond to the message:
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.greeting === "hello") {
sendResponse({ farewell: "goodbye" });
}
});Test the communication: Reload your extension and check the web page console to see the response message.
Conclusion
Building Chrome extensions can seem complex, but with a clear understanding of content scripts, permissions, and the storage API, you can develop powerful and useful tools. Keep exploring these techniques and take your extensions to the next level.
Suggested exercises
- Modify the CSS rule so that only images (
img) are blurred and not videos, then check the result across different sites. - Add the
storagepermission and save a user preference (for example, the blur level) using theasync/awaitform, retrieving it when the page loads. - Turn one of the host permissions into an optional permission and request it only when the user enables the feature.
3-point summary
- In Manifest V3, now the only valid target, every extension must declare its permissions in
manifest.json, includinghost_permissionsand optional permissions. - The storage API supports the modern promise and
async/awaitform, although callbacks still work. - When passing messages between
content-script.jsandbackground.js, always guardresponseand checkchrome.runtime.lastErrorto avoid console errors.
That's all, I hope this guide is useful to you and that you can apply it to a project you have in mind. Leave me a comment if it helped or if you have any questions, and remember that if you liked it you can also share it using the social links below. Good luck and keep improving your development skills.
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.