Building a Chrome extension can be a highly rewarding way to automate browser tasks, enhance web pages, or integrate third-party services directly into your browsing experience. This guide will walk through the process of developing a simple but functional Chrome extension, focusing on how modern AI coding assistants like GitHub Copilot, Cursor, or Codeium can dramatically accelerate development, reduce boilerplate, and even suggest solid solutions for common challenges. We will build a “Keyword Highlighter” extension that allows users to input keywords and have them highlighted on the active web page, demonstrating core extension concepts like Manifest V3, content scripts, and message passing, all while using AI to streamline the coding process.
Prerequisites
Before diving in, ensure you have the following setup:
- Basic Web Development Knowledge: Familiarity with HTML, CSS, and JavaScript is essential. While AI tools will assist, understanding the fundamentals helps in guiding the AI and reviewing its output.
- Node.js & npm (Optional but Recommended): For more complex extensions or if you plan to use build tools like Webpack or Parcel, Node.js and npm are necessary. For this basic extension, we won’t strictly require them, but they are good to have.
- Google Chrome Browser: The environment where our extension will run and be debugged.
- A Code Editor: Visual Studio Code is highly recommended due to its excellent JavaScript/TypeScript support and solid extension ecosystem, including integration with AI coding tools.
- An AI Coding Assistant:
- GitHub Copilot: Integrates directly into VS Code and many other IDEs, providing inline code suggestions.
- Cursor: A code editor built around AI, allowing chat-based interactions, code generation, and debugging directly within the editor.
- Codeium: Another powerful AI assistant with broad IDE support, offering code completion, chat, and command features.
- For this guide, we will refer to “your AI assistant” generically, assuming you are using one of these or a similar tool.
Step-by-step sections
Step 1: Project Setup and Manifest V3
Every Chrome extension starts with a manifest.json file, which provides essential metadata and defines the extension’s capabilities. We will be using Manifest V3, the latest standard, which introduces service workers and stricter security policies.
- Create a Project Directory: Create a new folder named
keyword-highlighterfor your extension. - Generate
manifest.jsonwith AI: Open your code editor and create a file namedmanifest.jsoninside thekeyword-highlighterfolder.
AI Prompt: “Generate a Chrome Extension Manifest V3 file for an extension named ‘Keyword Highlighter’. It should have a popup, a content script that runs on all URLs (
<all_urls>), and permission to access the active tab. Also, include an icon path for a 16x16, 48x48, and 128x128 icon.”AI Output (Example):
{
"manifest_version": 3,
"name": "Keyword Highlighter",
"version": "1.0",
"description": "Highlight specified keywords on any webpage.",
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"permissions": [
"activeTab",
"scripting"
],
"host_permissions": [
"<all_urls>"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}
```
* **Review and Adjust:**
* `manifest_version: 3`: Crucial for modern extensions.
* `action`: Defines the popup and default icons when the extension icon is clicked.
* `permissions`: `activeTab` grants temporary access to the currently active tab when the user invokes the extension. `scripting` is required for injecting content scripts programmatically (though here we define it declaratively).
* `host_permissions`: Grants the content script access to the specified URLs. `<all_urls>` is broad, for specific use cases you might narrow this down.
* `content_scripts`: Specifies `content.js` to run on all pages matching `<all_urls>`.
* **Action:** Create an `icons` folder inside `keyword-highlighter` and place some placeholder images (e.g., `icon16.png`, `icon48.png`, `icon128.png`). You can use any small image, even a solid color square for now.
### Step 2: Designing the Popup UI
The `popup.html` file defines the user interface that appears when the extension icon is clicked. It will contain an input field for keywords and a button to trigger the highlighting.
1. **Create `popup.html`:** Inside your `keyword-highlighter` folder, create `popup.html`.
* **AI Prompt:** "Write a simple HTML file for a Chrome extension popup. It should have a text input field for 'Keywords (comma-separated)' and a button labeled 'Highlight Keywords'. Include basic styling and link to a `popup.js` script."
* **AI Output (Example):**
```html
<!DOCTYPE html>
<html>
<head>
<title>Keyword Highlighter</title>
<style>
body {
font-family: Arial, sans-serif;
width: 300px;
padding: 10px;
}
label {
display: block;
margin-bottom: 5px;
}
input[type="text"] {
width: calc(100% - 20px);
padding: 8px;
margin-bottom: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<h2>Keyword Highlighter</h2>
<label for="keywords">Keywords (comma-separated):</label>
<input type="text" id="keywords" placeholder="e.g., Chrome, Extension, AI">
<button id="highlightButton">Highlight Keywords</button>
<script src="popup.js"></script>
</body>
</html>
```
* **Action:** Save the code as `popup.html`.
### Step 3: Implementing the Content Script
The `content.js` script runs in the context of the web page itself, allowing it to interact with the page's DOM. This script will receive keywords from the popup and perform the highlighting.
1. **Create `content.js`:** Create `content.js` inside your `keyword-highlighter` folder.
* **AI Prompt:** "Write a JavaScript content script for a Chrome extension. It should listen for messages containing a list of keywords. When a message is received, it should find all occurrences of these keywords in the document body's text nodes (excluding script and style tags) and wrap them in a `<span>` with a yellow background. Make sure to handle case-insensitivity."
* **AI Output (Example - may require minor edits for robustness):**
```javascript
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "highlightKeywords" && message.keywords) {
const keywords = message.keywords.map(k => k.trim()).filter(k => k.length > 0);
if (keywords.length === 0) {
console.log("No keywords provided for highlighting.");
return;
}
highlightTextNodes(document.body, keywords);
sendResponse({ status: "highlighted" });
}
});
function highlightTextNodes(node, keywords) {
for (let i = 0; i < node.childNodes.length; i++) {
const child = node.childNodes[i];
if (child.nodeType === Node.TEXT_NODE) {
let text = child.nodeValue;
let parent = child.parentNode;
// Skip script and style tags
if (parent && (parent.tagName === 'SCRIPT' || parent.tagName === 'STYLE')) {
continue;
}
let fragment = document.createDocumentFragment();
let lastIndex = 0;
keywords.forEach(keyword => {
const regex = new RegExp(`(${escapeRegExp(keyword)})`, 'gi');
let match;
while ((match = regex.exec(text)) !== null) {
// Add text before the match
if (match.index > lastIndex) {
fragment.appendChild(document.createTextNode(text.substring(lastIndex, match.index)));
}
// Add the highlighted span
let span = document.createElement('span');
span.style.backgroundColor = 'yellow';
span.style.fontWeight = 'bold';
span.textContent = match[0];
fragment.appendChild(span);
lastIndex = regex.lastIndex;
}
});
// Add any remaining text after the last match
if (lastIndex < text.length) {
fragment.appendChild(document.createTextNode(text.substring(lastIndex)));
}
// Only replace if actual highlights were made
if (fragment.childNodes.length > 1 || (fragment.childNodes.length === 1 && fragment.firstChild.nodeType !== Node.TEXT_NODE)) {
parent.replaceChild(fragment, child);
}
} else if (child.nodeType === Node.ELEMENT_NODE && child.childNodes.length > 0) {
// Recursively call for child elements, but skip highlighted ones to avoid re-highlighting
if (!child.classList.contains('highlighted-keyword')) { // Add a class to prevent re-processing
highlightTextNodes(child, keywords);
}
}
}
}
// Helper function to escape special characters for regex
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
```
* **Review and Adjust:**
* The AI correctly uses `chrome.runtime.onMessage.addListener` to receive messages.
* The `highlightTextNodes` function recursively traverses the DOM.
* A regular expression is used for case-insensitive matching and replacement.
* The `escapeRegExp` helper is crucial for handling keywords with special characters.
* **Downside:** Directly manipulating text nodes can sometimes break event listeners or complex DOM structures. A more solid solution might involve a library or more sophisticated parsing, but for simple text highlighting, this is generally sufficient. AI might not always predict these edge cases, requiring human oversight.
### Step 4: Connecting Popup and Content Script
Now we need to make the `popup.js` script send the keywords to the `content.js` script running on the active tab.
1. **Create `popup.js`:** Create `popup.js` inside your `keyword-highlighter` folder.
* **AI Prompt:** "Write a JavaScript file for `popup.js`. It should get the value from the 'keywords' input field when the 'highlightButton' is clicked. It should then split the input by commas, trim each keyword, and send these keywords as a message to the content script in the active tab. The message action should be 'highlightKeywords'."
* **AI Output (Example):**
```javascript
document.addEventListener('DOMContentLoaded', () => {
const keywordsInput = document.getElementById('keywords');
const highlightButton = document.getElementById('highlightButton');
highlightButton.addEventListener('click', () => {
const keywordString = keywordsInput.value;
const keywords = keywordString.split(',').map(keyword => keyword.trim()).filter(keyword => keyword.length > 0);
if (keywords.length > 0) {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, {
action: "highlightKeywords",
keywords: keywords
}, (response) => {
if (response && response.status === "highlighted") {
console.log("Keywords highlighted successfully!");
} else {
console.error("Failed to highlight keywords or no response received.");
}
});
});
} else {
console.log("Please enter some keywords.");
}
});
});
```
* **Review and Adjust:**
* `DOMContentLoaded` ensures the DOM is fully loaded before trying to access elements.
* `chrome.tabs.query` finds the currently active tab.
* `chrome.tabs.sendMessage` sends the message to the content script of that tab.
* Error handling for `sendMessage` response is included.
### Step 5: Loading and Testing the Extension
Now that all the files are in place, it's time to load your extension into Chrome and test it.
1. **Open Chrome Extensions Page:**
* Open Chrome.
* Navigate to `chrome://extensions/`.
2. **Enable Developer Mode:**
* In the top right corner, toggle the "Developer mode" switch to on.
3. **Load Unpacked Extension:**
* Click the "Load unpacked" button.
* Select your `keyword-highlighter` folder.
4. **Pin the Extension (Optional):**
* Click the puzzle piece icon in the Chrome toolbar.
* Find "Keyword Highlighter" and click the pin icon next to it to make it visible in the toolbar.
5. **Test the Extension:**
* Navigate to any website (e.g., a news article).
* Click the "Keyword Highlighter" icon in your toolbar.
* Enter some keywords (e.g., "AI, machine, learning") in the input field.
* Click "Highlight Keywords".
* Observe the page: The specified keywords should now be highlighted in yellow and bold.
6. **Debugging:**
* For the popup: Right-click on the extension icon and select "Inspect popup". This opens developer tools for `popup.html` and `popup.js`.
* For the content script: Open developer tools on the web page itself (F12 or right-click -> Inspect). Any `console.log` messages from `content.js` will appear here.
### Step 6: Refinement and Enhancements with AI (Optional)
Let's add a small enhancement to make the extension more user-friendly: storing the last entered keywords.
1. **Modify `popup.js` with AI:**
* **AI Prompt:** "Modify the `popup.js` to use `chrome.storage.sync` to store the last entered keywords. When the popup is opened, the input field should be pre-filled with the stored keywords. When keywords are highlighted, save them to storage."
* **AI Output (Example, integrated into `popup.js`):**
```javascript
document.addEventListener('DOMContentLoaded', () => {
const keywordsInput = document.getElementById('keywords');
const highlightButton = document.getElementById('highlightButton');
// Load keywords from storage when popup opens
chrome.storage.sync.get('lastKeywords', (data) => {
if (data.lastKeywords) {
keywordsInput.value = data.lastKeywords.join(', ');
}
});
highlightButton.addEventListener('click', () => {
const keywordString = keywordsInput.value;
const keywords = keywordString.split(',').map(keyword => keyword.trim()).filter(keyword => keyword.length > 0);
if (keywords.length > 0) {
// Save keywords to storage
chrome.storage.sync.set({ lastKeywords: keywords }, () => {
console.log('Keywords saved to storage.');
});
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, {
action: "highlightKeywords",
keywords: keywords
}, (response) => {
if (response && response.status === "highlighted") {
console.log("Keywords highlighted successfully!");
} else {
console.error("Failed to highlight keywords or no response received.");
}
});
});
} else {
console.log("Please enter some keywords.");
}
});
});
```
* **Action:** Update your `popup.js` with the new code. Reload the extension on `chrome://extensions/` by clicking the refresh icon next to your extension. Test by entering keywords, closing and reopening the popup.
## Common Issues
Even with AI assistance, you might encounter issues. Here are some common ones and how to troubleshoot them:
* **Manifest V3 Errors:**
* **Symptom:** Extension fails to load, or Chrome displays an error message on `chrome://extensions/`.
* **Cause:** Incorrect `manifest_version`, missing required fields, or deprecated Manifest V2 syntax.
* **Fix:** Carefully review the `manifest.json` against the official Manifest V3 documentation. AI can sometimes generate outdated V2 code if not prompted specifically for V3.
* **Content Security Policy (CSP) Issues:**
* **Symptom:** Inline scripts or styles don't work, or network requests are blocked. Console shows CSP errors.
* **Cause:** Manifest V3 has a strict CSP. Inline JavaScript (`<script>...</script>`) and inline styles are generally disallowed.
* **Fix:** Externalize all JavaScript into `.js` files and CSS into `.css` files. Avoid `eval()` and `new Function()`.
* **Message Passing Failures:**
* **Symptom:** Popup doesn't trigger content script actions, or vice-versa. Console logs might show `undefined` responses or no messages received.
* **Cause:** Incorrect `tabId` in `chrome.tabs.sendMessage`, listener not correctly set up (`chrome.runtime.onMessage.addListener`), or message structure mismatch.
* **Fix:** Verify `tabs[0].id` is correctly passed. Ensure `action` types match between sender and receiver. Use `console.log` in both `popup.js` and `content.js` to trace message flow.
* **DOM Manipulation Quirks:**
* **Symptom:** Highlighting breaks page layout, affects interactive elements, or misses text.
* **Cause:** Directly modifying complex DOM structures can be tricky. Shadow DOM, iframes, and dynamically loaded content require special handling.
* **Fix:** Be cautious with broad DOM changes. Test on various sites. Consider using more targeted selectors. For iframes, you might need to inject content scripts into each iframe. AI might provide a general solution which needs refinement for specific edge cases.
* **AI Tool Hallucinations/Outdated Information:**
* **Symptom:** AI generates code that looks plausible but uses deprecated APIs, incorrect syntax, or non-existent methods for Chrome extensions.
* **Cause:** AI models are trained on vast datasets and might not always have the most up-to-date or specific knowledge for niche areas like Chrome Extension APIs, especially with recent changes like Manifest V3.
* **Fix:** Always critically review AI-generated code. Cross-reference with official Chrome Extension documentation. Use specific prompts (e.g., "Manifest V3," "using `chrome.storage.sync`").
## Next Steps
Congratulations on building your first AI-assisted Chrome extension! This is just the beginning. Here are some areas to explore next:
* **Background Scripts (Service Workers):** For persistent tasks that don't require a UI, learn about service workers in Manifest V3. These replace traditional background pages and handle events like network requests, alarms, and context menu clicks.
* **Advanced API Integration:** Integrate your extension with external APIs (e.g., weather services, productivity tools, or even a real LLM API like OpenAI or [Gemini](/comparisons/chatgpt-vs-claude-vs-gemini-for-coding-best-ai-in-2026/) for more complex text processing).
* **UI Frameworks:** For more complex popups or options pages, consider using front-end frameworks like React, Vue, or Svelte. You can use build tools (Webpack, Parcel) to bundle these into your extension.
* **Internationalization (i18n):** Make your extension accessible to a wider audience by supporting multiple languages using Chrome's i18n API.
* **Publishing to the Chrome Web Store:** Learn the process of packaging, submitting, and maintaining your extension on the official Chrome Web Store, including handling developer accounts and review processes.
* **Exploring More AI Tools:** Experiment with different AI coding assistants. Each has its strengths and weaknesses. Some excel at boilerplate, others at refactoring, and some are better for deeper architectural suggestions.
* **Local AI Models:** Investigate using client-side AI models (e.g., via TensorFlow.js or ONNX Runtime) directly within your extension for privacy-focused or offline AI features, without relying on external API calls.
## Recommended Reading
*Deepen your skills with these highly-rated books. Links go to Amazon — as an affiliate, we may earn a small commission at no extra cost to you.*
- [JavaScript: The Good Parts](https://www.amazon.com/s?k=javascript+good+parts+crockford&tag=devtoolbox-20) by Douglas Crockford
- [Eloquent JavaScript](https://www.amazon.com/s?k=eloquent+javascript+haverbeke&tag=devtoolbox-20) by Marijn Haverbeke
- [Building Browser Extensions](https://www.amazon.com/s?k=building+browser+extensions+frisbie&tag=devtoolbox-20) by Matt Frisbie