Can you make a Chrome extension in Python?
Yes, you can make a chrome extension in Python, but not in the way you might think: Chrome cannot execute Python directly, so the two viable methods are embedding a Python runtime like Brython or PyScript inside your extension's HTML, or compiling your Python code to JavaScript ahead of time. This means your Python logic runs inside a browser sandbox, not as a native backend, but you still get to write your extension's core functionality in Python. The payoff is that you can leverage Python's readable syntax and rich ecosystem while still building a fully compliant Chrome extension, which is why this approach is so attractive to developers who prefer Python over JavaScript.
Understanding Manifest V3 for your extension
Before writing a single line of code, you need to know that Manifest V3 is the only supported standard for Chrome extensions, and as of January 2026, the Chrome Web Store no longer accepts Manifest V2 submissions. This isn't just a bureaucratic detail: Manifest V3 enhances security, performance, and privacy by replacing persistent background pages with service workers that run only when needed and by disallowing remotely hosted code. For you, this means your Python code must be bundled locally (either embedded or compiled), and your background logic must live in a service worker, not a long-running background page. Understanding this up front saves you from building something that will be rejected at the review stage, so it's worth internalizing the MV3 rules before you start coding.
Setting up your project structure
Start by creating a dedicated folder for your extension project. Inside it, you'll need at minimum a manifest.json file, an HTML file for your popup or options page, and your Python script that will be loaded via Brython or compiled to JavaScript. A typical structure looks like this:
- Create a new folder, e.g.,
my-python-extension/. - Inside, create
manifest.json. - Create
popup.html(orbackground.htmlif you're not using a popup). - Create
main.py, this is your Python source file. - If you're using Brython, download the Brython distribution and place it in a
lib/subfolder. If you're compiling, set up your Python-to-JavaScript compiler (like Transcrypt) in the same folder.
This structure keeps your code organized and makes it easy to package later. The key is that all files must be local, no remote scripts allowed under MV3.
Creating the Manifest V3 file
Your manifest.json is the backbone of the extension, and it must follow MV3 syntax exactly. Here's a complete, valid example that works with the Python approach:
{
"manifest_version": 3,
"name": "My Python Extension",
"version": "1.0",
"description": "A Chrome extension powered by Python.",
"permissions": ["storage", "tabs"],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
}
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}
Notice the differences from the old V2 format: action replaces browser_action, the background is a single service worker (not persistent scripts), and there's no persistent key. This is non-negotiable, Chrome will reject any V2 manifest. The permissions are minimal here, but you can expand them based on what your Python code needs to access.
Embedding Python with Brython or PyScript
Now comes the interesting part: getting Python to run inside your extension. The most straightforward method is to embed Brython, a Python interpreter written in JavaScript, directly into your HTML files. Here's how your popup.html would look:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="lib/brython.min.js"></script>
</head>
<body onload="brython()">
<script type="text/python" src="main.py"></script>
<button id="myButton">Click me</button>
<div id="output"></div>
</body>
</html>
Alternatively, PyScript (which builds on Pyodide) offers a higher-level interface with more built-in features, but it's heavier. For most extensions, Brython is the lighter choice. The critical point is that your Python code runs in the browser, so you can manipulate the DOM directly using Python syntax like document["myButton"].bind("click", ...), no JavaScript required for basic interactions.
Writing Python scripts that interact with Chrome APIs
Your Python code can't call Chrome's extension APIs directly, but you can bridge the gap using JavaScript interop. In Brython, you can use the js module to access any JavaScript object, including Chrome's APIs. Here's a concrete example that stores data in Chrome's storage:
from js import chrome, document
def save_data(event):
data = {"last_click": "yes"}
chrome.storage.local.set(data)
document["output"].textContent = "Data saved!"
document["myButton"].bind("click", save_data)
For tab management, you might do something like this:
from js import chrome
def get_tab_info():
def callback(tab):
print(f"Active tab URL: {tab.url}")
chrome.tabs.query({"active": True, "currentWindow": True}, callback)
This pattern, using from js import chrome, is your gateway to all extension APIs. The key is that you're writing pure Python, but the underlying calls are compiled down to JavaScript operations. This is why the compile-to-JavaScript approach also works: if you pre-compile your Python with a tool like Transcrypt, you get a pure JS file that you can load directly in your service worker or content script, bypassing the need for a runtime interpreter.
Loading and testing your extension in Chrome
Once your files are in place, testing is straightforward. Open Chrome and navigate to chrome://extensions/ in your browser, enable "Developer mode" (top right), click "Load unpacked," and select your extension's folder. Your extension will appear in the toolbar, and you can click its icon to open the popup and test your Python code. For debugging, open Chrome Developer Tools (right-click → Inspect) on the popup or the background service worker. You'll see console.log output from your Python code, and you can set breakpoints in the generated JavaScript if you need to step through. One common gotcha: if you change your Python code, you need to reload the extension (click the refresh icon on the extension card) and then reopen the popup, a simple page refresh won't pick up the changes.
Packaging and publishing to the Chrome Web Store
When your extension is ready, packaging is just a matter of zipping the entire folder, but make sure the manifest.json is at the root of the ZIP, not inside a subfolder. Then create a developer account on the Chrome Web Store (this involves a one-time registration fee and agreeing to the developer terms). Upload the ZIP via the developer dashboard, fill in the listing details (description, screenshots, category), and submit for review. The review process checks for MV3 compliance, so double-check that your manifest has no V2 remnants and that all code is bundled locally. Once approved, your extension goes live, and you'll need to maintain it by updating the version number in the manifest and re-uploading whenever you push changes. The entire process, from local testing to public availability, is designed to be iterative, so don't expect perfection on the first try. Instead, focus on getting a minimal viable extension working, then refine based on user feedback and Chrome's evolving platform requirements.

















