The Bug:

In the past few days, I noticed a bug I could not keep ignoring. Sometimes YouTube would randomly skip back in time during soft reloads, and whenever I would reload a video I did not finish watching, it would load noticeably earlier than the point where I stopped watching. This pissed me off so much I chose to dig into this issue as deeply as I could, with the goal of opening a ticket to Google and telling them "You have this issue, this is where the problem is, here is the fix, fix it and stop pushing slop." The resulting investigation produced something a bit less dramatic, but still quite insightful. So I decided to share.

I started off a bit too ambitious - I noticed a similar bug on Instagram which also appeared recently, and queried ChatGPT to figure out if Instagram and YouTube had anything in common in their stack. It was a long shot, and did not make much sense, but with the power of a thousand PhDs at my disposal, I figured I might as well churn some tokens and see where it leads. It thought for a while, and produced some interesting speculations... I chose to ignore all that, and narrowed my scope to the YouTube bug only.

I started messing about, changing tabs, pausing, unpausing, doing all kinds of things trying to reproduce the skip back in time behavior. It did not work. I concluded this mainly happens on soft reloads, i.e., when I watch YouTube, pause, and come back to that tab much later. I chose to assume that the main issue is not hidden in the soft reload itself, but rather in the restoration of checkpoint timestamps. So I paused a video, closed the tab, opened it - and voilà! - it restored the video quite a bit before where I paused it, 20 seconds earlier, to be precise.

I started tinkering further - I closed the tab again and reopened it - another 20-second drift.
Then I closed the whole browser and reopened it - an additional 20-second rewind.
In fact - I discovered a new YouTube hotkey; you can close the tab with Ctrl+W and reopen with Ctrl+Shift+T - this will rewind 20 seconds; do it enough times and you can easily rewind to any point in the video in case you missed something.
They should really document all their hotkeys:

  • Left Arrow for a 5-second rewind
  • H for a 10-second rewind
  • And now - Ctrl+W then Ctrl+Shift+T for a whopping 20-second rewind! - the only downside is that you need to reload the page every time :(

I also found that, for the same checkpoint, if I load it in the web browser I get the bug, but if I use the Android app for YouTube, it loads the right time, every time.
Even if I close the tab on the browser, I will get exactly the point where I left off once I open up the YouTube history on my phone, but if I reopen in my browser - I am forced to live through a strong sense of deja vu.

(After some sleep I understood what was causing the difference between the web app and the Android app behavior, but you will have to read to the end to find that out.)

Reverse Engineering:

In the world of web development, we have the privilege of having the code the developers wrote run directly in the browser, and the browser - the beast that it is - gives us a set of development tools. These tools allow us to debug any shitty code we come across when browsing the web; usually, the smelly code I choose to debug is written by me, but today, the code belonged to somebody working for a small indie company named Google.

A Note About DevTools (For Non-Web Developers)

If you are running Chrome, press F12 with a web page open. You can deep dive into what makes that page tick. You can inspect the source of HTML and the different elements, where they are located on the page, what CSS styling is applied to them, etc. You can add and remove those elements. Most importantly for our topic - you can see the JavaScript code which is being run; you can debug it, set breakpoints, and see the call stack. You can also modify everything on the page straight in those developer tools, including hacking the JavaScript.

This is very useful, because YouTube runs in the browser, and if there are bugs, you can see the code which produces them - as long as it is run on the client. (Unfortunately, some code runs on the server which we cannot access.) The main caveat is that the JS code is obfuscated, so it is a pain to debug.

I wanted to have one simple answer: how is the timestamp for the checkpoint deduced or calculated? Is it provided as is from the server? Or does it undergo any modifications on the client?
I had to know. Why? Because the developers at Google have kindly vibecoded the bug into the latest YouTube version, and I could not trust them to solve it. (I must stress that without any proof that vibecoding was applied - I have to say allegedly vibecoded. They could very well have just created this weird bug manually.) I deduced that by spelling out the solution to them, even they should be able to guide an LLM into resolving such a -complicated- issue.

I asked ChatGPT how to tackle this problem. How do I investigate something that happens as the page loads? It gave me a Tampermonkey script that attaches a handler that runs whenever the video seek happens; in other words, whenever the video jumps to another timestamp, it prints a convenient "Seek [from -> to]" message in the console. After I saw that the script works even on page reload and is triggered by the YouTube checkpoint jump, I was ready for the next step - write a debugger; line in the script whenever a video seek is triggered, and I can have a nice breakpoint with the call stack and everything I would need in order to investigate this problem.

A Note About Tampermonkey

Tampermonkey is an extension for Chrome. It allows you to inject JavaScript into the page so you can hack its behavior.

Tampermonkey is also useful when you want to understand how the page executes and which code is run. For example, if a video seek is triggered anywhere on the page, you can hook the seek function and print the timestamp it was called with. It can also set a breakpoint within the script, so you can break; within that seek and inspect the call stack - seeing the path of execution and checking how the variable for the seek timestamp was chosen.

It took me 10 minutes of going up and down an obfuscated code stack to understand exactly what I should do next - ask ChatGPT to do the debugging for me.

Good thing we're approaching singularity, because my benevolent LLM taught me that Chrome ships with a feature to open up a debugging port. Additionally, there is a nifty MCP server that I can attach to OpenCode (Claude Code for hipsters) - giving my personal PhD the capability to connect to Chrome and use DevTools in all sorts of ways, granting it complete access to violate my browser.
In other words - you press a button in Chrome, you give instructions to an LLM, and it can send commands to the browser to do anything it wants, including debugging YouTube. (Before you raise concerns about security and/or violation, you should know that any time OpenCode wants to connect to Chrome, Chrome opens up a popup asking me for permission. Everything is consensual and safe.)

A Note About MCP and Chrome Debugging

Chrome DevTools Protocol (CDP) is an API that can be used to talk to the browser in debug mode to see what is going on. It allows you to write software that talks directly to Chrome to inspect what is received over the network, read the loaded JS files, look at the page, and make modifications to the code.

If you open "chrome://inspect/#remote-debugging" in Chrome, you get a page with a checkbox that enables remote debugging. Once you enable it, external software can connect to Chrome and control it - including software used by an AI agent.

MCP (or Model Context Protocol) is a standard protocol that allows AI agents to use external tools. The Chrome DevTools MCP is a local server that exposes a set of browser debugging tools backed by CDP. When you configure OpenCode to use it, OpenCode starts or connects to that server. The agent can then call those tools, and the MCP server uses CDP to perform the actual operations in Chrome.

Conclusion:

I let GPT run for a while and do some testing, read obfuscated YouTube code, check the network to see what it receives as timestamps, and draw conclusions. This is what I found:

  1. YouTube checkpoints are received directly from the YouTube server, not from local storage or anywhere else.
  2. The checkpoint timestamp received from the YouTube server is already fucked. When you close a tab, the timestamp sent to the server is X; when you reopen the tab, the server gives X - 20 - truly a remarkable piece of engineering.

I suspect that one of two things can explain the discrepancy between YouTube in the browser and the YouTube Android app.

  • The Android app and the browser app receive different timestamps from Google servers (unlikely).
  • The Android app "knows" it gets a retarded timestamp from the server, so it fixes it on its end.

The first would imply a strange architectural decision in which the Android version of YouTube and the web version of YouTube deal with different servers and different metadata.

The second situation would constitute either an engineering decision that a braindead engineer would make, or a bug introduced by something that may reduce us all to paperclips in the future.

You be the judge of what might have happened there.

Conclusion Updated:

After some sleep I realized there was something I overlooked - I did most of my testing by loading the page with its YouTube link. BUT! If I click on the video from my YouTube history tab (YouTube saves history of all the videos you watch), it actually redirects to the following URL - "youtube.com/videoId_&t=123s_" MOTHER FUCKERS.

Ok so let me explain why I am mad. The first part "youtube.com/videoId" identifies the video; it is a direct URL. But the last part "&t=123s" is a page parameter; it lets the browser know "hey take this variable, the application will know what to do with it." So the application receives a different timestamp from the server through its URL parameter and forwards you to where you left off. The fucking problem with this approach is twofold:

  1. It violates the single responsibility principle as the page already receives a seek timestamp from the server independently of the URL parameter. This can create bugs, and also can hide bugs (as we saw). The hidden bug in this case is the fact that the checkpoint timestamp from the standard resume path causes the 20-second rewind.
  2. If the page soft reloads, it will actively ignore the stored checkpoint on the server and go to the timestamp provided by the URL.

So the following thing happens to me a lot:

  1. I watch a video for like 20 minutes.
  2. I close the video.
  3. I open the video after a while - URL timestamp 20min, checkpoint timestamp 20min.
  4. I watch the video for another 20 min. I pause the video - URL timestamp remains 20min, checkpoint sent to the server = 40min.
  5. I close the laptop, go work in a cafe, come back home.
  6. I start watching the video again on the tab - because the tab is stale it reloads the URL.
  7. It receives checkpoint at 40min (minus the 20-second bug), but the URL still reads 20min, so it sends me back in time.
  8. I open a bug report to YouTube.

The timestamp in the URL is good for one thing - to share videos with timestamps to friends. Reloading videos from history should rely on the checkpoint mechanism that is already in place. It should not load the fucking time parameter within the YouTube URL, exactly because shit like above happens. The URL timestamp was never designed as the standard video resume path, and changing it created the kind of wonderful user experience previously only Microsoft could provide.

Extra Notes Just for Fun:

  1. I could hardly call it a thorough investigation. While every word I wrote in this article's initial draft was mine, my investigation was as thoroughly conducted as the code review for YouTube's latest update. I vibe debugged with DevTools for the first time. In hindsight, I could have asked the LLM a few more questions just to make sure the conclusions were correct, so in case I was full of shit - I apologize for any mistake I have made.
  2. I prioritized speed and humor over accuracy. I do not have any beef with Google, and I think, in general, they are doing a reasonable job. I also produce retarded bugs when I rely on AI too much, so I allow myself to call them out when I see them. There is also a chance I did a retarded investigation in the first place, leading me to equally retarded conclusions. I expect both the readers and the people at Google who might stumble upon this to read everything as satire, not as a strong stance or an indication of how I perceive Google, AI, or anything else.
  3. In the bug report I opened to YouTube, I used a nicer set of words.