[javascript] How to check if the user can go back in browser history or not

I want using JavaScript to see if there is history or not, I mean if the back button is available on the browser or not.

This question is related to javascript

The answer is


Here is how i did it.

I used the 'beforeunload' event to set a boolean. Then I set a timeout to watch if the 'beforeunload' fired.

var $window = $(window),
    $trigger = $('.select_your_link'),
    fallback = 'your_fallback_url';
    hasHistory = false;

$window.on('beforeunload', function(){
    hasHistory = true;
});

$trigger.on('click', function(){

    window.history.go(-1);

    setTimeout(function(){
        if (!hasHistory){
            window.location.href = fallback;
        }
    }, 200);

    return false;
});

Seems to work in major browsers (tested FF, Chrome, IE11 so far).


You can't directly check whether the back button is usable. You can look at history.length>0, but that will hold true if there are pages ahead of the current page as well. You can only be sure that the back button is unusable when history.length===0.

If that's not good enough, about all you can do is call history.back() and, if your page is still loaded afterwards, the back button is unavailable! Of course that means if the back button is available, you've just navigated away from the page. You aren't allowed to cancel the navigation in onunload, so about all you can do to stop the back actually happening is to return something from onbeforeunload, which will result in a big annoying prompt appearing. It's not worth it.

In fact it's normally a Really Bad Idea to be doing anything with the history. History navigation is for browser chrome, not web pages. Adding “go back” links typically causes more user confusion than it's worth.


Check if window.history.length is equal to 0.


I am using a bit of PHP to achieve the result. It's a bit rusty though. But it should work.

<?php 
function pref(){ 
  return (isset($_SERVER['HTTP_REFERER'])) ? true : '';
}
?>
<html>
<body>

<input type="hidden" id="_pref" value="<?=pref()?>">

<button type="button" id="myButton">GoBack</button>

<!-- Include jquery library -->
<script> 
  if (!$('#_pref').val()) { 
    $('#myButton').hide() // or $('#myButton').remove()
  } 
</script>
</body>
</html>

Be careful with window.history.length because it includes also entries for window.history.forward()

So you may have maybe window.history.length with more than 1 entries, but no history back entries. This means that nothing happens if you fire window.history.back()


history.length is useless as it does not show if user can go back in history. Also different browsers uses initial values 0 or 1 - it depends on browser.

The working solution is to use $(window).on('beforeunload' event, but I'm not sure that it will work if page is loaded via ajax and uses pushState to change window history.

So I've used next solution:

var currentUrl = window.location.href;
window.history.back();
setTimeout(function(){
    // if location was not changed in 100 ms, then there is no history back
    if(currentUrl === window.location.href){
        // redirect to site root
        window.location.href = '/';
    }
}, 100);

this seems to do the trick:

function goBackOrClose() {  

    window.history.back();
    window.close(); 

    //or if you are not interested in closing the window, do something else here
    //e.g. 
    theBrowserCantGoBack();

}

Call history.back() and then window.close(). If the browser is able to go back in history it won't be able to get to the next statement. If it's not able to go back, it'll close the window.

However, please note that if the page has been reached by typing a url, then firefox wont allow the script to close the window.


There is a snippet I use in my projects:

function back(url) {
    if (history.length > 2) {
        // if history is not empty, go back:
        window.History.back();
    } else if (url) {
        // go to specified fallback url:
        window.History.replaceState(null, null, url);
    } else {
        // go home:
        window.History.replaceState(null, null, '/');
    }
}

FYI: I use History.js to manage browser history.


Why to compare history.length to number 2?

Because Chrome's startpage is counted as first item in the browser's history.


There are few possibilities of history.length and user's behaviour:

  • User opens new empty tab in the browser and then runs a page. history.length = 2 and we want to disable back() in this case, because user will go to empty tab.
  • User opens the page in new tab by clicking a link somewhere before. history.length = 1 and again we want to disable back() method.
  • And finally, user lands at current page after reloading few pages. history.length > 2 and now back() can be enabled.

Note: I omit case when user lands at current page after clicking link from external website without target="_blank".

Note 2: document.referrer is empty when you open website by typing its address and also when website uses ajax to load subpages, so I discontinued checking this value in the first case.


I'm not sure if this works and it is completely untested, but try this:

<script type="text/javascript">

    function goBack() {
        history.back();
    }

    if (history.length > 0) { //if there is a history...
        document.getElementsByTagName('button')[].onclick="goBack()"; //assign function "goBack()" to all buttons onClick
    } else {
        die();
    }
</script>

And somewhere in HTML:

<button value="Button1"> //These buttons have no action
<button value="Button2">

EDIT:

What you can also do is to research what browsers support the back function (I think they all do) and use the standard JavaScript browser detection object found, and described thoroughly, on this page. Then you can have 2 different pages: one for the "good browsers" compatible with the back button and one for the "bad browsers" telling them to go update their browser


I came up with the following approach. It utilizes the onbeforeunload event to detect whether the browser starts leaving the page or not. If it does not in a certain timespan it'll just redirect to the fallback.

var goBack = function goBack(fallback){
    var useFallback = true;

    window.addEventListener("beforeunload", function(){
      useFallback = false;
    });

    window.history.back();

    setTimeout(function(){
        if (useFallback){ window.location.href = fallback; }
    }, 100); 
}

You can call this function using goBack("fallback.example.org").


A solution that actually works

window.history.length == 1

This works on Chrome, Firefox, and Edge. You can use the following piece of JQuery code that worked for me on the latest versions of all of the above 3 browsers if you want to hide or remove a back button on your developed web page when there is no window history.

$(window).load(function() {
        if (window.history.length == 1) {
            $("#back-button").remove();
        }
    })

There is another way to check - check the referrer. The first page usually will have an empty referrer...

if (document.referrer == "") {
    window.close()
} else {
    history.back()
}

Building on the answer here and here. I think, the more conclusive answer is just to check if this is a new page in a new tab.

If the history of the page is more than one, then we can go back to the page previous to the current page. If not, the tab is a newly opened tab and we need to create a new tab.

Differently, to the answers linked, we are not checking for a referrer as a new tab will still have a referrer.

if(1 < history.length) {
    history.back();
}
else {
    window.close();
}

There is another near perfect solution, taken from another SO answer:

if( (1 < history.length) && document.referrer ) {
    history.back();
}
else {
    // If you can't go back in history, you could perhaps close the window ?
    window.close();
}

Someone reported that it does not work when using target="_blank" but it seems to work for me on Chrome.


I was trying to find a solution and this is the best i could get (but works great and it's the easiest solution i've found even here).

In my case, i wanted to go back on history with an back button, but if the first page the user opened was an subpage of my app, it would go back to the main page.

The solution was, as soon the app is loaded, i just did an replace on the history state:

history.replaceState( {root: true}, '', window.location.pathname + window.location.hash)

This way, i just need to check history.state.root before go back. If true, i make an history replace instead:

if(history.state && history.state.root)
    history.replaceState( {root: true}, '', '/')
else
    history.back() 

var fallbackUrl = "home.php";
if(history.back() === undefined)
    window.location.href = fallbackUrl;

the browser has back and forward button. I come up a solution on this question. but It will affect browser forward action and cause bug with some browsers.

It works like that: If the browser open a new url, that has never opened, the history.length will be grow.

so you can change hash like

  location.href = '#__transfer__' + new Date().getTime() 

to get a never shown url, then history.length will get the true length.

  var realHistoryLength = history.length - 1

but, It not always work well, and I don't known why ,especially the when url auto jump quickly.


My code let the browser go back one page, and if that fails it loads a fallback url. It also detect hashtags changes.

When the back button wasn't available, the fallback url will be loaded after 500 ms, so the browser has time enough to load the previous page. Loading the fallback url right after window.history.go(-1); would cause the browser to use the fallback url, because the js script didn't stop yet.

function historyBackWFallback(fallbackUrl) {
    fallbackUrl = fallbackUrl || '/';
    var prevPage = window.location.href;

    window.history.go(-1);

    setTimeout(function(){ 
        if (window.location.href == prevPage) {
            window.location.href = fallbackUrl; 
        }
    }, 500);
}

Solution

'use strict';
function previousPage() {
  if (window.location.pathname.split('/').filter(({ length }) => length > 0).length > 0) {
    window.history.back();
  }
}

Explaination

window.location.pathname will give you the current URI. For instance https://domain/question/1234/i-have-a-problem will give /question/1234/i-have-a-problem. See the documentation about window.location for more informations.

Next, the call to split() will give us all fragments of that URI. so if we take our previous URI, we will have something like ["", "question", "1234", "i-have-a-problem"]. See the documentation about String.prototype.split() for more informations.

The call to filter() is here to filter out the empty string generated by the backward slash. It will basically return only the fragment URI that have a length greater than 1 (non-empty string). So we would have something like ["question", "1234", "i-have-a-question"]. This could have been writen like so:

'use strict';
window.location.pathname.split('/').filter(function(fragment) {
  return fragment.length > 0;
});

See the documentation about Array.prototype.filter() and the Destructuring assignment for more informations.

Now, if the user tries to go back while being on https://domain/, we wont trigger the if-statement, and so wont trigger the window.history.back() method so the user will stay in our website. This URL will be equivalent to [] which has a length of 0, and 0 > 0 is false. Hence, silently failing. Of course, you can log something or have another action if you want.

'use strict';
function previousPage() {
  if (window.location.pathname.split('/').filter(({ length }) => length > 0).length > 0) {
    window.history.back();
  } else {
    alert('You cannot go back any further...');
  }
}

Limitations

Of course, this solution wont work if the browser do not support the History API. Check the documentation to know more about it before using this solution.