← Blog

Claude API Summarization for Long PDFs: A Guide

2026-10-14 · 5 min read · SubToAPI Team

Summarizing a long PDF with the Claude API comes down to one question: does the document fit inside Claude's context window, or does it need to be split into chunks first? Claude's larger models support context windows up to 200K tokens, which is roughly 500-700 pages of text depending on formatting. If your PDF fits, you can summarize it in a single request. If it doesn't — think multi-hundred-page reports, legal filings, or research corpora — you need a chunking strategy to avoid truncation and quality loss.

The second part of the answer is just as important: a PDF is not text. Before you can send anything to Claude, you need to extract the text layer (or run OCR if it's scanned), clean it up, and decide how to split it if necessary. This guide covers both the extraction step and the two summarization strategies — single-pass and map-reduce — with working code for each.

Step 1: Extract text from the PDF

Claude's API accepts text, not raw PDF binaries, so extraction happens before the API call. For most PDFs with a real text layer, a library is enough:

import fs from "fs";
import pdf from "pdf-parse";

const buffer = fs.readFileSync("report.pdf");
const { text } = await pdf(buffer);
console.log(text.length); // character count, roughly text.length / 4 ≈ tokens

Scanned PDFs need OCR (Tesseract or a cloud OCR service) before this step — Claude can't read pixels. Once you have clean text, estimate the token count. A rough rule of thumb: 1 token ≈ 4 characters of English text. This determines whether you go single-pass or map-reduce.

Single-pass summarization (fits in context)

If the extracted text plus your prompt comfortably fits under the model's context window (leaving room for the output), send it directly. This gives the best summary quality because Claude sees the whole document at once and can track references across sections.

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "Summarize the following report in 5 bullet points, focusing on financial outcomes and risks:\n\n<PDF_TEXT_HERE>"
      }
    ]
  }'

Be explicit about summary length, format (bullets vs prose), and what to prioritize. Vague prompts like "summarize this" produce generic output; a focused instruction ("extract key decisions, deadlines, and owners") produces something usable.

Map-reduce summarization (document too large)

For documents that exceed the context window, or where you want tighter, more reliable summaries regardless of size, use map-reduce:

  1. Split the text into chunks (by page, section heading, or token count — 8K-15K tokens per chunk is a reasonable default).
  2. Map: summarize each chunk independently.
  3. Reduce: feed the chunk summaries back into Claude as a single prompt and ask for a final synthesis.
async function summarizeChunk(chunkText) {
  const res = await fetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: {
      "x-api-key": process.env.ANTHROPIC_API_KEY,
      "anthropic-version": "2023-06-01",
      "content-type": "application/json",
    },
    body: JSON.stringify({
      model: "claude-sonnet-4-5",
      max_tokens: 400,
      messages: [
        {
          role: "user",
          content: `Summarize this section in 3-4 sentences, preserving any numbers or dates:\n\n${chunkText}`,
        },
      ],
    }),
  });
  const data = await res.json();
  return data.content[0].text;
}

async function summarizeDocument(chunks) {
  const partials = await Promise.all(chunks.map(summarizeChunk));
  const combined = partials.join("\n\n");

  const final = await fetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: {
      "x-api-key": process.env.ANTHROPIC_API_KEY,
      "anthropic-version": "2023-06-01",
      "content-type": "application/json",
    },
    body: JSON.stringify({
      model: "claude-sonnet-4-5",
      max_tokens: 800,
      messages: [
        {
          role: "user",
          content: `These are summaries of sequential sections of one document. Combine them into a single coherent summary with an overview followed by key points:\n\n${combined}`,
        },
      ],
    }),
  });
  return (await final.json()).content[0].text;
}

Chunk boundaries matter. Splitting mid-sentence or mid-table loses context, so split on paragraph or section breaks when possible, and overlap chunks by a sentence or two to avoid losing connective information at the seams.

Streaming for long outputs

If your summaries are long (e.g., full executive briefs rather than bullet lists), streaming improves perceived latency since you can render text as it arrives instead of waiting for the full response. Claude's API supports server-sent events for this — see /docs/streaming if you're building this through SubToAPI, which exposes the same streaming interface over a standard HTTPS API.

Using SubToAPI for PDF summarization pipelines

If you're building a product feature around PDF summarization — a dashboard, a Slack bot, an internal tool — you need stable API keys, usage visibility, and a way to let your team call Claude without sharing raw provider credentials. That's what SubToAPI wraps around your existing Claude access: application-scoped keys (sub_live_...), the same messages and streaming endpoints, and per-key usage metadata so you can see which feature or team member is driving token spend on PDF summarization jobs specifically.

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": 1024,
    "messages": [
      { "role": "user", "content": "Summarize this contract, flagging any termination clauses:\n\n<PDF_TEXT_HERE>" }
    ]
  }'

Start with the /docs/quickstart guide, check the /docs/messages reference for request/response shapes, and see /pricing for Solo, Team, and Scale plans — all with a free trial at /signup.

questions

Can Claude summarize a PDF directly, without extracting text first? No. The Messages API takes text input, so you need to extract the text layer (or run OCR on scanned pages) before sending it. There's no native PDF upload for summarization workflows.

How long can a PDF be before I need chunking? It depends on the model's context window (up to 200K tokens) and your prompt overhead. As a rough guide, documents under roughly 400-500 pages of plain text usually fit in a single request; anything larger needs map-reduce chunking.

Does map-reduce summarization lose important details? It can if chunks are split poorly or summarized too aggressively in the map step. Mitigate this by keeping chunk summaries fairly detailed (a few sentences, not one line) and giving the final reduce step explicit instructions about what to preserve, like numbers, dates, and named entities.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →