Built-in AI
Language models that ship with the browser: translate, summarise and chat with no server and no data leaving the device.
Chrome ships Gemini Nano and dedicated translation models, and pages use them through high-level APIs (Translator, LanguageDetector, Summarizer) or the Prompt API (LanguageModel), which since Chrome 148 accepts text, image and audio and can constrain the answer to a JSON schema.
Everything runs on the device: no per-request cost and no data leaving it. In exchange, it only works in desktop Chrome (Edge has part of it), the model downloads on first use and needs a capable machine. Mozilla has taken a negative position on the Prompt API.
What it is for
- Translating reviews or comments into the reader’s language
- Summarising articles, threads or long documents
- Classifying or extracting data with JSON output
Demo
Browser support
Limited availability| Feature | Desktop | Mobile | |||||
|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Safari | Chrome Android | Firefox Android | Safari iOS | |
| Prompt API (LanguageModel) | 148Chrome: 148 | 138flag1Edge: 138 flag | —Firefox: No | —Safari: No | —Chrome: No | —Firefox: No | —Safari: No |
| Summarizer | 1382Chrome: 138 | 138preview3Edge: 138 preview | —Firefox: No | —Safari: No | —Chrome: No | —Firefox: No | —Safari: No |
| Translator | 1382Chrome: 138 | 148Edge: 148 | —Firefox: No | —Safari: No | —Chrome: No | —Firefox: No | —Safari: No |
| LanguageDetector | 1382Chrome: 138 | 148Edge: 148 | —Firefox: No | —Safari: No | —Chrome: No | —Firefox: No | —Safari: No |
| Writer and Rewriter | ✓flag4Chrome: flag | ✓flag5Edge: flag | —Firefox: No | —Safari: No | —Chrome: No | —Firefox: No | —Safari: No |
| Proofreader | ✓flag6Chrome: flag | 142flag5Edge: 142 flag | —Firefox: No | —Safari: No | —Chrome: No | —Firefox: No | —Safari: No |
- 1Canary and Dev, behind a flag, with Phi-4-mini; not enabled in stable.
- 2Availability may be subject to geographical restrictions.
- 3On by default in Canary and Dev (Phi-4-mini); not in stable.
- 4The origin trial (137–148) has ended; now a developer trial behind a flag.
- 5Canary and Dev, behind a flag.
- 6The origin trial (141–145) has ended; now a developer trial behind a flag.
Compatibility generated on every deploy from MDN browser-compat-data 8.1.3 (24 Sep 2026) · web-features 3.40.0 · checked by hand: 1 Oct 2026
Minimal code
<!doctype html>
<meta charset="utf-8">
<title>IA integrada · ejemplo mínimo</title>
<!-- Detecta el idioma, traduce, resume y pregunta al modelo del navegador. Chrome 138+ (Prompt API: 148+), escritorio. -->
<textarea id="text" rows="4" cols="60">La Casa Botines es un edificio modernista de Antoni Gaudí en León, terminado en 1892.</textarea>
<p>
<button id="translate">Detectar y traducir al inglés</button>
<button id="summarize">Resumir</button>
<button id="prompt">Preguntar</button>
<progress id="progress" max="1" value="0"></progress>
</p>
<pre id="out"></pre>
<script type="module">
const $ = (s) => document.querySelector(s);
const out = $('#out');
// Las descargas del modelo informan del progreso (0..1)
const monitor = (m) => m.addEventListener('downloadprogress', (e) => ($('#progress').value = e.loaded));
// create() necesita un gesto del usuario si el modelo aún no está descargado: llámalo desde un clic.
$('#translate').onclick = async () => {
if (!('LanguageDetector' in self && 'Translator' in self)) return (out.textContent = 'Translator / LanguageDetector no disponibles.');
const detector = await LanguageDetector.create({ monitor });
const [{ detectedLanguage: sourceLanguage, confidence }] = await detector.detect($('#text').value);
const options = { sourceLanguage, targetLanguage: 'en' };
if ((await Translator.availability(options)) === 'unavailable') return (out.textContent = `No se puede traducir desde «${sourceLanguage}».`);
const translator = await Translator.create({ ...options, monitor });
out.textContent = `${sourceLanguage} (${Math.round(confidence * 100)} %) → en\n${await translator.translate($('#text').value)}`;
};
$('#summarize').onclick = async () => {
if (!('Summarizer' in self)) return (out.textContent = 'Summarizer no disponible.');
const options = { type: 'tldr', format: 'plain-text', length: 'short', expectedInputLanguages: ['es'], outputLanguage: 'es' };
if ((await Summarizer.availability(options)) === 'unavailable') return (out.textContent = 'El modelo no está disponible en este equipo.');
const summarizer = await Summarizer.create({ ...options, monitor });
out.textContent = '';
for await (const chunk of summarizer.summarizeStreaming($('#text').value)) out.textContent += chunk;
};
$('#prompt').onclick = async () => {
if (!('LanguageModel' in self)) return (out.textContent = 'Prompt API (LanguageModel) no disponible.');
const io = { expectedInputs: [{ type: 'text', languages: ['es'] }], expectedOutputs: [{ type: 'text', languages: ['es'] }] };
if ((await LanguageModel.availability(io)) === 'unavailable') return (out.textContent = 'El modelo no está disponible en este equipo.');
const session = await LanguageModel.create({
...io, monitor,
initialPrompts: [{ role: 'system', content: 'Responde en español, en una sola frase.' }],
});
out.textContent = '';
for await (const chunk of session.promptStreaming(`¿Quién diseñó este edificio? ${$('#text').value}`)) out.textContent += chunk;
// Salida estructurada: await session.prompt(texto, { responseConstraint: { type: 'boolean' } })
};
</script><!doctype html>
<meta charset="utf-8">
<title>IA integrada · ejemplo mínimo</title>
<!-- Detecta el idioma, traduce, resume y pregunta al modelo del navegador. Chrome 138+ (Prompt API: 148+), escritorio. -->
<textarea id="text" rows="4" cols="60">La Casa Botines es un edificio modernista de Antoni Gaudí en León, terminado en 1892.</textarea>
<p>
<button id="translate">Detectar y traducir al inglés</button>
<button id="summarize">Resumir</button>
<button id="prompt">Preguntar</button>
<progress id="progress" max="1" value="0"></progress>
</p>
<pre id="out"></pre>
<script type="module">
const $ = (s) => document.querySelector(s);
const out = $('#out');
// Las descargas del modelo informan del progreso (0..1)
const monitor = (m) => m.addEventListener('downloadprogress', (e) => ($('#progress').value = e.loaded));
// create() necesita un gesto del usuario si el modelo aún no está descargado: llámalo desde un clic.
$('#translate').onclick = async () => {
if (!('LanguageDetector' in self && 'Translator' in self)) return (out.textContent = 'Translator / LanguageDetector no disponibles.');
const detector = await LanguageDetector.create({ monitor });
const [{ detectedLanguage: sourceLanguage, confidence }] = await detector.detect($('#text').value);
const options = { sourceLanguage, targetLanguage: 'en' };
if ((await Translator.availability(options)) === 'unavailable') return (out.textContent = `No se puede traducir desde «${sourceLanguage}».`);
const translator = await Translator.create({ ...options, monitor });
out.textContent = `${sourceLanguage} (${Math.round(confidence * 100)} %) → en\n${await translator.translate($('#text').value)}`;
};
$('#summarize').onclick = async () => {
if (!('Summarizer' in self)) return (out.textContent = 'Summarizer no disponible.');
const options = { type: 'tldr', format: 'plain-text', length: 'short', expectedInputLanguages: ['es'], outputLanguage: 'es' };
if ((await Summarizer.availability(options)) === 'unavailable') return (out.textContent = 'El modelo no está disponible en este equipo.');
const summarizer = await Summarizer.create({ ...options, monitor });
out.textContent = '';
for await (const chunk of summarizer.summarizeStreaming($('#text').value)) out.textContent += chunk;
};
$('#prompt').onclick = async () => {
if (!('LanguageModel' in self)) return (out.textContent = 'Prompt API (LanguageModel) no disponible.');
const io = { expectedInputs: [{ type: 'text', languages: ['es'] }], expectedOutputs: [{ type: 'text', languages: ['es'] }] };
if ((await LanguageModel.availability(io)) === 'unavailable') return (out.textContent = 'El modelo no está disponible en este equipo.');
const session = await LanguageModel.create({
...io, monitor,
initialPrompts: [{ role: 'system', content: 'Responde en español, en una sola frase.' }],
});
out.textContent = '';
for await (const chunk of session.promptStreaming(`¿Quién diseñó este edificio? ${$('#text').value}`)) out.textContent += chunk;
// Salida estructurada: await session.prompt(texto, { responseConstraint: { type: 'boolean' } })
};
</script>What’s new
- Chrome 151: the language detector tells Simplified and Traditional Chinese apart.
- Chrome 149: Gemini Nano supports German and French, in addition to English, Spanish and Japanese.
- Edge expands its on-device models and APIs; Translator and LanguageDetector stable since Edge 148.
- Chrome 148 ships the Prompt API for web pages: multimodal input and responseConstraint.
- Chrome 149 no longer includes the Writer and Rewriter origin trial (137–148); like Proofreader (141–145), they remain developer trials.
Keep in mind
- Call create() from a click: if the model needs downloading, it requires a user gesture.
- Gemini Nano requirements: 22 GB free and a GPU with more than 4 GB of VRAM, or a CPU with 16 GB of RAM and 4 cores. There is no Android or iOS version.
- Translator.availability() answers “downloadable” for every language pair until the site creates a translator for it, so it does not reveal which languages you have. These APIs do not work in workers.
Further reading
Sources
- Chrome · Built-in AI APIs (estado)accessed 1 Oct 2026
- Chrome · Get started with built-in AI (requisitos)accessed 1 Oct 2026
- Chrome 148 release notes5 May 2026
- Prompt API (borrador)24 Sep 2026
- Microsoft Edge · Prompt API2 Jun 2026
- Mozilla standards-positions #1213accessed 1 Oct 2026