X Xerobit

Device Type Detection — Mobile, Tablet, Desktop in JavaScript

Detect whether a user is on mobile, tablet, or desktop using user agent strings, CSS media queries, and pointer media features. Includes reliable JavaScript methods and...

Mian Ali Khalid · · 4 min read
Use the tool
User Agent Parser
Parse any User-Agent string into browser, OS, device, and engine. Or detect your own. Built on the maintained ua-parser-js dataset.
Open User Agent Parser →

Device detection is needed for analytics, adaptive UX, and conditional code paths. The most reliable approach combines CSS media queries (viewport size) with pointer media features (input type) — UA sniffing is a fallback for cases that need it.

Use the User Agent Parser to analyze any device’s user agent string.

CSS media query approach (most reliable)

function getDeviceType() {
  // pointer: coarse = touch (mobile/tablet)
  // pointer: fine = mouse (desktop/laptop)
  // hover: none = no hover (touch devices)
  
  const hasTouch = window.matchMedia('(pointer: coarse)').matches;
  const canHover = window.matchMedia('(hover: hover)').matches;
  const isLargeScreen = window.matchMedia('(min-width: 1024px)').matches;
  const isMediumScreen = window.matchMedia('(min-width: 768px)').matches;
  
  if (!hasTouch && canHover) return 'desktop';
  if (hasTouch && isMediumScreen) return 'tablet';
  return 'mobile';
}

// Listen for changes (e.g., foldable phones):
const mq = window.matchMedia('(pointer: coarse)');
mq.addEventListener('change', () => {
  console.log('Device type changed:', getDeviceType());
});

User agent detection

function detectDeviceFromUA(ua = navigator.userAgent) {
  // Order matters: check tablet before mobile
  // (iPad UA contains "Mobile" in some versions)
  
  const isIPad = /iPad/.test(ua) || 
    (/Macintosh/.test(ua) && navigator.maxTouchPoints > 0); // iPadOS 13+
  
  const isTablet = isIPad || 
    (/Android/.test(ua) && !/Mobile/.test(ua)) ||
    /Tablet|tablet/i.test(ua);
  
  const isMobile = !isTablet && (
    /Mobi|Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini|Windows Phone/i.test(ua)
  );
  
  if (isTablet) return 'tablet';
  if (isMobile) return 'mobile';
  return 'desktop';
}

Viewport-based detection

// Simple viewport breakpoints (least accurate but widely used):
function getDeviceFromViewport() {
  const width = window.innerWidth;
  if (width < 768) return 'mobile';
  if (width < 1024) return 'tablet';
  return 'desktop';
}

// React hook:
import { useState, useEffect } from 'react';

function useDeviceType() {
  const [device, setDevice] = useState(() => getDeviceFromViewport());
  
  useEffect(() => {
    function handleResize() {
      setDevice(getDeviceFromViewport());
    }
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);
  
  return device;
}

// Usage:
const device = useDeviceType();
if (device === 'mobile') renderMobileLayout();

Touch capability detection

function hasTouch() {
  return (
    'ontouchstart' in window ||
    navigator.maxTouchPoints > 0 ||
    window.matchMedia('(pointer: coarse)').matches
  );
}

// Note: some laptops have touchscreens AND mouse
// hasTouch() would return true for them
// Use pointer media query for more nuance:

function getPrimaryInput() {
  if (window.matchMedia('(pointer: fine)').matches) return 'mouse';
  if (window.matchMedia('(pointer: coarse)').matches) return 'touch';
  return 'none';
}

Screen orientation detection

function getOrientation() {
  if (screen.orientation) {
    return screen.orientation.type.startsWith('landscape') ? 'landscape' : 'portrait';
  }
  return window.innerWidth > window.innerHeight ? 'landscape' : 'portrait';
}

// Listen for orientation changes:
screen.orientation?.addEventListener('change', () => {
  console.log('Orientation:', getOrientation());
});

// CSS approach:
// @media (orientation: portrait) { ... }
// @media (orientation: landscape) { ... }

Combined detection function

function getClientInfo() {
  const ua = navigator.userAgent;
  
  return {
    deviceType: getDeviceType(),          // mobile | tablet | desktop
    os: detectOS(ua),
    browser: detectBrowser(ua),
    hasTouch: hasTouch(),
    orientation: getOrientation(),
    viewport: {
      width: window.innerWidth,
      height: window.innerHeight,
    },
    pixelRatio: window.devicePixelRatio,  // Useful for image resolution
    isBotLikely: /bot|crawler|spider/i.test(ua),
  };
}

function detectOS(ua) {
  if (/iPhone|iPad|iPod/.test(ua)) return 'iOS';
  if (/Android/.test(ua)) return 'Android';
  if (/Windows/.test(ua)) return 'Windows';
  if (/Mac OS/.test(ua)) return 'macOS';
  if (/Linux/.test(ua)) return 'Linux';
  return 'Unknown';
}

function detectBrowser(ua) {
  if (/Edg\//.test(ua)) return 'Edge';
  if (/OPR\//.test(ua)) return 'Opera';
  if (/Chrome\//.test(ua)) return 'Chrome';
  if (/Firefox\//.test(ua)) return 'Firefox';
  if (/Safari\//.test(ua)) return 'Safari';
  return 'Unknown';
}

Server-side in Node.js

import UAParser from 'ua-parser-js'; // npm install ua-parser-js

app.get('/api/content', (req, res) => {
  const ua = req.headers['user-agent'] || '';
  const parser = new UAParser(ua);
  const device = parser.getDevice();
  
  // device.type: 'mobile' | 'tablet' | 'console' | 'smarttv' | undefined (desktop)
  const deviceType = device.type || 'desktop';
  
  // Serve different content by device:
  res.json({
    layout: deviceType === 'mobile' ? 'compact' : 'full',
    imageSize: deviceType === 'mobile' ? 'small' : 'large',
  });
});

Related posts

Related tool

User Agent Parser

Parse any User-Agent string into browser, OS, device, and engine. Or detect your own. Built on the maintained ua-parser-js dataset.

Written by Mian Ali Khalid. Part of the Dev Productivity pillar.