Site Logo
bad ui ux

Experience with vibe-coding a chrome extension

I’ve built a chrome extension only with AI tools. I used Cursor as my primary code editing IDE and sometimes switched to VS Code with Github Copilot. With cursor, I mostly relied on Antrophics Claude 3.7 . Overall, my general assumption was confirmed that most models only help for smaller task and aren’t (yet) capable of understanding overall concepts of an application. For me, these tools are helpful to write some boilerplate code, rename or refactor some function or write simple scripts without any side effects.

YouTube Shorts Tracking and Redirecting

I have never published a chrome extension before. I know some basic principles about the setup with a manifest.json, what the purpose of content.js and background.js is, how to send and receive messages between those and that the extension’s frontend is a basic .html and .js file. I have heared of the concept of permissions to access specific browser functionality such as storage, tabs or notification and I know that the content.js can be triggered by some matching urls. There’s probably not much more that you would need to know to get started.

The idea of the extension is to track the number of YouTube shorts that you watch for more than 1 second. It also tracks the number of shorts that you skipped. You can set up a redirect url to which you get redirected after you’ve watched a number of shorts. The default is the r/GetDisciplined subreddit after 5 shorts. Sometimes I somehow end up on YouTube shorts and I want to remind myself that I should do better with my time.

I thought that the extension would need the following:

I got started by simply telling cursor to set up my chrome extension. It added a mainfest.json and created some basic logic to notify the background.js to update the shorts watched count. It was quite capable of building a good looking ui after telling it to do so.

The content of the popup.html containing a nice chart.js chart and some other elements. All styled by Claude 3.7 in plain html, css and some javascript.
The badge of the YouTube shorts tracking extension. It shows the current # of shorts you watched in the current session.

In the manifest.json you specify the site on which the content.js should be triggered. The LLM added youtube.com/shorts/* which is the YouTube shorts url. For my testing purposes, this was fine. I always work in small iterations:

  1. Telling the LLM what to do
  2. Accepting code changes (or going back to step 1.)
  3. Reloading the chrome extension
  4. Test it directly on youtube.com/shorts/*

For my “final” version, I also tested to go to https://www.youtube.com and then click on a short, i.e. getting internally redirected1 from youtube.com to youtube.com/shorts/. In this case, the content.js script was disabled due to the restriction of the matching trigger in the manifest.json. This took me around 2 minutes to notice. After pointing it out to the LLM it was quick to correct the code and add a explanation. However, I’d expected the LLM to bring this up without me asking or testing the extension in a “real life scenario”.

The LLM letting me know what I already knew. The content script is only loaded, if the user directly navigates (or reloads) youtube.com/shorts/*.

Deeper technical concepts results in less helpful results

The most important part of the extension is to know when a short is being played, paused or skipped. When I first testet it, sometimes YouTube loaded (maybe ad) shorts in the background while I skipped a short. This resulted in another short being tracked in the stats even though I swipped only once. For this, I told the LLM to keep track of the current shorts url and add a timeout before the short is added to the statistics which it came up with a fine solution.

At one point, I had the idea to track the total seconds the user is watching shorts. I came up with the concept of sessions. In my concept, a session is the time spent watching activly, i.e. using the active tab. A session ends after 1 minute of being in the background or the short being stopped. I also wanted to show a timer in the popup.html for the current session. The implementation details for the background.js are straight forward. They feel like implementing an interface that provides a startSession and stopSession method. The rather complicated stuff is implementing a play-pause logic in the content.js. If I had to implement this, I’d try to read as much as possible online on <video>-tags and their events and look at the html of the YouTube website. Only after I have a good understanding of what kind of problems could occur and how I could address them would I start implementing this functionality. For me, it looked like the LLM is going for it right away without knowing almost anything about it. It provided me with so many wrong implementation details and completely got lost in the code. It also added more and more unorganized code, making it even more difficult to understand what’s going on. I didn’t want to give up yet so I continued with my iteration process: 1. Telling the LLM what to do, 2. Accepting code changes, 3. Reloading the chrome extension, 4. Test it directly on youtube.com/shorts/*. I didn’t even understand anymore what the LLM was doing so I simply applied its code changes and tried it in the browser just to notice that it does not work.

After half an hour I gave up on the idea of implementing the session timers.

The end

Getting rid of the session timers also brought the project to an abrupt end. I wanted to clean up the code, the LLM always added back some functionality that I wanted to add in the first place but later got rid of. When I told the LLM to add or change X it also added Y. This was of no use. Also trying to use the LLM to remove outdated / unused code was harder than I thought. It haven’t even tried to remove obvious testing code. In the end, I cleand up most of the code myself .

Releasing the extension

As always, administrative stuff takes more time than you’d expect. Creating a chrome extension developer account, adding descriptions, information on the permissions usage and adding images took me around 1 hour.

What I’ve learned

I use Cursor and other AI tools for daily programming tasks. Autocompletion, especially cursor tab , can be amazing and boilerplate code is also helpful. The main difference is that I do not use it to write specialized business logic or deeply technical stuff. It helps a lot for smaller task, improving UIs or adding tests, however, as soon as it gets too technical with too many different conditions, I write the code myself. There’s also no situation in which I’d accept the proposed code changes blindly. In this vibe-coding experiment I simply “accepted and prayed” and at some point, the LLM and I got lost in the code.

For me, LLMs are good coders, a tool to brainstorm ideas and to get “keywords” on a topic. For example, when I ask a LLM for “What should I be aware of when writing a frontend that sends user input to the backend?” , I can then open up my programmers handbook of choice and look for Input Sanitization or any other term that came up in the LLM’s response. However, there’s always a human-being involved who can adapt and think deeply on what to do next.

I believe that this reflects the opinion of many about the current state of LLMs. Probably many use it in the same way as I do. We’ll see what’s coming next. And for the YouTube Shorts Tracking extension: I plan on creating a safari implementation to support iOS mobile.


  1. YouTube is some kind of SPA. ↩︎