# Location Sharing

Location sharing lets users share their current position or real-time location. Stream Chat supports static and live sharing.

There are two types of location sharing:

- **Static Location**: A one-time location share that does not update over time.
- **Live Location**: A real-time location share that updates over time for a specified duration.

## Best Practices

- Request location permissions just-in-time and explain why you need them.
- Provide clear UI to stop live sharing and surface remaining time.
- Avoid high-frequency updates; use reasonable intervals to save battery.
- Handle permission denial gracefully by falling back to static sharing.
- Store location metadata on the message to render without extra lookups.

The SDK handles location messages and updates, but your app must handle device location tracking.

## Adding Live Location Sharing

This guide adds location sharing to a React Native chat app. The SDK provides the backend logic but not default UI. Use the examples in the [Sample App](https://github.com/GetStream/stream-chat-react-native/v8/tree/develop/examples/SampleApp) or [Expo Messaging app](https://github.com/GetStream/stream-chat-react-native/v8/tree/develop/examples/ExpoMessaging) as a reference.

## Setup

### Install Dependencies

Install dependencies:

<tabs>

<tabs-item value="native cli" label="Native CLI">

```bash
yarn add @react-native-community/geolocation
yarn add react-native-maps
```

- `@react-native-community/geolocation` library is used to watch the current location of the user and then send it in the message
- `react-native-maps` is used to display the location of the user using the native maps present on iOS and Android

</tabs-item>

<tabs-item value="expo" label="Expo">

```bash
yarn add expo-location
yarn add react-native-maps
```

- `expo-location` library is used to watch the current location of the user and then send it in the message
- `react-native-maps` is used to display the location of the user using the native maps present on iOS and Android

</tabs-item>

</tabs>

### Configure location permissions

To configure location permissions, you need to follow the platform-specific instructions below:

<tabs>

<tabs-item value="native cli" label="Native CLI">

**iOS**

You need to include `NSLocationWhenInUseUsageDescription` and `NSLocationAlwaysAndWhenInUseUsageDescription` in `Info.plist` to enable geolocation when using the app.

**Android**

To request access to location, you need to add the following line to your app's `AndroidManifest.xml`:

```xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
```

### Android: Add API Key

On Android, one has to use [Google Maps](https://developers.google.com/maps/documentation/), which in turn requires you to obtain an [API key for the Android SDK](https://developers.google.com/maps/documentation/android-sdk/signup). On iOS, the native Apple Maps implementation is used and API keys are not necessary.

Add your API key to your manifest file (`android/app/src/main/AndroidManifest.xml`):

```xml
<application>
   <!-- You will only need to add this meta-data tag, but make sure it's a child of application -->
   <meta-data
     android:name="com.google.android.geo.API_KEY"
     android:value="Your Google maps API Key Here"/>
</application>
```

</tabs-item>

<tabs-item value="expo" label="Expo">

Configure the location permissions in your `app.json` or `app.config.js` file:

```json
{
  "expo": {
    "plugins": [
      [
        "expo-location",
        {
          "locationAlwaysAndWhenInUsePermission": "Allow $(PRODUCT_NAME) to use your location."
        }
      ]
    ]
  }
}
```

Alternatively, you can follow this [`guide`](https://docs.expo.dev/versions/latest/sdk/location/#example-appjson-with-config-plugin).

#### Android: Add API Key

To set up the google maps API key, you can add the following to your `app.json` or `app.config.js` file:

```json
{
  "expo": {
    "android": {
      "config": {
        "googleMaps": {
          "apiKey": "Your Google maps API Key Here"
        }
      }
    }
  }
}
```

Alternatively, you can follow this [`guide`](https://docs.expo.dev/versions/latest/sdk/map-view/#deploy-app-with-google-maps).

</tabs-item>

</tabs>

## Implementation outline

You will build:

- A modal for static/live sharing
- A map renderer in `MessageList`
- A full-screen map on tap
- A way to stop live sharing and update the message

### Creating a static/live location message

To create a static location message, set data on `messageComposer.locationComposer`, then call `sendLocation`:

```ts
const sendStaticLocation = async () => {
  const { latitude, longitude } = await getCurrentLocation();
  await messageComposer.locationComposer.setData({
    latitude,
    longitude,
  });
  await messageComposer.sendLocation();
};
```

To create a live location message, set data on `locationComposer`, then call `sendLocation`. It will watch location changes and update the message.

```ts
const sendLiveLocation = async () => {
  const { latitude, longitude } = await getCurrentLocation();
  await messageComposer.locationComposer.setData({
    durationMs: 600000, // 10 minutes
    latitude,
    longitude,
  });
  await messageComposer.sendLocation();
};
```

![Preview of create location modal](@chat-sdk/react-native/v8/_assets/guides/location-sharing/location-creation-modal.png)

An example implementation using the Geolocation `watchPosition` method to send the static or live location message can be found here:

- [Expo](https://github.com/GetStream/stream-chat-react-native/v8/blob/develop/examples/ExpoMessaging/components/LocationSharing/CreateLocationModal.tsx)
- [Native CLI](https://github.com/GetStream/stream-chat-react-native/v8/blob/develop/examples/SampleApp/src/components/LocationSharing/CreateLocationModal.tsx)

To add the location sharing button, you can customize the `InputButtons` component in the `Channel` component. You can add a button that opens the modal to share the location.

```tsx
import React, { useState } from "react";
import { Pressable, StyleSheet } from "react-native";
import { Channel, InputButtons as DefaultInputButtons } from "stream-chat-expo";
import { ShareLocationIcon } from "../icons/ShareLocationIcon";
import { LiveLocationCreateModal } from "./LocationSharing/CreateLocationModal";

const InputButtons: NonNullable<
  React.ComponentProps<typeof Channel>["InputButtons"]
> = (props) => {
  const [modalVisible, setModalVisible] = useState(false);

  const onRequestClose = () => {
    setModalVisible(false);
  };

  const onOpenModal = () => {
    setModalVisible(true);
  };

  return (
    <>
      <DefaultInputButtons {...props} hasCommands={false} />
      <Pressable style={styles.liveLocationButton} onPress={onOpenModal}>
        <ShareLocationIcon />
      </Pressable>
      <LiveLocationCreateModal
        visible={modalVisible}
        onRequestClose={onRequestClose}
      />
    </>
  );
};

const styles = StyleSheet.create({
  liveLocationButton: {
    paddingLeft: 5,
  },
});

export default InputButtons;
```

### Showing the shared location in a message

If a message includes location data, you'll get the `shared_location` field with latitude/longitude and other details. The SDK does not provide default UI for this, so create a custom component to render the map and pass it via the `MessageLocation` prop on `Channel`.

To render the map, use `react-native-maps` and build a component that takes latitude/longitude.

![Preview of message location](@chat-sdk/react-native/v8/_assets/guides/location-sharing/message-location.png)

Example `MessageLocation` implementations:

- [Expo](https://github.com/GetStream/stream-chat-react-native/v8/blob/develop/examples/ExpoMessaging/components/LocationSharing/MessageLocation.tsx)
- [Native CLI](https://github.com/GetStream/stream-chat-react-native/v8/blob/develop/examples/SampleApp/src/components/LocationSharing/MessageLocation.tsx)

### Watching location globally with the manager

An app can have multiple active live locations across channels. Use `client.getSharedLocations()` to fetch `active_live_locations` for the current user.

To manage the live location sharing, we use the `LiveLocationManager` class from the `stream-chat` package. This manager allows you to watch the live location sharing for a specific message and update it in real-time.

The SDK exposes a context provider that supplies a `LiveLocationManager` instance and handles event registration/deregistration.

Wrap your app with `LiveLocationManagerProvider` from `stream-chat-react-native`. It expects a `watchLocation` function that watches device location.

Example `watchLocation` implementations:

<tabs>

<tabs-item value="native cli" label="Native CLI">

```ts
import Geolocation from "@react-native-community/geolocation";

type LocationHandler = (value: { latitude: number; longitude: number }) => void;

export const watchLocation = (handler: LocationHandler) => {
  let watchId: number | null = null;
  watchId = Geolocation.watchPosition(
    (position) => {
      const { latitude, longitude } = position.coords;
      handler({ latitude, longitude });
    },
    (error) => {
      console.warn("Error watching location:", error);
    },
    {
      enableHighAccuracy: true,
      timeout: 20000,
      maximumAge: 1000,
      interval: 2000, // android only
    },
  );

  return () => {
    if (watchId) {
      Geolocation.clearWatch(watchId);
    }
  };
};
```

</tabs-item>

<tabs-item value="expo" label="Expo">

```ts
import * as Location from "expo-location";

export type LocationHandler = (value: {
  latitude: number;
  longitude: number;
}) => void;

export const watchLocation = (handler: LocationHandler) => {
  let subscription: Location.LocationSubscription | null = null;
  Location.watchPositionAsync(
    {
      accuracy: Location.Accuracy.High,
      distanceInterval: 0,
      // Android only: these option are ignored on iOS
      timeInterval: 2000,
    },
    (location) => {
      const { latitude, longitude } = location.coords;
      handler({ latitude, longitude });
    },
    (error) => {
      console.warn("Error watching location:", error);
    },
  ).then((sub) => {
    subscription = sub;
  });

  return () => {
    subscription?.remove();
  };
};
```

</tabs-item>

</tabs>

Use it in your app:

```tsx
import { LiveLocationManagerProvider } from "stream-chat-react-native";

const App = () => {
  return (
    <LiveLocationManagerProvider watchLocation={watchLocation}>
      {/* Your app components */}
    </LiveLocationManagerProvider>
  );
};
```

Optionally pass `getDeviceId` (returns a string) to identify the device sharing the location.

### Navigating from the message to the map detail screen

To show a full-screen map, navigate to a detail screen when the user taps the location message. Use `onPressMessage` on `Channel`.

<tabs>

<tabs-item value="native cli" label="Native CLI">

```tsx
const App = () => {
  const onPressMessage: NonNullable<
    React.ComponentProps<typeof Channel>["onPressMessage"]
  > = (payload) => {
    const { message, defaultHandler, emitter } = payload;
    const { shared_location } = message ?? {};
    if (emitter === "messageContent" && shared_location) {
      navigation.navigate("MapScreen", shared_location);
    }
    defaultHandler?.();
  };

  return <Channel onPressMessage={onPressMessage}></Channel>;
};
```

</tabs-item>

<tabs-item value="expo" label="Expo">

```tsx
const App = () => {
  const onPressMessage: NonNullable<
    React.ComponentProps<typeof Channel>["onPressMessage"]
  > = (payload) => {
    const { message, defaultHandler, emitter } = payload;
    const { shared_location } = message;
    if (emitter === "messageContent" && shared_location) {
      // Create url params from shared_location
      const params = Object.entries(shared_location)
        .map(([key, value]) => `${key}=${value}`)
        .join("&");
      router.push(`/map/${message.id}?${params}`);
    }
    defaultHandler?.();
  };

  return <Channel onPressMessage={onPressMessage}></Channel>;
};
```

</tabs-item>

</tabs>

## Add the map details screen

This screen displays the location in a full-screen map, a stop-sharing button, and the end timestamp (if applicable).

| Current Location                                                                                                     | Live Location                                                                                                     | Live Location Ended                                                                                                     |
| -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| ![Preview of chat screen](@chat-sdk/react-native/v8/_assets/guides/location-sharing/current-location-fullscreen.png) | ![Preview of chat screen](@chat-sdk/react-native/v8/_assets/guides/location-sharing/live-location-fullscreen.png) | ![Preview of chat screen](@chat-sdk/react-native/v8/_assets/guides/location-sharing/live-location-ended-fullscreen.png) |

To keep the screen up to date, listen for backend events.

One of them being:

- `message.updated` - Received when the message's `shared_location` changes.

Use `useHandleLiveLocationEvents` with `messageId`, `channel`, and `onLocationUpdate`.

`onLocationUpdate` is called when `message.updated` fires and can update the map marker.

Example `MapScreen` implementations:

- [Expo](https://github.com/GetStream/stream-chat-react-native/v8/blob/develop/examples/ExpoMessaging/app/map/%5Bid%5D.tsx)
- [Native CLI](https://github.com/GetStream/stream-chat-react-native/v8/blob/develop/examples/SampleApp/src/screens/MapScreen.tsx)

You should now see the detailed map screen:

## Stopping the live location sharing

To stop the live location sharing, you can use the `stopLiveLocationSharing` function from the `client`. It expects the current location response as argument.

```tsx
const stopSharingLiveLocation = async () => {
  if (!locationResponse) {
    return;
  }
  await channel?.stopLiveLocationSharing(locationResponse);
};
```

## Sample code

This cookbook is available as a full sample app:

- [Expo](https://github.com/GetStream/stream-chat-react-native/v8/blob/develop/examples/ExpoMessaging)
- [Native CLI](https://github.com/GetStream/stream-chat-react-native/v8/blob/develop/examples/SampleApp)


---

This page was last updated at 2026-04-17T17:33:45.417Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v8/guides/location-sharing/](https://getstream.io/chat/docs/sdk/react-native/v8/guides/location-sharing/).