Images

+
UniversalWorks with Expo & React Native CLI

This tool works with both Expo and React Native CLI projects. Just install and go.

Images not loading? Loading slow? Stale avatars that never update? Memory ballooning until the app dies? React Native gives you zero visibility into any of it — image HTTP requests never touch the JS network stack, so even network devtools are permanently blind to them.

The Images tool is the visibility layer: every image your app loads — React Native's <Image> and expo-image — appears in a live registry with where it came from (memory cache / disk cache / network), how long it took, how big it decoded, and exactly why it failed. Pure JavaScript — works in Expo Go and release builds.

The tool below is the real thing, running in your browser on a mock storefront screen: watch the loads land, find the 4K hero decoding into a 390pt box, re-encode it on the device for real byte savings, then force a failure and undo it.

Every load, as it happens

1 / 6

Not a video — this is the shipped tool on mock loads. Image HTTP never touches the JS network stack, so network devtools are permanently blind to it.

9:41
Loading live demo…
Mock image loads, real component — the same code that renders in your app. Step through the tour, or just start tapping.

Installation

npm install @buoy-gg/images

Add the register import as the first line of your app entry file (index.js / index.ts):

ts
import "@buoy-gg/images/register";
import "@buoy-gg/images/register";

Then the IMAGES tool appears in your floating menu automatically — auto-discovery finds the installed package, no registration needed:

tsx
import { FloatingDevTools } from "@buoy-gg/core";

export default function App() {
  return (
    <>
      <YourApp />
      <FloatingDevTools />
    </>
  );
}
import { FloatingDevTools } from "@buoy-gg/core";

export default function App() {
  return (
    <>
      <YourApp />
      <FloatingDevTools />
    </>
  );
}

Why first? RN core's <Image> instrumentation uses React Native's official component-decorator hook, which must be installed before the Image module first evaluates. expo-image capture has no timing constraint — it works whenever the tool loads. If the import is missing or too late, the tool tells you exactly what to fix instead of sitting silently empty.


What You Can Do

  • See every image load, live — thumbnail, source URL, load time, decoded dimensions, format, status. Tap for the full detail view.
  • Get cache verdicts per load — memory, disk, or network. expo-image reports it directly on every load; RN core images are classified via Image.queryCache right after loading.
  • Catch oversized sources — the tool compares decoded pixels against the laid-out size × device pixel ratio, Lighthouse-style: green within 10%, red beyond 50% — with the estimated wasted decoded memory and the exact dimensions you should serve instead.
  • Catch upscaled (blurry) sources too — a 50px thumbnail stretched into a 300pt hero gets flagged the other way.
  • Track decoded memory — estimated decoded-bitmap bytes per image and totaled across mounted images, so you catch ballooning before the OOM crash.
  • Diagnose failures — every onError is captured with the error message; on iOS, RN core also gives you the HTTP status code and response headers.
  • Act on any image — hard reload (bypass caches + refetch), retry, or flash a red border on the on-screen image to locate it visually.
  • Simulate the bad day — force an error, an endless loading state, or a blank on any mounted image; swap its source URL in place; or flip app-wide modes: Offline (network images fail, bundled assets still load), Cold (every load bypasses caches like first launch), and Chrome-style blank images. Mass actions apply any of these to everything on screen at once.
  • Prove the savings — re-encode an oversized source at its displayed size as WebP on the device, get the real byte savings, and preview the optimized file in place before you touch your CDN.
  • Clear caches — expo-image memory and disk caches, one tap from the detail view.

How it works

React Native ships an official (if unstable_-prefixed) hook that lets a devtool wrap every <Image> in the app — the Images tool uses it to observe sources and attach load/progress/error handlers app-wide, with zero native code. expo-image's component is instrumented the same way through a render-level patch that's immune to import order. Both paths force-attach the load events the libraries already emit natively, so capture works identically in Expo Go, dev clients, and release builds.

Buoy's own UI (like the thumbnails inside the tool) is excluded from capture — the tool never appears in its own registry.

Coverage notes

  • Byte counts (loaded/total) come from image onProgress events: reliable on iOS RN core and expo-image; RN core on Android (Fresco) doesn't report real byte counts.
  • Cache classification for RN core images uses Image.queryCache, which reflects the cache after the load — combined with whether network progress events fired, the verdict distinguishes a fresh download from a cache hit.
  • Decoded-memory numbers are estimates (width × height × 4 bytes) — the same math the platforms use for RGBA bitmaps.

Desktop & AI

The same live registry streams to Buoy Desktop — the full tool (list, detail, simulations, mass actions) on a big screen — and to your editor's AI agent via the MCP server: get_images audits a screen's images in one call, image_action drives per-image reloads/overrides (including the on-device savings re-encode), and set_image_simulation flips the app-wide modes.

What's Next

Cache explorer (browse the actual disk cache directories with sizes and ages), per-screen waste reports, and an X-ray overlay mode (badges on every on-screen image).


FAQ

Why can’t my network inspector see image requests in React Native?

Image fetches happen in native code (NSURLSession / Fresco), never in the JS network stack — so JS-level network devtools can’t observe them. Buoy Images hooks the image components themselves instead, capturing every load with its cache verdict and timing.

Does it work in Expo Go and release builds?

Yes — capture is pure JavaScript (RN’s official component-decorator hook plus an expo-image render patch), so there’s no native module to install and it works in Expo Go, dev clients, and release builds.

How do I find images that waste memory?

The registry compares each image’s decoded pixels against its rendered size × device pixel ratio and totals the estimated wasted decoded bytes — sort by the red verdicts, then use the on-device re-encode to prove what a right-sized source would save.