Articles index

Safari forgets your history

November 21 2021 by Jeff Johnson
Support this blog: StopTheMadness, Tweaks for Twitter, StopTheScript, Link Unshortener, PayPal.Me

Clicking a link in a web browser changes the URL, and if you look at the browser's history after clicking, you'll see both the old URL and the new URL. The URL can also be changed programmatically, using the JavaScript Location API. After a new location is assigned in JavaScript, you should also see the old URL and the new URL in the browser's history. You should, and you do in Chrome and Firefox. But not in Safari! For some reason, Safari forgets the URLs. This bug appears to be many years old: it occurs in the latest version 15.1, and it occurs in the oldest version that I could test, Safari 11 on macOS 10.13 High Sierra. You can reproduce the bug by simply clicking the button below. The button runs a little script to change the location from my blog to my business web site.

Here's the code for the button:

<div>
<button id="mybutton1" type="button">
Change location
</button>
</div>

<script>
function MyClick1(event) {
  location = "https://underpassapp.com";
}
document.getElementById("mybutton1")
.addEventListener("click", MyClick1);
</script>

After you press the button, press ⌘Y to open the browser's history.

Chrome History

Firefox History

Safari History

As you can see, Safari is confused. Instead of the expected two history entries, there's one history entry with the new page title and the old page URL! Even stranger, the back button has the correct old page title.

Safari back button

Safari's behavior is the same regardless of whether I use location or location.href or location.assign() with either the window or document object.

My theory is that Safari history is trying (and failing) to do some kind of click detection. The behavior is a bit different (but still buggy) if we separate the button click and the JavaScript redirect by 1 second.

The code for this button:

<div>
<button id="mybutton2" type="button">
Delayed change
</button>
</div>

<script>
function MyClick2(event) {
  setTimeout(function() {
    location = "https://underpassapp.com";
  }, 1000);
}
document.getElementById("mybutton2")
.addEventListener("click", MyClick2);
</script>

The result is that there's still only one history entry, but it has the new URL rather than the old URL.

Safari History

If you want to see how this Safari bug plays out in "the real world" as opposed to just my contrived test, take a look at your history after searching the web with DuckDuckGo. Below you can see that I've clicked on a DuckDuckGo search result, but the new URL is missing from my Safari History.

DuckDuckGo History

The explanation is that DuckDuckGo, like many search engines, "clickjacks" your search results. (Despite its "saintly" reputation, DuckDuckGo is still in the business of selling ads.) When you click on a DuckDuckGo link, the click is canceled, analytics are collected, and then you're redirected via JavaScript to the destination URL.

By the way, if you want to stop clickjacking by DuckDuckGo and other search engines, just install my browser extension StopTheMadness. Here's the Safari history with clickjacking stopped.

DuckDuckGo History with StopTheMadness

Support this blog: StopTheMadness, Tweaks for Twitter, StopTheScript, Link Unshortener, PayPal.Me

Articles index