Macro close-up of microchips and MEMS sensor components on a circuit board inside a laptop

Apple Silicon MacBook Accelerometer Guide

September 19, 2026 · 10 min read · By Thomas A. Anderson

Key Takeaways:

  • Modern Apple Silicon MacBooks (M1 through M4) contain an undocumented MEMS accelerometer and gyroscope managed by the Sensor Processing Unit (SPU), an undocumented hardware component.
  • The sensors are reachable through the macOS IOKit HID interface, which delivers fixed 22-byte reports carrying raw 3-axis acceleration and angular velocity.
  • Open-source projects read that data at up to roughly 800 Hz via IOKit HID callbacks, with the Python reference implementation decimating to about 100 Hz for practical use.
  • Access requires root, and IOKit user-client interfaces remain a documented source of macOS privilege-escalation bugs, so the privileged surface matters.
  • Tested coverage is narrow. The reference implementation was verified on a MacBook Pro M3 Pro, and the maintainer lists Intel Macs, the M1 MacBook Pro (2020), and the Mac Studio M4 Max as incompatible.

Every M-series MacBook carries a MEMS inertial measurement unit that Apple never documented and never exposed through a public framework. It sits behind the Sensor Processing Unit (SPU), an undocumented hardware component, and the only way to reach it is to open a raw HID device through IOKit. A community project, olvvier/apple-silicon-accelerometer, reverse-engineered that path and now reads raw 3-axis acceleration and angular velocity at up to roughly 800 Hz. The work has since been ported to Go and Swift, which tells you the interface is stable enough to build on, even if Apple has never acknowledged it exists.

Apple Silicon’s Hidden MEMS Sensors

The hardware is not exotic. MEMS accelerometers and gyroscopes are commodity parts found in phones, watches, and game controllers. What makes the MacBook case unusual is that the sensor is present but walled off. Apple’s public frameworks do not surface it, and the IOKit documentation says nothing about the specific device path. The sensor is managed by the SPU, which forwards its data through the same HID stack that handles keyboards and trackpads.

Reading Raw Data in Practice

That forwarding is the opening. Because the sensor enumerates as a HID device, a user-space process can find it in the IOKit registry and subscribe to its reports. The reference implementation reads raw acceleration and angular velocity through IOKit HID callbacks, and the same interface also carries the ambient light sensor and the lid angle sensor. One enumeration gives you three data sources, which is part of why the project drew attention beyond the hobbyist crowd.

How the IOKit HID Interface Exposes the Sensor

The device lives under AppleSPUHIDDevice in the IOKit registry, on vendor usage page 0xFF00. Usage 3 is the accelerometer; usage 9 is the gyroscope. Both are the same physical IMU, which teardown analysis suggests is a Bosch BMI286, though that identification is community inference rather than an Apple statement. The driver handling the device is AppleSPUHIDDriver, part of the SPU stack.

The data format is fixed and simple. Each report is 22 bytes. The X, Y, and Z axes are signed 32-bit little-endian integers at byte offsets 6, 10, and 14. Dividing the raw integer by 65536 yields acceleration in g, or angular velocity in degrees per second for the gyroscope. That is the entire protocol, and its simplicity is what made the reverse-engineering tractable.

IOKit is also a well-known security surface. HackTricks’ macOS IOKit notes observe that IOKit functions can perform additional security checks when a client calls them, and that apps are usually limited by the sandbox to whichever IOKit functions they are permitted to touch. This sensor path sits outside the sandbox because it is not a documented service; reaching it requires elevated privileges rather than a sandbox entitlement.

Reverse-Engineering the Sensor Protocol

Two questions had to be answered before any code could read a value. The first is where the device lives in the registry. The second is what the bytes mean. Both were resolved by inspecting the device tree and the HID report descriptor rather than by any vendor documentation.

The device-discovery step is a single command, and it is the right first move on any machine before writing a reader:

ioreg -l -w0 | grep -A5 AppleSPUHIDDevice

If that returns a node, the hardware path is present. If it returns nothing, the sensor is not exposed on that machine or macOS build, and no amount of retrying the reader will change the outcome. The maintainer’s own notes list Intel Macs, the M1 MacBook Pro (2020), and the Mac Studio M4 Max as known incompatible, which is the practical boundary of the reverse-engineered path.

Once the device is located, the work moves to the report descriptor and the callback. The project registers an asynchronous callback with IOHIDDeviceRegisterInputReportCallback after opening the device with IOHIDDeviceCreate. Each incoming report is parsed at the fixed offsets, and the raw integers are scaled. The Swift port, junwatu/macimu, follows the same approach and extends it to the lid angle and ambient light sensors on the same interface, which confirms the offsets are not an artifact of one language binding.

Reading Raw Data in Practice

The minimal path uses the macimu Python package, which wraps the low-level IOKit bindings. You create a virtual environment and install it, then read samples through a context manager. The example below reads acceleration in g and angular velocity in degrees per second:

from macimu import IMU

with IMU() as imu:
 accel = imu.latest_accel() # Sample(x, y, z) in g
 gyro = imu.latest_gyro() # Sample(x, y, z) in deg/s

At rest the accelerometer reads about 1g from gravity, so subtract the gravity vector with the bundled remove_gravity() filter before detecting motion or impacts. The package ships biquad Butterworth low-pass, high-pass, and bandpass filters with no external dependencies, along with a peak detector for impact events.

For a long-running service, the Go port is the more operationally sensible choice. taigrr/apple-silicon-accelerometer splits the work into two binaries: sensord reads raw sensor data via IOKit HID callbacks and writes to POSIX shared memory ring buffers, and sensordash reads from shared memory for a terminal dashboard. It links macOS frameworks through purego with no CGO, and the shared memory layout is compatible with the original Python implementation, so mixed Go and Python consumers can read the same buffer.

sudo sensord # terminal 1, requires root
sensordash # terminal 2

That split is worth copying in any production reader. A daemon that only reads and publishes to shared memory keeps the privileged surface small, and consumers that just need samples read the buffer without root at all.

Findings, Limits, and Compatibility

The headline finding is the sample rate. The hardware reports at roughly 800 Hz, which is far above what most applications need. The Python reference implementation decimates that to about 100 Hz by default, and the package exposes a decimation parameter for callers who want the full native rate. That gap between native and delivered rate matters: a script that assumes 800 Hz through the Python path will not get it.

The tested scope is narrow, and the maintainer is explicit about it. Here is what the sources say per configuration:

Configuration Status Note
MacBook Pro M3 Pro, macOS 15.6.1 Verified Only configuration the maintainer tested
Intel Macs Incompatible No SPU present
M1 MacBook Pro (2020) Incompatible Listed in known-incompatible section
Mac Studio M4 Max Incompatible Listed in known-incompatible section
Other Apple Silicon MacBooks Untested README says “no guarantees”

Independent coverage of the project states that access “may break on future macOS updates.” For a production dependency, that is a silent, unannounced failure mode rather than a scheduled deprecation. The sensor data is also raw and noisy: the project documentation notes that fan vibration and other chassis noise affect readings, so threshold-based logic needs filtering and calibration rather than a hardcoded cutoff.

Applications, Security, and Sandboxing

The showed use cases cluster around physical interaction. The included demo detects vibration, computes orientation by fusing accelerometer and gyroscope data through a Mahony AHRS quaternion filter, and estimates heart rate from wrist vibrations using ballistocardiography. The project describes that last one as “experimental, not reliable, just fun,” and it says “not for medical use” outright. Other builders have used the sensor for laptop-tap gestures and typing-force feedback, which are closer to what the hardware is good at.

Security is the constraint that shapes every deployment. Opening a raw IOKit HID device requires root, and any process with that privilege can read motion data without user consent. Phrack’s mapping of IOKit methods exposed to user space treats the user-client interface as a priority target for vulnerability research precisely because kernel attack surface reachable from user space is where privilege escalation lives. Adding one more open device handle widens that surface.

Practical hardening follows from that:

  • Never run the reader inside a broad interactive sudo session. Run the privileged daemon and let unprivileged consumers read the shared buffer.
  • Pin the dependency set. The package pulls in native bindings, so hash-pin your lockfile and review version bumps rather than tracking latest.
  • Do not expose a socket or HTTP endpoint that triggers sensor reads from another process without authentication. That turns a local privilege into a remote one.
  • Treat motion data as potentially user-identifying telemetry. It correlates with typing and presence, so it belongs under the same controls as other host telemetry.

Internal Sensor vs External IMU and Public APIs

The obvious question is why anyone would use an undocumented internal sensor instead of a documented external one. The trade-off is real in both directions. An internal IMU measures the chassis directly, so it captures hand pressure, typing force, and impacts with no dongle and no cable. An external IMU is documented, stable across OS updates, and does not require root, but it measures the surface it sits on rather than the machine itself, and it adds a piece of hardware to manage.

The public-API comparison is simpler. There is no public API for this sensor on macOS. The community path relies entirely on reverse-engineered IOKit HID communication, which means the only support channel is the project’s own issue tracker. That is acceptable for experiments and internal tooling where you control the machines and can tolerate a break. It is not acceptable for anything that must keep working across an OS upgrade you did not schedule.

Open Questions and Compatibility Risk

Several questions remain open. The first is whether the path holds across the full M-series line. The maintainer tested one machine, and the known-incompatible list already excludes an M1 MacBook Pro and an M4 Max Mac Studio, so “Apple Silicon” is not a safe blanket assumption. The second is whether the interface survives future macOS releases. Nothing in the project’s documentation suggests Apple has committed to keeping it stable, and the maintainer’s own notes warn that it may break.

The same interface also carries the lid angle and ambient light sensors, so extending a reader to cover them is a matter of using the same device handle with different usage IDs. That is where the next round of experimentation is likely to go. For now, the honest summary is that this is an experimental, unofficial method with a narrow verified footprint. If you build on it, verify the device path before you start, keep the privileged surface small, and expect the interface to move under you. Check the current compatibility notes at the apple-silicon-accelerometer repository before you ship anything that runs with root.

More in-depth coverage from this blog on closely related topics:

Sources and References

Sources cited while researching and writing this article: