Skip to main content
Early Beta — The Web SDK is in early beta. APIs may change between releases.

Overview

This guide covers best practices for building performant, reliable, and user-friendly AI applications with the RunAnywhere Web SDK in the browser.

Model Selection

Choose the Right Model Size

Browser memory is more limited than native apps. Models larger than 2GB may cause tab crashes on devices with limited RAM. Start with smaller models and test on target devices.

Quantization Trade-offs

For browser use, Q4_0 and Q4_K_M offer the best balance of quality and memory efficiency. Start with smaller quantizations and only increase if output quality is insufficient.

Performance Optimization

Use Streaming for Better UX

Enable Cross-Origin Isolation

Multi-threaded WASM is significantly faster. Always configure COOP/COEP headers:

Exclude WASM Packages from Vite Pre-Bundling

This is the most common gotcha with Vite:
vite.config.ts
Without this, import.meta.url resolves to the wrong paths and WASM files won’t be found.

Limit Token Generation

Batch DOM Updates

For fast token generation, throttle UI updates to avoid rendering bottlenecks:

Model Management

Use OPFS for Persistent Storage

Download models to OPFS so they persist across browser sessions:

Show Download Progress

Handle Large Model Downloads

Models over ~200MB can crash the browser tab, especially on memory-constrained devices. Mitigations:
If the browser tab crashes during a model download, the partial download is stored in OPFS. On the next attempt, ModelManager.downloadModel() will resume from where it left off. Recommend starting with smaller models (LFM2 350M at ~250MB) before attempting larger ones.

Use coexist for Multi-Model Loading

When loading multiple models (e.g., for voice pipeline), pass coexist: true:

Idempotent SDK Initialization

Wrap initialization in a cached-promise pattern so it’s safe to call from multiple components:

Hosted IDE & Iframe Environments

Replit, CodeSandbox, StackBlitz

These platforms run your app inside an iframe, which has important implications:
Do not use COEP: require-corp in hosted IDE environments. It will block Vite’s internal /@fs/ module serving and cause “non-JavaScript MIME type” errors for worker scripts and WASM glue files. Always use COEP: credentialless.

SPA Routing and Static Assets

When using a custom Express/Node server with SPA catch-all routing, static asset routes must come before the catch-all. Otherwise, .wasm, .js, and worker files get served as index.html:

Browser-Specific Considerations

Handle Tab Visibility

Cancel in-progress generation when the tab is hidden:

Handle Memory Pressure

Safari Considerations

  • OPFS has known reliability issues in Safari — test thoroughly
  • WebGPU is not available in Safari (as of early 2026)
  • Prefer Chrome/Edge for the best experience

Mobile Browser Considerations

  • Mobile browsers have stricter memory limits
  • Models larger than 1GB may cause tab crashes
  • Use Q4_0 quantization for mobile
  • Test on actual mobile devices

Camera Permission Handling

Provide clear error messages for camera permissions (important for VLM):

Error Handling

Always Handle Errors Gracefully

Security & Privacy

All Data Stays Local

The Web SDK runs entirely in the browser via WebAssembly. No data is sent to any server. This is a key advantage for privacy-sensitive applications.

Use Correct Environment Mode

Vite Gotchas Summary

Summary Checklist

Install all three packages: @runanywhere/web, web-llamacpp, web-onnx
Register backends with LlamaCPP.register() and ONNX.register()
Choose appropriate model size for browser memory constraints
Use streaming for better perceived performance
Configure Cross-Origin Isolation headers (COEP: credentialless, NOT require-corp)
Add optimizeDeps.exclude in Vite config for WASM packages
Add copyWasmPlugin() to copy WASM files for production builds
Serve static assets (.wasm, .js) BEFORE SPA catch-all routes
Set Content-Type: application/wasm for .wasm files on custom servers
Use OPFS for persistent model storage via ModelManager
Use coexist: true when loading multiple models simultaneously
Wait for loadedmetadata before calling VideoCapture.captureFrame()
For voice pipeline: load all 4 models (VAD + STT + LLM + TTS) — VAD alone is not STT
Handle all error cases gracefully including WASM memory crashes
Show progress during model downloads via EventBus
Batch DOM updates during fast token streaming
Test on target browsers and devices (not just iframe previews)

Configuration

SDK configuration

Error Handling

Handle errors gracefully

Quick Start

Getting started guide