Skip to content

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.

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;
}
Name Type Description
input required string Text to summarize. Empty / whitespace resolves to { output: null }.
language required string BCP-47 language for input + output hints. Falls back to omitting hints if unsupported.
supportedLanguages readonly string[] Languages the model supports for hints. Hints are sent when language is in this set; omitted otherwise. Defaults to ["en", "es", "ja"].
type "tldr" | "key-points" | "teaser" | "headline" Summary shape. Defaults to "tldr".
length "short" | "medium" | "long" Length preset. Defaults to "medium".
format "plain-text" | "markdown" Output format. Defaults to "plain-text".
preference "auto" | "speed" | "capability" Performance preference hint. Defaults to "auto". See Performance preference.
sharedContext string Native sharedContext string (a hint about who/what the summary is for).
monitor (m) => void Observe first-call model download progress.
cache "session" | "local" | { get, set } Opt-in result cache.
cacheKey string Override the default cache key (defaults to JSON.stringify([pathname, trimmed input, normalizedLanguage, languageHints, type, length, format, preference, sharedContext]); normalizedLanguage is language’s lowercase primary subtag (for example, pt-BR becomes pt), and languageHints is a boolean for whether that language is in supportedLanguages).
cacheTtl number TTL in milliseconds for entries written by the built-in "session" / "local" shortcuts. Defaults to one hour. Ignored by custom { get, set } caches.
cacheRefresh boolean Skip the cache read and replace the cached value after a successful run. The refreshed run reports cached: false.
onUpdate (text: string) => void Streaming update callback. Receives the cumulative buffer, not deltas.
signal AbortSignal Abort signal.
interface SummarizeResult {
output: string | null;
cached: boolean;
}
  1. Trim and cache check. Whitespace-only input short-circuits to null. If a cache is configured and has the key, return immediately.
  2. Cache Summarizer.create() sessions by JSON-stringified options. First call pays the ~1-3s cold start; later same-config calls reuse the warm session.
  3. Stream summarizeStreaming() when the instance supports it, falling back to one-shot summarize(). Cleaned chunks are pushed to onUpdate as they arrive (cumulative buffer, not deltas).
  4. Optionally cache the final summary when you pass a cache. Off by default; opt in for revisits in the same tab to render instantly.

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 sessionStorage
summarize({ language: "en", input: text, cache: "session" });
// Persistent caching across tabs
summarize({ 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.

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.

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.

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;
}

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.

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.

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.