Skip to main content

Working with Location (expo-location)

1. Requesting Location Permissions

Permission Description Status Usage
ACCESS_FINE_LOCATION Allows access to precise location data NEW Required for high-accuracy geolocation
ACCESS_COARSE_LOCATION Allows access to approximate location data STABLE Used for less precise location services

Example: Requesting Location Permissions

import * as Permissions from 'expo-permissions';
import * as Location from 'expo-location';

const requestLocationPermission = async () => {
  const { status } = await Permissions.askAsync(Permissions.LOCATION);
  if (status !== 'granted') {
    console.log('Permission to access location was denied');
    return false;
  }
  return true;
};
Note: On Android, you must also add the ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions to your app.json or app.config.js.
Warning: Users may deny location permissions, which can lead to incomplete or inaccurate geolocation data. Always handle permission denials gracefully.

2. Getting Current Position

Property Description Default Notes
accuracy Accuracy level of the location data 10 Higher values mean more accurate but slower results
distanceInterval Minimum distance (in meters) to travel before updating location 0 Set to 0 for updates on every movement
heading Include heading information in the result false Requires additional permissions on some platforms

Example: Requesting Current Position

import * as Location from 'expo-location';

const getCurrentLocation = async () => {
  try {
    const { coords } = await Location.getCurrentPositionAsync({
      accuracy: Location.Accuracy.High,
      distanceInterval: 10,
    });

    console.log("Latitude:", coords.latitude);
    console.log("Longitude:", coords.longitude);
  } catch (error) {
    console.error("Error getting location:", error);
  }
};

getCurrentLocation();
Note: The user must grant location permissions for this to work. On iOS, you need to add NSLocationWhenInUseUsageDescription or NSLocationAlwaysAndWhenInUseUsageDescription to your Info.plist.
Warning: On Android, you must request ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions at runtime.

3. Watching Position Changes

Property Description Values
watchPositionAsync Starts watching for position changes Promise<Position>
watchPositionAsync(options) Options object to configure watching Object

Example: Watching Position Changes

import * as Location from &#x27;expo-location&#x27;;

const watchPosition = async () => {
  const { coords } = await Location.watchPositionAsync(
    {
      accuracy: Location.Accuracy.High,
      distanceInterval: 10,
      timeInterval: 5000,
    },
    (location) => {
      console.log("New location:", location.coords);
    }
  );
};

watchPosition();
Note: The callback function will be called every time the location changes according to the specified interval.
Warning: Make sure to stop watching when no longer needed using Location.stopWatchingPositionAsync to prevent memory leaks.
Option Description Default Value Notes
accuracy Desired accuracy level Location.Accuracy.High Use Location.Accuracy.Balanced for lower power usage
distanceInterval Minimum distance in meters to trigger a new position update 10 Set to 0 for updates on every change
timeInterval Minimum time in milliseconds between updates 5000 Set to 0 for updates on every change

4. Reverse Geocoding

Reverse geocoding is the process of converting geographic coordinates (latitude and longitude) into human-readable addresses.

Property Description Example
location Object containing latitude and longitude { latitude: 40.7128, longitude: -74.0060 }
locale Locale to use for address formatting (optional) 'en-US'

Example: Reverse Geocoding

import * as Location from 'expo-location';

const address = await Location.reverseGeocodeAsync({
  latitude: 40.7128,
  longitude: -74.0060,
});

console.log(address[0].formattedAddress);
// Output: "123 Main St, New York, NY 10001, USA"
Note: The reverseGeocodeAsync function returns an array of address objects. The first object in the array is typically the most accurate match.

5. Forward Geocoding

Property Description Values
address Address to geocode "1600 Amphitheatre Parkway, Mountain View, CA"
latitude Latitude of the location 37.4223
longitude Longitude of the location -122.0843

Example: Forward Geocoding an Address

import * as Location from 'expo-location';

const address = '1600 Amphitheatre Parkway, Mountain View, CA';
const geocoded = await Location.geocodeAsync(address);

console.log(geocoded[0]); // First geocoded result
Note: The geocodeAsync function returns an array of geocoded results. Each result includes latitude, longitude, and address components.

6. Setting Location Accuracy

Accuracy Level Description Use Case Notes
HIGH_ACCURACY Uses GPS and network-based location sources for the most precise location data. Navigation, mapping, real-time tracking May drain battery faster
MEDIUM_ACCURACY Uses GPS and network-based location sources, but with reduced precision for better battery life. General purpose apps, weather, local search Recommended for most use cases
LOW_ACCURACY Uses network-based location sources only (e.g., WiFi, cellular towers). Basic location services, app launch tracking Least battery drain, least accurate
PASSIVE Uses location data from other apps running on the device. Background tracking, analytics No direct access to GPS; relies on other apps

Example: Setting Location Accuracy

import * as Location from 'expo-location';

await Location.requestPermissionsAsync();

const location = await Location.getCurrentPositionAsync({
  accuracy: Location.Accuracy.High,
});

console.log(location.coords.latitude, location.coords.longitude);
Note: The accuracy property is part of the LocationOptions object used in methods like getCurrentPositionAsync and watchPositionAsync.

7. Requesting Background Permissions

Permission Description Required in Manifest Notes
ACCESS_FINE_LOCATION Allows access to precise location data Yes Required for background location access
ACCESS_COARSE_LOCATION Allows access to approximate location data Yes May be sufficient for some background use cases
ACCESS_BACKGROUND_LOCATION Allows access to location in background Yes Must be declared in manifest for background use

Example: Requesting Background Location Permission

import * as Location from &#x27;expo-location&#x27;;

const requestBackgroundLocationPermission = async () => {
  const { status } = await Location.requestForegroundPermissionsAsync();
  if (status !== &#x27;granted&#x27;) {
    console.log(&#x27;Permission to access location was denied&#x27;);
    return;
  }

  // For background access, you may need to request separately
  const backgroundStatus = await Location.requestBackgroundPermissionsAsync();
  if (backgroundStatus.status !== &#x27;granted&#x27;) {
    console.log(&#x27;Permission to access location in background was denied&#x27;);
  }
};
Note: On Android, background location permissions require additional setup in AndroidManifest.xml and may need to be requested separately from foreground permissions.
Warning: Users must explicitly grant background location permission in system settings. The app cannot request it directly if the user has previously denied it.

8. Starting Location Updates

Method Description Notes
Location.watchPositionAsync() Starts watching for location updates Returns a subscription object to stop watching

Example: Starting Location Updates

import * as Location from 'expo-location';

const startLocationUpdates = async () => {
  const { granted } = await Location.requestForegroundPermissionsAsync();
  if (!granted) {
    console.log('Permission denied');
    return;
  }

  const subscription = await Location.watchPositionAsync(
    {
      accuracy: Location.Accuracy.High,
      distanceInterval: 10,
      timeInterval: 1000,
    },
    (location) => {
      console.log('New location:', location.coords);
    }
  );

  return subscription;
};

startLocationUpdates();
Note: Ensure you have the necessary permissions declared in your app's manifest and that the user has granted location access.

9. Getting Last Known Position

Property Description Example
getLastKnownPositionAsync Retrieves the last known position of the device
import * as Location from 'expo-location';

const lastPosition = await Location.getLastKnownPositionAsync();
console.log(lastPosition);
Note: The last known position may be outdated or unavailable if the device has not moved recently.

10. Checking Location Services

Property Description Values
hasLocationPermission Indicates if the app has location permission true or false
hasBackgroundLocationPermission Indicates if the app has background location permission true or false
hasFineLocationPermission Indicates if the app has fine location permission true or false
hasCoarseLocationPermission Indicates if the app has coarse location permission true or false

Example: Check Location Permissions

import * as Location from 'expo-location';

const checkLocationPermissions = async () => {
  const { status } = await Location.requestForegroundPermissionsAsync();
  console.log("Location permission status:", status);
};

checkLocationPermissions();
Note: On Android, you must request ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions in your app's manifest.
Warning: On iOS, location permissions are requested at runtime. If the user denies permission, you must guide them to enable it in Settings.

11. Handling Location Errors

Error Type Description How to Handle
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION Permission denied for fine location access Request permission again or guide user to enable in settings
PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION Permission denied for coarse location access Request permission again or guide user to enable in settings
ExpoLocation.PermissionDeniedError User denied location permission Inform user and provide steps to enable permissions
ExpoLocation.PositionUnavailableError Location is unavailable (e.g., GPS is off) Inform user to enable location services
ExpoLocation.TimeoutError Location request timed out Retry or inform user to try again later

Example: Handling Location Errors

import * as Location from 'expo-location';

try {
  const location = await Location.getCurrentPositionAsync({});
} catch (error) {
  if (error.code === 'PERMISSION_DENIED') {
    console.log("Location permission denied");
  } else if (error.code === 'POSITION_UNAVAILABLE') {
    console.log("Location is unavailable");
  } else if (error.code === 'TIMEOUT') {
    console.log("Location request timed out");
  } else {
    console.log("Unknown error: ", error.message);
  }
}

12. Using Heading Updates

Property Description Notes
heading number Current heading in degrees (0-360)
magneticHeading number Heading relative to magnetic north
trueHeading number Heading relative to true north
accuracy number Estimated accuracy of heading in degrees

Example: Subscribe to Heading Updates

import * as Location from 'expo-location';

const subscribeToHeading = async () => {
  const { granted } = await Location.requestForegroundPermissionsAsync();
  if (!granted) {
    console.log("Permission denied");
    return;
  }

  const subscription = await Location.watchHeadingAsync((heading) => {
    console.log("Heading:", heading);
  });

  // To stop watching:
  // subscription.remove();
};

subscribeToHeading();
Note: Heading updates are only available on devices with a compass sensor. On devices without a compass, the heading will be null.

Was this article helpful?