> ## Documentation Index
> Fetch the complete documentation index at: https://docs.photon.codes/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Locations

> Request, list, fetch, and watch shared Find My friend locations

`im.locations` sends Find My location-sharing requests and reads friend locations that are already visible to the current iMessage account.

Use `request(chat, address)` when you want to ask someone to share location. Use `list(...)`, `get(...)`, and `watch(...)` after location is already shared with the current account.

<Warning>
  Location updates are not part of the durable event log. `im.locations.watch(...)` is a dedicated live stream. Updates missed while disconnected cannot be replayed with [`im.events.catchUp(...)`](/advanced-kits/imessage/events).
</Warning>

## What You Can Do

| Need                     | Use this when                                                         |
| ------------------------ | --------------------------------------------------------------------- |
| Request location sharing | You want to send a visible Find My request card to a chat participant |
| List shared locations    | You want every currently visible friend location                      |
| Fetch one location       | You want the latest snapshot for one friend                           |
| Watch live updates       | You are updating a map or background job as locations change          |

## Before You Use It

| Rule                           | Meaning                                                                                                |
| ------------------------------ | ------------------------------------------------------------------------------------------------------ |
| Requests do not grant access   | `request(...)` only sends a visible request card; the other person must accept or start sharing        |
| Reads only show visible shares | `list(...)`, `get(...)`, and `watch(...)` only return locations already visible to the current account |
| Coordinates can be absent      | Check both `latitude` and `longitude` before plotting a point                                          |
| Missed updates are gone        | `watch(...)` updates missed during a disconnect are not replayed by `catchUp(...)`                     |

## Request Location Sharing

Send a visible Find My request card in an existing direct or group chat:

```ts theme={null}
const receipt = await im.locations.request(chat.guid, "alice@example.com");

console.log(receipt.status, receipt.messageGuid);
```

Inputs:

| Argument                  | Meaning                                                                                           |
| ------------------------- | ------------------------------------------------------------------------------------------------- |
| `chat`                    | Where to send the request card. Pass a direct or group `chat.guid`, not an email or phone number. |
| `address`                 | Who to ask for location. Pass that person's full email address or E.164 phone number.             |
| `options.clientMessageId` | Optional idempotency key for retrying the same logical request.                                   |

The `address` must belong to someone in `chat`. In a direct chat, that means the other participant. In a group chat, that means an existing group member.

Returns `LocationRequestReceipt`. A successful call means the request card was sent or the server accepted the request operation. It does not mean the other person is now sharing location.

The returned receipt includes:

| Field         | Meaning                                                               |
| ------------- | --------------------------------------------------------------------- |
| `address`     | The normalized email address or E.164 phone number that was requested |
| `status`      | Server status for the request operation                               |
| `reason`      | Optional reason when the request was not sent or needs explanation    |
| `messageGuid` | Message GUID for the request card, when a card was created            |

When `messageGuid` is present, use it like any other message GUID. For example, you can look it up with [`im.messages.get(...)`](/advanced-kits/imessage/messages).

For idempotent retries from your job system, pass `clientMessageId`:

```ts theme={null}
await im.locations.request(chat.guid, "alice@example.com", {
  clientMessageId: `location-request-${job.id}`,
});
```

<Note>
  `clientMessageId` is only needed when your queue or worker may rerun the same logical request after a crash or timeout. Most direct calls can omit it. See [error handling](/advanced-kits/imessage/error-handling) for details.
</Note>

After the other person accepts or starts sharing, use `get(...)`, `list(...)`, or `watch(...)` to read their location.

## List Shared Locations

```ts theme={null}
const locations = await im.locations.list();

for (const location of locations) {
  if (location.latitude === undefined || location.longitude === undefined) {
    continue;
  }

  console.log(location.address, location.latitude, location.longitude);
}
```

`list(...)` takes no arguments.

Returns `SharedFriendLocation[]`. If no friends are sharing location, the array is empty. Each item is a location snapshot, and a snapshot is not guaranteed to include coordinates.

`latitude` and `longitude` are optional. They may be absent while a device is still locating, when location is unavailable, or when only address metadata is available.

<Warning>
  Check both `latitude` and `longitude` before showing a map marker. Do not rely only on `locationType`, and do not assume every listed location has coordinates.
</Warning>

## Get One Friend Location

```ts theme={null}
const location = await im.locations.get("alice@example.com");

console.log(location.name ?? location.address, location.locationType);
```

Input:

| Argument  | Meaning                                                                                                                         |
| --------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `address` | The friend whose location you want. Pass a full email address or E.164 phone number. Do not pass `chat.guid` or a display name. |

Phone numbers must include the country code, start with `+`, and omit spaces, parentheses, and dashes.

Returns `SharedFriendLocation`. If the address is not sharing location or is not visible to the current account, `get(...)` throws `NotFoundError`.

The returned object looks like this:

```jsonc theme={null}
{
  "address":              "alice@example.com",       // Normalized email address or E.164 phone number
  "isLocatingInProgress": false,                     // Whether the device is still locating
  "locationType":         "live",                    // Freshness of the location source
  "latitude":             37.7749,                   // Latitude; may be absent
  "longitude":            -122.4194,                 // Longitude; may be absent
  "accuracy":             12,                        // Horizontal accuracy in meters; may be absent
  "locationTimestamp":    "2026-01-01T12:00:00Z",    // Time the location was captured; may be absent
  "expiresAt":            "2026-01-01T13:00:00Z",    // Share expiration time; may be absent
  "name":                 "Alice",                   // Friend display name; may be absent
  "shortAddress":         "Mission, SF",             // Short human-readable address; may be absent
  "longAddress":          "Mission District, SF"     // Full human-readable address; may be absent
}
```

## Location Types

`location.locationType` describes how fresh the snapshot is:

| Value       | Meaning                                       |
| ----------- | --------------------------------------------- |
| `"live"`    | Actively updating live location               |
| `"shallow"` | Recent cached location                        |
| `"legacy"`  | Older cached location from a previous session |
| `"unknown"` | The server could not classify the source      |

`locationType` only describes freshness. It does not guarantee that coordinates are present.

## Watch Live Updates

### Scope

Watch every visible friend's location updates:

```ts theme={null}
for await (const update of im.locations.watch()) {
  console.log(update.location.address, update.sourceSequence);
}
```

Watch one address:

```ts theme={null}
for await (const update of im.locations.watch("alice@example.com")) {
  const { latitude, longitude } = update.location;

  if (latitude === undefined || longitude === undefined) {
    continue;
  }

  console.log(latitude, longitude);
}
```

Inputs:

| Call             | Meaning                                                      |
| ---------------- | ------------------------------------------------------------ |
| `watch()`        | Watch every visible friend's location updates                |
| `watch(address)` | Watch one friend by full email address or E.164 phone number |

Do not pass `chat.guid` or a display name to `watch(...)`.

### Update Shape

Each update is `SharedFriendLocationUpdated`:

```jsonc theme={null}
{
  "location": {                         // Latest SharedFriendLocation snapshot
    "address": "alice@example.com",
    "locationType": "live",
    "latitude": 37.7749,
    "longitude": -122.4194
  },
  "sourceSequence": 123                 // Live-location stream sequence; useful for duplicate detection
}
```

Breaking out of the `for await` loop closes the live stream.

<Warning>
  `sourceSequence` belongs only to the location live stream. It is not the same as durable event `sequence`. You can use it to detect duplicate live updates after reconnecting, but you cannot use `im.events.catchUp(...)` to recover location updates missed while disconnected.
</Warning>

## Next Steps

1. [Addresses](/advanced-kits/imessage/addresses) — check whether an email address or phone number is reachable over iMessage
2. [Events](/advanced-kits/imessage/events) — understand durable events and catch-up
3. [Chats](/advanced-kits/imessage/chats) — manage chats, read state, and typing state
