RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/Dev Tools
Dev Tools/2026-05-23Intermediate

expo-haptics Silent on Production Builds in Rork — Simulator, Device, and Low Power Mode Pitfalls

Your Rork-generated app taps the favorite button and nothing happens on TestFlight — but Expo Go works fine. Lessons from a wallpaper indie shop on the five most common reasons expo-haptics goes silent, with working call patterns for each.

expo-hapticsiOS109Android43production buildtroubleshooting65

You ship a Rork-generated app, tap the "favorite" button in Expo Go, and feel a satisfying tick under your fingertip. Then you push to TestFlight and the same button feels completely dead. I burned half a day on this exact pattern last week.

I have been shipping wallpaper and well-being apps as an indie developer since 2014. When I cross-reference AdMob session data against user behavior, apps with working haptics show 10–20% longer average session times than apps where haptics are silently broken. The feedback itself is only a few dozen milliseconds, but without it, taps lose their "this happened" feel. Shipping an app with broken haptics without noticing is the kind of bug that quietly erodes review scores for months.

The frustrating thing about expo-haptics is that the JavaScript surface is tiny, which means that when it does not work, the cause is almost always outside the call. Here are five reasons, in the order I check them.

Three things to isolate first

Before touching any code, confirm these. They cut the search space in half.

  • Is the device physically silent, or is the vibration so weak you do not notice?
  • Is only iOS broken, only Android, or both?
  • Does it work in Expo Go but break in EAS Build / TestFlight?

The iOS Simulator never fires haptics — that is by design, not a bug. I once spent hours debugging on Simulator after switching to a new Apple Silicon Mac. Always confirm on physical hardware.

Cause 1: System haptics disabled on the iPhone

The first suspect is the user's (or your own) iPhone setting. If Settings → Sounds & Haptics → System Haptics is off, expo-haptics calls silently no-op. There is no error and no callback — the call just disappears.

This is intentional. Apple's HIG says haptics must respect the OS setting, and there is no public API to force-fire when the user has disabled the system. When users report "no vibration" in App Store reviews, this setting accounts for more than half the cases in my experience.

I once panicked over a three-star review complaining about a dead app — turned out the reviewer had system haptics off. Adding a single line of in-app help text ("Haptics respect your iOS system settings") cuts these reports dramatically.

Cause 2: Low Power Mode throttles the Taptic Engine

When iOS enters Low Power Mode, the Taptic Engine is throttled to save battery. Haptics.impactAsync may produce only a click sound, or do nothing at all. Apple does not document this loudly, but the behavior is tied to UIDevice.current.isLowPowerModeEnabled. From React Native, you can read the same flag through expo-battery.

import * as Haptics from 'expo-haptics';
import * as Battery from 'expo-battery';
 
async function softTap() {
  const isLowPower = await Battery.isLowPowerModeEnabledAsync();
  if (isLowPower) {
    // Expected: skip haptics, fall back to a visual confirmation
    return;
  }
  await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}

Pair the haptic with a brief color animation on the UI element. That way, even in Low Power Mode, the user still gets a "tap registered" cue. In my wallpaper apps, every successful save fires both a haptic and a color flash, so the interaction feels intact even when the engine is silenced.

Cause 3: VIBRATE permission missing on Android

On Android, expo-haptics uses the VIBRATE permission internally. Expo SDK 50+ adds it automatically, but if you have manually narrowed android.permissions in app.json, you may have accidentally dropped it.

{
  "expo": {
    "android": {
      "permissions": ["VIBRATE"]
    }
  }
}

If you explicitly list other permissions but forget VIBRATE, the haptic call is a no-op on Android. Confirm the runtime permission set with adb shell dumpsys package <package-name> | grep VIBRATE. The trickiest case I have hit is a preview build that worked, followed by a production build that silently dropped the permission because of a different build profile.

Cause 4: Forgetting to await before navigating

A common pattern I see in Rork-generated code: calling Haptics.impactAsync without await and immediately navigating away.

// ❌ The screen transition cancels the haptic
<Pressable onPress={() => {
  Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
  router.push('/detail');
}}>

impactAsync returns a Promise. When you push a new screen before it resolves, the activity loses focus and the engine cancels the queued vibration.

// ✅ Fire haptic, then navigate
<Pressable onPress={async () => {
  await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
  router.push('/detail');
}}>

The actual delay is only a few dozen milliseconds, but the perceived difference is enormous. Sticking to the rule "haptic first, navigate second" eliminates a surprising number of "haptics broken on prod" reports.

Cause 5: Rapid taps overflow the haptic queue

The haptic engine maintains an internal queue. Firing too many vibrations in rapid succession overflows the queue, and subsequent calls are silently dropped. The classic symptom is a swipeable card UI where the haptics work for the first second and then go dead.

A tiny throttle solves it.

import * as Haptics from 'expo-haptics';
 
let lastHapticAt = 0;
const HAPTIC_MIN_INTERVAL = 80; // milliseconds
 
export async function throttledLightImpact() {
  const now = Date.now();
  if (now - lastHapticAt < HAPTIC_MIN_INTERVAL) return;
  lastHapticAt = now;
  await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}

My wallpaper apps were trying to fire haptics roughly eight times per second when users swiped quickly through thumbnails. Adding an 80 ms throttle made the feel sharper, not duller — the engine could keep up cleanly instead of dropping every other tap.

Pre-release checklist

Boil the above into a checklist you run before shipping:

  • Confirm physical vibration on both iOS and Android hardware
  • Test with iOS system haptics both on and off
  • Verify the Low Power Mode fallback path
  • Check there is no rapid-tap stall (80–100 ms throttle recommended)
  • Make sure all haptic calls await before navigation

I run these five checks during every Internal Testing pass in TestFlight. Since adopting that habit, haptic-related review complaints have basically dropped to zero. It is an unsexy area of polish, but how carefully you handle it shapes the overall feel of the app more than people realize.

Thanks for reading — I hope your apps feel just a little more alive after this.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Dev Tools2026-05-10
When expo-image-picker won't launch in your Rork app — Info.plist and permission fixes that actually worked
Your Rork-generated app's pick image button works in the simulator but does nothing on TestFlight builds. Walk through the four real-world causes I keep hitting: missing Info.plist keys, wrong permission order, iOS 14 Limited Photo Access, and Android 13+ media permissions.
Dev Tools2026-05-04
Microphone and Audio Recording Not Working in Rork — A Symptom-Based Troubleshooting Guide
When microphone or audio recording stops working in a Rork-generated app, the root cause is often not obvious. This guide walks through common failure patterns — permissions, audio mode setup, simulator limits, and async pitfalls — with working code fixes.
Dev Tools2026-04-23
Why Your Rork App Can't Save Images to the Camera Roll — A Complete Fix
Image and video saving often breaks the moment a Rork-generated app leaves the simulator. This guide walks through the permission model, expo-media-library quirks, and Android 13+ scoped storage changes that reliably trip people up.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →