Detect Back Button in Navigation Guards of Vue-Router

As stated by @Yuci, all the router hook callbacks are performed before popstate is updated (and therefore not helpful for this use case)

What you can do:

methods: {
    navigate(location) {
        this.internalNavigation = true;
        this.$router.push(location, function () {
            this.internalNavigation = false;
        }.bind(this));
    }
}
  1. Wrap 'router.push' with you own 'navigate' function
  2. Before calling router.push, set 'internalNavigation' flag to true
  3. Use vue router 'oncomplete' callback to set internalNavigation flag back to false

Now you can check the flag from within beforeEach callback and handle it accordingly.

router.beforeEach((to, from, next) => {
  if ( this.internalNavigation ) {
      //Do your stufff
  }
  next()
})

This is the only way that I've found:

We can listen for popstate, save it in a variable, and then check that variable

// This listener will execute before router.beforeEach only if registered
// before vue-router is registered with Vue.use(VueRouter)

window.popStateDetected = false
window.addEventListener('popstate', () => {
  window.popStateDetected = true
})


router.beforeEach((to, from, next) => {
  const IsItABackButton = window.popStateDetected
  window.popStateDetected = false
  if (IsItABackButton && from.meta.someLogica) {
    next(false) 
    return ''
  }
  next()
})

Slight improvement to @yair-levy answer.

Wrapping push to own navigate method is not convenient because you usually want to call push() from various places. Instead, router original methods can be patched in one place without changes in remaining code.

Following code is my Nuxt plugin to prevent navigation triggered by back/forward buttons (used in Electron app to avoid back caused by mouse additional "back" button, which makes mess in Electron app) Same principle can be used for vanilla Vue and to track common back button together with your custom handling.

export default ({ app }, inject) => {
  // this is Nuxt stuff, in vanilla Vue use just your router intances 
  const { router } = app

  let programmatic = false
  ;(['push', 'replace', 'go', 'back', 'forward']).forEach(methodName => {
    const method = router[methodName]
    router[methodName] = (...args) => {
      programmatic = true
      method.apply(router, args)
    }
  })

  router.beforeEach((to, from, next) => {
    // name is null for initial load or page reload
    if (from.name === null || programmatic) {
      // triggered bu router.push/go/... call
      // route as usual
      next()
    } else {
      // triggered by user back/forward 
      // do not route
      next(false)
    }
    programmatic = false // clear flag
  })
}