hero-image

Missing iPad tablet web traffic?

Benjamin CB

8/22/2019 1:30 PM

User Agent iPad Analysis News

Fix mobile decrease as iOS13 rolls out

Introduction

September 2019 will herald some big changes to the world of web marketing analytics. Apple will roll out iPadOS 13 across the following iPads and with it many analytics solutions will start reporting iPad web traffic as desktop, skewing carefully crafted mobile versus desktop analysis.

  • iPad Pro (12.9-inch)
  • iPad Pro (11-inch)
  • iPad Pro (10.5-inch)
  • iPad Pro (9.7-inch)
  • iPad (sixth generation)
  • iPad (fifth generation)
  • iPad Air (third generation)
  • iPad Air 2

This blog explains why this will happen and provides a simple JavaScript tweak to fix Google Analytics and other solutions.

What's happening?

Apple iPadOS 13 includes a feature with Safari to instruct the iPad to pretend to be a Mac laptop or desktop rather than an iPad. Apple appear to be mandating an identical experience across iPad and Mac despite major differences such as the presence of a cursor. keyboard or touch screen. The feature is enabled by default in the beta versions of iPadOS 13 beta 6 and there is no reason to believe Apple will reverse the decision before production deployment. As it's buried in the Settings menu most users won't change it.

Safari_settings_in_iPadOS13_defaults
Safari settings in iPadOS 13 - defaults to Request Desktop for all web sites.

The obvious consequence of iPads pretending to be Macs is that web site analytics will report the traffic as desktop and not tablet.

There will be other side effects for web sites that seek to optimize content for tablets. Apple's own beta web site picked the wrong defaults when accessed from an iPad upgraded to the beta.

ipad5_beta_website
An iPad 5 upgraded to iPadOS 13 is treated as macOS device when it returns to the beta web site.

User-Agents

iOS 12 and earlier versions of on iPad would report the following User-Agent string when accessing web sites.

Mozilla/5.0 (iPad; CPU OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Mobile/15E148 Safari/604.1

In iPadOS 13 with desktop mode enabled the User-Agent is altered to appear as a Macintosh.

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15

The important 'iPad' sequence of characters has been removed and replaced with 'Macintosh'. Most analytics packages use the presence of the characters 'iPad' to designate web traffic from the device as iPad and therefore assign the traffic to the Tablet device category.

The Fix - Intel vs Apple

There is another way of determining if the web page is displayed on an iPad or a Macintosh. Apple use Intel graphics processors within Macintosh devices. iPad's use Apple's own graphic processors.

The Web Graphics Language (WebGL) APIs available in JavaScript offer a feature to determine the manufacturer of the graphics renderer. The following JavaScript provides the logic needed setting the boolean flag iPad to true if the web page is displayed on a device with an Apple processor (currently only an iPad).

Here's the code for an example web page that would correctly identify iPads when Desktop Mode is enabled.


<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Example Apple Device Type</title>
    <style>
        table, input { width: 100%; }
        tr td:first-child { white-space: nowrap; }
        tr td:last-child { width: 100%; }
    </style>
</head>
<body>
    <table>
        <tr>
            <td><label for="typeField">Device Type</label></td>
            <td><input type="text" id="typeField" /></td>
        </tr>
        <tr>
            <td><label for="uaField">User-Agent</label></td>
            <td><input type="text" id="uaField" /></td>
        </tr>
    </table>
    <script>

        // Returns the portion of the User-Agent which represents the family of
        // Apple products the device belongs.
        // @return iPhone, iPad or Macintosh otherwise empty string
        function getFamily() {
            var segments = /iPhone|iPad|Macintosh/.exec(navigator.userAgent);
            if (segments && segments.length > 0) {
                return segments[0];
            }
        }

        // Try getting the renderer string via the conventional debug
        // extension.
        // @return the UNMASKED_RENDERER_WEBGL parameter value.
        function getReportedRenderer() {
            var canvas = document.createElement("canvas");
            if (canvas != null) {
                var context = canvas.getContext("webgl") ||
                    canvas.getContext("experimental-webgl");
                if (context) {
                    var info = context.getExtension(
                        "WEBGL_debug_renderer_info");
                    if (info) {
                        return context.getParameter(
                            info.UNMASKED_RENDERER_WEBGL);
                    }
                }
            }
        }

        // Returns the Apple device in a form that will match Google Analytics
        // device type settings.
        // @return Tablet, Mobile, Desktop or Unknown.
        function getAppleDeviceType() {
            var family = getFamily();

            // If User-Agent reports Macintosh double check this against the
            // graphics renderer.
            if (family == "Macintosh") {
                renderer = getReportedRenderer();
                if (renderer.includes("Apple")) {
                    family = "iPad";
                }
                else if (renderer.includes("Intel")) {
                    family = "Macintosh";
                }
            }

            // Map the Apple product family to the Google device type.
            switch (family) {
                case "iPad": return "Tablet";
                case "iPhone": return "Mobile";
                case "Macintosh": return "Desktop";
                default: return "Unknown";
            }
        }

        // Get the device type.
        var deviceType = getAppleDeviceType();
        document.getElementById("typeField").value = deviceType;

        // Display the User-Agent.
        document.getElementById("uaField").value = navigator.userAgent;
    </script>
</body>
</html>

The getReportedRenderer function in the example will return 'Intel Iris OpenGL Engine' on a real Macintosh. On an iPad it'll return 'Apple GPU'. The difference in GPU manufacturer can be used to override the User-Agent.

Google Analytics

Adding the previous snippet to Google Analytics via custom dimensions is simple. Google provide a quick tutorial on custom dimensions here.

The following modified code snippet shows how to set the device type in custom dimension 1.


<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Example Apple Device Type</title>
    <script src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-Y">
    </script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag() { dataLayer.push(arguments); }
        gtag('js', new Date());

        // Create a custom_map for the dimensions. Dimension 1 is
        // device type. The value is set at the end of the page.
        gtag('config', 'UA-XXXXXXXXX-Y', {
            'custom_map': {
                'dimension1': 'devicetype',
            }
        });
    </script>
    <style>
        table, input { width: 100%; }
        tr td:first-child { white-space: nowrap; }
        tr td:last-child { width: 100%; }
    </style>
</head>
<body>
    <table>
        <tr>
            <td><label for="typeField">Device Type</label></td>
            <td><input type="text" id="typeField" /></td>
        </tr>
        <tr>
            <td><label for="uaField">User-Agent</label></td>
            <td><input type="text" id="uaField" /></td>
        </tr>
    </table>
    <script>

        // Returns the portion of the User-Agent which represents the family of
        // Apple products the device belongs.
        // @return iPhone, iPad or Macintosh otherwise empty string
        function getFamily() {
            var segments = /iPhone|iPad|Macintosh/.exec(navigator.userAgent);
            if (segments && segments.length > 0) {
                return segments[0];
            }
        }

        // Try getting the renderer string via the conventional debug
        // extension.
        // @return the UNMASKED_RENDERER_WEBGL parameter value.
        function getReportedRenderer() {
            var canvas = document.createElement("canvas");
            if (canvas != null) {
                var context = canvas.getContext("webgl") ||
                    canvas.getContext("experimental-webgl");
                if (context) {
                    var info = context.getExtension(
                        "WEBGL_debug_renderer_info");
                    if (info) {
                        return context.getParameter(
                            info.UNMASKED_RENDERER_WEBGL);
                    }
                }
            }
        }

        // Returns the Apple device in a form that will match Google Analytics
        // device type settings.
        // @return Tablet, Mobile, Desktop or Unknown.
        function getAppleDeviceType() {
            var family = getFamily();

            // If User-Agent reports Macintosh double check this against the
            // graphics renderer.
            if (family == "Macintosh") {
                renderer = getReportedRenderer();
                if (renderer.includes("Apple")) {
                    family = "iPad";
                }
                else if (renderer.includes("Intel")) {
                    family = "Macintosh";
                }
            }

            // Map the Apple product family to the Google device type.
            switch (family) {
                case "iPad": return "Tablet";
                case "iPhone": return "Mobile";
                case "Macintosh": return "Desktop";
                default: return "Unknown";
            }
        }

        // Get the device type.
        var deviceType = getAppleDeviceType();
        document.getElementById("typeField").value = deviceType;

        // Display the User-Agent.
        document.getElementById("uaField").value = navigator.userAgent;

        // Add the device type as a custom dimension to GA.
        gtag('event', 'apple', {
            'devicetype': deviceType,
        });
    </script>
</body>
</html>

Summary

We've solved the problem. At least until Apple iOS 14 changes things again!

51Degrees takes care of this sort of complexity, not just for Apple but all device and browser vendors. Far more information is available for 51Degrees to support use cases as varied as artificial intelligence, performance marketing and insights with data including device price, age, physical screen size, networks, chipsets, video and more.

Adding 51Degrees to analytics, eCommerce, DXP, CMS and other web platforms provides a future proof and low maintenance fix to keep up to date with changes on the web.

It's possible Apple may decide to reverse the default setting before iPadOS 13 ships in the coming weeks. Is anyone taking bets?

51Degrees is the world's fastest and most accurate device detection solution for your website today, tomorrow and in the future. If you'd like to find out more please contact us and we'll be happy to discuss how we can help you maximize your business potential.

51Degrees enables you to detect over 55,000 different device models; allowing you to optimize your website and increase revenue.