# Customizing Image Loading

The Compose SDK loads images, GIFs, and video thumbnails through [Coil 3](https://coil-kt.github.io/coil/). The loader is exposed on `ChatTheme` via the `imageLoaderFactory` property — defaulting to `StreamCoilImageLoaderFactory.defaultFactory()` — so you can customize image loading globally without re-implementing any rendering code.

This page describes what the default factory provides and how to safely extend or replace it.

## StreamCoilImageLoaderFactory

`StreamCoilImageLoaderFactory.defaultFactory()` provides the default factory that creates new Coil `ImageLoader` instances.

You can find out more about it by reading the [class documentation](https://github.com/GetStream/stream-chat-android/blob/main/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/StreamCoilImageLoaderFactory.kt).

You can customize how images are loaded by passing your own implementation of `StreamCoilImageLoaderFactory` to `ChatTheme`, or by using the default factory to provide an `ImageLoader` and calling `loader.newBuilder()` to expand or override its behavior.

## Default Coil Components

The built-in `StreamImageLoaderFactory` registers:

- `OkHttpNetworkFetcherFactory` — fetches image bytes over HTTP/HTTPS. Registered explicitly in code so it is not affected by R8 full-mode stripping the Coil 3 `ServiceLoader` registration.
- `AnimatedImageDecoder` (API 28+) / `GifDecoder` — decodes GIF and animated WebP attachments, including Giphy.
- `VideoFrameDecoder` — decodes the first frame of video attachments to display video thumbnails.

If you provide a fully custom `StreamCoilImageLoaderFactory` without delegating to `StreamImageLoaderFactory`, you must re-register these components yourself, otherwise GIFs render as static frames, video thumbnails go missing, and HTTP fetching can fail under R8 full mode.

## Customizing the Component Registry

`ImageLoader.Builder.components { … }` **replaces** the existing component registry on the builder — it is not additive. Because the `StreamImageLoaderFactory` builder lambda runs after the SDK populates its own components, any `components { … }` block you supply overwrites the SDK defaults.

If you need a custom Coil component (decoder, mapper, or network fetcher), re-register every component the SDK provides alongside your additions:

```kotlin
val factory = StreamCoilImageLoaderFactory { context ->
    StreamImageLoaderFactory {
        components {
            // SDK defaults — must be re-registered when you supply your own components block.
            add(OkHttpNetworkFetcherFactory())
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                add(AnimatedImageDecoder.Factory(enforceMinimumFrameDelay = true))
            } else {
                add(GifDecoder.Factory(enforceMinimumFrameDelay = true))
            }
            add(VideoFrameDecoder.Factory())

            // Your additions:
            add(MyCustomDecoder.Factory())
        }
    }.newImageLoader(context)
}

ChatTheme(imageLoaderFactory = factory) {
    // Your UI content
}
```

<admonition type="info">

**Need auth headers or signed URLs on image requests?** Use the [`CDN`](/chat/docs/sdk/android/client/guides/custom-cdn/) interface instead of customizing Coil. `CDN.imageRequest` applies to every image URL the SDK loads and avoids the need to replace the loader's component registry.

</admonition>

## Troubleshooting: blank or placeholder images

<admonition type="note">

Apps on the default loader are not affected — `StreamImageLoaderFactory` registers the OkHttp fetcher in code. Manual component registration only matters if you provide a fully custom `ImageLoader`.

Symptoms are typically release-build-only with R8 enabled, because Coil 3 auto-registers the fetcher through `ServiceLoader`, which R8 full-mode can strip. The snippet under [Customizing the Component Registry](#customizing-the-component-registry) is the canonical component list — register the OkHttp fetcher there explicitly to bypass auto-registration.

</admonition>


---

This page was last updated at 2026-04-29T16:23:21.020Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/android/compose/general-customization/image-loading/](https://getstream.io/chat/docs/sdk/android/compose/general-customization/image-loading/).