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

AppBooster Team · · 9 min read
Chrome Summarizer API cover illustration showing on-device summarization

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:

RequirementSpecification
OSWindows 10/11, macOS 13+, Linux, ChromeOS (Chromebook Plus)
Storage22 GB free (model removes itself if free space drops below 10 GB)
RAM16 GB with 4+ cores (CPU) or >4 GB VRAM (GPU)
NetworkUnmetered connection for initial ~4 GB model download
BrowserChrome 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.

TypeOutputUse it for
key-points (default)Bulleted list of main ideasArticle TL;DRs, meeting notes, RSS readers
tldrProse summary, 1–5 sentencesChat previews, email digests, search snippets
teaserAn intriguing hook, not a spoilerLink previews, “read more” cards, aggregators
headlineSingle-sentence article titleAuto-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:

ValueMeaningWhat to do
readily-availableModel on diskCall create() immediately
downloadableCapable device, not downloadedShow progress UI
unavailableDevice doesn’t qualifyUse 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 teaser mode for better link cards

Avoid it for: cross-browser consumer apps, anything needing deterministic output, mobile-first products.


Current Status & What’s Next

DetailStatus
API StatusStable in Chrome 138+
ModelGemini Nano (on-device, shared across Chrome)
SpecW3C Writing Assistance APIs
DocsChrome 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

  1. Zero cost, zero latency, zero privacy risk — Gemini Nano runs entirely on-device
  2. Four summary typeskey-points, tldr, teaser, headline — pick by UI, not length
  3. Stream by defaultsummarizeStreaming() is the production pattern
  4. Use context aggressively — it’s the biggest quality lever you have
  5. Always ship a fallback — native → cloud → dumb-split
  6. Destroy sessions — memory leaks sink Chrome Web Store ratings
  7. Feature-detect first'Summarizer' in self before 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