How to Build a Chrome Extension for Domain Extraction
Published August 27, 2026 Β· 15 min read Β· By Domain Extractor Team
We get asked all the time whether we have a Chrome extension. The short answer today is not yet β the browser tool works great, and we're waiting to make sure the extension solves a real problem beyond convenience. But the whole thing is a small enough project that you can build your own in a couple of hours. This tutorial shows how, using the same extraction algorithm the tool at domainextractoronline.com uses.
What we're building
A minimal Chrome extension that, when you click its toolbar icon on any page, shows a popup listing every unique domain referenced by that page's HTML. Copy-to-clipboard and CSV export included.
Total code: about 200 lines across four files. No build step. Manifest V3, so it will be accepted by the Chrome Web Store today (Chrome removed Manifest V2 support in June 2025).
Prerequisites
- Chrome (or any Chromium-based browser: Edge, Brave, Arc, Opera)
- A text editor
- Basic JavaScript
- Optional: a Chrome Web Store developer account ($5 one-time) for publishing
Project structure
domain-extractor-ext/
βββ manifest.json β Extension configuration
βββ content.js β Runs on each page, extracts domains
βββ popup.html β The toolbar-icon popup UI
βββ popup.js β Handles popup interactions
βββ icon16.png β Toolbar icon (16Γ16)
βββ icon48.png β Extensions page icon (48Γ48)
βββ icon128.png β Web Store icon (128Γ128)
Step 1 β The manifest
manifest.json tells Chrome what your extension is and what it's allowed to do:
{
"manifest_version": 3,
"name": "Domain Extractor",
"version": "1.0.0",
"description": "Extract every unique domain referenced by the current page.",
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
}
},
"icons": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
},
"permissions": ["activeTab", "scripting"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_idle"
}
]
}
Key choices:
activeTabgives permission to interact with the currently-active tab only when the user clicks the extension icon. This is much less invasive than requesting<all_urls>upfront and users are more likely to install it.scriptinglets the popup ask Chrome to execute code in the tab.content_scriptsauto-injectscontent.jsinto every page so it's ready when the popup opens. If you want to be more conservative, remove this and usechrome.scripting.executeScriptfrom the popup instead.
Step 2 β The content script
content.js runs in the page's context and scans everything visible or referenced:
// content.js β runs inside each page
(function() {
const HOSTNAME_RE = /(?:https?:\/\/)?(?:www\.)?([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}/gi;
const EMAIL_RE = /[a-zA-Z0-9._-]+@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/gi;
function extractDomains() {
// Sources to scan
const sources = [];
// 1. Href attributes
document.querySelectorAll('a[href], link[href], area[href]').forEach(el => {
sources.push(el.href);
});
// 2. src attributes
document.querySelectorAll('[src]').forEach(el => sources.push(el.src));
// 3. Visible text
sources.push(document.body.innerText);
// Extract and clean
const allText = sources.join(' ');
const found = new Set();
// Hostname matches
(allText.match(HOSTNAME_RE) || []).forEach(raw => {
const clean = raw
.replace(/^https?:\/\//i, '')
.replace(/^www\./i, '')
.replace(/[\/:?#].*$/, '')
.replace(/[.,;!?]+$/, '')
.toLowerCase();
if (clean) found.add(clean);
});
// Email domain matches
(allText.matchAll(EMAIL_RE)).forEach(m => {
found.add(m[1].toLowerCase());
});
return [...found].sort();
}
// Listen for messages from popup
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.type === 'extract') {
sendResponse({ domains: extractDomains() });
}
return true; // async response
});
})();
This is intentionally simpler than the full domainextractoronline.com engine β no PSL, no TLD validation. Add those if you need higher precision.
Step 3 β The popup
popup.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body { width: 320px; margin: 0; padding: 12px; font: 13px system-ui; }
h1 { font-size: 14px; margin: 0 0 8px; }
#list { max-height: 400px; overflow: auto; border: 1px solid #ddd; padding: 4px; }
.item { padding: 4px 6px; border-bottom: 1px solid #f1f1f1; font-family: monospace; }
.btn { margin-top: 8px; padding: 6px 10px; cursor: pointer; }
</style>
</head>
<body>
<h1>Domain Extractor</h1>
<div id="count">Scanningβ¦</div>
<div id="list"></div>
<button class="btn" id="copyBtn">Copy All</button>
<button class="btn" id="csvBtn">Download CSV</button>
<script src="popup.js"></script>
</body>
</html>
popup.js:
let currentDomains = [];
async function loadDomains() {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.tabs.sendMessage(tab.id, { type: 'extract' }, (response) => {
if (chrome.runtime.lastError) {
document.getElementById('count').textContent = 'Cannot access this page.';
return;
}
currentDomains = response.domains || [];
render();
});
}
function render() {
document.getElementById('count').textContent = `${currentDomains.length} domains`;
document.getElementById('list').innerHTML = currentDomains
.map(d => `<div class="item">${d}</div>`).join('');
}
document.getElementById('copyBtn').addEventListener('click', () => {
navigator.clipboard.writeText(currentDomains.join('\n'));
});
document.getElementById('csvBtn').addEventListener('click', () => {
const blob = new Blob([currentDomains.join('\n')], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'domains.csv';
a.click();
URL.revokeObjectURL(url);
});
loadDomains();
Step 4 β Icons
Any square PNG will work. For a placeholder, generate three sizes: 16Γ16, 48Γ48, 128Γ128. A simple magnifying glass or globe icon is fine to start. If you're publishing, invest in a real icon later β it's the first thing users see.
Step 5 β Load it in Chrome
- Open
chrome://extensions - Toggle Developer mode (top right)
- Click Load unpacked
- Select your
domain-extractor-extfolder - The extension icon appears in your toolbar. Click it on any page.
You should see a list of every domain referenced by the current page. Reload the extension after any code change from the same chrome://extensions screen.
Step 6 β Publish to the Chrome Web Store
- Sign up at Chrome Web Store Developer Dashboard ($5 one-time)
- Zip your extension folder (not the parent β the files should be at the zip root)
- Click New Item and upload the zip
- Fill in the store listing: description, screenshots (at least one 1280Γ800), a promotional tile
- Justify each permission β
activeTabandscriptingare both easily justifiable ("The extension reads the current page's DOM to extract domain names when the user clicks the icon.") - Submit for review. First review usually takes 1-3 business days.
Enhancements you might add
- PSL support: Bundle a stripped Public Suffix List and reduce to registrable domain. See our root-vs-subdomain post.
- Filter options: Toggle between "all domains" and "external only" (excluding the current site).
- Right-click menu: Add a context menu item to extract domains from selected text.
- Batch tabs: Extract from every open tab in one shot.
- Sync clipboard: Use
chrome.storage.syncto remember last extraction across devices. - Dark mode: Match the user's Chrome theme via
prefers-color-scheme.
Firefox and Edge
The extension above will work almost unchanged in Edge (same Chromium base) and Firefox (with minor manifest tweaks β browser_specific_settings). Publish to addons.mozilla.org and Microsoft Partner Center the same way.
Or just use the web tool
If you don't want to build and maintain an extension, the online tool covers 95% of the use cases:
Copy the current page's HTML into it and you get the same result as the extension above, minus the toolbar button convenience.
Further reading
- How Domain Extraction Logic Works β the algorithm behind both the extension and the online tool.
- Root Domain vs Subdomain: The Complete Guide.
- Chrome Extensions: Getting Started.
- Publishing to the Chrome Web Store.