Chrome extension is not loading on browser navigation at YouTube

Let's say I have an extension that loads when you arrive at a YouTube video page.I have noticed that when one navigates back and forth using the Chrome buttons, the extension most probably won't load.

As an example, I have 2 files, the manifest:

{
    "name": "back forth",
    "version": "0.1",
    "manifest_version": 2,
    "description": "back forth",
    "permissions": ["storage", "*://www.youtube.com/watch*"],
    "content_scripts": [
        {
            "matches": ["*://www.youtube.com/watch*"],
            "js": ["contentscript.js"]
        }
    ]
}

and the contentscript

alert("loaded");

The alert does not always show up when navigating back and forth. How can I overcome this, so that the extension loads every time?


Solution 1:

YouTube has started a trial with pushState-based navigation. In general, such navigations can only be detected within content scripts by injecting code that intercept calls to history.replaceState / history.pushState (or by using the chrome.webNavigation.onHistoryStateUpdated event in the background page).

The remainder of this answer is specific to YouTube.
YouTube shows a (red) progress bar on top of the page during load. This progress bar is animated using a CSS transition. Since transition events bubble, you can bind a transition event listener to <body>, and check navigation in these cases.

You have to insert your content script at *://www.youtube.com/* instead of *://www.youtube.com/watch*, because pushState can be used to navigate from / to /watch...

function afterNavigate() {
    if ('/watch' === location.pathname) {
        alert('Watch page!');
    }
}
(document.body || document.documentElement).addEventListener('transitionend',
  function(/*TransitionEvent*/ event) {
    if (event.propertyName === 'width' && event.target.id === 'progress') {
        afterNavigate();
    }
}, true);
// After page load
afterNavigate();

Note: This method depends on the fact that the progress bar is inserted. Whenever Google decides to rename the ID of the progress bar, or remove the progress bar altogether, your code will cease to work.

Note 2: This only works for active tabs. If you need to detect navigation changes while the tab is not focused, then you need to bind a window.onfocus and window.onblur event, and check whether document.title has changed between these events.