Best practices for browser version detection

Hey, I’m looking at updating travis-web to Ember 3. Having checked our analytics, I see that there are still a handful of users who visit with older versions of Internet Explorer that are no longer supported in the new major version; over a dozen in the past week :disappointed:

It’s a business decision whether it’s okay to end support for these browsers, but if we do decide to do so, I’m wondering what approaches people are using to catch unsupported browsers before they run into any exceptions caused by Javascript they can’t handle. I suppose user agent sniffing is the answer, though I’ve accumulated an aversion to that from the old days…?

This isn’t exactly an Ember-specific problem but I wanted to ask here in case anyone had any special approaches :grinning:

1 Like

I think there’s a big difference between using user agent sniffing to test for “new enough browser” vs testing for “too old browser”. Most of the abuses in the olden days were because of people only serving the best features to browsers that they identified as new enough, which then breaks in the future as more browsers gain capability (and which created an arms race among browser vendors to fake each other’s user agent strings).

But testing the user agent for specific older browsers is much safer, because those browsers are going to stay old and broken.

Some of the read-only aspects of travis-web seem like they might actually work OK for old browsers by using fastboot. Mostly this comes down to making sure all the navigation is done using real <a> tags, so that even when there’s no live ember app people can get around. For private repos, you’d probably need to do some additional work to make sure the session is available in the fastboot server.


User agent targeting is the most reliable method. Ember UserAgent exposes a service for Fastboot-enabled UA parsing. In our projects, we extend the service in our app, adding a isBrowserSupported computed property and use that in our application route beforeModel hook to short-circuit transition to a ‘sorry’ page!


yeah, thanks for the reassurance about sniffing, it makes sense that this is a different case than the nightmare scenarios of yore.

It’s definitely a dream of mine to use FastBoot for travis-web but it’s an old application with extensive extra-Ember DOM use, so it’ll be a while before we can get to it.

That looks like a useful addon, @willviles, thanks for the link! My concern in this case is that unsupported browsers won’t even get to the point of being able to execute Ember code at all. I experienced this previously when experimenting with changing the targets.js file for narrower support; an older Safari, for instance, would just show complete blankness and a parsing error! I can probably use UAParser earlier in the process (somehow?? haha), so good to know about that.

I agree, I wouldn’t use code that gets delivered in vendor.js to show the browser unsupported message, because a parser error in there can cause it to never run.

One solution is to write a dedicated checker script in public/check-browser-support.js (keeping in mind it will get no transpilation or anything, you’re authoring lowest-common-denominator javascript here) that effectively does:

if (isUnsupportedBrowser()) {
  window.location.href = '/sorry.html'

And make public/sorry.html for the message.

And put <script src="/check-browser-support.js" async> in your index.html.


I’ve opened this PR to try this out, it looks like it’ll be suitable! Now I’ll feel better about moving to Ember 3 and just generally tuning our targets.js. Thank yous!

my solution:

in app/index.html

    <div id='unsupported'>
        This browser unsupported. Please install <a href="">Google Chrome</a>
    {{content-for "body"}}


  beforeModel:  ->


'use strict';

const browsers = [
  'last 1 Chrome versions',
  'last 1 Firefox versions',
  'last 1 Safari versions'

// const isCI = !!process.env.CI;
// const isProduction = process.env.EMBER_ENV === 'production';

// if (isCI || isProduction) {
//   browsers.push('ie 11');
// }

module.exports = {