ChatGPTSalesRevenue growthAI score · 66/100AI-assisted edit · no obvious prompt-injection riskn8n.io

n8n AI Meeting Summary: Extract Decisions & Action Items to Notion, Slack, and Gmail

Webhook meeting transcript → GPT-4 structured analysis → multi-channel sync of summaries, tasks, and reminders

Some experienceStepsWorkflowPrompt
Who
Product teams, remote companies, and operations teams needing automated meeting follow-up
You get
Within 8-12 seconds after a meeting ends, generate structured summaries, decision lists, and prioritized action items with owners, then sync to Slack, Notion, Gmail, Google Calendar, and Sheets
You need
n8n · webhook · code · openai · slack · gmail · google-sheets

Constraints

Prerequisites: n8n instance (self-hosted or cloud), OpenAI API key, Slack workspace with bot token (chat:write), Notion integration token plus two databases (Meeting Notes + Action Items), Google Workspace OAuth2 credentials for Gmail/Calendar/Sheets. Estimated setup: 25-35 minutes. Cost: ~$0.0024 per meeting on GPT-3.5 (author estimate).

What they did

Template author Daniel Shashko built an n8n workflow that receives meeting transcripts via webhook, uses GPT-4 to extract structured information, calculates priority and completeness scores through code nodes, and distributes results to Slack, Notion, Gmail, Google Calendar, and Google Sheets.

How it went

The author reports the full pipeline executes in 8-12 seconds from submission to distribution, generating action items with unique IDs and priority scores, plus a 0-100 completeness score. (Source: author report; unverified)

Worth knowing

Multiple critical fields in the template are placeholders: Slack channel ID, Notion pageId, Google Sheet ID (GOOGLE_SHEET_ID), and email domain (@company.com) must all be manually replaced. Notion requires pre-creating two databases with configured fields. Author estimates GPT-3.5 cost at ~$0.0024 per meeting, but actual cost depends on token usage and model choice. Setup time estimated at 25-35 minutes. This site has not run or verified the workflow.

n8n workflow template

Structure checked · Not run-tested

Use “Import from File” in n8n, or copy the JSON and paste it into the editor. Connect your own accounts, then try test data. The template is inactive by default.

Setup and test checklist

Credentials to connect

  • After import, connect your own credentials on auth-required nodes; author secrets are not included.

Configuration to replace

  • Source template is n8n public workflow #10286 (~25 nodes). Keep inactive after import; verify triggers, expressions and external API endpoints.
  • Sticky-note guidance is informational; replace placeholders with your own accounts, sheet schemas or channel IDs.

Test input and expected output

  • Manually run the main path once in a test workspace and confirm credentialed nodes authenticate without errors.
  • Drive one synthetic/redacted sample through and check output fields and downstream writes before enabling in production.

Template changes

  • Author credential bindings, webhookId and execution data are removed; the workflow is inactive. Nodes, connections and original prompts are preserved. Not run-tested in n8n.
  • No business-logic edits; verify keys, quotas and privacy compliance before use.

Template retrieved: 2026-10-24

Steps

  1. Configure webhook trigger and input source

    Add a Webhook node in n8n, set method to POST, path to meeting-transcript. Use the generated URL as the webhook endpoint for Zoom, Google Meet, Otter.ai, etc., or create a manual submission form. Supports JSON, form data, and other input formats.

  2. Configure OpenAI analysis node

    Add an OpenAI node, select Chat resource, and configure API credentials. Choose GPT-4 or GPT-3.5-turbo, temperature 0.3, max tokens 1500. The node includes a system prompt defining the output JSON structure, and a user prompt template injecting meeting metadata and transcript text.

    Execution prompt · Source text。OpenAI node system message field

    You are an executive assistant AI specializing in meeting analysis. Extract and structure information from meeting transcripts. Return ONLY valid JSON with these exact keys:
    
    {
      "executive_summary": "2-3 sentence overview",
      "key_decisions": ["decision 1", "decision 2"],
      "action_items": [
        {"task": "description", "owner": "name", "due_date": "YYYY-MM-DD or 'not specified'", "priority": "High/Medium/Low"},
      ],
      "discussion_topics": ["topic 1", "topic 2"],
      "open_questions": ["question 1"],
      "next_steps": ["step 1", "step 2"],
      "risks_identified": ["risk 1"],
      "follow_up_meeting_needed": true/false,
      "sentiment": "Positive/Neutral/Negative",
      "engagement_level": "High/Medium/Low"
    }

    Execution prompt · Source text。OpenAI node user message field (n8n expression, variables resolved at runtime)

    Meeting: {{ $json.title }}
    Date: {{ $json.date }}
    Attendees: {{ $json.attendees.join(', ') }}
    Duration: {{ $json.duration }} minutes
    
    Transcript:
    {{ $json.transcript }}
  3. Configure intelligence synthesis and scoring code node

    Add a Code node (Synthesize Intelligence) running JavaScript to calculate action item priority scores (0-40 range) and meeting completeness score (0-100). The code parses OpenAI's JSON response, generates unique IDs for each action item, sorts them, and flags unassigned tasks. Thresholds can be customized as needed.

    Execution prompt · Source text。Synthesize Intelligence Code node jsCode field

    const meetingData = $('Parse Meeting Input').first().json;
    const aiResponse = JSON.parse($input.first().json.choices[0].message.content);
    
    // Calculate priority scores
    function calculatePriorityScore(actionItem) {
      const priorityScores = { 'High': 3, 'Medium': 2, 'Low': 1 };
      const hasOwner = actionItem.owner && actionItem.owner !== 'not specified' ? 1 : 0;
      const hasDueDate = actionItem.due_date && actionItem.due_date !== 'not specified' ? 1 : 0;
      return (priorityScores[actionItem.priority] || 2) * 10 + hasOwner * 5 + hasDueDate * 5;
    }
    
    // Enrich action items
    const enrichedActionItems = aiResponse.action_items.map((item, index) => ({
      id: `${Date.now()}-${index}`,
      task: item.task,
      owner: item.owner || 'Unassigned',
      due_date: item.due_date !== 'not specified' ? item.due_date : '',
      priority: item.priority,
      priority_score: calculatePriorityScore(item),
      status: 'Not Started',
      meeting_title: meetingData.title,
      meeting_date: meetingData.date,
      created_at: new Date().toISOString()
    }));
    
    // Sort by priority score
    enrichedActionItems.sort((a, b) => b.priority_score - a.priority_score);
    
    return {
      json: {
        // Meeting metadata
        meeting_id: `meeting-${Date.now()}`,
        meeting_title: meetingData.title,
        meeting_date: meetingData.date,
        attendees: meetingData.attendees,
        attendee_count: meetingData.attendee_count,
        duration: meetingData.duration,
        organizer: meetingData.organizer,
        meeting_url: meetingData.meeting_url,
        recording_url: meetingData.recording_url,
        
        // AI Analysis
        executive_summary: aiResponse.executive_summary,
        key_decisions: aiResponse.key_decisions,
        action_items: enrichedActionItems,
        action_item_count: enrichedActionItems.length,
        high_priority_count: enrichedActionItems.filter(a => a.priority === 'High').length,
        discussion_topics: aiResponse.discussion_topics,
        open_questions: aiResponse.open_questions,
        next_steps: aiResponse.next_steps,
        risks_identified: aiResponse.risks_identified,
        follow_up_meeting_needed: aiResponse.follow_up_meeting_needed,
        sentiment: aiResponse.sentiment,
        engagement_level: aiResponse.engagement_level,
        
        // Calculated flags
        requires_urgent_attention: enrichedActionItems.some(a => a.priority === 'High'),
        has_unassigned_tasks: enrichedActionItems.some(a => a.owner === 'Unassigned'),
        completeness_score: calculateCompletenessScore(enrichedActionItems, aiResponse)
      }
    };
    
    function calculateCompletenessScore(actionItems, analysis) {
      let score = 50; // Base score
      
      // Penalties
      if (actionItems.length === 0) score -= 20;
      if (actionItems.filter(a => a.owner === 'Unassigned').length > 0) score -= 10;
      if (actionItems.filter(a => !a.due_date).length > 0) score -= 10;
      if (analysis.open_questions.length > 3) score -= 10;
      
      // Bonuses
      if (analysis.key_decisions.length > 0) score += 15;
      if (analysis.next_steps.length > 0) score += 10;
      if (actionItems.every(a => a.owner !== 'Unassigned')) score += 15;
      if (actionItems.every(a => a.due_date)) score += 10;
      
      return Math.max(0, Math.min(100, score));
    }
  4. Configure Slack summary post

    Add a Slack node, select OAuth2 authentication, create a Slack app with chat:write scope. Replace the channel ID placeholder with your actual channel (e.g., #meeting-summaries). The message template uses mrkdwn format with meeting summary, decisions, action items, and completeness score.

    Execution prompt · Source text。Slack node text field (mrkdwn message template)

    📋 *Meeting Summary: {{ $json.meeting_title }}*
    
    🗓️ *Date:* {{ $json.meeting_date.split('T')[0] }} | *Duration:* {{ $json.duration }}min
    👥 *Attendees:* {{ $json.attendee_count }} people
    📊 *Completeness:* {{ $json.completeness_score }}%
    
    *Executive Summary:*
    {{ $json.executive_summary }}
    
    *✅ Key Decisions ({{ $json.key_decisions.length }}):*
    {{ $json.key_decisions.map((d, i) => `${i+1}. ${d}`).join('\n') }}
    
    *🎯 Action Items ({{ $json.action_item_count }}):*
    {{ $json.action_items.slice(0, 5).map(a => `• [${a.priority}] ${a.task} - *${a.owner}* ${a.due_date ? '(Due: ' + a.due_date + ')' : ''}`).join('\n') }}
    {{ $json.action_item_count > 5 ? `\n...and ${$json.action_item_count - 5} more` : '' }}
    
    {{ $json.has_unassigned_tasks ? '⚠️ *Warning:* Some tasks are unassigned' : '' }}
    {{ $json.recording_url ? '🎥 <' + $json.recording_url + '|Watch Recording>' : '' }}
  5. Configure Notion database sync

    Create two databases in Notion: Meeting Notes (fields: title, date, attendees, summary, action items, completeness, recording URL) and Action Items (fields: title, assigned to, due date, priority, status, meeting relation). Share both with your integration and add the Notion token. Configure Create Meeting Note and Create Task in Notion nodes with the database page IDs.

  6. Configure email notifications and calendar reminders

    Add a Gmail node, configure OAuth2 or SMTP credentials. The email template is HTML with priority color-coding and meeting context. Add a Google Calendar node, enable Calendar API, create reminder events at 9:00 AM on due dates (adjustable), adding the task owner as attendee.

    Execution prompt · Source text。Gmail node message field (HTML email template)

    =<h2>New Action Item from Meeting</h2>
    
    <p><strong>Meeting:</strong> {{ $json.meeting_title }}<br>
    <strong>Date:</strong> {{ $json.meeting_date.split('T')[0] }}</p>
    
    <h3>Your Task:</h3>
    <p>{{ $json.task }}</p>
    
    <p><strong>Priority:</strong> <span style="color: {{ $json.priority === 'High' ? 'red' : $json.priority === 'Medium' ? 'orange' : 'green' }}">{{ $json.priority }}</span><br>
    <strong>Due Date:</strong> {{ $json.due_date || 'Not specified' }}</p>
    
    {{ $json.meeting_url ? '<p><a href="' + $json.meeting_url + '">View Meeting Details</a></p>' : '' }}
    
    <hr>
    <p style="font-size: 12px; color: #666;">This action item was automatically extracted from the meeting transcript using AI.</p>
  7. Configure analytics tracking and test validation

    Create a Google Sheet with columns: Meeting_ID, Title, Date, Attendees, Duration, Action_Items, High_Priority, Decisions, Completeness, Unassigned_Tasks, Follow_Up_Needed. Configure the Google Sheets node to append rows. Test by POSTing a sample transcript, then verify Slack messages, Notion entries, emails, calendar events, and Sheets records.

Prompt you can copy

Setup guidance · Editorial suggestion。Give to setup assistant; confirm inputs and permissions first

This block is the prompt. Ads are never placed here.

You are an n8n workflow setup assistant. The user wants to replicate the "AI Meeting Summary Auto-Distribution" template. First confirm they have: n8n instance, OpenAI API key, Slack bot token (chat:write), Notion integration token, Google Workspace OAuth2 credentials. Then guide them step by step through configuring the webhook, OpenAI node, Slack/Notion/Gmail/Calendar/Sheets nodes, and remind them to replace all placeholders (channel ID, database page IDs, Sheet ID, email domain).

Confirm all API credentials before starting; Notion requires creating two databases and sharing with integration; test with sample JSON trigger first

Source

AI meeting summary & action item tracker with Notion, Slack, and Gmail · tomax · n8n.io · 2025-10-29

Comments & feedback

Tried this method? Share results, problems or improvements. Comments appear after moderation. Please avoid sensitive information.

Loading…

    Related