Responsive layouts can pass desktop Selenium tests while failing under phone-sized viewports, touch input, or mobile-only navigation. Chrome mobile emulation lets a browser test exercise those client-side branches without moving the whole test run to a physical device farm.

ChromeDriver applies mobile emulation when the browser session starts through the mobileEmulation entry in ChromeOptions. Custom device metrics keep the test independent of Chrome DevTools' named-device list, while the user-agent string and client hints keep server-side and browser-side mobile checks aligned.

Emulation is still desktop Chrome running with mobile viewport behavior. It does not reproduce device GPU performance, browser address-bar behavior, mobile OS dialogs, sensors, or every hardware API, so keep real-device coverage for release paths that depend on those boundaries.

Steps to use Chrome mobile emulation in Selenium:

  1. Choose the emulated device metrics for the test target.

    Use explicit width, height, pixelRatio, mobile, and touch values when CI runners may use different ChromeDriver builds. Named devices such as Nexus 5 depend on the device list bundled with the active driver.

  2. Create selenium-mobile-emulation-use.py with ChromeOptions and a small proof page.
    selenium-mobile-emulation-use.py
    import shutil
    from urllib.parse import quote
     
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.chrome.service import Service
     
     
    HTML = """<!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Selenium mobile emulation demo</title>
      </head>
      <body>
        <h1>Mobile layout ready</h1>
      </body>
    </html>
    """
     
     
    mobile_emulation = {
        "deviceMetrics": {
            "width": 390,
            "height": 844,
            "pixelRatio": 3.0,
            "mobile": True,
            "touch": True,
        },
        "userAgent": (
            "Mozilla/5.0 (Linux; Android 14; Pixel 8 Build/AP2A.240905.003) "
            "AppleWebKit/537.36 (KHTML, like Gecko) "
            "Chrome/148.0.0.0 Mobile Safari/537.36"
        ),
        "clientHints": {"platform": "Android", "mobile": True},
    }
     
    options = Options()
    options.add_argument("--headless=new")
    options.add_experimental_option("mobileEmulation", mobile_emulation)
     
    for browser_name in ("google-chrome", "chromium", "chromium-browser"):
        browser_path = shutil.which(browser_name)
        if browser_path:
            options.binary_location = browser_path
            break
     
    driver_path = shutil.which("chromedriver")
    service = Service(driver_path) if driver_path else Service()
     
    driver = webdriver.Chrome(service=service, options=options)
    try:
        driver.get("data:text/html;charset=utf-8," + quote(HTML))
        metrics = driver.execute_script(
            """
            return {
              title: document.title,
              viewport: `${window.innerWidth}x${window.innerHeight}`,
              screen: `${screen.width}x${screen.height}`,
              pixelRatio: window.devicePixelRatio,
              maxTouchPoints: navigator.maxTouchPoints,
              mobileUA: navigator.userAgent.includes("Mobile")
            };
            """
        )
     
        print(f"title: {metrics['title']}")
        print(f"viewport: {metrics['viewport']}")
        print(f"screen: {metrics['screen']}")
        print(f"device_pixel_ratio: {metrics['pixelRatio']}")
        print(f"max_touch_points: {metrics['maxTouchPoints']}")
        print(f"user_agent_mobile: {metrics['mobileUA']}")
    finally:
        driver.quit()

    The mobileEmulation option must be added before webdriver.Chrome() creates the session. Changing it later requires a new browser session.

  3. Run the script to confirm the emulated viewport and mobile browser signals.
    $ python3 selenium-mobile-emulation-use.py
    title: Selenium mobile emulation demo
    viewport: 390x844
    screen: 390x844
    device_pixel_ratio: 3
    max_touch_points: 1
    user_agent_mobile: True
  4. Move the mobile_emulation dictionary into the project's WebDriver fixture.
    options = Options()
    options.add_argument("--headless=new")
    options.add_experimental_option("mobileEmulation", mobile_emulation)
     
    driver = webdriver.Chrome(options=options)

    Keep the option in the shared fixture so every mobile-layout test starts with the same viewport, touch, user-agent, and client-hints behavior.

  5. Assert a mobile-specific state after opening the real application page.
    driver.get("https://app.example.com/")
     
    assert driver.execute_script("return window.innerWidth") == 390
    assert driver.execute_script("return navigator.maxTouchPoints") > 0
    assert "Mobile" in driver.execute_script("return navigator.userAgent")

    Viewport checks prove the browser session is emulated. Application checks should still assert the real mobile menu, responsive component, or page branch the test depends on.

  6. Keep real-device coverage for behavior that Chrome emulation cannot reproduce.

    Mobile emulation does not validate device GPU performance, OS-level permission prompts, camera behavior, virtual keyboard effects, or Safari-on-iOS behavior.

  7. Remove the temporary proof script after the fixture is updated.
    $ rm selenium-mobile-emulation-use.py