The Journey So Far

I’m building a web app/Chrome extension pair that allows your bookmarks to “decay” (grow old and disappear) over time; the intention is to encourage you to actually read those tabs you have open as opposed to letting them linger until your browser crashes. Now that I’ve completed the MVP for the extension, it’s time to work on the web app!


Missed another part of this project series? Check out all the Bookmark Decay posts here!


Current Progress

Once I’d completed the basics for the Bookmark Decay extension, I was ready to start the web app. My favorite part, hooray!

However, it turns out I’d made a foolish assumption - that the chrome.storage API was available to a web browser. I wasn’t going to be able to simply call chrome.storage.local.get('my-bookmark-decay-key') to grab my Bookmark Decay data! Hmm.

What Happened

Once I setup the initial Bookmark Decay webapp with Vite, I began, naturally, by fetching my existing bookmarks. Unfortunately for me, since it turns out the Storage API is strictly for extensions I’d either have to:

  1. Find a new way to store the data from the extension in a more website-accessible way
  2. Find a way to retrieve the data I’m already storing via the extension

Since I’d already completed my extension work, I thought I’d go with #2 and see how I could grab the data from the extension itself.

My failure to appropriately understand content scripts

Eugh, boy, I definitely went through some “I’m a genius no wait I’m an idiot” cycles on this one. And I definitely should’ve taken own my advice on more that one occasion. When will I learn, y’all? I got pretty far down the content scripts rabbit hole before realizing it didn’t have the tools I needed.

In the docs content scripts are described as executing in the context of the web page and having the ability to modify the DOM of the pages they’re injected into. That, in addition to having access to the Storage API, seemed to my untrained eye to be exactly what I was looking for.

It turns out that, unfortunately, I was incorrect. While there’s messaging built into content scripts, that messaging is intended to go between extensions, not from extensions to website. It sounds like content scripts are really best used for when you want to manipulate the DOM (say, insert data from the extension directly into the webpage), vs. strictly messaging.

I won’t bore you with the multitude of attempts I made here1, but suffice it to say that this is when I went back to the drawing board and started reading about my other options.

Bart Simpson carrying a cake that has 'At Least You Tried' written on it
FAIL

The real solution: background scripts (or “extension service workers”)

Unlike content scripts, service workers’ primary role is to respond to events from the page. I think I initially discounted them because, in my mind, I wasn’t interested in responding to a browser-specific event (at least, I didn’t think so at the time). However one of the events service workers can listen for is onMessageExternal - fired when a message is sent from either another extension or a website. This made service workers exactly what I needed.

Creating a service worker that listened for the onMessageExternal event and calling its associated sendMessage function in the webapp turned out to be the solution I needed. Whew/hooray!

Next Steps

Now that I can successfully retrieve my saved bookmarks from the extension, I can actually start building the Bookmark Decay webapp. Looking forward to it!

And finally: keep an eye out for a tutorial on retrieving data from an extension via a webpage - I’ve learned enough about messaging between the two that I can lay it out pretty clearly. 👍


  1. I’ll do it here! I tried multiple combinations of postMessage, sendMessage, and simple event listeners for the message event to get this to work from a content script. While sending an initial message was more or less a breeze, capturing it successfully and returning data wasn’t something I could ever get working. A lot of errors about the port being closed, or the source no longer existing plagued my existence until I discovered extension service workers. ↩︎