By Sagar Shankaran, Founder of CallSphere
Learn how to compile AI models to WebAssembly for browser-based agent inference, covering WASM compilation, model loading strategies, browser constraints, and progressive enhancement patterns.
Key takeaways
Browser-based AI inference eliminates server costs, removes latency, and keeps data entirely on the user's device. With WebAssembly (WASM), you can run compiled C/C++ model inference engines at near-native speed inside any modern browser.
For AI agents, this means building chat interfaces, form assistants, or document analyzers that work without any backend — the model runs in the browser tab alongside your JavaScript application.
The typical stack for browser AI consists of three layers:
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
The fastest path to browser AI is ONNX Runtime Web, which provides both WASM and WebGL backends:
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
// Install: npm install onnxruntime-web
import * as ort from "onnxruntime-web";
// Configure WASM backend
ort.env.wasm.numThreads = navigator.hardwareConcurrency || 4;
ort.env.wasm.simd = true;
async function loadAgentModel() {
const session = await ort.InferenceSession.create(
"/models/intent_classifier.onnx",
{
executionProviders: ["wasm"],
graphOptimizationLevel: "all",
}
);
return session;
}
async function classifyIntent(session, tokenIds) {
const inputTensor = new ort.Tensor(
"int64",
BigInt64Array.from(tokenIds.map(BigInt)),
[1, tokenIds.length]
);
const attentionMask = new ort.Tensor(
"int64",
BigInt64Array.from(tokenIds.map(() => BigInt(1))),
[1, tokenIds.length]
);
const results = await session.run({
input_ids: inputTensor,
attention_mask: attentionMask,
});
const logits = results.logits.data;
return softmax(Array.from(logits));
}
function softmax(arr) {
const max = Math.max(...arr);
const exps = arr.map((x) => Math.exp(x - max));
const sum = exps.reduce((a, b) => a + b, 0);
return exps.map((e) => e / sum);
}
Browser models can be large. A quantized DistilBERT is about 64 MB. Here are strategies to handle loading:
class BrowserAgent {
constructor() {
this.session = null;
this.loading = false;
}
async ensureModel(onProgress) {
if (this.session) return;
if (this.loading) return;
this.loading = true;
try {
// Check cache first
const cache = await caches.open("agent-models-v1");
const cached = await cache.match("/models/agent.onnx");
if (!cached) {
// Download with progress tracking
const response = await fetch("/models/agent.onnx");
const reader = response.body.getReader();
const contentLength = +response.headers.get("Content-Length");
let received = 0;
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
received += value.length;
onProgress?.(received / contentLength);
}
const blob = new Blob(chunks);
await cache.put("/models/agent.onnx", new Response(blob));
}
const modelResponse = await cache.match("/models/agent.onnx");
const buffer = await modelResponse.arrayBuffer();
this.session = await ort.InferenceSession.create(buffer, {
executionProviders: ["wasm"],
});
} finally {
this.loading = false;
}
}
}
Run inference in a Web Worker to keep the main thread responsive:
// agent-worker.js
import * as ort from "onnxruntime-web";
let session = null;
self.onmessage = async (event) => {
const { type, payload } = event.data;
if (type === "load") {
session = await ort.InferenceSession.create(payload.modelBuffer, {
executionProviders: ["wasm"],
});
self.postMessage({ type: "ready" });
}
if (type === "infer") {
const input = new ort.Tensor("int64",
BigInt64Array.from(payload.tokens.map(BigInt)),
[1, payload.tokens.length]
);
const results = await session.run({ input_ids: input });
self.postMessage({ type: "result", data: Array.from(results.logits.data) });
}
};
Running AI in the browser comes with hard limits:
Build your agent to work without the local model, then enhance when it loads:
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
class ProgressiveAgent {
constructor(apiEndpoint) {
this.apiEndpoint = apiEndpoint;
this.localModel = null;
this.loadLocalModel();
}
async loadLocalModel() {
try {
const session = await ort.InferenceSession.create("/models/agent.onnx");
this.localModel = session;
console.log("Local model loaded — switching to browser inference");
} catch (err) {
console.warn("Local model unavailable, using cloud fallback", err);
}
}
async processInput(text) {
if (this.localModel) {
return this.inferLocally(text);
}
return this.inferViaAPI(text);
}
async inferViaAPI(text) {
const res = await fetch(this.apiEndpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text }),
});
return res.json();
}
async inferLocally(text) {
// Tokenize and run through local ONNX model
const tokens = this.tokenize(text);
// ... run inference as shown above
}
}
WASM inference is typically 2 to 4 times slower than native C++ for the same model on the same hardware. However, with SIMD instructions enabled and multi-threading via SharedArrayBuffer, the gap narrows to 1.5 to 2 times. For many agent tasks like classification or embedding, the absolute latency (20 to 50 milliseconds) is fast enough to feel instant.
All modern browsers — Chrome 57 and later, Firefox 52 and later, Safari 11 and later, and Edge 16 and later — support WebAssembly. For multi-threaded WASM (which ONNX Runtime Web uses for performance), you need SharedArrayBuffer support, which requires cross-origin isolation headers: Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp.
Small language models up to about 1 billion parameters (quantized) can run in the browser, though generation is slow — roughly 2 to 10 tokens per second. For practical browser-based agents, use smaller specialized models for intent routing and tool selection, and reserve cloud LLMs for complex generation tasks.
#WebAssembly #BrowserAI #WASM #JavaScript #ClientSideAI #EdgeAI #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
On-device voice LLMs are now real. What Apple Intelligence, Gemini Nano, and Phi-4 ship in 2026 — and what they cannot do yet.
Anthropic acquires Bun, the all-in-one JavaScript toolkit, to power Claude Code, Claude Agent SDK, and future AI coding products while keeping Bun open-source.
NeuTTS Air brings super-realistic TTS and 3-second voice cloning to edge devices. Learn about its 0.5B parameter architecture, privacy benefits, and practical applications.
Sports physical therapy and student health clinics in Pullman, Washington lose patients to missed calls every semester surge. How to answer every single one.
Bilingual family medicine clinics in Yakima, Washington field English and Spanish calls from harvest crews at all hours. An AI receptionist answers them all.
Physical therapy clinics in Astoria, Oregon juggle fishing-fleet injuries and summer tourism surges. How an AI answering service catches every missed call.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI