Device and Sensor Integration APIs

1. Geolocation API for Location Services

Method Syntax Description Browser Support
getCurrentPosition navigator.geolocation.getCurrentPosition(success, error, options) Gets current location once. Requires user permission. HTTPS required. All Browsers
watchPosition navigator.geolocation.watchPosition(success, error, options) Watches location changes continuously. Returns watch ID. Requires permission. All Browsers
clearWatch navigator.geolocation.clearWatch(id) Stops watching location. Use watch ID from watchPosition. All Browsers
Position Property Type Description Always Available
coords.latitude number Latitude in decimal degrees (-90 to 90). Yes
coords.longitude number Longitude in decimal degrees (-180 to 180). Yes
coords.accuracy number Accuracy in meters. Lower is better. Yes
coords.altitude number | null Altitude in meters above sea level. May be null. No
coords.altitudeAccuracy number | null Altitude accuracy in meters. May be null. No
coords.heading number | null Direction of travel in degrees (0-360). 0 is north. May be null. No
coords.speed number | null Speed in meters per second. May be null. No
timestamp number DOMTimeStamp when position was acquired. Yes
Option Type Description Default
enableHighAccuracy boolean Request GPS/high accuracy. Slower, more battery. Desktop may ignore. false
timeout number Max time in milliseconds to wait. 0 means no timeout. Infinity
maximumAge number Max age in milliseconds of cached position. 0 means no cache. 0
Error Code Value Meaning
PERMISSION_DENIED 1 User denied permission or location disabled.
POSITION_UNAVAILABLE 2 Location information unavailable (no GPS signal, network error).
TIMEOUT 3 Request timed out before getting location.

Example: Get current location

// Check if geolocation is supported
if ("geolocation" in navigator) {
  console.log("Geolocation available");
} else {
  console.log("Geolocation not supported");
}

// Get current position
navigator.geolocation.getCurrentPosition(
  (position) => {
    const { latitude, longitude, accuracy } = position.coords;
    console.log(`Location: ${latitude}, ${longitude}`);
    console.log(`Accuracy: ${accuracy} meters`);
    console.log(`Timestamp: ${new Date(position.timestamp)}`);
    
    // Optional fields
    if (position.coords.altitude !== null) {
      console.log(`Altitude: ${position.coords.altitude} meters`);
    }
    if (position.coords.speed !== null) {
      console.log(`Speed: ${position.coords.speed} m/s`);
    }
    if (position.coords.heading !== null) {
      console.log(`Heading: ${position.coords.heading} degrees`);
    }
  },
  (error) => {
    switch (error.code) {
      case error.PERMISSION_DENIED:
        console.error("User denied geolocation permission");
        break;
      case error.POSITION_UNAVAILABLE:
        console.error("Location unavailable");
        break;
      case error.TIMEOUT:
        console.error("Geolocation timeout");
        break;
      default:
        console.error("Unknown geolocation error");
    }
  },
  {
    "enableHighAccuracy": true,
    "timeout": 10000,
    "maximumAge": 0
  }
);

Example: Watch position and distance calculation

let watchId;

// Start watching position
function startWatching() {
  watchId = navigator.geolocation.watchPosition(
    (position) => {
      const { latitude, longitude, accuracy } = position.coords;
      console.log(`Updated location: ${latitude}, ${longitude}`);
      console.log(`Accuracy: ${accuracy}m`);
      
      // Update map or UI
      updateMap(latitude, longitude);
    },
    (error) => {
      console.error("Watch position error:", error.message);
    },
    {
      "enableHighAccuracy": true,
      "timeout": 5000,
      "maximumAge": 2000
    }
  );
  
  console.log("Watching position, ID:", watchId);
}

// Stop watching
function stopWatching() {
  if (watchId) {
    navigator.geolocation.clearWatch(watchId);
    console.log("Stopped watching position");
  }
}

// Calculate distance between two points (Haversine formula)
function calculateDistance(lat1, lon1, lat2, lon2) {
  const R = 6371e3; // Earth radius in meters
  const φ1 = lat1 * Math.PI / 180;
  const φ2 = lat2 * Math.PI / 180;
  const Δφ = (lat2 - lat1) * Math.PI / 180;
  const Δλ = (lon2 - lon1) * Math.PI / 180;
  
  const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
            Math.cos(φ1) * Math.cos(φ2) *
            Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  
  return R * c; // Distance in meters
}

// Usage
const distance = calculateDistance(51.5074, -0.1278, 48.8566, 2.3522);
console.log(`Distance: ${(distance / 1000).toFixed(2)} km`);
Note: Geolocation requires HTTPS (or localhost for development). User must grant permission - request shows browser prompt. Accuracy varies by device (GPS, WiFi, IP). enableHighAccuracy uses GPS on mobile (slower, more battery). Desktop typically uses IP/WiFi regardless.
Warning: watchPosition can drain battery - always clearWatch() when done. Don't rely on optional fields (altitude, speed, heading) - may be null. Location can be spoofed - don't trust for security. Privacy concern - explain why you need location to users.

2. Device Orientation and Motion APIs

Event Description Browser Support
deviceorientation Fires when device orientation changes. Provides alpha, beta, gamma rotation angles. Mobile Browsers
deviceorientationabsolute Like deviceorientation but relative to Earth's coordinate frame (compass). Modern Mobile
devicemotion Fires when device acceleration changes. Provides acceleration and rotation rate data. Mobile Browsers
DeviceOrientation Property Type Description Range
alpha number Rotation around Z axis (compass direction). 0-360 degrees. 0-360
beta number Rotation around X axis (front-to-back tilt). -180 to 180 degrees. -180 to 180
gamma number Rotation around Y axis (left-to-right tilt). -90 to 90 degrees. -90 to 90
absolute boolean true if orientation is absolute (compass-based), false if arbitrary. -
DeviceMotion Property Type Description Units
acceleration object Acceleration excluding gravity. Properties: x, y, z. m/s²
accelerationIncludingGravity object Acceleration including gravity. Properties: x, y, z. m/s²
rotationRate object Rotation speed. Properties: alpha, beta, gamma. deg/s
interval number Interval in milliseconds between events. ms

Example: Device orientation

// Request permission (iOS 13+)
async function requestOrientationPermission() {
  if (typeof DeviceOrientationEvent !== "undefined" &&
      typeof DeviceOrientationEvent.requestPermission === "function") {
    try {
      const permission = await DeviceOrientationEvent.requestPermission();
      if (permission === "granted") {
        console.log("Orientation permission granted");
        return true;
      }
    } catch (error) {
      console.error("Orientation permission error:", error);
    }
    return false;
  }
  return true; // No permission needed (Android, older iOS)
}

// Listen for orientation changes
window.addEventListener("deviceorientation", (event) => {
  const alpha = event.alpha; // Compass direction (0-360)
  const beta = event.beta;   // Front-to-back tilt (-180 to 180)
  const gamma = event.gamma; // Left-to-right tilt (-90 to 90)
  const absolute = event.absolute;
  
  console.log(`Alpha (Z): ${alpha?.toFixed(2)}°`);
  console.log(`Beta (X): ${beta?.toFixed(2)}°`);
  console.log(`Gamma (Y): ${gamma?.toFixed(2)}°`);
  console.log(`Absolute: ${absolute}`);
  
  // Rotate element based on device orientation
  const element = document.querySelector(".compass");
  if (alpha !== null) {
    element.style.transform = `rotate(${-alpha}deg)`;
  }
});

// Compass heading (absolute orientation)
window.addEventListener("deviceorientationabsolute", (event) => {
  const heading = event.alpha; // True compass heading
  console.log(`Compass heading: ${heading?.toFixed(2)}°`);
});

Example: Device motion and shake detection

// Request permission (iOS 13+)
async function requestMotionPermission() {
  if (typeof DeviceMotionEvent !== "undefined" &&
      typeof DeviceMotionEvent.requestPermission === "function") {
    try {
      const permission = await DeviceMotionEvent.requestPermission();
      return permission === "granted";
    } catch (error) {
      console.error("Motion permission error:", error);
      return false;
    }
  }
  return true;
}

// Listen for motion events
window.addEventListener("devicemotion", (event) => {
  // Acceleration (without gravity)
  const acc = event.acceleration;
  if (acc) {
    console.log(`Acceleration: x=${acc.x}, y=${acc.y}, z=${acc.z} m/s²`);
  }
  
  // Acceleration (with gravity)
  const accGrav = event.accelerationIncludingGravity;
  if (accGrav) {
    console.log(`With gravity: x=${accGrav.x}, y=${accGrav.y}, z=${accGrav.z}`);
  }
  
  // Rotation rate
  const rotation = event.rotationRate;
  if (rotation) {
    console.log(`Rotation: α=${rotation.alpha}, β=${rotation.beta}, γ=${rotation.gamma} deg/s`);
  }
  
  console.log(`Interval: ${event.interval}ms`);
});

// Shake detection
let lastTime = 0;
let lastX = 0, lastY = 0, lastZ = 0;
const shakeThreshold = 15; // Adjust sensitivity

window.addEventListener("devicemotion", (event) => {
  const acc = event.accelerationIncludingGravity;
  if (!acc) return;
  
  const currentTime = Date.now();
  const timeDiff = currentTime - lastTime;
  
  if (timeDiff > 100) {
    const deltaX = Math.abs(acc.x - lastX);
    const deltaY = Math.abs(acc.y - lastY);
    const deltaZ = Math.abs(acc.z - lastZ);
    
    const speed = (deltaX + deltaY + deltaZ) / timeDiff * 10000;
    
    if (speed > shakeThreshold) {
      console.log("Device shaken!");
      onShake();
    }
    
    lastTime = currentTime;
    lastX = acc.x;
    lastY = acc.y;
    lastZ = acc.z;
  }
});

function onShake() {
  console.log("Shake detected!");
  // Trigger shake action
}
Note: iOS 13+ requires user permission and user gesture to access orientation/motion. Request permission with DeviceOrientationEvent.requestPermission(). Events fire frequently (30-60 times/second) - throttle expensive operations. Desktop browsers may not support these events.
Warning: Sensor data can be noisy - apply smoothing/filtering for better results. Battery drain with continuous monitoring - remove listeners when not needed. Privacy concern - can be used for fingerprinting. Not all devices have all sensors (gyroscope, magnetometer).

3. Battery Status API (deprecated but legacy)

Property Type Description Status
navigator.getBattery() Promise<BatteryManager> Returns Promise with battery status object. DEPRECATED
level number Battery level 0.0 to 1.0 (0% to 100%). Read-only
charging boolean true if device is charging. Read-only
chargingTime number Seconds until fully charged. Infinity if not charging or unknown. Read-only
dischargingTime number Seconds until battery empty. Infinity if charging or unknown. Read-only
Event When Fired
levelchange Battery level changed
chargingchange Charging status changed (plugged/unplugged)
chargingtimechange Charging time estimate changed
dischargingtimechange Discharging time estimate changed

Example: Battery status monitoring

// Check if API is available
if ("getBattery" in navigator) {
  navigator.getBattery().then((battery) => {
    // Initial state
    console.log(`Battery level: ${battery.level * 100}%`);
    console.log(`Charging: ${battery.charging}`);
    console.log(`Charging time: ${battery.chargingTime} seconds`);
    console.log(`Discharging time: ${battery.dischargingTime} seconds`);
    
    // Listen for level changes
    battery.addEventListener("levelchange", () => {
      console.log(`Battery level: ${battery.level * 100}%`);
      
      // Warn if low battery
      if (battery.level < 0.2 && !battery.charging) {
        console.warn("Low battery!");
      }
    });
    
    // Listen for charging state changes
    battery.addEventListener("chargingchange", () => {
      if (battery.charging) {
        console.log("Device is charging");
      } else {
        console.log("Device is not charging");
      }
    });
    
    // Charging time updates
    battery.addEventListener("chargingtimechange", () => {
      if (battery.chargingTime !== Infinity) {
        const minutes = Math.floor(battery.chargingTime / 60);
        console.log(`Fully charged in ${minutes} minutes`);
      }
    });
    
    // Discharging time updates
    battery.addEventListener("dischargingtimechange", () => {
      if (battery.dischargingTime !== Infinity) {
        const minutes = Math.floor(battery.dischargingTime / 60);
        console.log(`Battery empty in ${minutes} minutes`);
      }
    });
  });
} else {
  console.log("Battery Status API not supported");
}
Warning: Battery Status API is DEPRECATED due to privacy concerns (fingerprinting). Removed from most browsers. Firefox disabled by default. Chrome plans removal. Don't rely on this API for new projects. Use feature detection before accessing.

4. Vibration API for Haptic Feedback

Method Syntax Description Browser Support
vibrate navigator.vibrate(pattern) Vibrates device with pattern. Pattern is number (ms) or array [vibrate, pause, ...]. Mobile Browsers
vibrate(0) navigator.vibrate(0) Stops ongoing vibration. Mobile Browsers

Example: Vibration patterns

// Check support
if ("vibrate" in navigator) {
  console.log("Vibration API supported");
} else {
  console.log("Vibration not supported");
}

// Simple vibration (200ms)
navigator.vibrate(200);

// Vibration pattern [vibrate, pause, vibrate, pause, ...]
// Vibrate 200ms, pause 100ms, vibrate 200ms
navigator.vibrate([200, 100, 200]);

// SOS pattern (... --- ...)
navigator.vibrate([
  100, 30, 100, 30, 100,  // S (...)
  200,                     // Pause
  200, 30, 200, 30, 200,  // O (---)
  200,                     // Pause
  100, 30, 100, 30, 100   // S (...)
]);

// Stop vibration
navigator.vibrate(0);
// or
navigator.vibrate([]);

// Pulse pattern (heartbeat)
function vibratePulse() {
  navigator.vibrate([50, 50, 50, 50, 200]);
}

// Success feedback
function vibrateSuccess() {
  navigator.vibrate([100, 50, 100]);
}

// Error feedback
function vibrateError() {
  navigator.vibrate([200, 100, 200, 100, 200]);
}

// Click feedback
function vibrateClick() {
  navigator.vibrate(10); // Short tap
}

// Button with haptic feedback
document.querySelector("button").addEventListener("click", () => {
  navigator.vibrate(50);
  // Handle button action
});
Note: Vibration only works on mobile devices with vibration hardware. Desktop browsers ignore vibrate() calls. Maximum vibration time limited by browsers (few seconds). User can disable vibration in system settings. Requires user gesture on some browsers.
Warning: Don't overuse vibration - annoying and drains battery. Respect user preferences - provide option to disable. Some users rely on vibration for accessibility - use meaningfully. Vibration patterns limited to prevent abuse (max length, max duration).

5. Screen Orientation API and Lock

Property/Method Description Browser Support
screen.orientation.type Current orientation: "portrait-primary", "portrait-secondary", "landscape-primary", "landscape-secondary". Modern Browsers
screen.orientation.angle Orientation angle: 0, 90, 180, or 270 degrees. Modern Browsers
screen.orientation.lock(orientation) Locks to specific orientation. Returns Promise. Requires fullscreen on most browsers. Modern Mobile
screen.orientation.unlock() Unlocks orientation, allowing device rotation. Modern Mobile
orientationchange event Fires when screen orientation changes. Modern Browsers
Orientation Value Description
portrait-primary Normal portrait (0° or 180°)
portrait-secondary Upside-down portrait (180° or 0°)
landscape-primary Normal landscape (90° or 270°)
landscape-secondary Reverse landscape (270° or 90°)
portrait Any portrait orientation
landscape Any landscape orientation
any Allow all orientations (default)

Example: Detect and lock orientation

// Check current orientation
if (screen.orientation) {
  console.log(`Type: ${screen.orientation.type}`);
  console.log(`Angle: ${screen.orientation.angle}°`);
} else {
  console.log("Screen Orientation API not supported");
}

// Listen for orientation changes
screen.orientation?.addEventListener("change", () => {
  console.log(`Orientation changed to: ${screen.orientation.type}`);
  console.log(`Angle: ${screen.orientation.angle}°`);
  
  // Adjust layout based on orientation
  if (screen.orientation.type.startsWith("landscape")) {
    document.body.classList.add("landscape");
    document.body.classList.remove("portrait");
  } else {
    document.body.classList.add("portrait");
    document.body.classList.remove("landscape");
  }
});

// Lock orientation (requires fullscreen)
async function lockLandscape() {
  try {
    // Enter fullscreen first
    await document.documentElement.requestFullscreen();
    
    // Lock to landscape
    await screen.orientation.lock("landscape");
    console.log("Locked to landscape");
  } catch (error) {
    console.error("Failed to lock orientation:", error);
  }
}

// Lock to specific orientation
async function lockOrientation(orientation) {
  try {
    await screen.orientation.lock(orientation);
    console.log(`Locked to ${orientation}`);
  } catch (error) {
    if (error.name === "NotSupportedError") {
      console.error("Orientation lock not supported");
    } else if (error.name === "SecurityError") {
      console.error("Must be in fullscreen to lock orientation");
    } else {
      console.error("Lock failed:", error);
    }
  }
}

// Unlock orientation
function unlockOrientation() {
  screen.orientation?.unlock();
  console.log("Orientation unlocked");
}

// Game example: lock to landscape when playing
async function startGame() {
  await document.documentElement.requestFullscreen();
  await screen.orientation.lock("landscape");
  // Start game
}

function exitGame() {
  screen.orientation.unlock();
  document.exitFullscreen();
}
Note: Orientation lock typically requires fullscreen mode. Desktop browsers may not support orientation lock. Use CSS media queries for responsive design alongside API. Some browsers use window.orientation (deprecated) - use screen.orientation instead.
Warning: Don't lock orientation unless necessary (games, video). Respect user preference - they rotated device intentionally. Unlock orientation when leaving fullscreen. May not work in iframes or certain contexts.

6. Generic Sensor API and Accelerometer

Sensor Description Browser Support
Accelerometer Measures acceleration in m/s² along X, Y, Z axes. Limited (Chrome)
LinearAccelerationSensor Acceleration excluding gravity. Limited (Chrome)
GravitySensor Gravity component of acceleration. Limited (Chrome)
Gyroscope Measures angular velocity (rotation rate) in rad/s. Limited (Chrome)
Magnetometer Measures magnetic field in µT (microtesla). Limited (Chrome)
AbsoluteOrientationSensor Device orientation relative to Earth's coordinate system. Limited (Chrome)
RelativeOrientationSensor Device orientation relative to arbitrary reference. Limited (Chrome)
AmbientLightSensor Measures ambient light in lux. Limited (Chrome)
Sensor Method/Property Description
start() Starts sensor. Fires reading event when data available.
stop() Stops sensor and data collection.
x, y, z Sensor readings for respective axes.
timestamp DOMHighResTimeStamp when reading was taken.
activated true if sensor is active and providing readings.
reading event Fires when new sensor reading is available.
error event Fires when sensor error occurs.

Example: Accelerometer usage

// Request permission (if needed)
async function requestSensorPermission() {
  try {
    const result = await navigator.permissions.query({ "name": "accelerometer" });
    if (result.state === "denied") {
      console.error("Accelerometer permission denied");
      return false;
    }
    return true;
  } catch (error) {
    console.error("Permission query failed:", error);
    return false;
  }
}

// Create accelerometer
try {
  const accelerometer = new Accelerometer({
    "frequency": 60 // 60 Hz (readings per second)
  });
  
  // Listen for readings
  accelerometer.addEventListener("reading", () => {
    console.log(`Acceleration: x=${accelerometer.x}, y=${accelerometer.y}, z=${accelerometer.z} m/s²`);
    console.log(`Timestamp: ${accelerometer.timestamp}`);
    
    // Detect device tilt
    const tiltX = Math.atan2(accelerometer.y, accelerometer.z) * 180 / Math.PI;
    const tiltY = Math.atan2(accelerometer.x, accelerometer.z) * 180 / Math.PI;
    console.log(`Tilt: X=${tiltX.toFixed(2)}°, Y=${tiltY.toFixed(2)}°`);
  });
  
  // Handle errors
  accelerometer.addEventListener("error", (event) => {
    console.error("Accelerometer error:", event.error.name, event.error.message);
  });
  
  // Start sensor
  accelerometer.start();
  console.log("Accelerometer started");
  
  // Stop after 10 seconds
  setTimeout(() => {
    accelerometer.stop();
    console.log("Accelerometer stopped");
  }, 10000);
  
} catch (error) {
  console.error("Accelerometer not supported:", error);
}

// Linear acceleration (without gravity)
try {
  const linearAccel = new LinearAccelerationSensor({ "frequency": 60 });
  
  linearAccel.addEventListener("reading", () => {
    console.log(`Linear acceleration: x=${linearAccel.x}, y=${linearAccel.y}, z=${linearAccel.z}`);
  });
  
  linearAccel.start();
} catch (error) {
  console.error("LinearAccelerationSensor not supported:", error);
}

Example: Gyroscope and orientation sensors

// Gyroscope (rotation rate)
try {
  const gyroscope = new Gyroscope({ "frequency": 60 });
  
  gyroscope.addEventListener("reading", () => {
    console.log(`Rotation rate: x=${gyroscope.x}, y=${gyroscope.y}, z=${gyroscope.z} rad/s`);
    
    // Convert to degrees per second
    const degPerSec = {
      "x": gyroscope.x * 180 / Math.PI,
      "y": gyroscope.y * 180 / Math.PI,
      "z": gyroscope.z * 180 / Math.PI
    };
    console.log(`Rotation (deg/s): x=${degPerSec.x.toFixed(2)}, y=${degPerSec.y.toFixed(2)}, z=${degPerSec.z.toFixed(2)}`);
  });
  
  gyroscope.start();
} catch (error) {
  console.error("Gyroscope not supported:", error);
}

// Absolute orientation (quaternion)
try {
  const orientation = new AbsoluteOrientationSensor({ "frequency": 60 });
  
  orientation.addEventListener("reading", () => {
    // Quaternion representation
    const [x, y, z, w] = orientation.quaternion;
    console.log(`Quaternion: [${x}, ${y}, ${z}, ${w}]`);
    
    // Convert to Euler angles
    const angles = quaternionToEuler(x, y, z, w);
    console.log(`Euler angles: ${JSON.stringify(angles)}`);
  });
  
  orientation.start();
} catch (error) {
  console.error("AbsoluteOrientationSensor not supported:", error);
}

// Helper: Convert quaternion to Euler angles
function quaternionToEuler(x, y, z, w) {
  const roll = Math.atan2(2 * (w * x + y * z), 1 - 2 * (x * x + y * y));
  const pitch = Math.asin(2 * (w * y - z * x));
  const yaw = Math.atan2(2 * (w * z + x * y), 1 - 2 * (y * y + z * z));
  
  return {
    "roll": roll * 180 / Math.PI,
    "pitch": pitch * 180 / Math.PI,
    "yaw": yaw * 180 / Math.PI
  };
}

// Ambient light sensor
try {
  const lightSensor = new AmbientLightSensor({ "frequency": 1 });
  
  lightSensor.addEventListener("reading", () => {
    console.log(`Illuminance: ${lightSensor.illuminance} lux`);
    
    // Adjust UI based on ambient light
    if (lightSensor.illuminance < 50) {
      document.body.classList.add("dark-mode");
    } else {
      document.body.classList.remove("dark-mode");
    }
  });
  
  lightSensor.start();
} catch (error) {
  console.error("AmbientLightSensor not supported:", error);
}
Note: Generic Sensor API has limited browser support (mainly Chrome). Requires HTTPS and user permission. Sensors may not be available on all devices. Use frequency option to control sampling rate (affects battery and CPU). Always wrap in try/catch for feature detection.
Warning: Sensor APIs can drain battery with high frequency - use lowest frequency needed. Always stop() sensors when not in use. Privacy concern - sensor data can be used for fingerprinting or side-channel attacks. Check browser compatibility before using - very limited support.

Device and Sensor API Best Practices

  • Always check feature availability with if ("geolocation" in navigator) before using APIs
  • Request location/sensor permissions with clear explanation why you need them
  • Use enableHighAccuracy: false for geolocation unless GPS precision is critical
  • Always clearWatch() geolocation watches when done to save battery
  • Throttle or debounce orientation/motion event handlers - they fire very frequently
  • Request DeviceOrientation/Motion permissions on iOS 13+ with user gesture
  • Don't rely on Battery Status API - deprecated and removed from most browsers
  • Use vibration sparingly - annoying when overused and drains battery
  • Orientation lock requires fullscreen mode - unlock when exiting fullscreen
  • Generic Sensor API has limited support - use DeviceOrientation/Motion for broader compatibility
  • Always stop sensors when not needed to conserve battery and CPU
  • Handle permission denials gracefully - provide fallback UX