# Link previews

When the user types a text that resembles a URL link, the composer can show a preview of the page it points to: its title, description and image. The link previews manager, `messageComposer.linkPreviewsManager`, finds the links in the text, loads a preview for each one, and adds the loaded previews to the message attachments when it's sent.

>
> **Info:** **Example**
>
> The user types "Look at `https://example.com`" and stops typing:
>
> 1. After a short pause, the manager finds the link and adds a preview for it with the status `loading`.
> 2. When the page's preview data arrives, the preview's status becomes `loaded`, and it holds the page's title, description and image.
> 3. The user sends the message. The preview goes out as one of the message's attachments.
>

## What it holds

`linkPreviewsManager.state` has one field, `previews`: a `Map` with one entry for each link found in the text. The key is the link, and the value is its preview. `linkPreviewsManager.previews` reads the current `Map`.

A preview is the attachment the message will carry for the link: the page's data, as the server's link enrichment returns it, plus a `status`. A loaded preview looks like this:

```ts
const preview = {
  og_scrape_url: "https://getstream.io/chat/",
  title: "Chat API & SDK",
  text: "Build real-time chat in less time.",
  title_link: "https://getstream.io/chat/",
  image_url: "https://getstream.io/images/og/chat.png",
  status: "loaded",
};
```

The `status` says where the preview is, and whether it goes out with the message:

| `status`    | What it means                                                                | Sent | Getter                                  |
| ----------- | ---------------------------------------------------------------------------- | ---- | --------------------------------------- |
| `loading`   | The page's data is being loaded.                                             | no   | `linkPreviewsManager.loadingPreviews`   |
| `loaded`    | The data arrived.                                                            | yes  | `linkPreviewsManager.loadedPreviews`    |
| `failed`    | The request failed. No notification is published.                            | no   | `linkPreviewsManager.failedPreviews`    |
| `dismissed` | The user removed it. It isn't loaded again while the link stays in the text. | no   | `linkPreviewsManager.dismissedPreviews` |
| `pending`   | Added from code without a status. The manager doesn't load it.               | no   | `linkPreviewsManager.pendingPreviews`   |

Each getter returns the previews with that status, as an array.

```ts
const { linkPreviewsManager } = channel.messageComposer;

const unsubscribe = linkPreviewsManager.state.subscribeWithSelector(
  ({ previews }) => ({ previews }),
  ({ previews }) => {
    previews.forEach((preview, url) => {
      console.log(url, preview.status, preview.title);
    });
  },
);
```

## Loading previews

While the user types, the manager watches the text. When typing pauses for the time the `debounceURLEnrichmentMs` [setting](#settings) gives, 1.5 seconds by default, it finds the links with the `findURLFn` setting and loads a preview for each link that doesn't have one yet.

When the text has no links left, every preview goes, the dismissed ones too.

What a preview list needs, and the call for each:

| To…                                    | Call                                              | What happens                                                                                                                                                                                                                                                                           |
| -------------------------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| remove a preview the user doesn't want | `LinkPreviewsManager.dismissPreview(url)`         | Marks the preview `dismissed`: the link stays in the text, but the message goes out without its preview, and the preview isn't loaded again while the link stays. Calls the `onLinkPreviewDismissed` setting with it.                                                                  |
| stop previews from starting to load    | `LinkPreviewsManager.cancelURLEnrichment()`       | Drops the link search that the last change to the text scheduled, so no new preview starts loading until the user types again. Previews that are already loading still finish.                                                                                                         |
| remove every preview                   | `LinkPreviewsManager.clearPreviews()`             | Removes all previews except the dismissed ones, so those aren't loaded again.                                                                                                                                                                                                          |
| add a preview from code, or change one | `LinkPreviewsManager.updatePreview(url, preview)` | Changes the fields you pass in the preview for `url`, and keeps the others. If `url` has no preview yet, adds one. Pass a `status` to set it; otherwise an existing preview keeps its status, and a new one is `pending`, which the manager doesn't load and the message doesn't send. |

## Sending previews

When the message is sent, its link previews come from one of two places.

- **From the composer.** The loaded previews go out with the message, after its other attachments, and the server leaves those links alone. Previews with any other status don't go out.
- **From the server.** If any preview is still loading when the message is sent, the composer sends none of them, not even the loaded ones. The server may then add its own, as the channel type's `url_enrichment` setting decides.

A [draft](https://getstream.io/chat/docs/sdk/react/state/writing-messages/message-composer/#drafts) keeps the loaded previews. When a draft or a message to edit is loaded into the composer, its previews come back as `loaded`.

## When previews are on

Previews are on while `linkPreviewsManager.enabled` is `true`. That's when both the `linkPreviews.enabled` setting in `client.config` and the channel type's `url_enrichment` setting are on. Otherwise, the manager loads no previews.

## Settings

Set them for every composer in `client.config`, under `messageComposer.linkPreviews`:

```ts
client.config.set({
  messageComposer: {
    linkPreviews: { debounceURLEnrichmentMs: 800 },
  },
});
```

To change a setting for one composer only, set it on that composer's link previews manager, for example `channel.messageComposer.linkPreviewsManager.enabled = false`.

| Setting                   | Default         | What it does                                                                                                                                                                                                                                |
| ------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`                 | `true`          | `false` turns off link previews. Combined with the channel type's `url_enrichment` setting.                                                                                                                                                 |
| `debounceURLEnrichmentMs` | `1500`          | How long, in milliseconds, the user must pause typing before previews load. A composer reads it once, when it's created, as [Settings read once](https://getstream.io/chat/docs/sdk/react/state/state-and-entities/configuration/#settings-read-once) explains. |
| `findURLFn`               | finds web links | Returns the links in the text to load previews for. The default finds web addresses whose host name has a dot and a top-level domain of two or more letters, and adds `https://` to a link typed without it.                                |
| `onLinkPreviewDismissed`  | none            | Called with the preview when the user dismisses it.                                                                                                                                                                                         |

See [Link previews](https://getstream.io/chat/docs/sdk/react/features/rich-content/link-previews/) for the feature.

## Used in

- [Link previews](https://getstream.io/chat/docs/sdk/react/features/rich-content/link-previews/)

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/state/writing-messages/link-previews/](https://getstream.io/chat/docs/sdk/react/state/writing-messages/link-previews/).