At Google I/O 2026 Chrome graduated the Prompt API to stable in Chrome 138 for extensions and Chrome 148 for the web, so any page can now call the on-device Gemini Nano model directly from JavaScript.
In this guide I show you which APIs are stable, which are still in origin trial, and the exact feature-detection pattern to ship on-device AI with a cloud fallback.
1. Context: From Origin Trial to Stable
For two years, built-in AI lived behind flags and the Early Preview Program: early samples used a window.ai shape, and every API required an origin-trial token. That era is over for the core set. Starting with Chrome 138, the Summarizer, Translator, and Language Detector APIs are stable, and the Prompt API joined them — first for Chrome Extensions in 138, then for any website in Chrome 148.
One naming note that will save you debugging hours: the current 2026 API surface uses the LanguageModel global — LanguageModel.availability() then LanguageModel.create() — not the window.ai shape from the earliest previews. If you copy a 2024-era snippet and it throws, that rename is almost certainly why.
Stable and shippable today
Summarizer, Translator, and Language Detector APIs are stable since Chrome 138. The Prompt API is stable in extensions since 138 and on the web since Chrome 148. No origin-trial token needed for these.
Developer trial — not stable yet
Writer, Rewriter, and Proofreader are listed as Developer trial in the official built-in AI status table. The old origin-trial windows (Writer/Rewriter 137–148, Proofreader 141–145) have expired, so do not ship these without a fallback — their surface can still change before stable.
Under the hood every API runs on Gemini Nano, a compact model Chrome downloads once and shares across origins. Your site never ships the runtime — the browser does — which is why there is no API key and no per-token bill.
2. Four Implications for Developers
Stable on-device inference changes the economics of AI features. Here are the four consequences I consider load-bearing for extension and web developers:
Zero marginal cost features
No API key · No per-token billing
Summaries, rewrites, translations, and classifications that used to cost cents per call are now free at the margin. Features you could never justify — summarize every tab, translate every comment — suddenly pencil out.
Private by architecture
Inference stays on the device
Text never leaves the machine, which unblocks AI features in privacy-sensitive contexts: internal tools, health and finance copy, and enterprise extensions where sending data to a cloud endpoint was a non-starter.
Task APIs beat raw prompts
Summarizer · Translator · Writer · Rewriter
The narrow APIs are easier to ship than the open-ended Prompt API: no prompt engineering, predictable outputs, and purpose-tuned behavior. Reach for them first and reserve LanguageModel for what they cannot express.
The fallback is mandatory
Hardware gate · ~60% coverage
On-device AI needs Windows 10/11, macOS 13+, Linux, or Chromebook Plus, plus 22 GB of free disk and a capable GPU. Roughly half your users will not qualify — Chrome’s own guidance says the model fails open, so your code must degrade to a cloud path.
Hardware requirements (official)
Desktop only: Windows 10/11, macOS 13+, Linux, or Chromebook Plus. At least 22 GB of free space on the Chrome profile volume, and a GPU with more than 4 GB of VRAM. Inspect status anytime at chrome://on-device-internals, and enable localhost testing via chrome://flags.
3. The Code: Feature-Detect, Create, Stream
Every built-in AI API follows the same rhythm: check availability() with the same options you will create() with, create a session, then prompt. The snippets below come straight from the official Chrome developer docs (Prompt API, updated Aug 26 2026) — no invented flags, no invented method names. Since Chrome 149 the Prompt API also supports multilingual sessions (en, es, ja, de, fr) and multimodal input (text/image/audio in, text out) plus JSON-schema structured output via responseConstraint.
Prompt API — availability and first session
// Pass the same options to availability() and create().
// expectedInputs: text | image | audio — expectedOutputs: text only.
// Languages (Chrome 149): "en" | "es" | "ja" | "de" | "fr".
const status = await LanguageModel.availability({
expectedInputs: [{ type: "text", languages: ["en"] }],
expectedOutputs: [{ type: "text", languages: ["en"] }]
});
// "available" | "downloadable" | "downloading" | "unavailable"
if (status === "available") {
const session = await LanguageModel.create({
expectedInputs: [{ type: "text", languages: ["en"] }],
expectedOutputs: [{ type: "text", languages: ["en"] }]
});
const result = await session.prompt("Summarize this in one sentence: ...");
}
// samplingMode ("most-predictable" … "most-creative") is web origin-trial
// only; extensions still use legacy topK/temperature + LanguageModel.params().
// const session = await LanguageModel.create({ samplingMode: "creative" });Prompt API — streaming + JSON-schema output
const stream = session.promptStreaming("Rewrite this paragraph:");
for await (const chunk of stream) {
process.stdout.write(chunk);
}
// Structured output (JSON Schema) — same shape for prompt()/promptStreaming():
const schema = { type: "object", properties: { rating: { type: "number" } } };
const raw = await session.prompt("Rate this feedback 0-5 as JSON:", {
responseConstraint: schema
});
const { rating } = JSON.parse(raw);Summarizer API — key points from long content
const summarizer = await Summarizer.create({
type: "key-points",
format: "markdown",
length: "medium"
});
const summary = await summarizer.summarize(longText);Translator API — on-device translation
const translator = await Translator.create({
sourceLanguage: "en",
targetLanguage: "es"
});
const text = await translator.translate("Hello, world");Writer + Rewriter APIs — Developer trial only
const writer = await Writer.create({
tone: "formal",
format: "plain-text",
length: "medium",
sharedContext: "Release notes for a Chrome extension"
});
const draft = await writer.write("A new offline mode");
const rewriter = await Rewriter.create({
tone: "more-casual",
length: "shorter",
format: "plain-text"
});
const revised = await rewriter.rewrite(draft);What Nano is good at — and what it is not
Keep on-device tasks narrow: summarize, rewrite, extract, classify, and translate short texts. Nano is a small model with a small context window, so long-document QA, code generation, and multi-step reasoning still belong on a cloud model behind your fallback. Declare expectedInputs/expectedOutputs up front so Chrome can download language packs or throw NotSupportedError early instead of failing mid-prompt.
4. What to Do This Week
A concrete five-step plan to go from zero to a shipped on-device feature before Friday:
âś… Your shipping checklist
- 1. Install Chrome 148+ and open chrome://on-device-internals to confirm the model state on your machine.
- 2. Add a LanguageModel.availability() gate to one existing feature — a summarize button is the classic first win.
- 3. Ship the cloud fallback first: if status is not “available”, route to your current server endpoint.
- 4. Replace one hand-rolled prompt with a task API: Summarizer for digests, Translator for user-generated content.
- 5. If you need Writer, Rewriter, or Proofreader, treat them as Developer trial: gate behind availability(), keep the cloud path as default, and expect the surface to change.
📦 Best first feature for extensions
- • Summarize the current tab: stable API, obvious value, tiny context needs.
- • Translate selected text in place: stable Translator API, no server round-trip.
- • Rewriter review replies with tone control: Developer trial — fence behind availability().
5. Sources
All API names, statuses, and code shapes above are taken from official Chrome documentation and the W3C explainer — never from third-party tutorials alone:
Conclusion
Chrome turned the browser into an AI runtime: Gemini Nano ships with the browser, the Prompt API is stable, and the task APIs cover the most common jobs for free. The teams that win in 2026 will treat on-device inference as a new free tier in their stack, not as a replacement for cloud models.
Start with one summarize button behind an availability() check and a cloud fallback. That single pattern — detect, create, stream, degrade gracefully — is the whole game, and it works in production today.
Cheat Sheet: Status at a Glance
Stable
- • Prompt API (web: 148+)
- • Summarizer (138+)
- • Translator (138+)
Developer trial
- • Writer (Developer trial)
- • Rewriter (Developer trial)
- • Proofreader (Developer trial)
Always check
- • availability() first
- • Cloud fallback
- • on-device-internals



