← Blog

How to Build a Meeting Notes Summarizer With Claude

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

Building a meeting notes summarizer with Claude means sending a raw transcript (or rolling audio-to-text output) to the model with a prompt that extracts decisions, action items, and key discussion points, then returning structured text or JSON your team can actually use. The core work isn't the AI call itself — it's deciding what "good summary" means for your use case, handling long transcripts that exceed context limits, and getting consistent formatting back every time.

This guide walks through the full pipeline: capturing the transcript, designing a prompt that produces reliable structure, chunking long meetings, and wiring it up to a real API so you can ship it as a Slack bot, a dashboard widget, or a CLI tool.

Step 1: Get a Clean Transcript

Claude doesn't record meetings — you need a transcript first, from a tool like Zoom's built-in transcription, Otter.ai, Whisper, or your video conferencing platform's export feature. Quality matters: garbled speaker labels and missing punctuation degrade summary quality more than people expect. If your transcript tool supports speaker diarization (labeling who said what), keep those labels — they let Claude attribute action items to the right person.

A reasonable input looks like:

[00:02] Sarah: Let's start with the Q3 roadmap review.
[00:15] Mike: I think we need to push the API redesign to Q4.
[00:40] Sarah: Agreed. Can you own that decision and update the ticket?
[01:05] Mike: Yes, I'll update it by Friday.

Step 2: Design the Summarization Prompt

The most common mistake is asking Claude to "summarize this meeting" with no structure. You'll get a paragraph of prose that's hard to scan and inconsistent between runs. Instead, specify the exact sections you want and the format.

You are a meeting notes assistant. Given a raw transcript, produce:

1. **Summary** (2-3 sentences, what the meeting was about)
2. **Decisions Made** (bulleted list)
3. **Action Items** (bulleted list, format: "Owner — task — due date if mentioned")
4. **Open Questions** (bulleted list, unresolved items raised but not decided)

Only include information explicitly stated in the transcript. Do not infer
owners or dates that weren't mentioned. If a section has no items, write "None noted."

Transcript:
{transcript}

This structure does two things: it gives the model a checklist instead of an open-ended task, and it constrains hallucination by explicitly telling Claude not to invent owners or deadlines — a real risk with meeting transcripts where people talk over each other or trail off mid-sentence.

If you want machine-readable output instead of markdown (for feeding into a ticketing system), ask for JSON directly and give Claude a schema:

Respond only with valid JSON matching this shape:
{
  "summary": "string",
  "decisions": ["string"],
  "action_items": [{"owner": "string", "task": "string", "due": "string or null"}],
  "open_questions": ["string"]
}

Step 3: Handle Long Meetings With Chunking

A one-hour meeting transcript can easily run 8,000–12,000 words. That's fine for Claude's context window, but a 90-minute all-hands with multiple speakers can push past what you want to send in a single call, especially if you're also including prior context (agenda, previous meeting notes) in the same request.

Two practical approaches:

Single-pass with a large context window. For most meetings under 90 minutes, just send the whole transcript in one request. This is simpler and avoids the "summary of summaries" quality loss that chunking introduces.

Map-reduce for very long sessions. Split the transcript into time-based chunks (e.g., 20-minute segments), summarize each chunk separately with the same structured prompt, then run a second pass that merges the chunk summaries into one final summary. Use this only when you genuinely exceed context limits — it adds latency and an extra API call per chunk.

async function summarizeChunk(chunk) {
  const res = 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",
      max_tokens: 1024,
      messages: [{ role: "user", content: `Summarize this meeting segment:\n\n${chunk}` }]
    })
  });
  return res.json();
}

Step 4: Wire It Into Your Workflow

A summarizer is only useful if it shows up where people already work. Common setups:

For any of these, you need an API key, request logging, and usage visibility — especially once multiple team members are triggering summarization jobs independently. This is where a dedicated API layer like SubToAPI helps: it turns your existing Claude access into a standard HTTPS API with sub_live_ keys per application, so your Slack bot and your email cron job can use separate keys with separate usage tracking, without sharing credentials. Setup takes a few minutes — see the quickstart for the full flow.

If you're planning to stream long summaries back into a UI incrementally (useful for a dashboard where you want to show the summary as it generates rather than waiting for the full response), check the streaming docs. For the request format used in the examples above, see messages.

Step 5: Add Guardrails

A few things that noticeably improve real-world reliability:

Once this is running reliably, extending it to generate follow-up emails, sync action items to a task tracker, or flag overdue items is mostly additional prompting on the same transcript-in, structured-output-out pattern.

Questions

Does Claude record or transcribe meetings directly? No. Claude only processes text you send it. You need a separate transcription tool (Zoom, Otter.ai, Whisper, etc.) to convert audio to text first, then pass that transcript to Claude for summarization.

How do I stop Claude from inventing action items that weren't said? Explicitly instruct it in the prompt to only include information stated in the transcript and to write "None noted" for empty sections rather than guessing. This single instruction dramatically reduces hallucinated owners and deadlines.

What's the best way to get consistent summary formatting across meetings? Give Claude an exact structure or JSON schema in the system prompt rather than a vague "summarize this" instruction, and reuse the same prompt template for every meeting so formatting stays consistent over time.

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 →