Mobile Web JavaScript APIs for iOS and Android
Mobile browsers expose a surprisingly rich set of device capabilities through JavaScript. Here’s a breakdown of what’s available, with notes on platform differences between iOS and Android.
Sensors & Motion
DeviceOrientation & DeviceMotion provide access to the accelerometer, gyroscope, and compass heading.
window.addEventListener('devicemotion', (e) => {
console.log(e.acceleration.x, e.acceleration.y, e.acceleration.z);
});
// iOS 13+ requires explicit permission via a user gesture
if (typeof DeviceMotionEvent.requestPermission === 'function') {
DeviceMotionEvent.requestPermission().then(state => {
if (state === 'granted') { /* attach listener */ }
});
}
Note: Android Chrome grants it on secure (HTTPS) origins without a prompt.
Geolocation
Works on both platforms but requires HTTPS and explicit user permission.
navigator.geolocation.getCurrentPosition(
pos => console.log(pos.coords.latitude, pos.coords.longitude),
err => console.error(err),
{ enableHighAccuracy: true, timeout: 5000 }
);
Camera & Microphone
Use getUserMedia for live streams, or a <input type="file" capture> for one-shot photos.
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: 'environment' },
audio: true
});
document.querySelector('video').srcObject = stream;
Note: iOS Safari supports it but historically had quirks with inline playback (ensure you use the playsinline attribute on <video> tags).
Web Share API
One of the best cross-platform mobile-web wins. It invokes the native sharing sheet.
await navigator.share({
title: 'Check this out',
text: 'Cool article',
url: window.location.href,
});
Quick Reference: Android-only Gaps
These are the things you can do on Android Chrome but not iOS Safari, which often dictate whether a project needs a native wrapper (like React Native/Expo):
- Web Bluetooth, Web USB, Web Serial, Web HID, Web NFC
- Vibration API (
navigator.vibrate) - Network Information API (
navigator.connection) - File System Access API (persistent handles)
- Background Sync, Periodic Background Sync
- Web push in regular browser tabs (iOS requires PWA install to the home screen)
Detecting Web Clients in JavaScript
There are several layers to “client detection” — from least to most reliable.
1. User Agent String (Least Reliable)
UA strings can be spoofed and are increasingly frozen for privacy. Use them as a hint, not a gate.
const ua = navigator.userAgent;
// One critical iPad gotcha: iPadOS 13+ reports a desktop Safari user agent by default!
const isIOS = /iPad|iPhone|iPod/.test(ua) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
2. Feature Detection (Preferred)
Instead of asking “what browser are you,” ask “can you do this thing.” This survives browser updates and spoofing.
if ('serviceWorker' in navigator) { /* register SW */ }
if ('bluetooth' in navigator) { /* show BT pairing UI */ }
if (window.matchMedia('(hover: hover)').matches) { /* hover-capable */ }
3. A Practical Detection Helper
Here is a great pattern that bundles useful checks for a typical web app:
const client = {
// Platform
isIOS: /iPad|iPhone|iPod/.test(navigator.userAgent) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1),
isAndroid: /Android/.test(navigator.userAgent),
isMobile: window.matchMedia('(pointer: coarse)').matches,
// Capabilities
hasTouch: navigator.maxTouchPoints > 0,
hasShare: 'share' in navigator,
// Preferences
prefersDark: window.matchMedia('(prefers-color-scheme: dark)').matches,
};
Rule of Thumb
- For layout decisions → use CSS media queries and
matchMedia. - For capability decisions → use feature detection (
'x' in y). - For “is this an iPhone” → combine UA +
maxTouchPoints+ platform. - Avoid UA sniffing as the basis for feature gating — every time someone has done that historically, it broke when a new browser shipped.