← Chrome 147 reference

v147 · web api · origin trial

WebNN

The Web Neural Network API lets web apps and frameworks run neural network inference against the device's hardware accelerators — CPU, GPU, or a dedicated NPU — without tying the code to any platform-specific backend. navigator.ml is the entry point; the rest is a graph builder API that compiles to whatever hardware is available.

Experimental WebNN is in an origin trial phase. The API surface has evolved substantially through 2026 (over 100 spec changes since April 2024). Field names, operator lists, and the MLTensor buffer-sharing API are still stabilising. Check the spec before shipping anything.

at a glance

Shipping targetChrome 147 (origin trial; exact GA milestone TBD)
StatusOrigin trial / Proposed
Flagchrome://flags/#web-machine-learning-neural-network
Standards positionFirefox: Positive  ·  Safari: No signal (Apple active in WG)
SpecWeb Neural Network API (W3C WebML Working Group, Candidate Recommendation)
Explainerwebmachinelearning / webnn / explainer.md
Sampleswebnn-samples  ·  Microsoft developer preview
ChromeStatus5176273954144256 — WebNN

why it exists

Neural network inference on the web has historically meant one of two things: a heavyweight WASM runtime that can't touch the GPU, or WebGL/WebGPU compute shaders that require hand-rolling matrix math and shader strings. Neither path can reach a device's Neural Processing Unit. WebNN is a hardware-agnostic graph API — the browser maps it onto Windows DirectML, macOS ML Compute, Android NNAPI, or whatever native stack is present. The Chromium implementation is a three-way collaboration between Google, Intel, and Microsoft; Edge ships WebNN at the same time as Chrome from the same code.

Source: chromestatus motivation and the WebNN explainer §1 ("Background").

shape of the API

Four core interfaces; the workflow is always: create a context → build a graph → compile → compute.

navigator.ml → ML

navigator.ml.createContext(options?)Returns Promise<MLContext>. Options can specify a device preference ("cpu", "gpu", "npu") and a power preference ("high-performance", "low-power", "default").

MLContext

compute(graph, inputs, outputs)Runs a compiled MLGraph. inputs and outputs are plain objects keyed by operand name; values are ArrayBufferView. Returns Promise<MLComputeResult>.
createTensor(descriptor, writable?, readable?)Allocates a device-side MLTensor for zero-copy buffer sharing between the graph and WebGPU (if available).
dispatch(graph, inputs, outputs)Fire-and-forget version of compute for MLTensor-backed buffers; does not transfer data back to JS until readTensor() is called.

MLGraphBuilder

new MLGraphBuilder(context)Constructor. Binds the builder to a context.
input(name, descriptor)Declares an input operand. Descriptor: { dataType, dimensions }.
constant(descriptor, data)Embeds a constant (e.g. model weights) into the graph at build time.
Operatorsadd, mul, matMul, conv2d, relu, sigmoid, softmax, transpose, reshape, gather, layerNormalization, gru, lstm, and ~70 more. Each returns an MLOperand.
build(outputs)Compiles the graph. outputs is an object mapping output names to MLOperand. Returns Promise<MLGraph>.

MLGraph

Opaque compiled representation. Pass to context.compute() or context.dispatch(). Immutable after construction.
Source: WebNN explainer §3–§6 and webnn.io API reference. Operator count as of January 2026 Candidate Recommendation snapshot.

example: add two matrices

const context = await navigator.ml.createContext({ deviceType: 'gpu' });
const builder = new MLGraphBuilder(context);

// Declare two 2×2 float32 inputs
const A = builder.input('A', { dataType: 'float32', dimensions: [2, 2] });
const B = builder.input('B', { dataType: 'float32', dimensions: [2, 2] });

// Build a computation: C = A + B
const C = builder.add(A, B);
const graph = await builder.build({ C });

// Run inference
const inputs = {
  A: new Float32Array([1, 2, 3, 4]),
  B: new Float32Array([5, 6, 7, 8]),
};
const outputs = { C: new Float32Array(4) };
await context.compute(graph, inputs, outputs);
// outputs.C → [6, 8, 10, 12]

example: softmax classifier (weights as constants)

const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);

// Embed weights and bias as graph constants
const W = builder.constant(
  { dataType: 'float32', dimensions: [4, 128] },
  Float32Array.from(modelWeights)          // pre-loaded Uint8Array / Float32Array
);
const b = builder.constant(
  { dataType: 'float32', dimensions: [4] },
  Float32Array.from(modelBias)
);

// Single input: a 128-d feature vector
const x = builder.input('x', { dataType: 'float32', dimensions: [128] });

// Linear layer + softmax
const logits = builder.add(builder.matMul(x, builder.transpose(W)), b);
const probs  = builder.softmax(logits, 0);

const graph = await builder.build({ probs });

// Reuse the graph for every prediction — graph compilation is the slow step
async function predict(featureVector) {
  const out = { probs: new Float32Array(4) };
  await context.compute(graph, { x: featureVector }, out);
  return out.probs;
}

browser support

ChromeOrigin trial in 147 (Google + Intel + Microsoft collaboration)
EdgeLaunches alongside Chrome (same Chromium code)
FirefoxPositive — Mozilla standards position #1215
SafariNo signal (Apple active in W3C WebML Working Group)
Source: chromestatus browser views and Mozilla standards-positions issue #1215, May 2026.

see also