How to Build a Document Summarizer with Claude
Building a document summarizer with Claude means solving three problems: getting the document text into the model within its context window, writing a prompt that produces consistent, useful summaries, and wiring that logic into an application via an API call. Claude's large context window (up to 200K tokens on most models) makes it well suited for summarizing long reports, contracts, transcripts, and research papers without heavy preprocessing.
This guide walks through the actual implementation: how to chunk long documents, how to structure the summarization prompt, how to call the API, and how to handle streaming and cost control so the feature works well in production, not just in a demo.
Step 1: Decide how the document reaches Claude
For most documents under roughly 100K tokens (around 75,000 words), you can send the full text in a single request. Claude handles long inputs natively — you don't need a vector database or embedding pipeline just to summarize one document.
If your documents are larger, or you're summarizing dozens of files in a batch job, split by structure rather than by fixed character count:
- Split PDFs and reports by section or heading, not arbitrary token windows.
- Split transcripts by speaker turn or timestamp block.
- Keep each chunk self-contained enough that a human could summarize it without reading the rest.
Then either summarize each chunk and combine the summaries (map-reduce), or, if the document fits in context, summarize it in one pass — which produces noticeably better results because Claude sees the full document's structure and can prioritize accordingly.
Step 2: Write a summarization prompt that actually works
A vague prompt like "summarize this" produces vague output. Be explicit about length, format, and what to prioritize:
You will summarize a document for someone who has not read it.
Requirements:
- 150-250 words
- Lead with the main conclusion or decision, not background
- Use plain sentences, no bullet points unless the source is a list
- Preserve specific numbers, dates, and names exactly as written
- If the document contains no clear conclusion, say so explicitly
Document:
{document_text}
For structured output your app can parse — say, a title, a 2-sentence summary, and 3 key points — ask Claude to return JSON and validate it before displaying it:
Return only valid JSON matching this shape:
{
"title": "string",
"summary": "string, 2 sentences max",
"key_points": ["string", "string", "string"]
}
Claude follows structured formatting instructions reliably, but always validate the JSON on your side before trusting it downstream — a malformed response should fail gracefully, not crash your pipeline.
Step 3: Call the API
Here's a working example using SubToAPI, which exposes Claude through a standard HTTPS endpoint with your own sub_live_... API key — useful if you already have Claude access through a subscription and want to call it from a backend without managing separate provider billing.
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 400,
"messages": [
{
"role": "user",
"content": "Summarize this document in 150-250 words, leading with the main conclusion:\n\n<document text here>"
}
]
}'
In JavaScript, the same call in a Node backend or serverless function:
const response = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "claude-sonnet-4-5",
max_tokens: 400,
messages: [
{
role: "user",
content: `Summarize this document in 150-250 words:\n\n${documentText}`
}
]
})
});
const data = await response.json();
const summary = data.content[0].text;
Full request and response shapes are documented at /docs/messages — the response includes the summary text along with usage metadata (input and output token counts), which matters for cost tracking once you're summarizing documents at volume.
Step 4: Stream long summaries to the UI
If you're summarizing long documents and generating longer outputs — say, a one-page summary of a 40-page report — streaming the response makes the feature feel responsive instead of making users stare at a spinner. Set "stream": true in the request and read the response as server-sent events. See /docs/streaming for the exact event format and a full client example.
Step 5: Handle edge cases
A production summarizer needs to handle more than the happy path:
- Documents with no real content (scanned images, empty PDFs) — detect this before calling the API rather than burning tokens on garbage input.
- Documents that exceed the context window — chunk and use map-reduce summarization, then summarize the summaries.
- Inconsistent output length — pin down word or sentence counts explicitly in the prompt; Claude follows numeric constraints well but needs them stated, not implied.
- Sensitive documents — don't log full document text alongside API responses if you're handling contracts, medical records, or PII; log token counts and metadata instead.
Step 6: Control cost as usage scales
Summarization is one of the more cost-predictable Claude use cases because input length is bounded by the document and output length is bounded by your prompt constraints. Still, at scale it's worth tracking:
- Average input tokens per document (varies by document type)
- Output tokens per summary (should stay flat if your prompt fixes the length)
- Cost per summary, so you can price the feature or set usage limits per user
If your team is already paying for Claude access and wants a straightforward way to turn it into an API your application can call — with per-application keys, usage tracking, and team seats — see /pricing or start with the /docs/quickstart guide. A free trial is available at /signup.
Questions
Do I need to chunk every document before summarizing it? No. If the document fits within the model's context window (most reports, articles, and transcripts do), send it in one request. Chunking is only necessary for documents that exceed the context limit or when you're batch-processing many files and want to parallelize.
How do I keep summary length consistent? State an explicit word or sentence count in the prompt rather than saying "brief" or "short." Claude follows numeric constraints reliably; vague length instructions produce inconsistent output.
Can I get structured summary data instead of plain text? Yes — ask Claude to return JSON with a defined schema (title, summary, key points, etc.) and validate it on your side before using it. This works well for populating UI components or storing summaries in a database.