How to check if the user can go back in browser history or not
Asked Answered
N

29

214

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.

Neon answered 27/8, 2010 at 21:38 Comment(2)
related #19417584Tartary
If your purpose is to check goback is work, I think you can setup a timer after the goback call ... so you can redirect to a fallback link if the goback not work.Polygynous
M
158

Short answer: You can't.

Technically there is an accurate way, which would be checking the property:

history.previous

However, it won't work. The problem with this is that in most browsers this is considered a security violation and usually just returns undefined.

history.length

Is a property that others have suggested...
However, the length doesn't work completely because it doesn't indicate where in the history you are. Additionally, it doesn't always start at the same number. A browser not set to have a landing page, for example, starts at 0 while another browser that uses a landing page will start at 1.

alt text

Most of the time a link is added that calls:

history.back();

or

 history.go(-1);

and it's just expected that if you can't go back then clicking the link does nothing.

Meimeibers answered 27/8, 2010 at 22:0 Comment(6)
This is good info, but it does not resolve the problem. It'd be to elaborate some code that actually works on any browser. Perhaps a code that first checks the browser you are using.Plier
What I'm saying is that there is not a definitive answer. You are saying the pros and cons of each approach but not how to get a script that checks what browser you are using and conditionally execute one or the other pieces of code.Plier
May I know what do you mean by 'The problem with this is that in most browsers this is considered a security violation' Another user in another thread also pointed that being able to get client's browser history is violating the security, but doesn't explain why is that. Can anyone give some example what are the security threats?Handbook
A website shouldn't be able to know a user's history which could include indirect personal information. A site can use tracking/cookies to know what the user is doing on the site itself but they shouldn't, for example, be allowed to figure out what bank I use, which school my kids go to, etc... Therefore, the browsers won't allow access to that propertyMeimeibers
I have added an way to detect it using the history state, it allows you to detect if you are on the first url stateLeaves
TL;DR version: history.length > 1 ? history.back() : location.href='/';Twohanded
T
106

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()
}
Triggerfish answered 4/10, 2011 at 16:47 Comment(11)
Referrer can be hidden for privacy reasons.Ru
The referrer is always empty when a page was not loaded by a link but by entering the URL into the address bar, or loading a bookmark. Such pages can sure have a history though, when the browser tab/window had loaded another page before!Lucky
But is applicable solution for navigation across the multipage websiteSchrecklichkeit
Does not work if a window was opened with target="_blank" to force a new window. The back button on the browser won't work, but there will be a document.referrerGantz
or if i right click and open it in new window. The browser's back button is disabled, but the document.refererr points to the previous pageImprovement
Works perfectly for redirecting from an iOS shortcut that isn't a web app.Beefy
This will not work if you are coming from a secure (HTTPS) page to an insecure page (HTTP), as that will strip the referrer.Darmit
window.close() is considered a security risk by many modern browsers. Some just wont let you do it. Better to redirect to a fall-back URL.Nippy
Referrer is passed if browser tab is opened via target="_blank" link.Diagnostics
that's a good idea. I ended up with server side $_SERVER['HTTP_REFERER']Cappuccino
No it is not working. it's always empty for my use cases. There is history for the current website and the user navigates within the same site. The referrer is still empty.Receptacle
S
74

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);
}
Stanger answered 5/6, 2014 at 9:41 Comment(5)
I think this really nails the heart of the question, the why a person cares and what can actually be done about it in a reliable manner and consistent.Dignity
This worked until I took the url where the back-button resides and pasted it in a new tab in chrome. Clicking on the back-button resulted in being sent to an empty tab. :(Schaeffer
That's Chrome's default behaviour. You "visited" the page chrome://newtab and thus you can go back in history.Stanger
Careful with this because with a slow network connection you will hit the fallback url pretty regularly.Radiograph
If you use this and you also prompt the user before leaving the page and the user opts to stay on the current page, the user will see the prompt twice (when there is history to return to). window.history.go(-1) will prompt them and they will cancel. Then the timeout will fire and ask them again. I haven't found a way to resolve this.Deform
C
26

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).

Ceuta answered 27/8, 2014 at 10:33 Comment(2)
This is by far the best answer to the question. You can easily replace window.location.href = fallback with window.close() and it works too.Honea
This doesn't work with modern web apps, since browser back doesn't necessarily unload the page.Nevins
C
20

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.

Chalfant answered 15/4, 2016 at 11:21 Comment(4)
This approach worked great for me. I actually store static fallback back links for my pages that I use on the fallback.Heliopolis
But, if you go back, the history.length won't change.. So, it doesn't work properlyRegality
Your're right, unfortunately. I use this snippet with "one-step-back" structure only…Chalfant
This is incorrect. For example, if you open a tab by middle-clicking a link, the new tab won't have any history.Nevins
C
19

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.

Cognizance answered 16/5, 2013 at 6:1 Comment(5)
I've found this doesn't work unless I use a setTimeout with a delay of a few hundred milliseconds or so before trying to run the next statement, otherwise it'll run anyway after running history.back()Incentive
I haven't experienced that personally, which browser was it?Cognizance
I had worked fine with setTimeout function in below answer. ex: setTimeout(function() { window.close() }, 400);Bonkers
window.close() is considered a security risk by many modern browsers. Some just wont let you do it.Nippy
you can do anything after window.history.back(); window.close(); is just an examplePescara
S
19

Be careful with window.history.length because it also includes 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()

Starlin answered 22/1, 2016 at 14:43 Comment(0)
I
10

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.

Individuation answered 27/8, 2010 at 21:55 Comment(3)
regarding length - not even then in all browsers. Some browsers count the current page as a history item and start at 1. You'd have to include browser detection.Meimeibers
Actually I thought it was always 1! The 0 was a brainfart, I thought browsers would always respond with 1 or more. Turns out Opera and IE think otherwise—good catch.Individuation
"History navigation is for browser chrome, not web pages" - AgreedArte
C
5

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);
Clog answered 23/12, 2014 at 14:27 Comment(1)
Works for me like this: function goBackOrTo(targetUrl){ var currentUrl = window.location.href; window.history.go(-1); setTimeout(function(){ // if location was not changed in 800 ms, then there is no history back if(currentUrl === window.location.href){ // redirect to site root window.location.href = targetUrl; } }, 800); }Endaendall
C
5

There are two properties in Navigation API that might help with it, but they are currently experimental.
canGoBack: https://developer.mozilla.org/en-US/docs/Web/API/Navigation/canGoBack
canGoForward: https://developer.mozilla.org/en-US/docs/Web/API/Navigation/canGoForward

Centime answered 5/4, 2023 at 6:19 Comment(0)
F
3

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();
}
Fca answered 17/6, 2019 at 12:45 Comment(0)
A
3

This work for me using react but can work in another case; when history is in the first page (you cannot go back) window.history.state will be null, so if you want to know if you can navigate back you only need:

if (window.history.state == null) {
   //you cannot go back
}

Documentation:

The History.state property returns a value representing the state at the top of the history stack. This is a way to look at the state without having to wait for a popstate event.

Arborvitae answered 14/10, 2021 at 14:32 Comment(0)
P
3

The following solution will navigate back AND will tell if the navigation occurred or not:

async function goBack() {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => reject('nowhere to go'), 100);
    window.history.back();
    const onBack = () => {
      window.removeEventListener('beforeunload', onBack);
      window.removeEventListener('popstate', onBack);
      clearTimeout(timer);
      resolve(true);
    };
    window.addEventListener('beforeunload', onBack);
    window.addEventListener('popstate', onBack);
  });
}

// usage
await goBack().catch(err => console.log('failed'));

How it works:

  1. Try to navigate back
  2. Add event listeners that will trigger on navigation to another website or to another page on the same site (SPA website, etc.)
  3. If above events didn't occur in 100ms, deduce that there's nowhere to go back to

Notice that goBack() is an async function.

Protest answered 12/10, 2022 at 16:59 Comment(0)
L
2

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() 
Leaves answered 30/6, 2020 at 13:30 Comment(1)
I don't think there is other good use case. Maybe isn't an good idea If you want to check the history outside your app.Leaves
M
1

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").

Mireille answered 6/9, 2016 at 10:3 Comment(1)
I like this the most, I just changed windows.onbeforeunload to event listener window.addEventListener("beforeunload", function (event) { useFallback = false; }); so it doesn't overwrite window.onbeforeunload.Schottische
A
1

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.

Amice answered 31/10, 2017 at 10:29 Comment(0)
N
0

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.

Neigh answered 4/5, 2017 at 6:0 Comment(0)
F
0

I am using window.history in Angular for the FAQ on my site.

Whenever the user wants to exit the FAQ they can click the exit button (next to the back button)

My logic for this "exit" strategy is based on the entry ID and then just go back the number of states till that state.

So on enter:

  enterState: { navigationId:number } = {navigationId: 1}

  constructor() {
    this.enterState = window.history.state
  }

pretent the user navigates through the faq

And then, when the user clicks the exit button, read the current state and calculate your delta:

exitFaq() {
    // when user started in faq, go back to first state, replace it with home and navigate
    if (this.enterState.navigationId === 1) {
      window.history.go((window.history.state.navigationId - 1) * -1)
      this.router.navigateByUrl('/')
      //  non-angular
      //  const obj = {Title: 'Home', Url: '/'}
      //  window.history.replaceState(obj, obj.Title, obj.Url)
    } else {
      window.history.go(this.enterState.navigationId - window.history.state.navigationId - 1)
    }
  }

As you can see, I also use a fallback for when the user started in the faq, in that case the state.navigationId is 1 and we want to route back, replace the first state and show the homepage (For this I'm using the Angular router, but you can use history.replaceState as well when you handle your own routes)

For reference:

Forswear answered 13/5, 2021 at 7:58 Comment(0)
E
0

This might help:

const prev = window.location.pathname;
window.history.back();
setTimeout(() => {
  if (prev === window.location.pathname) {
    // Do something else ... 
  }
}, 1000);
Escent answered 17/8, 2022 at 10:46 Comment(0)
E
0

I'm using Angular, I need to check if there is history, trigger location.back(), else redirect to parent route.

Solution from https://mcmap.net/q/125748/-how-to-check-if-the-user-can-go-back-in-browser-history-or-not works well.

constructor(
    private activatedRoute: ActivatedRoute,
    private router: Router,
    private location: Location,
}
...

back(): void {
    if (window.history.state === null) {
      this.router.navigate(['../'], { relativeTo: this.activatedRoute });
      return;
    }

    this.location.back();
}
Executioner answered 5/9, 2022 at 17:33 Comment(0)
I
0

This is my solution:

function historyBack() {
  console.log('back');
  window.history.back() || window.history.go(-1);
  if (!window.history.length) window.close();
  var currentUrl = window.location.href;
  setTimeout(function(){
    // if location was not changed in 100 ms, then there is no history back
    if(current === window.location.href){
        console.log('History back is empty!');
    }
  }, 100);
}
function historyForward() {
  console.log('forward');
  window.history.forward() || window.history.go(+1);
  var current = window.location.href;
  setTimeout(function(){
    // if location was not changed in 100 ms, then there is no history forward
    if(current === window.location.href){
        console.log('History forward is empty!');
    }
  }, 100);
}
Impartial answered 20/9, 2022 at 18:47 Comment(0)
H
0

How to check if the user is at the first place of the browser history stack, then execute custom logic

Solution 1:

navigation.canGoBack can solve the problem, but the compatibility with browsers is poor.

Solution 2 (Recommended):

history.go(-1);
var timeout = 100;
var timer = setTimeout(() => {
  // If timeout occurs, execute your custom logic
}, timeout);

  // If the page is destroyed, clear the contingency plan
addEventListener('pageOnDestroy',()=>{
    window.clearTimeout(timer)
})

Angular Instance

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject, interval } from 'rxjs'
import { takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-test-page',
  templateUrl: './test-page.component.html',
  styleUrls: ['./test-page.component.scss']
})
export class TestPageComponent implements OnInit, OnDestroy {

  constructor() { }

  ngOnInit(): void {
  }
  
  destroy = new Subject();

  ngOnDestroy(): void {
    this.destroy.next(null);
  }
  goback() {
    history.go(-1);

    interval(100)
      .pipe(takeUntil(this.destroy))
      .subscribe(data => {
      // If there is no previous page, page destruction will not be triggered, close the page after timeout
      (window as any).javaobj?.close();
    });
  }
}

Helpful answered 13/3 at 8:8 Comment(0)
H
-1
var fallbackUrl = "home.php";
if(history.back() === undefined)
    window.location.href = fallbackUrl;
Hindrance answered 22/1, 2016 at 5:59 Comment(2)
this looks super easy?! is it tested on the various browsers?Tondatone
in Chrome history.back() is undefined only on empty tab pageChalfant
D
-1

I found a JQuery 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();
        }
    })
Draghound answered 18/11, 2020 at 3:37 Comment(0)
C
-1

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>
Chandachandal answered 4/2, 2021 at 16:0 Comment(0)
P
-1
var func = function(){ console.log("do something"); };
if(document.referrer.includes(window.location.hostname) && history.length-1 <= 1){
    func();
}
else{
    const currentUrl = window.location.href;
    history.back();
    setTimeout(function(){
        currentUrl === window.location.href && func();
    }, 100);
}
Proliferous answered 25/3, 2021 at 17:14 Comment(0)
C
-4

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.

Coat answered 27/3, 2019 at 20:49 Comment(0)
C
-6

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

Critic answered 27/8, 2010 at 21:44 Comment(2)
history.back is a function. You want to check if history.length > 0 then if it is go back with history.back()Ardithardme
Also [] on a NodeList makes no sense, and you can't assign a string to an event handler.Individuation
O
-9

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

Osprey answered 27/8, 2010 at 21:48 Comment(2)
Not a good way, since history.length does not tell you where you are in the history...Triggerfish
@Ron Reiter: Yes, I think the top answer and other comments for this question had already established that over a year ago...Osprey

© 2022 - 2024 — McMap. All rights reserved.