# Cloudflare R2 Image URL Display Issue: Detailed Explanation and Fix

**URL:** https://meta.discourse.org/t/cloudflare-r2-image-url-display-issue-detailed-explanation-and-fix/358204
**Category:** Bug
**Tags:** chat
**Created:** [March 20, 2025, 6:41pm UTC](https://meta.discourse.org/t/cloudflare-r2-image-url-display-issue-detailed-explanation-and-fix/358204 "2025-03-20T18:41:59Z")
**Posts on this page:** 1
**Showing post:** 8

<div class="post-metadata">

### Author: ![Lilly](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/lilly/32/575047_2.png) [@Lilly](https://meta.discourse.org/u/Lilly)
#### Post date: [May 29, 2026, 7:57pm UTC](https://meta.discourse.org/t/cloudflare-r2-image-url-display-issue-detailed-explanation-and-fix/358204/8 "2026-05-29T19:57:27Z")

</div>

i have managed to fix this with an updated theme component that has settings for the domains. thus anyone can use it without having to hard code their own component. this works for any s3 compatible storage:

> **[GitHub - Lillinator/chat-s3-thumbnails-fix: Fixes the chat thumbnail path bug for Cloudflare...](https://github.com/Lillinator/chat-s3-thumbnails-fix)**
>
> Fixes the chat thumbnail path bug for Cloudflare R2 object storage uploads

> **if you do patch it yourself, the initializer should look like this**
>
> ```js
> import { apiInitializer } from "discourse/lib/api";
> 
> export default apiInitializer("1.8.0", (api) => {
> 
> // ⚠️ Ensure these are your exact domains!
> // look at the image paths for post thumbnail & chat thumbnail and compare!
> 
> const badDomain = "yoursite-uploads.xxx.r2.cloudflarestorage.com";
> const goodDomain = "uploads.yoursite.com";
> 
> function fixImage(img) {
> if (img.src && img.src.includes(badDomain)) {
> img.src = img.src.replace(badDomain, goodDomain);
> }
> if (img.dataset?.src && img.dataset.src.includes(badDomain)) {
> img.dataset.src = img.dataset.src.replace(badDomain, goodDomain);
> }
> }
> 
> // 1. Safely fix images rendered in standard posts/HTML
> api.decorateCooked($elem => {
> const container = $elem[0];
> if (!container) return;
>     
> container.querySelectorAll(`img[src*="${badDomain}"]`).forEach(fixImage);
> }, { id: 'fix-r2-chat-bug' });
> 
> // 2. High-performance observer strictly for dynamically injected Chat elements
> const observer = new MutationObserver(mutations => {
> for (const mutation of mutations) {
>       
> // If a new chat message or element is injected into the DOM
> if (mutation.type === 'childList') {
> for (const node of mutation.addedNodes) {
> if (node.nodeType === 1) { // ELEMENT_NODE
> if (node.tagName === 'IMG') fixImage(node);
>             
> // Only search INSIDE the new node, not the whole document
> node.querySelectorAll(`img[src*="${badDomain}"]`).forEach(fixImage);
> }
> }
> } 
> // If an existing image's src attribute changes (lazy loading)
> else if (mutation.type === 'attributes') {
> if (mutation.target.tagName === 'IMG') {
> fixImage(mutation.target);
> }
> }
> }
> });
> 
> // Start the observer immediately
> observer.observe(document.body, {
> childList: true,
> subtree: true,
> attributes: true,
> attributeFilter: ['src', 'data-src']
> });
> });
> 
> ```

---

_[View the full topic](https://meta.discourse.org/t/cloudflare-r2-image-url-display-issue-detailed-explanation-and-fix/358204)._
