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-04-27Intermediate

Five Things to Check First When Geolocation Stops Working in Your Rork App

Geolocation looks easy until it doesn't work. This guide walks through the five most common reasons your Rork app can't read the user's location — from a missing app.json plugin block to subtle simulator quirks.

troubleshooting65geolocationexpo-locationpermissions7rork58

When you ask Rork to "build me a nearby-shop finder" or "build me a running tracker," the AI happily wires up expo-location or react-native-geolocation and the code looks reasonable. Then you run it on a real device and nothing happens. No coordinates. No permission dialog. Sometimes a silent timeout, sometimes a flat-out crash. I've spent more than half a day chasing this on a single project, and the punchline is almost always something other than the JavaScript itself.

Location is one of those features where the code can be perfect but a missing line in app.json, a simulator setting, or an OS-level toggle stops everything. This article walks through the five checks I now run, in order, whenever a Rork-generated app refuses to deliver coordinates.

1. Figure out whether the dialog is even showing

Before anything else, separate two very different problems: "the dialog appeared and the user denied it" versus "the dialog never appeared at all." The fixes are completely different.

On iOS, open Settings → your app → Location. If the row is missing entirely, your app has never asked for location permission. On Android, go to Settings → Apps → your app → Permissions and check the same way.

// Log the current permission state so you can tell which case you're in
import * as Location from 'expo-location';
 
async function checkLocationPermission() {
  const { status, canAskAgain, granted } = await Location.getForegroundPermissionsAsync();
  console.log('current state:', { status, canAskAgain, granted });
  // Expected outputs:
  // { status: 'undetermined', canAskAgain: true, granted: false } -> never requested
  // { status: 'denied', canAskAgain: false, granted: false }     -> denied, can't reprompt
  // { status: 'granted', canAskAgain: true, granted: true }      -> good to go
}

If status is undetermined and you've never called requestForegroundPermissionsAsync(), jump to point 3. If it's denied with canAskAgain: false, you can't reprompt from code — your only path is a button that opens system settings.

2. The missing app.json plugin block (by far the most common cause)

In my experience, this is the single biggest reason Rork-generated apps silently fail at location. Just installing expo-location doesn't add the iOS usage descriptions, so the build succeeds but the dialog never appears on a real device.

Add the plugin block to app.json:

{
  "expo": {
    "plugins": [
      [
        "expo-location",
        {
          "locationAlwaysAndWhenInUsePermission": "We use your location to track runs in the background and on screen.",
          "locationWhenInUsePermission": "We use your location to show nearby shops.",
          "isIosBackgroundLocationEnabled": false,
          "isAndroidBackgroundLocationEnabled": false
        }
      ]
    ]
  }
}

The wording matters. Apple's review team will reject vague strings like "we use your location" — you need a sentence that makes the user's brain say "okay, that's reasonable." Tie the explanation to a concrete feature: tracking a run, showing nearby shops, calculating delivery distance.

After updating app.json, Expo Go will not pick up the change. You need to run npx expo prebuild --clean to regenerate the native projects and then build a fresh dev or production binary with EAS Build. Forgetting this step is what makes people swear they "fixed the JS but it still doesn't work."

3. Asking for permission too early

Rork tends to put the permission request inside the top-level useEffect, firing it the second the app launches. It works, but it's a bad UX choice — and on iOS, dialogs that appear before the user has done anything tend to get reflexively denied.

// Bad: hits the user with a dialog the moment the app opens
useEffect(() => {
  (async () => {
    await Location.requestForegroundPermissionsAsync();
  })();
}, []);
 
// Good: ask only when the user taps "use my current location"
const handleUseCurrentLocation = async () => {
  const { status } = await Location.requestForegroundPermissionsAsync();
  if (status !== 'granted') {
    Alert.alert(
      'Location needed',
      'To search near you, please allow location access in Settings.',
      [
        { text: 'Cancel', style: 'cancel' },
        { text: 'Open Settings', onPress: () => Linking.openSettings() },
      ]
    );
    return;
  }
  const location = await Location.getCurrentPositionAsync({});
  setLocation(location);
};

Tying the request to a clear user action — a "find nearby" button, a map screen, a "start run" tap — typically doubles or triples the grant rate compared to asking on launch.

4. Works on the simulator, fails on real devices

If your code works in the simulator but breaks on a phone (or vice versa), one of these is almost always the culprit:

  • iOS simulator location is set to None. In the simulator menu, Features → Location must be set to something other than "None" for the simulator to return coordinates. "Apple" or "City Run" gives you a moving fake location.
  • Real device with weak signal indoors. GPS cold-start can take 10+ seconds indoors. A 3-second timeout will fail nearly every time. Set getCurrentPositionAsync({ timeout: 15000 }) or fall back to a network-based lookup.
  • Android device-wide location services off. On Android, app permission can be "granted" while the device's overall location switch is off. You need Location.hasServicesEnabledAsync() as a pre-check.
async function getLocationSafely() {
  // Android: is the device-wide location switch on?
  const enabled = await Location.hasServicesEnabledAsync();
  if (!enabled) {
    Alert.alert('Location services off', 'Please turn on location services in your device settings.');
    return null;
  }
 
  const { status } = await Location.requestForegroundPermissionsAsync();
  if (status !== 'granted') return null;
 
  try {
    const location = await Location.getCurrentPositionAsync({
      accuracy: Location.Accuracy.Balanced, // good enough for most map use cases
      timeout: 15000,
    });
    return location;
  } catch (error) {
    console.error('location failed:', error);
    return null;
  }
}

I'd avoid defaulting to Location.Accuracy.Highest. It drains battery and is much more likely to time out indoors. For a "show me on a map" feature, Balanced or High is plenty.

5. The background-location trap

For features like "keep tracking a run when the screen is off" or "follow a delivery driver in the background," foreground permission isn't enough. This is where things get noticeably harder, and Rork's initial scaffold rarely covers it.

On iOS you need isIosBackgroundLocationEnabled: true in your plugin config and UIBackgroundModes including location in the Info.plist. The user also has to choose "Always" — and Apple's review process scrutinizes background location more than almost any other API. If the user has only granted "While Using," background-location calls will silently return nothing.

// Always request foreground first, then background
async function requestBackgroundPermission() {
  const fg = await Location.requestForegroundPermissionsAsync();
  if (fg.status !== 'granted') return false;
 
  // On iOS, a brief delay between the two prompts improves grant rates
  await new Promise((r) => setTimeout(r, 500));
 
  const bg = await Location.requestBackgroundPermissionsAsync();
  return bg.status === 'granted';
}

For App Store review, the reason for background location must be obvious from the feature itself. If you don't actually need "Always," strip it out — your reviewer will be happier and your users will grant foreground permission far more readily.

A quick checklist for next time

When location stops working, run through these in order:

  • Log getForegroundPermissionsAsync() and read the status
  • Open Settings on the device and check whether the app's Location row exists
  • Verify the expo-location plugin block in app.json is correct
  • Confirm you've run npx expo prebuild --clean and rebuilt with EAS
  • Check the simulator's Location setting, or the device's location-services toggle
  • Bump the timeout to ~15 seconds and lower accuracy to Balanced
  • Reconsider whether you actually need background location

Location bugs feel mysterious because the failure mode is so often silent. Working through the list above turns a half-day debugging session into a 15-minute checklist.

If you want to think more broadly about permissions in Rork apps, our Rork Permissions Troubleshooting Guide covers the same patterns for camera, notifications, and photo library — the ideas transfer directly.

The fastest move you can make today is to drop a single console.log of getForegroundPermissionsAsync() into your app and run it on a real device. That one log usually points straight at which of the five issues above is biting you.

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-24
Why your Rork app shows a blank screen or loses state after returning from background
Your Rork app sits in the background overnight, you tap the icon the next morning, and the screen is blank — or your drafts have disappeared, or you have been silently logged out. iOS process reclamation, AsyncStorage rehydration timing, and Navigation state restoration each cause a different version of this bug. Notes from running wallpaper and wellness apps with 50M downloads as an indie developer.
Dev Tools2026-05-23
Rork-Specific 'expo start --offline forbidden': Four Causes in Rork's Template Config
When expo start --offline returns 'forbidden' specifically on a Rork-generated project, the cause is usually Rork template config: tsconfigPaths, an un-generated expo-router cache, native prebuild, or a lockfile mismatch. Four Rork-specific fixes; the generic Expo proxy and dependency-validation guide is covered separately.
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.
📚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 →