Mobile Device Detection

By John Boxall


How do you detect a mobile browser?

One solution relies on inspecting the User-Agent header that a browser sends when it makes an HTTP request. In theory each browser sends an identifiable User-Agent. If we knew what browsers sent which User-Agents then we could identify the mobile browsers!

The problem is there are about a bajillion unique mobile device User-Agents and no clear way to distinguish what makes a User-Agent mobile. But what if we reversed the problem?

How do you detect a desktop browser?

At some point someone smart sat down and decided that desktop User-Agents would be predictable. Turns out most of them include the name of the desktop OS they are running inside the string. If we know what browsers include a desktop OS string then ..!

Enough talk, let's code it.
First we'll setup regular expressions to detect desktop OSs in User-Agents:

import re

RE_DESKTOP = re.compile(r"(windows|linux|os\s+[x9]|solaris|bsd)", re.I)

Next we'll pick the browser User-Agent from an HTTP request and use our regular expressions to test whether it looks like the browser is running on a desktop OS:

def is_desktop(user_agent):
  return bool(RE_DESKTOP.search(user_agent))
        
def view(request):
  user_agent = request.headers.get('HTTP_USER_AGENT', '')
  if is_desktop(user_agent):
    return desktop_response()
  else:
    return mobile_response()

Like most theories there are a few "except after c" clauses. Specifically:

Let's deal with these wrinkles:
import re

# Some mobile browsers which look like desktop browsers.
RE_MOBILE = re.compile(r"(iphone|ipod|blackberry|android|palm|windows\s+ce)", re.I)
RE_DESKTOP = re.compile(r"(windows|linux|os\s+[x9]|solaris|bsd)", re.I)
RE_BOT = re.compile(r"(spider|crawl|slurp|bot)", re.I)

        
def is_desktop(user_agent):
  """
  Anything that looks like a phone isn't a desktop.
  Anything that looks like a desktop probably is.
  Anything that looks like a bot should default to desktop.
  
  """
  return not bool(RE_MOBILE.search(user_agent)) and \
    bool(RE_DESKTOP.search(user_agent)) or \
    bool(RE_BOT.search(user_agent))

def get_user_agent(request):
  # Some mobile browsers put the User-Agent in a HTTP-X header
  return request.headers.get('HTTP_X_OPERAMINI_PHONE_UA') or \
         request.headers.get('HTTP_X_SKYFIRE_PHONE') or \
         request.headers.get('HTTP_USER_AGENT', '')

def view(request):
  user_agent = get_user_agent(request)
  if is_desktop(user_agent):
    return desktop_response()
  else:
    return mobile_response()
This code is used to display an image of a desktop or phone below.


Looks like you're browsing on a ...

Desktop!

desktop

Your User-Agent (grabbed from the HTTP_USER_AGENT):

CCBot/2.0 (http://commoncrawl.org/faq/)

Doesn't look right?




This is really just the tip of the iceberg of browser detection. Interesting leads:

In the end your method of detection depends on your website. Accept the fact that with User-Agent detection logic there will always be some browsers that slip through the cracks. Decide whether it's worse to show a mobile view to your desktop users or a desktop view to your mobile users and try to do the least amount of damage.

Thanks to Rob Manson for the inspiration!
The code is available on GitHub - forks away!


March 31st Update:

This algorithm has been run against the two hundred and thirty two unique User-Agent strings that have so far visited the site. Of those fifteen were actual mobile device User-Agents, all of which were correctly identified by the updated algorithm. Seven non-mainstream bots and scrapers were misidentified as mobile.


Resources:


View Comments