Location
The user can share where they are in a message: once, as a static location, or for a while, as a live location that follows them. The location composer, messageComposer.locationComposer, holds the location to share until it's sent.
Example
The user wants to show the channel where they are for the next 15 minutes:
- The user's app reads the device's position and gives it to the location composer, with a duration of 15 minutes.
- The composer sends a message that carries the location.
- For the next 15 minutes, the user's app sends each new position of the device to the server.
- The other members' apps receive each new position as an update of that message, and their map moves with the user. After 15 minutes, the updates stop.
The SDK has no location picker and doesn't read the device's position. Your app reads it and gives it to the location composer, as Location sharing explains.
What it holds
The location composer's state is in locationComposer.state. Its one field, location, is the location to share, or null when there is none:
| Field | What it holds | Set by |
|---|---|---|
latitude |
The position's latitude. | your app |
longitude |
The position's longitude. | your app |
durationMs |
For a live location: how long to share it, in milliseconds. Absent for a static location. | your app |
end_at |
Only while a message with a live location is edited: when its sharing ends, taken from the message. | the edited message |
message_id |
The id of the message that will carry the location, which is the composer's id. |
the composer |
created_by_device_id |
The device the location is shared from. | the composer, from the getDeviceId setting |
The composer adds message_id and created_by_device_id itself. By default, the device id is a random one, new for each composer. To keep one id per device, set messageComposer.location.getDeviceId in client.config to return an id your app stores, as Settings shows.
A new live location gets its end_at when the message is sent: the send time plus durationMs. The message then carries it in message.shared_location.end_at. While that message is edited, the composer keeps its end_at, so editing doesn't extend the sharing.
Two getters read the location:
| Getter | Returns | Use it to |
|---|---|---|
locationComposer.location |
The location as the composer holds it, or null. |
show what's being shared |
locationComposer.validLocation |
The location the composer will send, or null when it can't be sent yet: a field is missing, or durationMs is shorter than the minShareDurationMs setting. MessageComposer.sendLocation() sends nothing while it's null. |
enable sharing only when the location can be sent |
Sharing a location
What a location picker needs, and the call for each:
| To... | Call | What happens |
|---|---|---|
| set the location to share | LocationComposer.setData({ latitude, longitude }) |
Sets the location, with the composer's id and the device id. Does nothing while location sharing is off, or when latitude or longitude is missing. |
| set a live location | LocationComposer.setData({ latitude, longitude, durationMs }) |
The same, for a location shared for durationMs milliseconds. |
| send the location as a message of its own | MessageComposer.sendLocation() |
Sends a message that carries only the location, then removes the location from the composer and gives the composer a new id. Text and attachments stay. Does nothing in a thread composer, or while locationComposer.validLocation is null. |
| remove the location | LocationComposer.initState() |
Sets location back to null. |
const composer = channel.messageComposer;
composer.locationComposer.setData({
durationMs: 15 * 60 * 1000,
latitude: 50.0875,
longitude: 14.4213,
});
await composer.sendLocation();MessageComposer.sendLocation() doesn't add the message to the list at once: the message appears when the server's copy arrives. When the request fails, it publishes an api:location:create:failed notification and throws.
A valid location also counts as content for MessageComposer.send(), which then sends it as the message's shared_location, together with the text and attachments. The SDK's composer shows no preview of a location it holds.
Once a live location is shared, its updates are not the composer's job. Location sharing explains how LiveLocationManager sends them and how the sharing stops.
When location sharing is on
Location sharing is on while messageComposer.config.location.enabled is true. That's when both the location.enabled setting in client.config and the channel type's shared_locations setting are on. While sharing is off, LocationComposer.setData() ignores the location it's given, so the composer has no new location to send.
Settings
Set them for every composer in client.config, under messageComposer.location:
import { StreamChat } from "stream-chat";
const client = StreamChat.getInstance("YOUR_API_KEY");
const deviceId = "my-app-device-id"; // for example, an id your app keeps for this device
client.config.set({
messageComposer: {
location: {
getDeviceId: () => deviceId,
minShareDurationMs: 5 * 60 * 1000,
},
},
});The location composer has no setters. To change a setting for one composer only, patch that composer's configuration, for example channel.messageComposer.updateConfig({ location: { enabled: false } }).
| Setting | Default | What it does |
|---|---|---|
enabled |
true |
false turns off location sharing. Combined with the channel type's shared_locations setting. |
getDeviceId |
a new random id per composer | Returns the id of the device the location is shared from. The default gives each composer a different id: to keep one id per device, return an id your app stores. A composer calls it once, when it's created, as Settings read once explains. |
minShareDurationMs |
60000, one minute |
The shortest durationMs a live location can have. A location with a shorter one isn't valid, so it isn't sent. |
See Location sharing for the feature.