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

# Media Caching

> Cache image, video, audio and file attachments on the device so media stays viewable offline with the CometChat JavaScript SDK.

> [accordion] AI Integration Quick Reference
>
> ```javascript theme={null}
> // Set the media caching mode at init (fixed for the session)
> const appSetting = new CometChat.AppSettingsBuilder()
>   .setRegion("REGION")
>   .setOfflineConfig({
>     enabled: true,
>     mediaCaching: CometChat.MediaCachingMode.AUTO, // AUTO (default) or OFF
>     maxMediaCacheSize: 500 * 1024 * 1024,          // bytes; 0 = unlimited
>   })
>   .build();
>
> // Read the mode in effect
> const mode = CometChat.getMediaCachingMode();      // "OFF" when offline is not active
>
> // Resolve cached bytes for an attachment
> const attachment = mediaMessage.getAttachment();
> const url = await CometChat.getCachedMediaObjectURL(attachment); // blob: URL, or null if not cached
> // ...use as <img src>/<video src>, then URL.revokeObjectURL(url) when done
> const handle = await CometChat.getCachedMediaPath(attachment);   // storage handle, or null
>
> // Download on demand
> CometChat.downloadMedia(attachment, new CometChat.MediaCallbackListener({
>   onSuccess: (localPath) => {},
>   onProgress: (percent) => {},
>   onError: (error) => {},
> }));
>
> // Observe background (AUTO) downloads
> CometChat.addMediaDownloadListener("MEDIA_LISTENER", new CometChat.MediaDownloadListener({
>   onMediaDownloaded: (messageId, attachmentId, localPath) => {},
>   onMediaDownloadFailed: (messageId, attachmentId, error) => {},
> }));
> ```

With offline support on, the SDK can cache attachment bytes durably on the device so media stays viewable offline — even after the server's signed URL has expired. This page covers the caching modes, how to read cached bytes, and how to download media on demand.

> [!NOTE]
>
> Media caching applies only while offline support is active for the logged-in user (`CometChat.isOfflineEnabled()` is `true`). See [Enable Offline Support](https://www.cometchat.com/docs/sdk/javascript/offline-enable.md). In a browser, media bytes are kept in the Origin Private File System (OPFS); **where OPFS is not available, media is not cached** (messages and attachment metadata still are).

## Caching modes

The caching mode is set once, in the offline config you pass at initialization, and is fixed for the SDK session. There is no runtime switch — to change it, re-initialize the SDK with a new config.

| `MediaCachingMode` | Behavior |
| - | - |
| `AUTO` (default) | Incoming media bytes are downloaded and cached on receipt, then LRU-managed, so they are available offline. |
| `OFF` | Incoming media bytes are **not** downloaded or cached. The message and its attachment metadata (including the URL) are still cached, so the message appears offline and the UI loads media live from the URL when online. |

Sending media always works in both modes.

> [tab] TypeScript
>
> ```typescript theme={null}
> const appSetting: CometChat.AppSettings = new CometChat.AppSettingsBuilder()
>   .setRegion("REGION")
>   .setOfflineConfig({
>     enabled: true,
>     mediaCaching: CometChat.MediaCachingMode.AUTO,
>     maxMediaCacheSize: 500 * 1024 * 1024,
>   })
>   .build();
> ```

> [tab] JavaScript
>
> ```javascript theme={null}
> const appSetting = new CometChat.AppSettingsBuilder()
>   .setRegion("REGION")
>   .setOfflineConfig({
>     enabled: true,
>     mediaCaching: CometChat.MediaCachingMode.AUTO,
>     maxMediaCacheSize: 500 * 1024 * 1024,
>   })
>   .build();
> ```

Read the mode in effect at runtime with `CometChat.getMediaCachingMode()`. It returns `"OFF"` whenever offline support is not active, whatever the app configured, so a UI layer can rely on it without reading the config itself.

## What downloads automatically

In `AUTO` mode, media bytes are downloaded and cached automatically on the two live receive paths:

* a **realtime** media message received while connected, and
* opening a chat **online** (the server read refreshes and caches its media).

A media message that arrives through a reconnect catch-up [sync](https://www.cometchat.com/docs/sdk/javascript/offline-sync.md) is cached as **metadata only**; its bytes download the next time you open that chat online. This holds in both `AUTO` and `OFF`.

In `OFF` mode, nothing is auto-downloaded on any path; media loads live from its URL when online. `downloadMedia` still works.

## Reading cached media

When bytes are already cached, the SDK **sets the attachment's local path automatically** on the messages it delivers. Read it with `attachment.getLocalPath()`. In a browser that value is an OPFS storage handle (`opfs:…`), **not** something you can put in an `src` — to render a cached file, ask for an object URL instead.

`getCachedMediaObjectURL` resolves a `blob:` URL for a cached attachment, or `null` when its bytes are not cached. **You must revoke the URL** with `URL.revokeObjectURL` when you are done with it.

> [tab] TypeScript
>
> ```typescript theme={null}
> const attachment: CometChat.Attachment = mediaMessage.getAttachment();
>
> const objectUrl: string | null = await CometChat.getCachedMediaObjectURL(attachment);
> if (objectUrl) {
>   imageElement.src = objectUrl;               // render from disk — no network fetch
>   imageElement.onload = () => URL.revokeObjectURL(objectUrl);
> } else {
>   imageElement.src = attachment.getUrl();     // not cached: load live when online
> }
> ```

> [tab] JavaScript
>
> ```javascript theme={null}
> const attachment = mediaMessage.getAttachment();
>
> const objectUrl = await CometChat.getCachedMediaObjectURL(attachment);
> if (objectUrl) {
>   imageElement.src = objectUrl;               // render from disk — no network fetch
>   imageElement.onload = () => URL.revokeObjectURL(objectUrl);
> } else {
>   imageElement.src = attachment.getUrl();     // not cached: load live when online
> }
> ```

To look up the cached handle without creating a URL, call `getCachedMediaPath`. It resolves `null` when the bytes are not cached (call `downloadMedia` to fetch them).

```javascript theme={null}
const handle = await CometChat.getCachedMediaPath(attachment); // null if not cached
```

> [!NOTE]
>
> Each attachment of a multi-attachment message resolves independently. An attachment with no cached bytes has no local path, and the UI loads it from the URL as before.

## Downloading on demand

Call `downloadMedia` to fetch and cache an attachment's bytes — for example when the user taps a placeholder. The SDK resolves cached bytes first, then the URL, and re-signs an expired link (HTTP 401, 403 or 410) through the message the attachment was delivered with before retrying once. `downloadMedia` returns nothing; results arrive on the `MediaCallbackListener`.

> [tab] TypeScript
>
> ```typescript theme={null}
> CometChat.downloadMedia(
>   attachment,
>   new CometChat.MediaCallbackListener({
>     onSuccess: (localPath: string) => {
>       // Bytes cached; render via getCachedMediaObjectURL(attachment).
>     },
>     onProgress: (percent: number) => {
>       // 0..100, best-effort.
>     },
>     onError: (error: CometChat.CometChatException) => {
>       console.log(error.code);
>     },
>   })
> );
> ```

> [tab] JavaScript
>
> ```javascript theme={null}
> CometChat.downloadMedia(
>   attachment,
>   new CometChat.MediaCallbackListener({
>     onSuccess: (localPath) => {
>       // Bytes cached; render via getCachedMediaObjectURL(attachment).
>     },
>     onProgress: (percent) => {
>       // 0..100, best-effort.
>     },
>     onError: (error) => {
>       console.log(error.code);
>     },
>   })
> );
> ```

`downloadMedia` calls `onError` with `ERROR_OFFLINE_DISABLED` when offline support is not running, and with `ERROR_OFFLINE_MEDIA_NO_URL` when no attachment, or an attachment without a URL, is given.

## Observe background downloads

In `AUTO` mode, incoming media downloads in the background with no per-call callback. Register a `MediaDownloadListener` to learn when the bytes land (or fail) so a UI tile can refresh.

> [tab] TypeScript
>
> ```typescript theme={null}
> CometChat.addMediaDownloadListener(
>   "MEDIA_LISTENER",
>   new CometChat.MediaDownloadListener({
>     onMediaDownloaded: (messageId: string, attachmentId: string, localPath: string) => {
>       // attachmentId: the attachment URL without its query string
>     },
>     onMediaDownloadFailed: (messageId: string, attachmentId: string, error: CometChat.CometChatException) => {},
>   })
> );
> ```

> [tab] JavaScript
>
> ```javascript theme={null}
> CometChat.addMediaDownloadListener(
>   "MEDIA_LISTENER",
>   new CometChat.MediaDownloadListener({
>     onMediaDownloaded: (messageId, attachmentId, localPath) => {
>       // attachmentId: the attachment URL without its query string
>     },
>     onMediaDownloadFailed: (messageId, attachmentId, error) => {},
>   })
> );
> ```

Remove the listener with `CometChat.removeMediaDownloadListener("MEDIA_LISTENER")`. The background listener carries no progress callback — progress is reported only on the explicit `downloadMedia` path. `MessageListener` also gains optional `onMediaDownloaded` and `onMediaDownloadFailed` callbacks.

## Media cache size limit

Cached media bytes are bounded by `maxMediaCacheSize` (default **500 MB**; `0` means unlimited). When the cache exceeds the limit, the least recently accessed media is deleted first until it is back under budget. Media belonging to un-sent messages and in-progress uploads is never evicted and does not count toward the budget. A single outgoing file larger than the budget is refused (a send fails with `BYTE_OVERFLOW`).

Media is stored in OPFS (browser) or as files on disk (Electron); the location is not configurable. Eviction runs silently in the background — there is no cache-limit callback. To reason about size, use `CometChat.getCacheSize()` and the configured limits. See the [reference](https://www.cometchat.com/docs/sdk/javascript/offline-reference.md) for the full set of options.

> [!WARNING]
>
> Cached media files are **not encrypted**, even when you turn on [cache encryption](https://www.cometchat.com/docs/sdk/javascript/offline-encryption.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.