Prompt and scope
A web application wants to run an image-classification model locally in the browser to reduce image-upload privacy risk and network latency. The team is considering the May 2026 W3C Web Neural Network API Candidate Recommendation Draft. WebNN is a computational-graph API that can target CPU, GPU, and NPU execution; the specification is still evolving, so a Candidate Recommendation Draft is not a promise of stable support in every browser.
Give a complete answer covering model conversion, graph construction and compilation, inference dispatch, device choice, fallback, and release validation.
What the interviewer evaluates
The interviewer looks for a clear “build once, execute many times” lifecycle and a distinction between asynchronous MLGraphBuilder.build() compilation and asynchronous MLContext.dispatch() execution. WebNN should be described as a hardware-agnostic abstraction, not as a guarantee that every operator performs equally on every device.
Strong answers discuss operator coverage, tensor binding, main-thread blocking, capability detection, privacy and fingerprinting, browser compatibility, and a reversible canary plan.
Clarifying questions before answering
- Does the model use fixed shapes, or must it support dynamic shapes and multiple precisions?
- Do target browsers and operating systems expose the same operators and backends?
- Must inference stay offline, or is a safe server fallback acceptable?
- Is the target first-paint speed, per-frame latency, throughput, energy, or privacy?
- Does the model process sensitive images, and may hardware capability become a fingerprint signal?
A 30-second answer framework
“I would treat WebNN as a candidate execution backend. First I would validate model operators and tensor layouts, then move graph construction and compilation out of the inference path. Compilation and dispatch are asynchronous, with named tensors binding inputs and outputs. Before release I would build a browser, device, and model-version matrix; unsupported capabilities or compilation failures would fall back to WebAssembly or the server with a clear data boundary. I would measure first compile, steady-state inference, memory, energy, and main-thread responsiveness, canary gradually, and keep a kill switch.”
Step-by-step deep answer
Freeze the model contract
Fix input shape, data type, layout, normalization, output labels, and an error tolerance. Convert the model into a supported operator subgraph, detecting unsupported operators during graph construction rather than after partial execution on a user device. Keep a WebAssembly or server reference implementation for layer-by-layer comparisons.
Build and compile the graph
Create a context and MLGraphBuilder through navigator.ml, then compose inputs, constants, and operators. build() compiles the graph and returns a Promise; each builder should own one graph. Warm the graph in advance or in a Worker so first compilation does not become click latency.
const context = await navigator.ml.createContext({ deviceType: 'gpu' });
const builder = new MLGraphBuilder(context);
const input = builder.input('image', {
dataType: 'float32',
dimensions: [1, 224, 224, 3],
});
const weights = builder.constant(weightDescriptor, weightBuffer);
const logits = builder.conv2d(input, weights, convOptions);
const graph = await builder.build({ logits });The device option is only a candidate policy; an implementation must be validated against the target browser and specification version rather than assumed to accept every value.
Design asynchronous execution and memory flow
dispatch() submits graph execution to an execution timeline and returns immediately. Bind named input and output tensors, then read results after execution completes. Reuse the compiled graph, context, and buffers for repeated inference instead of allocating per frame. A camera stream needs backpressure: drop or coalesce a new frame while the previous one is still running rather than building an unbounded queue.
Choose devices and fallbacks
Detect API, operator, and model support before choosing CPU, GPU, or NPU. Device availability does not prove that the target operators are efficient; choose from end-to-end measurements. A fallback chain can be WebNN → WebAssembly → server, but every level must share preprocessing and result checks. A server fallback uploads images, so the UI and network layer must state consent and retention boundaries.
Protect the main thread and interaction
Graph construction, compilation, preprocessing, and postprocessing can affect interaction. Put heavy work in a Dedicated Worker and keep the main thread on input capture and UI state. Use cancellation or sequence numbers to discard stale results. Measure long tasks, input bursts, and background-tab recovery, not only average inference time.
Build correctness and compatibility matrices
Matrix browser version, operating system, device type, model precision, and operator set. Compare outputs, accuracy, and boundary inputs with the reference backend. Record compilation failures, unsupported operators, device loss, and context destruction. Because the W3C document is still a Candidate Recommendation Draft, a release plan must allow specification changes and implementation differences.
Handle privacy, permissions, and fingerprinting
Local execution reduces image uploads, but model files, caches, and telemetry can still leak information. Cache only required weights, avoid logging input features, and do not turn device type into a user identifier. The specification notes that device scheduling can create fingerprint signals; capability results should therefore be minimized and short-lived, with a software or server alternative.
Canary, observe, and roll back
Start with a non-sensitive model and a small browser set. Compare first compile, steady-state P50/P95, main-thread long tasks, memory, energy, failure rate, and fallback rate. Re-run the matrix on model or browser upgrades. If devices crash, accuracy drifts, energy is excessive, or privacy requirements fail, disable WebNN and use the reference backend; retain version, device, and model hashes for analysis.
High-quality model answer
“I would freeze the model input, output, and error contract, then verify operator mapping to WebNN. The graph is built and compiled once; build() and dispatch() follow asynchronous flows, and the inference loop reuses its context and buffers. The release matrix covers browser, device, and model versions, with Workers handling compilation and preprocessing. WebNN, WebAssembly, and the server form an observable fallback chain, and server fallback states the upload boundary. Canary metrics include first and steady-state latency, long tasks, memory, energy, accuracy, and failure rate; a kill switch immediately restores the reference backend.”
Common mistakes
- Treating a Candidate Recommendation as universal support → browser or operator gaps break users → build a version and capability matrix.
- Compiling the graph on every request → first-run cost repeats → warm and reuse the compiled graph.
- Benchmarking only an ideal GPU → CPU or NPU paths fail → measure end to end on each backend.
- Treating dispatch as synchronous → jank or out-of-order results → use asynchronous state and sequence numbers.
- Queueing every camera frame → latency grows without bound → apply backpressure and drop stale frames.
- Reporting device capability as identity → fingerprint risk increases → minimize detection and keep a software fallback.
Follow-up questions and responses
Follow-up 1: Why not use WebGPU directly?
WebGPU exposes lower-level resources and shader control, which suits custom operators and fine scheduling. WebNN provides a higher-level neural-network graph abstraction that maps more directly to frameworks and hardware backends. Choose based on operator coverage, maintenance ability, performance goals, and privacy boundaries.
Follow-up 2: Compilation takes ten seconds. How do you avoid user-visible waiting?
Move model loading and compilation into a Worker, warm during idle time, and cache integrity-checked weights. If the first request is still unavailable, show a truthful state and use WebAssembly or server fallback; never hide compilation failure behind fake output.
Follow-up 3: GPU output sometimes differs from the reference. What do you do?
Separate floating-point rounding, precision conversion, operator implementation differences, and a real model defect. Reproduce with fixed inputs, intermediate tensors, and tolerance thresholds; if product tolerance is exceeded, use another backend and record browser, driver, and model versions.
Follow-up 4: The user refuses image upload and WebNN is unavailable. What then?
Offer local WebAssembly or a clear unavailable state; do not bypass the choice. The product may reduce model complexity or offer a manual flow, but it must keep the data boundary transparent.