πŸ“ Tutorials
Β· 3 min read

Build an AI Meeting Notes Summarizer


Your meeting lasted 45 minutes. The transcript is 8,000 words. Nobody wants to read it. Everyone needs the action items.

In this tutorial, we’ll build a web app that takes a meeting transcript (pasted or uploaded) and generates structured notes: key decisions, action items with owners, open questions, and a 3-sentence summary.

What we’re building

Upload or paste a transcript β†’ get structured notes:

πŸ“‹ Meeting Summary (March 25, 2026 β€” Sprint Planning)

## TL;DR
Team committed to 34 story points. Payment refactor pushed to next sprint 
due to dependency on the new API. New hire starts Monday β€” Alex is onboarding buddy.

## Decisions
- βœ… Ship the dashboard redesign by Friday
- βœ… Push payment refactor to Sprint 14 (blocked by API team)
- βœ… Alex onboards the new hire starting Monday

## Action Items
- @sarah: Finalize dashboard designs by Wednesday
- @jake: Write API dependency doc and share with payment team
- @alex: Prepare onboarding checklist by Friday
- @team: Review sprint board before Thursday standup

## Open Questions
- When will the new API be ready? (Jake to follow up)
- Do we need a design review for the mobile version?

The code

Backend (Express + Claude)

// server.js
import express from 'express';
import Anthropic from '@anthropic-ai/sdk';

const app = express();
app.use(express.json({ limit: '1mb' }));
app.use(express.static('public'));

const anthropic = new Anthropic();

app.post('/api/summarize', async (req, res) => {
  const { transcript } = req.body;
  if (!transcript) return res.status(400).json({ error: 'No transcript provided' });

  try {
    const response = await anthropic.messages.create({
      model: 'claude-sonnet-4-6',
      max_tokens: 1500,
      messages: [{
        role: 'user',
        content: `Summarize this meeting transcript into structured notes.

Format:
## TL;DR
[3 sentences max β€” what was this meeting about and what was decided]

## Decisions
[Bullet list of decisions made, prefixed with βœ…]

## Action Items  
[Bullet list with @owner and deadline if mentioned]

## Open Questions
[Anything unresolved that needs follow-up]

Rules:
- Be specific β€” use names, dates, and details from the transcript
- If no decisions were made, say "No formal decisions"
- If no action items, say "No action items assigned"
- Skip small talk and off-topic discussion

Transcript:
${transcript.slice(0, 20000)}`
      }],
    });

    res.json({ summary: response.content[0].text });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000, () => console.log('Running on http://localhost:3000'));

Frontend (simple HTML)

<!-- public/index.html -->
<!DOCTYPE html>
<html>
<head>
  <title>Meeting Notes AI</title>
  <style>
    body { font-family: system-ui; max-width: 800px; margin: 2em auto; padding: 0 1em; }
    textarea { width: 100%; height: 200px; padding: 1em; font-size: 14px; border: 2px solid #e5e7eb; border-radius: 8px; }
    button { padding: 0.8em 2em; background: #4f46e5; color: white; border: none; border-radius: 8px; font-size: 16px; cursor: pointer; margin-top: 1em; }
    #result { margin-top: 2em; padding: 1.5em; background: #f9fafb; border-radius: 8px; white-space: pre-wrap; line-height: 1.6; }
    .loading { color: #666; }
  </style>
</head>
<body>
  <h1>πŸ“‹ Meeting Notes AI</h1>
  <p>Paste your meeting transcript below.</p>
  <textarea id="transcript" placeholder="Paste transcript here..."></textarea>
  <button onclick="summarize()">Generate Notes</button>
  <div id="result"></div>
  <script>
    async function summarize() {
      const transcript = document.getElementById('transcript').value;
      const result = document.getElementById('result');
      result.innerHTML = '<p class="loading">⏳ Generating notes...</p>';
      
      const res = await fetch('/api/summarize', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ transcript }),
      });
      const data = await res.json();
      result.textContent = data.summary || data.error;
    }
  </script>
</body>
</html>

Setup and run

mkdir meeting-notes && cd meeting-notes
npm init -y && npm install express @anthropic-ai/sdk
# Create server.js and public/index.html as above
ANTHROPIC_API_KEY=sk-ant-xxx node server.js
# Open http://localhost:3000

Making it better

  • File upload: Accept .txt, .vtt (Zoom transcripts), and .srt files
  • Otter.ai integration: Pull transcripts directly from Otter’s API
  • Slack posting: Send the summary to a Slack channel after generation
  • Multiple formats: Output as markdown, Notion block, or email draft
  • Speaker detection: If the transcript has speaker labels, attribute action items to speakers

Total build time: ~30 minutes. API cost: ~$0.02-0.05 per meeting.

Related: Best Free AI APIs 2026 Β· How to Build an AI Agent Β· 5 AI Prompts for Debugging Β· Build Code Snippet Manager

πŸ“˜