
Company News
Free Business Plan Upgrades for Open Source Maintainers
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.
cypress-device-emulate
Advanced tools
Mobile device emulation for Cypress — viewport, touch, device pixel ratio, user agent, and live orientation rotation, correctly cascading through CSS media queries. Chrome/Edge only.
Mobile device emulation for Cypress. cy.viewport() only resizes the app under
test — it does not flip @media (hover: none) or @media (pointer: coarse),
does not change navigator.userAgent, and does not expose the Touch API. This
plugin sets all of that correctly, by driving the Chrome DevTools Protocol
connection Cypress already has open — the same mechanism Chrome's own DevTools
Device Mode is built on.

cy.viewport() | cy.emulate() | |
|---|---|---|
| Resizes viewport | ✅ | ✅ |
@media (hover: none) / (pointer: coarse) | ❌ | ✅ |
navigator.userAgent | ❌ | ✅ |
Touch API (ontouchstart, TouchEvent) | ❌ | ✅ |
| Device pixel ratio | ❌ | ✅ |
screen.orientation + live rotation | ❌ | ✅ (cy.rotate()) |
locale / timezoneId / geolocation | ❌ | ✅ |
Chromium-based browsers only (Chrome, Edge, or Cypress's bundled Electron
browser). Firefox dropped Chrome DevTools Protocol support, so it is not
supported — cy.emulate() throws a clear error naming the detected browser if
you try.
npm install --save-dev cypress-device-emulate
Register the commands by adding this to cypress/support/e2e.js:
import 'cypress-device-emulate'
it('logs in on a Galaxy S25 and opens the mobile menu', () => {
cy.emulate('Galaxy S25')
cy.visit('https://www.saucedemo.com/')
cy.get('[data-test="username"]').type('standard_user')
cy.get('[data-test="password"]').type('secret_sauce')
cy.get('[data-test="login-button"]').click()
cy.get('[data-test="open-menu"]').should('be.visible')
})
Sets viewport, device pixel ratio, the mobile flag, touch support, user agent, and screen orientation, for a named device from the catalog or a custom descriptor.
cy.emulate('iPhone 16')
cy.emulate(customDescriptor)
Custom descriptor fields:
{ width: number, height: number }Optional maxTouchPoints: number, defaults to 5Optional locale: stringOptional timezoneId: stringOptional geolocation: { latitude: number, longitude: number, accuracy?: number }, accuracy defaults to 1cy.emulate({
viewport: { width: 410, height: 890 },
deviceScaleFactor: 3,
isMobile: true,
hasTouch: true,
userAgent: 'Mozilla/5.0 (Linux; Android 15; Pixel 9a) ...',
})
Every catalog entry also has a landscape variant, e.g.
cy.emulate("iPhone 16 landscape").
Call cy.emulate() before cy.visit() for full fidelity. It also works called
on an already-loaded page — viewport, user agent, device pixel ratio, and the
hover/pointer media queries all update immediately. The one exception is
'ontouchstart' in window, which Chromium decides at document creation and
does not flip until the page reloads:
cy.visit('/')
cy.emulate('Pixel 9') // viewport/UA/media-queries correct immediately
cy.reload() // needed only if your code checks 'ontouchstart' in window
Rotates whatever device is currently emulated, firing a real orientationchange
event and updating window.screen.orientation — not just a resize. Requires
cy.emulate() to have been called first in the same test.
cy.rotate('portrait')
cy.rotate('landscape')
For a named catalog device, this uses that device's real landscape/portrait
counterpart — the same data as the landscape catalog entries, not a naive
width/height swap. For a custom descriptor it swaps width/height, since there
is no catalog entry to look up. Calling it again with the same orientation is a
no-op.
Clears all emulation overrides and restores the configured viewport. Called
automatically after every test — CDP overrides are session-level in Chrome, not
per-test, so without this a test that never calls cy.emulate() would inherit
state left over from a previous test.
cy.resetEmulation()
To manage resets yourself instead, disable the automatic hook:
// cypress.config.js
module.exports = defineConfig({
env: { cyDeviceEmulateAutoReset: false },
})
import { devices } from 'cypress-device-emulate'
About 80 phones and tablets:
src/devices.ts).Desktop browser profiles and long-discontinued devices (BlackBerry, Kindle
Fire, old Nexus/Lumia phones) are out of scope. Every descriptor is plain data
in src/devices.ts, so adding or updating a device is a data change, not a
code change — see CONTRIBUTING.md.
Android devices are close to a real device, since real Android phones also run Chromium under Chrome. iPhone and iPad profiles get viewport, touch, user agent, and responsive CSS right, but still render in Chromium, not WebKit/Safari — Safari-only rendering quirks will not reproduce. Use this for responsive layout and touch-interaction testing, not for Safari-engine-specific bugs.
locale, timezoneId, and geolocation work the same on Chrome and Edge. On
Electron, the geolocation permission grant silently no-ops (Electron's CDP
implementation does not support the Browser.* permission domain), but this
does not matter in practice: Electron does not gate navigator.geolocation
behind the Permissions API the way Chrome does, so getCurrentPosition() still
works.
Nothing in this library is platform-specific. CI runs on Ubuntu, Windows, and macOS, on both Node 18 and 20: the full ~186-test suite under real Chrome, plus the cross-browser regression tests under Electron.
The project is licensed under the terms of the MIT license
FAQs
Mobile device emulation for Cypress — viewport, touch, device pixel ratio, user agent, and live orientation rotation, correctly cascading through CSS media queries. Chrome/Edge only.
We found that cypress-device-emulate demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.