Chrome's Summarizer API: Ship Free, On-Device AI Summaries in Your Extension

Your users read long articles, emails, and support threads inside your extension. They want a “summarize this” button. You want to ship it — without paying OpenAI per call, without leaking private text to a third-party server, and without a 1 GB model download the first time they click.
Chrome’s Summarizer API solves all three. Starting in Chrome 138, a single Summarizer.create() call gives you article TL;DRs, key-point lists, teasers, and headlines — powered by Gemini Nano running locally on the user’s device.
If you’re building a Chrome extension that handles text, this is the AI API you ship this quarter.
Why the Chrome Summarizer API Matters for Extension Developers
Adding summarization to an extension used to mean one of three bad options:
- Paid cloud API — OpenAI or Anthropic fees scale linearly with users
- Local model via WebLLM — 1+ GB download per origin, janky first run
- Regex hack — grab the first paragraph, call it a summary, hope nobody notices
The Chrome Summarizer API eliminates all three. Gemini Nano is bundled with Chrome itself — shared across every site and extension. Your users pay the storage cost once, and every extension that uses the API gets free, private, instant summarization.
The unlock for extensions specifically: on-device inference means you can summarize the user’s Gmail, DMs, or internal documents without a privacy disclosure, without SOC 2, and without a backend.
Hardware Requirements: What Your Users Need
Before building, know the minimum specs:
| Requirement | Specification |
|---|---|
| OS | Windows 10/11, macOS 13+, Linux, ChromeOS (Chromebook Plus) |
| Storage | 22 GB free (model removes itself if free space drops below 10 GB) |
| RAM | 16 GB with 4+ cores (CPU) or >4 GB VRAM (GPU) |
| Network | Unmetered connection for initial ~4 GB model download |
| Browser | Chrome 138+ stable, Edge (behind flag) |
Not yet supported: Android, iOS, mobile Chrome, Firefox, Safari, Web Workers.
Pro tip: The Gemini Nano model is shared across the entire browser. If another extension or site already triggered the download, your users pay zero install cost.
Your First Summary in 4 Lines
Here’s the shortest useful Chrome Summarizer API call:
if (!('Summarizer' in self)) return;
const summarizer = await Summarizer.create({ type: 'tldr', length: 'short' });
const summary = await summarizer.summarize(document.body.innerText);
console.log(summary);That’s the entire API surface for a basic summary. No fetch, no auth, no provider SDK, no billing.
The Four Summary Types (This Is Where It Gets Powerful)
The type option doesn’t just change output length — it changes what the model is trying to do. Pick the right one for the UI you’re building.
| Type | Output | Use it for |
|---|---|---|
key-points (default) | Bulleted list of main ideas | Article TL;DRs, meeting notes, RSS readers |
tldr | Prose summary, 1–5 sentences | Chat previews, email digests, search snippets |
teaser | An intriguing hook, not a spoiler | Link previews, “read more” cards, aggregators |
headline | Single-sentence article title | Auto-titles for saved articles, notifications |
teaser is the underrated one. Most summarizers flatten text into facts. teaser is tuned to make the reader want the full article — a feature you’d normally build with a custom prompt.
Length options
- short — 3 bullets / 1 sentence / ~12 words
- medium (recommended) — 5 bullets / 3 sentences / ~17 words
- long — 7 bullets / 5 sentences / ~22 words
Treat these as hints, not contracts.
Streaming: The UX Pattern You Should Default To
Batch summarization (summarizer.summarize(text)) blocks until the whole summary returns. On a long article that’s a 3–8 second spinner. Stream instead:
const stream = summarizer.summarizeStreaming(article, {
context: 'Intended for a junior developer audience',
});
const output = document.getElementById('summary');
for await (const chunk of stream) {
output.textContent += chunk;
}Text starts appearing in under a second and writes in real time. Only use batch mode when you need the complete string before continuing (saving to storage, piping to another model, stringifying to JSON).
The 86% rule applies here. Users decide in the first few seconds whether a feature feels fast. Streaming turns a “loading…” state into a live animation — same latency, completely different perception.
Context Is the Secret Weapon
This is where the Chrome Summarizer API moves from “toy” to “production tool.”
Every summarizer can take a sharedContext at creation time, and every call can take a per-request context. Both are injected into the prompt and meaningfully change the output quality.
const summarizer = await Summarizer.create({
type: 'tldr',
length: 'short',
sharedContext: 'These are customer support tickets from a SaaS billing product.',
});
const summary = await summarizer.summarize(ticketText, {
context: 'Focus on the billing error and what the user already tried.',
});Without context, the model doesn’t know if it’s summarizing a research paper, a tweet thread, or a lease agreement. Treat sharedContext like a system prompt and context like a per-request instruction.
Handling the Model Download Gracefully
Summarizer.availability() returns one of three values:
| Value | Meaning | What to do |
|---|---|---|
readily-available | Model on disk | Call create() immediately |
downloadable | Capable device, not downloaded | Show progress UI |
unavailable | Device doesn’t qualify | Use fallback |
A 4 GB download is not a spinner. Show real progress:
const summarizer = await Summarizer.create({
type: 'key-points',
monitor(m) {
m.addEventListener('downloadprogress', (e) => {
const percent = Math.round(e.loaded * 100);
progressBar.style.width = `${percent}%`;
statusText.textContent = `Downloading AI model… ${percent}%`;
});
},
});Things that will trip you up:
create()requires user activation (click or keypress). Don’t call it on page load.- Initial download needs an unmetered connection.
- Model is shared across origins — your user may already have it from another site.
button.addEventListener('click', async () => {
if (navigator.userActivation.isActive) {
const summarizer = await Summarizer.create(options);
}
});Multilingual Summaries
The Chrome Summarizer API accepts input in multiple languages and can translate the output:
const summarizer = await Summarizer.create({
type: 'key-points',
expectedInputLanguages: ['en', 'ja', 'es'],
outputLanguage: 'es',
sharedContext: 'Output Spanish summaries regardless of input language.',
});Declaring expectedInputLanguages upfront lets Chrome pre-load language resources. Skip it and unexpected-language inputs will produce lower quality output.
Using It Inside a Chrome Extension
The Summarizer API is available in extension contexts with DOM access:
✅ Popup pages ✅ Options pages ✅ Side panels ✅ Content scripts (with caveats)
❌ Service workers / background scripts ❌ Offscreen documents (varies)
Cross-origin iframes need the Permissions Policy:
<iframe src="https://cross-origin.example.com/" allow="summarizer"></iframe>Extension manifest: No special permission is required to use Summarizer itself. You only need permissions for whatever content you’re reading (activeTab, scripting, etc.).
The Fallback Pattern Every Extension Needs
Because the API is Chrome-only and hardware-gated, ship three paths:
async function getSummary(text) {
// 1. Native Summarizer API (free, private, instant)
if ('Summarizer' in self) {
const availability = await Summarizer.availability();
if (availability !== 'unavailable') {
const s = await Summarizer.create({ type: 'tldr', length: 'short' });
return s.summarize(text);
}
}
// 2. Cloud fallback (paid, but reliable cross-browser)
if (navigator.onLine) {
const res = await fetch('/api/summarize', {
method: 'POST',
body: JSON.stringify({ text }),
});
return (await res.json()).summary;
}
// 3. Graceful degradation
return text.split('. ').slice(0, 2).join('. ') + '.';
}Native first, cloud fallback, dumb fallback last. This is the right shape for any new browser AI API.
Session Cleanup (Don’t Skip This)
Each summarizer holds model state in memory. For single-use summaries, destroy the session when done:
const summarizer = await Summarizer.create(options);
try {
const summary = await summarizer.summarize(text);
return summary;
} finally {
summarizer.destroy();
}For long-lived summarizers (e.g. a persistent “summarize every new tab” feature), reuse one instance across calls instead of creating per-request. Memory leaks kill extension reviews faster than almost any other bug.
Honest Limitations of the Chrome Summarizer API
If you ship the Chrome Summarizer API to users today, here’s what will bite you:
- Desktop only. No Android, iOS, or mobile Chrome yet.
- Hardware floor is real. Older laptops and budget Chromebooks are excluded.
- No Web Workers. Main thread only for now.
- No fine-tuning, no system prompts. You get the options provided.
- Non-determinism. Same input, different output. Don’t use for reproducible hashes or test snapshots.
- Not limitless. No per-day cap, but every call occupies the GPU/CPU. Batch and throttle.
Use Cases That Actually Make Sense
Not every extension needs summarization. These are where the tradeoffs line up:
- RSS and read-later extensions — Generate TL;DRs for every saved article offline
- Gmail / email helpers — Summarize long threads without sending content to a server
- Tab managers — Auto-generate headlines for saved tab groups
- Support and CRM dashboards — Summarize ticket history on-device (no compliance rewrite)
- Documentation readers — Add “summarize this page” to any docs site
- News aggregators — Use
teasermode for better link cards
Avoid it for: cross-browser consumer apps, anything needing deterministic output, mobile-first products.
Current Status & What’s Next
| Detail | Status |
|---|---|
| API Status | Stable in Chrome 138+ |
| Model | Gemini Nano (on-device, shared across Chrome) |
| Spec | W3C Writing Assistance APIs |
| Docs | Chrome Summarizer API |
The Chrome Summarizer API is the first of several built-in AI APIs Chrome is shipping, alongside the Prompt API, Translator API, and Language Detector API. Together they replace most cloud AI calls a modern extension would need.
Key Takeaways
- Zero cost, zero latency, zero privacy risk — Gemini Nano runs entirely on-device
- Four summary types —
key-points,tldr,teaser,headline— pick by UI, not length - Stream by default —
summarizeStreaming()is the production pattern - Use
contextaggressively — it’s the biggest quality lever you have - Always ship a fallback — native → cloud → dumb-split
- Destroy sessions — memory leaks sink Chrome Web Store ratings
- Feature-detect first —
'Summarizer' in selfbefore anything else
The Chrome Summarizer API is the easiest path to shipping free, private AI summaries in a Chrome extension. No billing, no backend, no excuses.
Ready to build? Try the Summarizer API docs and start experimenting today. When your AI-powered extension is ready for the Chrome Web Store, AppBooster has the tools to help you launch, optimize, and grow.
Share this article
Build better extensions with free tools
Icon generator, MV3 converter, review exporter, and more — no signup needed.
Related Articles
Building Accessible Chrome Extensions: Keyboard, Screen Reader, and WCAG Compliance
26% of US adults have disabilities. Make your Chrome extension accessible with focus traps, ARIA, keyboard nav, and WCAG 2.1 AA compliance.
I Built the Same Chrome Extension With 5 Different Frameworks. Here's What Actually Happened.
WXT vs Plasmo vs CRXJS vs Extension.js vs Bedframe. Real benchmarks, honest opinions, and the framework with 12K stars that's quietly dying.
5 Best Email Marketing Services to Grow Your Chrome Extension (2026)
Compare the top email marketing platforms for SaaS and Chrome extension developers. MailerLite, Mailchimp, Brevo, ActiveCampaign, and Drip reviewed.