Skip to main content
A flow full of images can flash blank placeholders as the user moves between screens. Media preloading fetches a flow’s images ahead of the user in screen order, so each screen paints with its images already in the cache. It runs automatically when a session is created, and you can also drive it manually.

Automatic preloading

When a session is created (and mediaPreloadingEnabled is not false), the SDK preloads media in the background using the shared mediaPreloader. It does not block presentation: the first screen shows as soon as it is ready while later screens warm behind it.
FlowPilot.configure({
  apiKey: 'fp_live_...',
  appId: 'your-app-id',
  mediaPreloadingEnabled: true, // default
});
The preloader walks media in priority order:
  1. Persistent zones first (nav bar, footer, overlay), since they are visible on every screen.
  2. Screens in navigation order, following edges from the entry node.
  3. Within a screen, all images load concurrently; between screens, sequentially, so the next screen is prioritized over far-off ones.
Images are prefetched through expo-image (falling back to React Native’s Image.prefetch if needed). Fonts are handled separately by the font manager.

Manual preloading with progress

For a custom loading experience (a progress bar before a media-heavy flow), use the MediaPreloader directly. Create your own instance so you do not disturb the session’s automatic preload.
import { MediaPreloader } from '@flowpilotjs/react-native-sdk';

const preloader = new MediaPreloader();

const progress = await preloader.preload(
  session.flow,                 // FlowDefinition
  session.mediaBaseUrl,         // from the session
  session.iconBaseUrl,
  (p) => {
    console.log(`${Math.round(p.progress * 100)}% (${p.completedItems}/${p.totalItems})`);
  },
  { firstScreenOnly: false },   // true to bound to the first screen + zones
);

console.log('done', progress.isComplete, 'failed:', progress.failedItems);

preload(...) signature

preload(
  flow: FlowDefinition,
  mediaBaseUrl: string,
  iconBaseUrl: string,
  onProgress?: (progress: PreloadProgress) => void,
  options?: { firstScreenOnly?: boolean },
): Promise<PreloadProgress>
preload aborts any previous preload on the same instance before starting, and never rejects. Each onProgress call (one per screen group) and the resolved value are a PreloadProgress:
interface PreloadProgress {
  totalItems: number;
  completedItems: number;   // includes failures (they still advance progress)
  failedItems: number;
  currentScreenIndex: number;
  progress: number;         // 0..1
  isComplete: boolean;
}
A failed image still counts toward completedItems (so progress always reaches 1) and is also counted in failedItems, so you can tell a fully-successful preload from a partial one. Call preloader.abort() to cancel an in-progress preload (for example if the user leaves the screen).

The mediaPreloader singleton

The same mediaPreloader singleton the SDK uses for automatic preloading is exported, alongside the MediaPreloader class. Prefer a fresh new MediaPreloader() for manual work, because calling preload on the singleton aborts the session’s automatic preload (they share the instance).

Relationship to prefetch

Media preloading and prefetch overlap but serve different moments:
  • Media preloading warms images for a flow you are about to present (a session already exists).
  • Prefetch { warmMedia: true } warms images for a flow you have not presented yet, bounded by prefetchMediaStrategy. It uses a fresh MediaPreloader internally so it never disturbs an active session.

Common mistakes

  • Calling preload on the mediaPreloader singleton during a live session. It aborts the session’s own preload. Use new MediaPreloader() for manual work.
  • Awaiting the full preload before showing the flow. Automatic preloading is non-blocking by design; do not gate presentation on it unless you intentionally want a pre-flow progress screen.
  • Expecting fonts in PreloadProgress. The preloader handles images and icons; fonts load through the font manager separately.
  • Disabling preloading then wondering about flashes. With mediaPreloadingEnabled: false, images load on demand as screens appear. Leave it on for smooth navigation.

Troubleshooting

  • Images still flash on navigation. The flow may have more images than warm in time on a slow network, or mediaPreloadingEnabled is false. Consider prefetch(..., { warmMedia: true }) ahead of time, or a manual preload with a progress UI.
  • failedItems is non-zero. Some image URLs failed to fetch (offline, 404, bad CDN URL). The flow still renders; those images fall back to blank. Check the URLs in the flow and the network.
  • Manual preload seems to do nothing. Confirm you passed the session’s mediaBaseUrl / iconBaseUrl, and that the flow actually references images.