WebGPU: The GPU API the Web Deserved
After years of development, WebGPU is now the default GPU API in Chrome, Edge, and Firefox Nightly. It replaces WebGL — which was essentially a port of OpenGL ES 2.0 from 2007 — with a modern API designed for today's hardware. The difference is dramatic: WebGPU offers compute shaders, better parallelism, and direct GPU memory management.
For the first time, you can run serious GPU computing workloads directly in the browser. No plugins. No native code. No server. Just JavaScript (and WGSL shaders) talking directly to your GPU.
WebGL vs WebGPU: What Changed?
WebGL was designed for drawing triangles and textures. You could abuse it for computing (GPGPU), but it was painful. WebGPU was built from the ground up for both graphics and compute:
- Compute Shaders — WebGPU's killer feature. Run arbitrary parallel computations on the GPU, not just vertex/fragment shaders.
- Bind Groups — batch resource binding instead of one-at-a-time WebGL calls.
- Pipeline State Objects — pre-compiled pipeline state for zero-overhead draw calls.
- WGSL — a new shading language designed for safety and readability (replacing GLSL).
- Multithreaded Command Recording — record GPU commands from multiple workers simultaneously.
Real-world performance: WebGPU delivers 2-5x better throughput than WebGL for compute workloads, and up to 30% better for traditional rendering.
Your First Compute Shader
Let's start with a simple example: adding two arrays on the GPU.
// 1. Get the GPU adapter and device
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
// 2. Create input data
const dataA = new Float32Array([1, 2, 3, 4, 5]);
const dataB = new Float32Array([10, 20, 30, 40, 50]);
// 3. Create GPU buffers
const bufferA = device.createBuffer({
size: dataA.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
mappedAtCreation: true
});
new Float32Array(bufferA.getMappedRange()).set(dataA);
bufferA.unmap();
const bufferB = device.createBuffer({ /* same as A */ });
const bufferResult = device.createBuffer({
size: dataA.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_READ
});
// 4. Write the compute shader in WGSL
const shaderCode = `
@group(0) @binding(0) var<storage, read> a: array<f32>;
@group(0) @binding(1) var<storage, read> b: array<f32>;
@group(0) @binding(2) var<storage, read_write> result: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
result[id.x] = a[id.x] + b[id.x];
}
`;
// 5. Create and dispatch the compute pipeline
const module = device.createShaderModule({ code: shaderCode });
const pipeline = device.createComputePipeline({
layout: 'auto',
compute: { module, entryPoint: 'main' }
});
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{ binding: 0, resource: { buffer: bufferA } },
{ binding: 1, resource: { buffer: bufferB } },
{ binding: 2, resource: { buffer: bufferResult } }
]
});
const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(Math.ceil(dataA.length / 64));
pass.end();
device.queue.submit([encoder.finish()]);
// 6. Read back the result
const result = await readBuffer(device, bufferResult);
console.log(new Float32Array(result)); // [11, 22, 33, 44, 55]
This is a trivial example, but the pattern scales. Replace the addition with matrix multiplication, convolution, or any parallelizable operation, and you have a GPU-accelerated computing engine in the browser.
Running AI Models with WebGPU
The hottest application of WebGPU is on-device AI inference. Frameworks like ONNX Runtime Web, TensorFlow.js, and Transformers.js now support WebGPU backends, allowing you to run models directly on the user's GPU:
// Using Transformers.js with WebGPU
import { pipeline } from '@xenova/transformers';
// This model runs entirely on the user's GPU — no server needed
const classifier = await pipeline(
'text-classification',
'Xenova/distilbert-base-uncased-finetuned-sst-2-english',
{ device: 'webgpu' }
);
const result = await classifier('I love building browser extensions!');
// [{ label: 'POSITIVE', score: 0.9998 }]
What's happening under the hood: the model weights are downloaded once and cached. Every inference call runs on the GPU through WebGPU compute shaders. No data leaves the browser.
Image Classification
// Image classification with WebGPU
import { pipeline } from '@xenova/transformers';
const classifier = await pipeline(
'image-classification',
'Xenova/vit-base-patch16-224',
{ device: 'webgpu' }
);
const result = await classifier('photo.jpg');
// [{ label: 'golden retriever', score: 0.92 }]
Text Embeddings for Semantic Search
// Generate embeddings locally
const extractor = await pipeline(
'feature-extraction',
'Xenova/all-MiniLM-L6-v2',
{ device: 'webgpu' }
);
const embedding = await extractor('browser extension privacy');
// Float32Array(384) — a 384-dimensional vector
This enables local semantic search — build a search engine over your bookmarks, notes, or documents without sending any text to a server. The embeddings are computed on your GPU in milliseconds.
GPU-Accelerated Image Processing
Beyond AI, WebGPU excels at image processing. A compute shader can process millions of pixels in parallel:
// GPU-accelerated image blur (simplified)
const blurShader = `
@group(0) @binding(0) var input_texture: texture_2d<f32>;
@group(0) @binding(1) var output_texture: texture_storage_2d<rgba8unorm, write>;
@group(0) @binding(2) var<uniform> params: vec2<f32>; // width, height
@compute @workgroup_size(16, 16)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
let coords = vec2<i32>(id.xy);
var color = vec4<f32>(0.0);
var count = 0.0;
// 5x5 Gaussian blur kernel
for (var dy = -2; dy <= 2; dy++) {
for (var dx = -2; dx <= 2; dx++) {
let sample = vec2<i32>(coords.x + dx, coords.y + dy);
color += textureLoad(input_texture, sample, 0);
count += 1.0;
}
}
textureStore(output_texture, coords, color / count);
}
`;
This blur runs on the GPU's massively parallel architecture. A 4K image (8.3 million pixels) is processed in under 2 milliseconds — hundreds of times faster than the equivalent JavaScript loop.
Practical Uses in Browser Extensions
WebGPU opens up possibilities for browser extensions that were previously impossible without native code:
- Real-time image filters — apply Instagram-style filters to any image on any webpage, processed locally on the GPU
- Video frame analysis — process video frames for content detection, thumbnail generation, or scene changes
- Local AI assistants — run small language models for text summarization, translation, or code completion without a server
- Privacy scanning — detect tracking pixels, fingerprinting scripts, or data leaks by analyzing page content with AI models
For image-focused extensions like ImageConv and PageShot, WebGPU means faster processing and the ability to add GPU-accelerated filters and transformations that would be too slow in pure JavaScript.
WGSL: The Shading Language
WebGPU uses WGSL (WebGPU Shading Language) instead of GLSL. It's designed for safety and readability:
// WGSL compute shader for image brightness adjustment
@group(0) @binding(0) var<storage, read> input: array<u32>;
@group(0) @binding(1) var<storage, read_write> output: array<u32>;
@group(0) @binding(2) var<uniform> brightness: f32;
@compute @workgroup_size(256)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
let pixel = input[id.x];
// Unpack RGBA
var r = f32((pixel >> 0u) & 0xFFu);
var g = f32((pixel >> 8u) & 0xFFu);
var b = f32((pixel >> 16u) & 0xFFu);
let a = f32((pixel >> 24u) & 0xFFu);
// Apply brightness
r = clamp(r + brightness, 0.0, 255.0);
g = clamp(g + brightness, 0.0, 255.0);
b = clamp(b + brightness, 0.0, 255.0);
// Pack back to u32
output[id.x] = u32(r) | (u32(g) << 8u) | (u32(b) << 16u) | (u32(a) << 24u);
}
WGSL is more verbose than GLSL, but it's also more explicit and harder to make mistakes. The type system catches errors at shader compilation time rather than at runtime.
Browser Support & Fallbacks
As of September 2026:
- Chrome 113+ — Full support (enabled by default)
- Edge 113+ — Full support (Chromium-based)
- Firefox — Nightly only, behind a flag. Stable support expected by end of 2026.
- Safari — Technology Preview has experimental support. Full support expected in Safari 19.
For production use, always check for WebGPU availability and fall back to WebGL or CPU processing:
async function getGPUDevice() {
if (!navigator.gpu) {
console.warn('WebGPU not supported, falling back to WebGL');
return null;
}
const adapter = await navigator.gpu.requestAdapter();
if (!adapter) return null;
return await adapter.requestDevice();
}
The Browser as a Computing Platform
WebGPU represents a fundamental shift in what the browser can do. It's no longer just a document renderer or an app container. With direct GPU access, the browser becomes a genuine computing platform — capable of running AI models, processing video, and performing scientific computations that previously required native applications.
For privacy-conscious users, this is particularly exciting. On-device AI inference means your data stays on your machine. GPU-accelerated image processing means you don't need to upload photos to a server. Local semantic search means your browsing history never leaves your browser.
The web platform is catching up to native. And in some ways — with its sandboxed security model, instant deployment, and zero installation — it's already ahead.