Summarizer API
This package wraps the built-in Summarizer API. It adds session reuse, streaming, output cleanup, and optional result caching. For React, see useSummarizer.
Before shipping, review the Production checklist for task-relevant text extraction, safe rendering, progress, user control, and cache freshness.
Use prepareSummarizer to warm a session on user intent and release it when the feature closes. See the Session lifecycle guide.
import { summarize } from "@web-ai-sdk/summarizer";
const result = await summarize({ input: longArticleText, language: "en", type: "key-points", length: "short", onUpdate: (text) => console.log("partial", text),});
console.log(result.output, result.cached);result.output is the cleaned summary text, or null when the input is empty. result.cached tells you whether the response came from the cache without invoking the model.
Options
Section titled “Options”interface SummarizeOptions { input: string; language: string; supportedLanguages?: readonly string[]; type?: "tldr" | "key-points" | "teaser" | "headline"; length?: "short" | "medium" | "long"; format?: "plain-text" | "markdown"; preference?: "auto" | "speed" | "capability"; sharedContext?: string; monitor?: (m: CreateMonitor) => void; cache?: "session" | "local" | { get, set }; cacheKey?: string; cacheTtl?: number; // built-in shortcut TTL in ms; default 1 hour cacheRefresh?: boolean; // skip the cache read, write the fresh result onUpdate?: (text: string) => void; signal?: AbortSignal;}Returns
Section titled “Returns”interface SummarizeResult { output: string | null; cached: boolean;}How it works
Section titled “How it works”- Trim and cache check. Whitespace-only input short-circuits to
null. If acacheis configured and has the key, return immediately. - Cache
Summarizer.create()sessions by JSON-stringified options. First call pays the ~1-3s cold start; later same-config calls reuse the warm session. - Stream
summarizeStreaming()when the instance supports it, falling back to one-shotsummarize(). Cleaned chunks are pushed toonUpdateas they arrive (cumulative buffer, not deltas). - Optionally cache the final summary when you pass a
cache. Off by default; opt in for revisits in the same tab to render instantly.
Two caches, two purposes
Section titled “Two caches, two purposes”Session cache (internal, in-memory, always on): a bounded LRU of Summarizer instances so the second call with the same { language, type, length, sharedContext, … } reuses the warm session. Cold-start is ~1-3s; warm sessions are sub-second. Cleared on full page reload.
Result cache (opt-in): off by default; every call hits the model. Pass cache: "session" for sessionStorage, cache: "local" for localStorage, or any { get, set }-shaped object to memoize the final summary string by cacheKey.
Built-in "session" / "local" entries expire after one hour by default. Pass cacheTtl (milliseconds) to change the TTL per call. Pass cacheRefresh: true to skip the read and replace the cached value after a successful run. Custom { get, set } caches own their expiry policy.
import { summarize } from "@web-ai-sdk/summarizer";
// Off by default; every call hits the model.summarize({ language: "en", input: text });
// Per-tab caching via sessionStoragesummarize({ language: "en", input: text, cache: "session" });
// Persistent caching across tabssummarize({ language: "en", input: text, cache: "local" });result.cached tells you which path served the response, so you can render a “From cache” hint or skip a re-fetch.
Streaming
Section titled “Streaming”When the underlying Summarizer instance exposes summarizeStreaming(), the library uses it and pushes cleaned chunks to onUpdate as they arrive (cumulative buffer, not deltas). Otherwise it falls back to one-shot summarize(). Either way, result.output is the final cleaned text.
Performance preference
Section titled “Performance preference”preference is a hint about the speed/quality tradeoff the browser should make when it picks the underlying model. It maps straight to the native Summarizer.create() option:
"auto"(default) — the browser balances execution speed with summarization capability, and may adjust based on the environment, system constraints, or context."speed"— prioritizes low latency and fast execution. This can route to a smaller, faster model, which may produce less nuanced or simpler summaries."capability"— prioritizes comprehensiveness and coherence, capturing subtler context at the cost of higher latency.
// Fast path for short, low-stakes summaries (e.g. list previews).summarize({ language: "en", input: text, preference: "speed", length: "short" });
// Quality path for a single, carefully written summary.summarize({ language: "en", input: text, preference: "capability" });The default is "auto" to match the platform default; "speed" and "capability" are explicit opt-ins.
Model tiering for "speed" and "capability" is experimental: enable the Summarizer API performance preference flag, restart your browser, and reload — otherwise the browser may accept the hint without switching models.
"speed" is narrower than "auto"
Section titled “"speed" is narrower than "auto"”The faster model behind "speed" does not serve every configuration. Some combinations of language, type, length, and format are not available on the speed path, and there is no promise that the browser silently upgrades you to a more capable model when they aren’t — the configuration can instead be reported as unavailable. When that happens, summarize() throws SummarizerUnavailableError, the same way it does for any unavailable configuration.
This wrapper forwards preference into the availability() probe, so the probe and the session create() agree: if availability() reports the "speed" configuration as unavailable, summarize() fails fast instead of creating a session that can’t serve the request. Because of this, treat "speed" as an opt-in you guard — be ready to fall back to "auto" on unavailability (or pre-check with checkAvailability({ preference: "speed", … })):
import { summarize, SummarizerUnavailableError } from "@web-ai-sdk/summarizer";
const opts = { language: "en", input: text, type: "tldr", length: "short" } as const;
try { await summarize({ ...opts, preference: "speed" });} catch (err) { if (err instanceof SummarizerUnavailableError) { await summarize({ ...opts, preference: "auto" }); } else throw err;}Output normalization
Section titled “Output normalization”The wrapper strips wrapping quotes / whitespace and collapses internal whitespace on every result regardless of type. Anything beyond that — e.g. trimming the trailing period from a type: "headline" result so it reads as a label rather than a sentence — is your concern. A one-line regex after the call covers the headline case.
Language support beyond en/es/ja
Section titled “Language support beyond en/es/ja”By default, the wrapper emits expectedInputLanguages / outputLanguage hints only for ["en", "es", "ja"]. Pass another language as language: "pt" and the library omits those hints; steer the output via sharedContext instead:
summarize({ language: "pt", input: text, sharedContext: "Resuma o artigo em português em 2-3 frases curtas.",});When your target browser documents more accepted languages, pass them explicitly via supportedLanguages: ["en", "es", "ja", "pt"] and the hints fire through.
Errors and unavailability
Section titled “Errors and unavailability”The vanilla summarize() throws SummarizerUnavailableError when the API is missing. Callers branch explicitly:
import { summarize, SummarizerUnavailableError } from "@web-ai-sdk/summarizer";
try { const result = await summarize({ language: "en", input: text });} catch (err) { if (err instanceof SummarizerUnavailableError) { return; } throw err;}AbortSignal is supported. Aborting mid-stream resolves cleanly; an opt-in result cache is not written for aborted runs.