Imagine translating a customer support message without sending it to a cloud-based AI model, making an API call, or waiting for a network response. What if your browser could handle that task directly on the user’s device?
Browser-based AI APIs make this possible by using small language models (SLMs) built into modern browsers to handle everyday AI tasks locally. This can reduce latency, eliminate per-request API costs, and improve privacy by keeping data on the user’s device. However, these APIs are still evolving, and browser support, hardware requirements, and model capabilities vary.
In this article, we’ll explore how browser-based AI task APIs work, where they make the most sense, and which browsers currently support them. We’ll also walk through practical implementation patterns, including feature detection, availability checks, model download handling, and graceful fallbacks, before looking at examples of the Summarizer, Language Detector, and Translator APIs.
Some modern browsers now ship their own in-browser SLMs, accessible only through specific developer-facing interfaces called AI task APIs.
Let’s say you are working on a customer support portal where tickets will come from across the globe in different languages. The usual flow to tackle the language problem here would be to detect each ticket’s language first, then summarize it, and then translate it.
Obviously, this flow would cost you multiple round trips to the cloud, which may not bother at first. But as the app scales, handling this within the browser without API keys, backend calls, and per-request cost can make a difference.
There are four metrics that make the idea of browser-based AI task APIs interesting:
Sounds fascinating. Before running to conclusions, let’s also understand where these APIs can really shine and where you should avoid them.
Here’s the thing: SLMs are limited in shape and size. Capabilities like providing the latest data, maintaining predictable quality, multi-step reasoning, extended creative writing, and image/audio/video generation are way beyond an SLM’s scope.
In-browser SLMs with their task APIs are best suited for simple, frequent textual content tasks like language detection, translation, paraphrasing, and summarizing. The support ticket flow we discussed above is one of the best use cases where small and redundant tasks can be handled locally with an in-browser SLM.
Currently, these APIs are available only with some Chromium-based desktop browsers. Chrome and Edge are the only leading players with active development in this area.
| Browser | Built-in APIs | Underlying Model | Support Status | Version |
|---|---|---|---|---|
| Google Chrome | Stable: Summarizer, Translator, Language Detector, Prompt Origin Trial / Preview: Writer, Rewriter, Proofreader |
Gemini Nano (Prompt, Summarizer, Writer, Rewriter, Proofreader) Task-specific models (Translator, Language Detector) |
Stable (Desktop only) Origin Trial (Writer, Rewriter, Proofreader) |
138+ (Summarizer, Translator, Language Detector) 138+ Extensions / 148+ Web (Prompt) |
| Microsoft Edge | Stable: Translator, Language Detector Preview / Origin Trial: Summarizer, Prompt, Writer, Rewriter, Proofreader |
Phi-4-mini (Summarizer, Prompt, Writer, Rewriter) Aion-1.0-Instruct (Prerelease SLM override) Task-specific models (Translator, Language Detector) |
Stable (Translator, Language Detector) Dev Preview / Flag / Origin Trial (Summarizer, Prompt, Writer, Rewriter) |
148+ (Translator, Language Detector) 138+ Canary/Dev (Phi-4-mini APIs) 150+ Canary/Dev (Aion-1.0-Instruct) |
| Apple Safari | N/A | — | Not supported | — |
| Mozilla Firefox | Web: N/A (Uses internal Bergamot translation UI) Extensions: browser.trial.ml |
Web: — Extensions: Transformers.js + ONNX Runtime (Hugging Face models) |
Not supported on Web Experimental / Behind Flag ( browser.ml.enable for Extensions) |
— |
Even though Chrome alone takes about two-thirds of the market, not all Chrome users will have access to these features, which require promising hardware support.
This sounds ridiculous, doesn’t it? I mean, these high-end requirements take away nearly 70% of the users from that meaty portion that the two browsers cover. Out of the remaining 30%, only 10-15% are actively using browser SLMs, but that’s exactly where our value is, and this number will only grow from here.
Currently, using LanguageDetector, Translator, and Summarizer is ideal due to their greatest stability. Before hopping on working examples, let’s learn some foundational patterns for using these APIs safely and effectively, considering their limited support and experimental features.
To detect API support, we can simply check whether or not the API object exists in the window or self object. We’ll prefer self over window here, which is a slightly better practice now since it works on both browsers and web workers.
if (!('LanguageDetector' in self)) {
// No built-in language detection found
}
Task APIs work well in development mode (localhost), but strictly require a secure context or HTTPS in production:
if (!window.isSecureContext) {
console.warn('Built-in AI needs HTTPS. Falling back to the server.');
}
The availability() method covers both of the scenarios when hardware or OS requirements aren’t met or the user has the feature turned off.
const summarizeText = async (text) => {
if (!('Summarizer' in self)) {
throw new Error('Summarizer API is not supported');
}
const options = {
type: 'tldr',
length: 'short',
};
const availability = await Summarizer.availability(options);
if (availability === 'unavailable') {
throw new Error('Summarizer API is unavailable on this device');
}
const summarizer = await Summarizer.create(options);
return summarizer.summarize(text);
};
This availability() method may also return downloadable, which means the API is supported, but the associated SLM isn’t downloaded on the device yet. In that case, calling create() will trigger the download.
The model download takes some time on the first use of in-browser SLM features. In that case, consider showing a dialog asking the user to continue with the download. You may also show a progress indication following the pattern below:
const dialogRef = document.querySelector('#ai-slm-download-dialog');
const summarizeText = async (text) => {
// Previous setup...
if (availability === 'unavailable') {
throw new Error('Summarizer API is unavailable');
}
if (availability === 'downloadable') {
dialog.showModal();
const confirmed = await new Promise((resolve) => {
dialog.addEventListener('close', () => {
resolve(dialog.returnValue === 'continue');
}, { once: true });
});
if (!confirmed) return null;
}
const summarizer = await Summarizer.create(options);
try {
return await summarizer.summarize(text);
} finally {
summarizer.destroy();
}
};
Going back to our customer support ticketing scenario: let’s make a check up front, and add a cloud fallback when the browser can’t help.
async function handleTicket(text, targetLang = 'en') {
if (!('LanguageDetector' in self)) {
return processOnServer(text, targetLang); // no built-in AI: use the cloud
}
const detector = await LanguageDetector.create();
const lang = (await detector.detect(text))[0].detectedLanguage;
const summarizer = await Summarizer.create({ type: 'tl;dr', length: 'short' });
const summary = await summarizer.summarize(text);
const translator = await Translator.create({
sourceLanguage: lang,
targetLanguage: targetLang,
});
return { lang, summary, translation: await translator.translate(summary) };
}
One check decides the whole flow: if the browser doesn’t offer the API, the ticket goes to the server. If the API is supported and available, all three tasks will execute locally in the browser.
Upon first use, Chrome automatically triggers the model download after any page interaction. Instead of shocking the user with hidden downloading, attach the download triggering logic (the create() call) to a clear user action, like a button click:
summarizeButton.addEventListener('click', async () => {
// The click grants user activation, create() may now start the download
const summarizer = await Summarizer.create(options);
});
if (!navigator.userActivation.isActive) {
// Ask the user to click something first
}
If you can, go one step further and ask the user with a dialog box to cancel or continue the download. This will help people with a metered connection decide better.
The cross-origin frames need explicit permission. For example, if I embed a CodePen example to demo the implementation of these APIs, it won’t work out of the box despite your browser fulfilling all the requirements.
Try it yourself in the example below:
See the Pen
Testing Summarizer API by Rahul (@rahuldotdev)
on CodePen.
To have embeds like this working, you have to provide the allowed APIs using the allow attribute as shown below:
<iframe src="https://codepen.io/..." allow="summarizer; translator; language-detector"></iframe>
We’ll quickly touch on the stable task APIs for both Chrome and Edge with small examples. I’m using the general syntax, which you may pair with the patterns discussed above as homework. I’m sharing my experience based on Chrome/Linux and Edge/Windows usage.
The Summarizer API doesn’t work instantly, even if your browser has already downloaded the required SLM. It takes time depending on the payload size. That’s exactly where you notice the limitation of working with an SLM. Still, given that in-browser SLMs are in their early phase, I can cut it some slack.
const summarizer = await Summarizer.create({ type: 'tl;dr', length: 'short' });
const result = await summarizer.summarize(text);
The Summarizer API is supported on Chrome and Edge from version 138 onwards.
The language detection API worked almost instantly. In my tests, the detected language was correct even for short, slang-heavy content.
const detector = await LanguageDetector.create(); const detected = (await detector.detect(text))[0].detectedLanguage;
The LanguageDetection API is supported on Chrome 138+ and Edge 148+.
The translation also worked swiftly. I tried 7-8 languages a few times; the results were accurate nearly all the time except when I added random gibberish to the payload.
const translator = await Translator.create({
sourceLanguage: detected,
targetLanguage: target,
});
const result = await translator.translate(text);
The Translator API is supported on Chrome 138+ and Edge 148+.
See these APIs working together in this sample Ticket Triage application. The app is written in React, demonstrating the exact same support ticket language detection, summarizing, and translation.
create() again and again, maintain it as a shared client and reuse it everywhereChrome and Edge together cover a huge portion of desktop browsing. Acknowledging their AI capabilities can definitely help you cut costs, especially at scale.
So, what’s shippable today? The simple answer to this question is a hybrid approach: detect the API, use it, and enjoy the latency and cost benefits, or gracefully fall back to a stable cloud backend.
With that said, I’d keep an eye on standardization and start today with feature detection and graceful degradation. This will keep the code feature-proof, and as support grows, your app will notice more benefits down the line.

Learn how to build and install three Claude Code mods to monitor usage, protect secrets, and track changes.

I tested Jev against popular LLMs to compare speed, cost, and accuracy on real bank support messages.

Is react-markdown slowing down your app? We benchmarked three top streaming Markdown renderers to find the fastest, most efficient alternative for React.

Learn how coding agents streamline TDD with automated tests, quality guardrails, and mutation testing to catch bugs and build reliable software.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now