How to get notified about changes of the history via history.pushState? How to get notified about changes of the history via history.pushState? javascript javascript

How to get notified about changes of the history via history.pushState?


5.5.9.1 Event definitions

The popstate event is fired in certain cases when navigating to a session history entry.

According to this, there is no reason for popstate to be fired when you use pushState. But an event such as pushstate would come in handy. Because history is a host object, you should be careful with it, but Firefox seems to be nice in this case. This code works just fine:

(function(history){    var pushState = history.pushState;    history.pushState = function(state) {        if (typeof history.onpushstate == "function") {            history.onpushstate({state: state});        }        // ... whatever else you want to do        // maybe call onhashchange e.handler        return pushState.apply(history, arguments);    };})(window.history);

Your jsfiddle becomes:

window.onpopstate = history.onpushstate = function(e) { ... }

You can monkey-patch window.history.replaceState in the same way.

Note: of course you can add onpushstate simply to the global object, and you can even make it handle more events via add/removeListener


Finally found the "correct" way to do this! It requires adding a privilege to your extension and using the background page (not just a content script), but it does work.

The event you want is browser.webNavigation.onHistoryStateUpdated, which is fired when a page uses the history API to change the URL. It only fires for sites that you have permission to access, and you can also use a URL filter to further cut down on the spam if you need to. It requires the webNavigation permission (and of course host permission for the relevant domain(s)).

The event callback gets the tab ID, the URL that is being "navigated" to, and other such details. If you need to take an action in the content script on that page when the event fires, either inject the relevant script directly from the background page, or have the content script open a port to the background page when it loads, have the background page save that port in a collection indexed by tab ID, and send a message across the relevant port (from the background script to the content script) when the event fires.


I do this with simple proxy. This is an alternative to prototype

window.history.pushState = new Proxy(window.history.pushState, {  apply: (target: any, thisArg: any, argArray?: any) => {    // trigger here what you need    return target.apply(thisArg, argArray);  },});