DEV Community

Roman Builder
Roman Builder

Posted on

I Built a Chrome Extension to Copy URLs Faster — Here's What I Learned

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:

  1. Move hand to mouse
  2. Click the address bar (or hit Ctrl+L)
  3. Hope the full URL is selected (spoiler: sometimes it's not)
  4. Ctrl+C
  5. Click back into whatever I was doing
  6. Ctrl+V

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 Idea: One Shortcut, Zero Friction

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:

  • 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

I wanted something that did one thing perfectly and nothing else.

Building It: Lessons from the Trenches

Lesson 1: Chrome Extension APIs Are Simpler Than You Think

If you've never built a Chrome extension, the barrier to entry is surprisingly low. At its core, you need:

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

The manifest.json is where everything starts:

{
  "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

Notice the permissions: just activeTab and clipboardWrite. No "<all_urls>", no "tabs", no access to browsing history or page content. Minimal permissions = maximum trust.

Lesson 2: The Clipboard API Has Quirks

The core logic is straightforward — listen for the command, grab the URL, write to clipboard:

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

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:

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

Lesson 3: Feedback Matters More Than You Think

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:

// 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

Small detail. Huge impact on user confidence.

Lesson 4: Size Is a Feature

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:

  • 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

In a world of bloated software, smallness is a competitive advantage.

Privacy as a Core Design Decision

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.

  • No analytics pings
  • No usage tracking
  • No error reporting calls home
  • No account system
  • No server-side anything

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.

The Launch: What Worked and What Didn't

What Worked

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.

What Didn't Work

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.

Current Stats (Building in Public)

Since this is a build-in-public post, here's where things stand:

  • 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

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."

What I'd Tell You If You're Building Your First Extension

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.

What's Next

I'm keeping the extension deliberately simple, but there are a few things on the roadmap:

  • 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

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.

Top comments (0)