Making a Simple Chrome Extension in 2020 to Copy URLs from Open Tabs

• ~1,000 words • 6 minute read

I recently released a Chrome extension called Copy Open Tab URLs in a feeble effort to make my browser tab situation a little more manageable. All it does is copy the URLs of all my open tabs to the clipboard. This is useful for my personal workflow and gives me enough peace of mind to close all these tabs as they accrue.

There are lots of extensions that more or less do what mine does. I made my own because:

  1. I recently finished a batch at the Recurse Center and my brain is still in this joyful computing state. I feel reacquainted with my curiosity and I like making things—even simple things—and feel at my best when I'm chasing this curiosity.

  2. I don't really trust any of the other extensions to not track me or do other weird things, nor do I really trust the vetting process going on at the Chrome Web Store. The script I ended up writing to accomplish this was 795 bytes. The smallest extension I saw offhand was 18kb. What the hell?

The last time I made a proper extension for the Chrome Web Store was probably close to a decade ago. I had to relearn the ins-and-outs of creating and deploying an extension.

The good news? Not a lot has changed in that time!

This is also the bad news. Or at least, frustrating news.

The Fun Parts

If you enjoy web development and have never made a Chrome extension I encourage you to give it a try. It's kind of fun! You don't have to worry about cross-browser JavaScript compatibility, which is admittedly becoming less of an issue by the day, but still nice.

It's also fun to write JavaScript that can somewhat step outside of the traditional webpage paradigm and do "unsafe" things and slightly terrifying things in the browser, like have awareness of all the pages the user is looking at in the browser and be able to rewrite and interact with the DOM on each one of them, or intercept all the network traffic from any site.

Lastly, it's easy to load your extension and have it feel like a first-class citizen alongside other extensions. It's nice to not have to manage device provisioning, pay app store fees or navigate other barriers to entry if all you want to do is write an extension for your own personal use. I find this refreshing.

Biggest Hangups

The Clipboard

I wanted to use the Clipboard API because it seemed like the more modern solution to what I was trying to solve. Knowing that this extension could only work in Chrome also gave me some peace of mind that I wouldn't have to lean on polyfills or other fallbacks.

This would have worked great except you can't (seemingly) write to the clipboard without document focus. The line to write to the clipboard looked more or less like this:

await window.navigator.clipboard.writeText(listOfURLs)

However I kept getting this error when it came time to actually copy the data to the clipboard:

Uncaught DOMException: Document is not focused.

The script for the extension runs in the background and, as far as I can tell, will never have focus? I tried calling document.body.focus() but it never seemed to make a different.

Curiously though, I tried this workaround and it ended up being my solution:

  • Create a dummy textarea element
  • Change the input text to the text I want to copy
  • Select it with select() and run document.exeCommand('copy') to copy that selected text to the clipboard

This feels like a weird hack, but it seems to be the only way to achieve what I wanted. It's curious to me that this invisible process can run select() on an input element but can't give it focus. It kind of feels like a bug that this should work at all.

Another interesting takeaway from this approach: it still works even though I'm not requesting clipboard permissions in my manifest file.

One downside to this approach is that technically this is synchronous and blocking, but I don't think that really matters in this context as the extension runs in its own process anyway. Also, how "blocking" could a text copy operation in the browser really be, in practice?

Screenshots, Icons & Promo Images

Once I figured out a workaround for the clipboard the script was basically done. I spent most of my time after that navigating the idiosyncrasies of deploying to the Chrome Web Store.

The images for the icon, screenshots and promo tiles needed to be very specific dimensions:

  • 128x128 (for the icon)
  • 1280x800 or 640x400 (for screenshots)
  • 440x280
  • 920x680
  • 1400x560

The icon needed to be exactly 128x128 to appear in the web store. I originally had one that was 256x256. Chrome will scale this down in usage and it worked fine, but the store just ignores it completely, which was confusing at first. Once I resized it to 128x128 it appeared correctly in the store.

This extension didn't really lend itself to screenshots but I made due. Trying to make one fit the 1400x560 promo tile size was the strangest one.

Web Store Woes

The Chrome Web Store deployment experience feels broken. Or at least, extremely neglected by Google. I ran into opaque error messages uploading promo images when the problem was the file size (not dimensions). There's a link taking you to the "old" interface to do things the "new" interface can't do, like reorder your screen shots or manually upload an icon if you haven't provided one in your manifest. Judging from the styling on those pages the "old" interface might be circa 2008 or 2009.

All in all, very strange for something that seems like a significant part of the Chrome ecosystem.

Dilapidating Documentation

Like I said, for something that's so seemingly integral to the Chrome ecosystem, I'm surprised by the state of the documentation. It's not so much that it's incomplete or poorly designed. Rather it's just clearly unmaintained to the point where it's starting to feel a little abandoned.

This page, despite maybe feeling a little long in the tooth, is fine and thorough:


The Chrome API documentation is similarly okay, though a far cry from the general quality of the MDN web docs:


However the video at the bottom of that page is from 2009 and the latest versions of Chrome referenced in the table are all close to 12+ versions behind as of this writing—I'm seeing Chrome 69 as the latest version in the table and am currently running version 81. Maybe nothing has changed since then, but it feels like a bit of a red flag.

Overall it feels neglected, even though I know it's not, which gives me pause.

The sample extensions page has some problems as well:


Many of the links on that page produce nothing when you click on them, like the accessibilityFeatures API, perhaps ironically, and events. The example code that is present is helpful and useful to learn from, but individual files in the extension are linked to directly in a confusing way. You can download a zip file for the entire sample project and peruse by clicking the title of the example, but it feels a little weird to not see this on GitHub or some such thing.

In Review

It was fun to get reacquainted with the Chrome APIs, event if it left me wondering about their long-term viability and what Google's overall strategy is here. I'm not sure I'll be making more extensions any time soon unless it's something my clients start requesting or some additional ideas come to me for something super-simple.

A quick comment on file size: I'm proud of how small the entire extension was, ultimately, at least compared to others I saw in the store. Mine came in at 4.34kb total and the next smallest one I saw was about 18kb.

To break that down:

  • The icon is 917 bytes. I ran it through Squoosh and went a little crazy optimizing it.
  • The script itself 795 byes.
  • The manifest is 445 bytes.

That's about 2.1kb. I'm not exactly sure where the other 2.2kb comes from?

Thanks for reading! If you'd like to try the plugin you can find it in the Chrome Web Store here:


You can also find the the source code here: