By Sagar Shankaran, Founder of CallSphere
Build client-side AI agents using WebGPU acceleration and the transformers.js library, covering model loading, GPU inference in the browser, performance tuning, and privacy-first agent design.
Key takeaways
WebGPU is the successor to WebGL for GPU compute in browsers. Unlike WebGL, which was designed for graphics rendering and awkwardly repurposed for machine learning, WebGPU provides direct access to GPU compute shaders — the same paradigm that CUDA and Metal use. This makes it viable for running transformer models at speeds approaching native GPU inference.
For AI agents, WebGPU means you can run meaningful inference — embedding generation, classification, even small generative models — directly in the browser with GPU acceleration, keeping all user data on the client.
The transformers.js library from Hugging Face brings the familiar Transformers API to JavaScript. It supports ONNX models and can use WebGPU, WASM, or WebGL backends:
flowchart LR
IN(["Input text"])
TOK["Tokenizer<br/>BPE or SentencePiece"]
EMB["Token plus position<br/>embeddings"]
subgraph BLOCK["Transformer block (xN)"]
ATTN["Multi head<br/>self attention"]
NORM1["Layer norm"]
FF["Feed forward<br/>MLP"]
NORM2["Layer norm"]
end
HEAD["LM head plus<br/>softmax"]
SAMP["Sampling<br/>top-p, temperature"]
OUT(["Next token"])
IN --> TOK --> EMB --> ATTN --> NORM1 --> FF --> NORM2 --> HEAD --> SAMP --> OUT
SAMP -.->|Append| EMB
style BLOCK fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style ATTN fill:#4f46e5,stroke:#4338ca,color:#fff
style OUT fill:#059669,stroke:#047857,color:#fff
// Install: npm install @huggingface/transformers
import { pipeline, env } from "@huggingface/transformers";
// Configure for WebGPU if available
env.backends.onnx.wasm.proxy = true;
async function createAgentPipeline() {
// Feature extraction for semantic search / RAG
const embedder = await pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2", {
device: "webgpu", // Falls back to wasm if WebGPU unavailable
});
// Text classification for intent routing
const classifier = await pipeline(
"text-classification",
"Xenova/distilbert-base-uncased-finetuned-sst-2-english",
{ device: "webgpu" }
);
return { embedder, classifier };
}
// Usage
const { embedder, classifier } = await createAgentPipeline();
const embedding = await embedder("Schedule a meeting tomorrow", {
pooling: "mean",
normalize: true,
});
console.log("Embedding dimensions:", embedding.dims);
const intent = await classifier("I need to cancel my appointment");
console.log(intent);
// [{ label: "NEGATIVE", score: 0.98 }]
Here is a complete browser-based agent that uses local models for intent classification and semantic search:
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
class BrowserAgent {
constructor() {
this.pipelines = {};
this.knowledgeBase = [];
this.ready = false;
}
async initialize(onProgress) {
onProgress?.("Loading intent classifier...");
this.pipelines.classifier = await pipeline(
"zero-shot-classification",
"Xenova/mobilebert-uncased-mnli",
{ device: "webgpu" }
);
onProgress?.("Loading embedding model...");
this.pipelines.embedder = await pipeline(
"feature-extraction",
"Xenova/all-MiniLM-L6-v2",
{ device: "webgpu" }
);
onProgress?.("Loading text generator...");
this.pipelines.generator = await pipeline(
"text2text-generation",
"Xenova/flan-t5-small",
{ device: "webgpu" }
);
this.ready = true;
onProgress?.("Agent ready");
}
async classifyIntent(text) {
const labels = [
"question answering",
"task execution",
"casual conversation",
"search request",
];
const result = await this.pipelines.classifier(text, labels);
return {
intent: result.labels[0],
confidence: result.scores[0],
};
}
async semanticSearch(query, topK = 3) {
const queryEmbedding = await this.getEmbedding(query);
const scored = this.knowledgeBase.map((doc) => ({
...doc,
score: this.cosineSimilarity(queryEmbedding, doc.embedding),
}));
return scored
.sort((a, b) => b.score - a.score)
.slice(0, topK);
}
async getEmbedding(text) {
const output = await this.pipelines.embedder(text, {
pooling: "mean",
normalize: true,
});
return Array.from(output.data);
}
async generateResponse(prompt) {
const output = await this.pipelines.generator(prompt, {
max_new_tokens: 100,
});
return output[0].generated_text;
}
cosineSimilarity(a, b) {
let dot = 0, normA = 0, normB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
async addDocument(text, metadata = {}) {
const embedding = await this.getEmbedding(text);
this.knowledgeBase.push({ text, metadata, embedding });
}
}
Not all browsers support WebGPU yet. Always implement detection and graceful degradation:
async function detectBestBackend() {
// Check WebGPU support
if (navigator.gpu) {
try {
const adapter = await navigator.gpu.requestAdapter();
if (adapter) {
const device = await adapter.requestDevice();
if (device) {
console.log("WebGPU available:", adapter.info);
return "webgpu";
}
}
} catch (e) {
console.warn("WebGPU detection failed:", e);
}
}
// Check WebGL 2 support
const canvas = document.createElement("canvas");
const gl = canvas.getContext("webgl2");
if (gl) {
console.log("Falling back to WebGL");
return "webgl";
}
console.log("Falling back to WASM");
return "wasm";
}
// Use the detected backend
const backend = await detectBestBackend();
const classifier = await pipeline("text-classification", "Xenova/distilbert-base-uncased", {
device: backend,
});
Inference times for common tasks using transformers.js on different backends (measured on a MacBook Pro M2):
| Task | WebGPU | WebGL | WASM |
|---|---|---|---|
| Embedding (384-dim) | 3 ms | 8 ms | 15 ms |
| Classification | 5 ms | 12 ms | 25 ms |
| Text generation (50 tokens) | 800 ms | 2.1 s | 4.5 s |
| Zero-shot classify | 12 ms | 28 ms | 55 ms |
WebGPU provides 2 to 5 times speedup over WASM for transformer inference. The gap is most dramatic for generation tasks.
Browser-based agents offer unique privacy guarantees:
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 PrivateAgent extends BrowserAgent {
async processInput(text) {
// All inference happens locally — no network calls
const intent = await this.classifyIntent(text);
const results = await this.semanticSearch(text);
const context = results.map((r) => r.text).join("\n");
const response = await this.generateResponse(
\`Answer based on this context: \${context}\nQuestion: \${text}\`
);
// Data never leaves the browser
// No server logs, no API provider data retention
// Full compliance with data residency requirements
return {
intent,
response,
privacyGuarantee: "all-processing-local",
};
}
}
No user data touches a server. No API calls are made. The browser tab is the entire processing environment. This is ideal for agents handling medical information, financial data, or any scenario where data sovereignty is legally required.
As of early 2026, Chrome 113 and later and Edge 113 and later ship with WebGPU enabled by default. Firefox has experimental support behind a flag (dom.webgpu.enabled). Safari has partial support starting in Safari 18 (macOS Sequoia). For production deployments, always implement the WebGL and WASM fallback chain shown above.
Practically, models up to about 500 million parameters work well with WebGPU. The Xenova/flan-t5-small (60 million parameters) loads in under 2 seconds and generates fluently. Models around 1 billion parameters (like Phi-2 quantized) load but generate slowly — about 2 to 5 tokens per second. Beyond 1 billion parameters, browser memory limits become the bottleneck.
Chrome on Android supports WebGPU starting in version 121. iOS Safari has limited WebGPU support as of Safari 18. Mobile GPU memory is more constrained, so stick to smaller models (under 200 million parameters). On mobile, WASM is often the more reliable backend since it works across all modern mobile browsers without GPU compatibility concerns.
#WebGPU #Transformersjs #BrowserAI #ClientSideAI #JavaScript #Privacy #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.
Receptionist bots need to remember callers across visits without violating privacy. The privacy-aware memory architecture for voice receptionists that scales cleanly.
On-device voice LLMs are now real. What Apple Intelligence, Gemini Nano, and Phi-4 ship in 2026 — and what they cannot do yet.
Cloud-based code assistants ship your whole repo to remote LLMs every few minutes. Code-Review-Graph keeps the index local and only sends what matters — saving tokens, latency, and your IP.
Run Whisper, Kokoro, and LFM2.5-Audio entirely in the browser with ONNX Runtime Web + WebGPU. Flash Attention, qMoE, sub-100ms latency on a laptop. Privacy-first voice without a backend.
Comparing ChatGPT Operator 2.0 and Perplexity Comet for browser-based AI workflows — features, accuracy, pricing, and which fits your team in 2026.
Production traces are the best eval data you have. A workflow for promoting LangSmith traces into golden datasets without leaking PII or breaking compliance.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco