Tools
Tools: I Built a Chrome Extension to Copy URLs Faster — Here's What I Learned
2026-02-19
0 views
admin
The Idea: One Shortcut, Zero Friction ## Building It: Lessons from the Trenches ## Lesson 1: Chrome Extension APIs Are Simpler Than You Think ## Lesson 2: The Clipboard API Has Quirks ## Lesson 3: Feedback Matters More Than You Think ## Lesson 4: Size Is a Feature ## Privacy as a Core Design Decision ## The Launch: What Worked and What Didn't ## What Worked ## What Didn't Work ## Current Stats (Building in Public) ## What I'd Tell You If You're Building Your First Extension ## What's Next Every developer has that one tiny annoyance they tolerate for years before finally snapping and building something about it. For me, it was copying URLs. I know — it sounds absurd. But hear me out. I'm a developer who spends 8+ hours a day bouncing between GitHub PRs, Stack Overflow threads, Jira tickets, documentation pages, and Slack conversations. And every single time I needed to share a link, the same ritual played out: Six steps. For something I do 30-40 times a day. That's roughly 200 micro-interruptions per week — each one pulling me out of flow state for just long enough to be annoying. So one weekend, I decided to fix it. The concept was dead simple: press Ctrl+Shift+C on any page, and the current URL goes straight to your clipboard. No popup menus, no address bar interaction, no extra clicks. Just a keyboard shortcut and a brief confirmation that it worked. That's it. That's the whole product. I know what you're thinking: "Surely this already exists?" It does — sort of. But every alternative I found had at least one of these problems: I wanted something that did one thing perfectly and nothing else. If you've never built a Chrome extension, the barrier to entry is surprisingly low. At its core, you need: The manifest.json is where everything starts: Notice the permissions: just activeTab and clipboardWrite. No "<all_urls>", no "tabs", no access to browsing history or page content. Minimal permissions = maximum trust. The core logic is straightforward — listen for the command, grab the URL, write to clipboard: But here's the thing — navigator.clipboard.writeText() requires a secure context and user activation. A keyboard shortcut triggered from the background service worker doesn't always count as "user activation" in every context. The workaround? Inject a temporary textarea element, select its contents, and use the old-school document.execCommand('copy') as a fallback. It's not elegant, but it works everywhere: The first version had no visual feedback. You'd press the shortcut and... nothing visible happened. The URL was in your clipboard, but you had no confirmation. Users hated it. Even I hated it. Without feedback, you second-guess whether it worked and end up Ctrl+V-ing somewhere just to check. Adding a brief notification badge on the extension icon made a massive difference: Small detail. Huge impact on user confidence. The final extension is under 50KB. For context, many popular Chrome extensions are 2-10MB. Some are 50MB+. I obsessed over keeping it tiny because: In a world of bloated software, smallness is a competitive advantage. Here's something that genuinely bothers me about the browser extension ecosystem: the default is surveillance. Most extensions request far more permissions than they need. Many include analytics SDKs, telemetry systems, or outright tracking. Some sell browsing data to third parties. And users have largely been trained to click "Add to Chrome" without reading the permission dialog. For Copy URL, I made a deliberate choice: zero data collection. Period. The extension is entirely client-side. It never makes a network request. There's nothing to phone home to because there's no home to phone to. Is this a business disadvantage? Absolutely. I have no idea how many people use it daily, which features they'd want, or where they get stuck. But I think the tradeoff is worth it. Users shouldn't have to sacrifice privacy for a tool that copies URLs. 1. Solving my own problem first. I didn't do market research or competitive analysis before building. I scratched my own itch, and it turned out thousands of other developers had the same itch. 2. Keeping the scope microscopic. One feature. One shortcut. One action. No settings page, no options, no "premium tier." This made development fast, testing easy, and the value proposition crystal clear. 3. Writing a decent Chrome Web Store listing. I spent almost as much time on the CWS description, screenshots, and metadata as I did on the actual code. Good CWS SEO matters — most users discover extensions through search. 1. Expecting organic growth to be fast. The Chrome Web Store algorithm favors extensions with existing momentum. Getting those first 100 users is genuinely hard when you're starting from zero. 2. Underestimating the importance of the icon. My first icon was generic. Replacing it with something distinctive improved click-through rates noticeably. 3. Not having a landing page from day one. A simple website (ctrlshiftcopy.com) gave me a place to link from social media, blog posts, and directory listings. Should've had it ready at launch. Since this is a build-in-public post, here's where things stand: The growth has been gradual but steady. Most users find it through Chrome Web Store search for terms like "copy URL shortcut" or "keyboard shortcut copy link." Start absurdly small. Your first extension should do one thing. Not three things. Not "one thing with options." One thing. Request minimal permissions. Every permission you request is a reason for a user to not install. The Chrome Web Store even shows a warning for extensions with broad permissions. Keep it tight. Test on weird pages. Your extension will encounter Chrome internal pages (chrome://), PDF viewers, web store pages (where extensions are disabled), and pages with strict Content Security Policies. Handle these edge cases gracefully. Read the Manifest V3 docs carefully. If you're coming from MV2, the service worker model is different. Background pages are gone. Persistent state is gone. Plan accordingly. Ship, then iterate. I published the first version within a weekend. It wasn't perfect, but it was functional. Every improvement since then has been informed by real user feedback rather than speculation. I'm keeping the extension deliberately simple, but there are a few things on the roadmap: If you want to try it: Copy URL (Ctrl+Shift+C) on Chrome Web Store Website: ctrlshiftcopy.com Have you built a Chrome extension? What's the smallest tool you've built that you use every day? I'd love to hear about it in the comments. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK:
my-extension/ manifest.json // Extension metadata + permissions background.js // Service worker for shortcut handling content.js // Script that runs on web pages (optional) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
my-extension/ manifest.json // Extension metadata + permissions background.js // Service worker for shortcut handling content.js // Script that runs on web pages (optional) CODE_BLOCK:
my-extension/ manifest.json // Extension metadata + permissions background.js // Service worker for shortcut handling content.js // Script that runs on web pages (optional) CODE_BLOCK:
{ "manifest_version": 3, "name": "Copy URL (Ctrl+Shift+C)", "version": "1.0", "description": "Copy any page URL with a keyboard shortcut", "permissions": ["activeTab", "clipboardWrite"], "commands": { "copy-url": { "suggested_key": { "default": "Ctrl+Shift+C", "mac": "Command+Shift+C" }, "description": "Copy current tab URL" } }, "background": { "service_worker": "background.js" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "manifest_version": 3, "name": "Copy URL (Ctrl+Shift+C)", "version": "1.0", "description": "Copy any page URL with a keyboard shortcut", "permissions": ["activeTab", "clipboardWrite"], "commands": { "copy-url": { "suggested_key": { "default": "Ctrl+Shift+C", "mac": "Command+Shift+C" }, "description": "Copy current tab URL" } }, "background": { "service_worker": "background.js" }
} CODE_BLOCK:
{ "manifest_version": 3, "name": "Copy URL (Ctrl+Shift+C)", "version": "1.0", "description": "Copy any page URL with a keyboard shortcut", "permissions": ["activeTab", "clipboardWrite"], "commands": { "copy-url": { "suggested_key": { "default": "Ctrl+Shift+C", "mac": "Command+Shift+C" }, "description": "Copy current tab URL" } }, "background": { "service_worker": "background.js" }
} COMMAND_BLOCK:
chrome.commands.onCommand.addListener(async (command) => { if (command === 'copy-url') { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); // Execute script in the tab to access clipboard await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: (url) => { navigator.clipboard.writeText(url); }, args: [tab.url] }); }
}); Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
chrome.commands.onCommand.addListener(async (command) => { if (command === 'copy-url') { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); // Execute script in the tab to access clipboard await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: (url) => { navigator.clipboard.writeText(url); }, args: [tab.url] }); }
}); COMMAND_BLOCK:
chrome.commands.onCommand.addListener(async (command) => { if (command === 'copy-url') { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); // Execute script in the tab to access clipboard await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: (url) => { navigator.clipboard.writeText(url); }, args: [tab.url] }); }
}); COMMAND_BLOCK:
func: (url) => { try { navigator.clipboard.writeText(url); } catch { const el = document.createElement('textarea'); el.value = url; el.style.position = 'fixed'; el.style.opacity = '0'; document.body.appendChild(el); el.select(); document.execCommand('copy'); document.body.removeChild(el); }
} Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
func: (url) => { try { navigator.clipboard.writeText(url); } catch { const el = document.createElement('textarea'); el.value = url; el.style.position = 'fixed'; el.style.opacity = '0'; document.body.appendChild(el); el.select(); document.execCommand('copy'); document.body.removeChild(el); }
} COMMAND_BLOCK:
func: (url) => { try { navigator.clipboard.writeText(url); } catch { const el = document.createElement('textarea'); el.value = url; el.style.position = 'fixed'; el.style.opacity = '0'; document.body.appendChild(el); el.select(); document.execCommand('copy'); document.body.removeChild(el); }
} COMMAND_BLOCK:
// Show brief "Copied!" badge
chrome.action.setBadgeText({ text: '✓', tabId: tab.id });
chrome.action.setBadgeBackgroundColor({ color: '#10B981' }); // Clear after 1.5 seconds
setTimeout(() => { chrome.action.setBadgeText({ text: '', tabId: tab.id });
}, 1500); Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// Show brief "Copied!" badge
chrome.action.setBadgeText({ text: '✓', tabId: tab.id });
chrome.action.setBadgeBackgroundColor({ color: '#10B981' }); // Clear after 1.5 seconds
setTimeout(() => { chrome.action.setBadgeText({ text: '', tabId: tab.id });
}, 1500); COMMAND_BLOCK:
// Show brief "Copied!" badge
chrome.action.setBadgeText({ text: '✓', tabId: tab.id });
chrome.action.setBadgeBackgroundColor({ color: '#10B981' }); // Clear after 1.5 seconds
setTimeout(() => { chrome.action.setBadgeText({ text: '', tabId: tab.id });
}, 1500); - Move hand to mouse
- Click the address bar (or hit Ctrl+L)
- Hope the full URL is selected (spoiler: sometimes it's not)
- Click back into whatever I was doing - Bloated permissions — asking to "read and change all your data on all websites" just to copy a URL
- Unnecessary UI — popup windows, options pages, toolbar menus for a one-action tool
- Abandoned — last updated in 2019, broken on newer Chrome versions
- Bundled with other stuff — URL copying as a side feature of a 2MB extension suite - Faster installs — downloads in under a second
- Smaller attack surface — less code means fewer potential vulnerabilities
- Zero performance impact — no background processes eating RAM
- Trust signal — users can see the extension is minimal when they inspect it - No analytics pings
- No usage tracking
- No error reporting calls home
- No account system
- No server-side anything - Chrome Web Store rating: 4.9 stars (50 reviews)
- Extension size: 48KB
- Permissions requested: 2 (activeTab + clipboardWrite)
- Data collected: None
- Price: Free. No premium tier. No ads.
- Time from idea to first publish: One weekend - Markdown link format — copy as [Page Title](URL) for developers who write docs
- Multiple format options — plain URL, Markdown, HTML link, with a quick toggle
- Firefox port — the APIs are similar enough that this should be straightforward
how-totutorialguidedev.toaimlservernetworkgitgithub