microsoft/playwright · error · Error

Mouse wheel is not supported in mobile WebKit

Error message

Mouse wheel is not supported in mobile WebKit

What it means

WK mouse input does not support wheel events when the context is emulated as mobile (hasTouch/isMobile => isMobile option). The wheel() method short-circuits before dispatching because mobile WebKit touch scrolling semantics conflict with synthetic wheel dispatch.

Source

Thrown at packages/playwright-core/src/server/webkit/wkInput.ts:157

      clickCount
    }));
  }

  async up(progress: Progress, x: number, y: number, button: types.MouseButton, buttons: Set<types.MouseButton>, modifiers: Set<types.KeyboardModifier>, clickCount: number): Promise<void> {
    await progress.race(this._pageProxySession.send('Input.dispatchMouseEvent', {
      type: 'up',
      button,
      buttons: toButtonsMask(buttons),
      x,
      y,
      modifiers: toModifiersMask(modifiers),
      clickCount
    }));
  }

  async wheel(progress: Progress, x: number, y: number, buttons: Set<types.MouseButton>, modifiers: Set<types.KeyboardModifier>, deltaX: number, deltaY: number): Promise<void> {
    if (this._page?.browserContext._options.isMobile)
      throw new Error('Mouse wheel is not supported in mobile WebKit');
    await progress.race(this._session!.send('Page.updateScrollingState'));
    // Wheel events hit the compositor first, so wait one frame for it to be synced.
    await this._page!.mainFrame().evaluateExpression(progress, `new Promise(requestAnimationFrame)`, { world: 'utility' });
    await progress.race(this._pageProxySession.send('Input.dispatchWheelEvent', {
      x,
      y,
      deltaX,
      deltaY,
      modifiers: toModifiersMask(modifiers),
    }));
  }

  setPage(page: Page) {
    this._page = page;
  }
}

export class RawTouchscreenImpl implements input.RawTouchscreen {

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Drop isMobile from context options (or use a non-mobile device descriptor) if you need wheel events.
  2. For mobile emulation, scroll via touch-based APIs (e.g. page.touchscreen.tap/swipe patterns or evaluate window.scrollBy) instead of mouse.wheel.
  3. Branch test logic on the emulation mode: wheel for desktop, touch-scroll for mobile.

Example fix

// before
const ctx = await browser.newContext({ ...devices['iPhone 13'] });
await page.mouse.wheel(0, 500); // throws

// after
await page.evaluate(y => window.scrollBy(0, y), 500);
Defensive patterns

Strategy: validation

Validate before calling

function supportsWheel(contextOptions) { return !contextOptions.isMobile; }
if (supportsWheel(ctxOptions)) await page.mouse.wheel(0, 500);
else await page.evaluate(y => window.scrollBy(0, y), 500);

Type guard

function isMobileContext(opts: { isMobile?: boolean }): boolean { return !!opts.isMobile; }

Try / catch

try { await page.mouse.wheel(0, 500); }
catch (e) {
  if (/mobile WebKit/.test(e.message)) await page.evaluate(y => window.scrollBy(0, y), 500);
  else throw e;
}

Prevention

When it happens

Trigger: Calling page.mouse.wheel(...) (or locator/keyboard-driven scroll-by-wheel) on a context launched with isMobile:true or a device descriptor setting isMobile. Also via tools that synthesize wheel for scrolling.

Common situations: Using a mobile device descriptor (iPhone/Pixel presets set isMobile) and then attempting page.mouse.wheel. Mixing desktop scroll idioms into mobile emulation tests.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/2db04f534818f1f1. Report an issue: GitHub.