> ## 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 Android SDK.

> [accordion] AI Integration Quick Reference
>
> ```kotlin theme={null}
> // Set the media caching mode at init (fixed for the session)
> val offlineConfig = OfflineConfig.Builder()
>     .enabled(true)
>     .mediaCaching(MediaCachingMode.AUTO)       // AUTO (default) or OFF
>     .maxMediaCacheSize(500L * 1024 * 1024)     // bytes; 0 = unlimited
>     .build()
>
> // Read the mode in effect
> val mode: MediaCachingMode = CometChat.getMediaCachingMode()   // OFF when offline is not active
>
> // Resolve cached bytes for an attachment
> val attachment = mediaMessage.attachment
> val localPath: String? = attachment.localPath                  // hydrated automatically on reads
> val cached: String? = CometChat.getCachedMediaPath(attachment) // null if not cached
>
> // Download on demand
> CometChat.downloadMedia(attachment, object : MediaCallbackListener {
>     override fun onSuccess(localPath: String?) { }
>     override fun onProgress(percent: Int) { }
>     override fun onError(e: CometChatException) { }
> })
>
> // Observe background (AUTO) downloads
> CometChat.addMediaDownloadListener("MEDIA_LISTENER", object : MediaDownloadListener {
>     override fun onMediaDownloaded(messageLocalId: String?, attachmentId: String?, localPath: String?) { }
>     override fun onMediaDownloadFailed(messageLocalId: String?, attachmentId: String?, error: CometChatException?) { }
> })
> ```

With offline support on, the SDK can cache attachment bytes durably on the device so media stays viewable offline — even after the server's presigned URL has expired. This page covers the caching modes, what downloads automatically, 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/android/v5/offline-enable.md).

## Caching modes

The caching mode is set once, in the `OfflineConfig` 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 eagerly downloaded and cached on any network, then LRU-managed. The outgoing copy is retained after the server acknowledges the send. |
| `OFF` | Incoming media bytes are **not** cached. The message metadata (including `fileUrl`) is still cached, so the message appears offline and the UI loads media live from the URL when online. The outgoing copy is dropped after the send is acknowledged. |

Sending media always works in both modes.

> [tab] Java
>
> ```java theme={null}
> OfflineConfig offlineConfig = new OfflineConfig.Builder()
>     .enabled(true)
>     .mediaCaching(MediaCachingMode.AUTO)
>     .maxMediaCacheSize(500L * 1024 * 1024)
>     .build();
> ```

> [tab] Kotlin
>
> ```kotlin theme={null}
> val offlineConfig = OfflineConfig.Builder()
>     .enabled(true)
>     .mediaCaching(MediaCachingMode.AUTO)
>     .maxMediaCacheSize(500L * 1024 * 1024)
>     .build()
> ```

Read the mode in effect at runtime with `CometChat.getMediaCachingMode()`. It returns `MediaCachingMode.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/android/v5/offline-sync.md) is cached as **metadata only** and renders as a placeholder; its bytes download lazily 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.

## Reading cached media

When bytes are already cached, the SDK **hydrates the local path automatically** on every message it delivers — you do not have to ask. Read it straight off the attachment:

> [tab] Java
>
> ```java theme={null}
> Attachment attachment = mediaMessage.getAttachment();
> String localPath = attachment.getLocalPath();   // non-null when bytes are cached
> if (localPath != null) {
>     // Render directly from disk — no network fetch.
> }
> ```

> [tab] Kotlin
>
> ```kotlin theme={null}
> val attachment = mediaMessage.attachment
> val localPath = attachment.localPath   // non-null when bytes are cached
> if (localPath != null) {
>     // Render directly from disk — no network fetch.
> }
> ```

To look up the cached path explicitly, call `getCachedMediaPath`. It is a cheap filesystem check, safe on the main thread, and returns `null` when the bytes are not cached (call `downloadMedia` to fetch them).

> [tab] Java
>
> ```java theme={null}
> String path = CometChat.getCachedMediaPath(attachment);  // null if not cached
> ```

> [tab] Kotlin
>
> ```kotlin theme={null}
> val path = CometChat.getCachedMediaPath(attachment)      // null if not cached
> ```

> [!NOTE]
>
> Each attachment of a multi-attachment message resolves independently. An attachment with no cached bytes keeps `localPath == null` 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 runs the resolution off the main thread (cached bytes, then a valid URL, then, for a CometChat-hosted URL the server rejects as expired or forbidden (HTTP 401, 403 or 410), one re-signed URL) and delivers on the main thread.

> [tab] Java
>
> ```java theme={null}
> CometChat.downloadMedia(attachment, new MediaCallbackListener() {
>     @Override
>     public void onSuccess(String localPath) {
>         // Bytes cached; render from localPath.
>     }
>
>     @Override
>     public void onProgress(int percent) {
>         // 0..100, best-effort.
>     }
>
>     @Override
>     public void onError(CometChatException e) { }
> });
> ```

> [tab] Kotlin
>
> ```kotlin theme={null}
> CometChat.downloadMedia(attachment, object : MediaCallbackListener {
>     override fun onSuccess(localPath: String?) {
>         // Bytes cached; render from localPath.
>     }
>
>     override fun onProgress(percent: Int) {
>         // 0..100, best-effort.
>     }
>
>     override fun onError(e: CometChatException) { }
> })
> ```

`onProgress(int percent)` reports `0..100`, best-effort and monotonic non-decreasing. It is emitted only when the server reports a content length; for an unknown-length download it is skipped and the call goes straight to `onSuccess`. Progress never blocks or fails the download.

`onError` receives one of these codes:

| Error code | Meaning |
| - | - |
| `ERROR_INVALID_FILE_URL` | The attachment has no URL. |
| `ERROR_MEDIA_UNAVAILABLE` | The bytes are not cached and could not be fetched (for example, the device is offline), or offline support is not active. |
| `ERROR_MEDIA_DOWNLOAD_FAILED` | The download started but failed. |

## 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. All callbacks fire on the main thread.

> [tab] Java
>
> ```java theme={null}
> CometChat.addMediaDownloadListener("MEDIA_LISTENER", new MediaDownloadListener() {
>     @Override
>     public void onMediaDownloaded(String messageLocalId, String attachmentId, String localPath) {
>         // messageLocalId: the message's server id (or local id if not yet sent)
>         // attachmentId:   the attachment URL without its query string
>         // localPath:      where the bytes landed
>     }
>
>     @Override
>     public void onMediaDownloadFailed(String messageLocalId, String attachmentId, CometChatException error) { }
> });
> ```

> [tab] Kotlin
>
> ```kotlin theme={null}
> CometChat.addMediaDownloadListener("MEDIA_LISTENER", object : MediaDownloadListener {
>     override fun onMediaDownloaded(messageLocalId: String?, attachmentId: String?, localPath: String?) {
>         // messageLocalId: the message's server id (or local id if not yet sent)
>         // attachmentId:   the attachment URL without its query string
>         // localPath:      where the bytes landed
>     }
>
>     override fun onMediaDownloadFailed(messageLocalId: String?, attachmentId: String?, error: CometChatException?) { }
> })
> ```

Remove the listener with `CometChat.removeMediaDownloadListener("MEDIA_LISTENER")`. The background `MediaDownloadListener` carries no progress callback — progress is reported only on the explicit `downloadMedia` path above.

## 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 for un-sent (queued) messages is never evicted, though it still counts toward the budget; copies held for an in-progress upload are excluded from the budget. Because protected media is never evicted, the cache can briefly exceed `maxMediaCacheSize`. Bulk list loads and syncs do not refresh an item's recency.

Media is stored as files in durable, backup-excluded storage; 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 [configuration reference](https://www.cometchat.com/docs/sdk/android/v5/offline-reference.md) for the full set of options.


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