AutomationFlowsAI & RAG › Extract Action Items from Google Drive Meeting Notes

Extract Action Items from Google Drive Meeting Notes

Original n8n title: W11 - Meeting Notes & Action Item Extractor

W11 - Meeting Notes & Action Item Extractor. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 9 nodes.

Event trigger★★★★☆ complexity9 nodesGoogle Drive TriggerGoogle DriveN8N Nodes PdfvectorGoogle SheetsSlack
AI & RAG Trigger: Event Nodes: 9 Complexity: ★★★★☆ Added:

This workflow follows the Google Drive → Google Drive Trigger recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "W11 - Meeting Notes & Action Item Extractor",
  "nodes": [
    {
      "parameters": {
        "content": "## \ud83d\udcdd Meeting Notes & Action Item Extractor\n\n### What this workflow does\n1. Watches Google Drive folder for meeting notes\n2. Downloads and reads the document\n3. Extracts attendees, decisions, and action items\n4. Logs summary to Google Sheets\n5. Posts formatted summary to Slack with task assignments\n\n### Setup steps\n1. Connect Google Drive account (OAuth2)\n2. Get PDF Vector API key from pdfvector.com/api-keys\n3. Create Google Sheet with columns: Meeting Title, Date, Duration, Attendees, Attendee Count, Decisions Made, Action Items, High Priority, Follow-up Date, Notes Link, Processed\n4. Update folder ID and spreadsheet ID in the nodes\n5. Connect Slack and select your team channel\n\n### Perfect for\n- Project managers tracking action items\n- Team leads distributing meeting summaries\n- Executive assistants organizing follow-ups",
        "height": 480,
        "width": 340,
        "color": 5
      },
      "id": "sticky-main",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        60,
        60
      ]
    },
    {
      "parameters": {
        "content": "## \u2705 Extracted Fields\n\n- Meeting title & date\n- Attendees (names, roles, emails)\n- Key discussion points\n- Decisions made + rationale\n- Action items + owners + due dates\n- Priority levels (High/Medium/Low)\n- Follow-up meeting details\n- Parking lot items",
        "height": 240,
        "width": 240
      },
      "id": "sticky-fields",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        420,
        60
      ]
    },
    {
      "parameters": {
        "content": "## \ud83d\udcca Google Sheets Columns\n\nMeeting Title | Date | Duration | Attendees | Attendee Count | Decisions Made | Action Items | High Priority | Follow-up Date | Notes Link | Processed",
        "height": 100,
        "width": 520
      },
      "id": "sticky-sheets",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        60,
        560
      ]
    },
    {
      "parameters": {
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "value": "YOUR_FOLDER_ID",
          "mode": "list"
        },
        "event": "fileCreated",
        "options": {}
      },
      "id": "gdrive-trigger",
      "name": "Google Drive Trigger",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "typeVersion": 1,
      "position": [
        180,
        340
      ],
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": "={{ $json.id }}",
        "options": {}
      },
      "id": "gdrive-download",
      "name": "Download Notes",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        380,
        340
      ],
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "extract",
        "inputType": "file",
        "prompt": "Extract meeting notes data as flat fields. meetingTitle, meetingDate (YYYY-MM-DD), meetingDuration, attendeesList (comma-separated names as single string), agendaList (semicolon-separated agenda items), discussionSummary (semicolon-separated key points formatted as topic: summary), decisionsList (semicolon-separated decisions made), actionItemsList (semicolon-separated action items formatted as: task | owner | dueDate | priority), followUpDate (YYYY-MM-DD), followUpPurpose, parkingLotList (semicolon-separated parked items).",
        "schema": "{\"type\": \"object\", \"properties\": {\"meetingTitle\": {\"type\": \"string\"}, \"meetingDate\": {\"type\": \"string\"}, \"meetingDuration\": {\"type\": \"string\"}, \"attendeesList\": {\"type\": \"string\"}, \"agendaList\": {\"type\": \"string\"}, \"discussionSummary\": {\"type\": \"string\"}, \"decisionsList\": {\"type\": \"string\"}, \"actionItemsList\": {\"type\": \"string\"}, \"followUpDate\": {\"type\": \"string\"}, \"followUpPurpose\": {\"type\": \"string\"}, \"parkingLotList\": {\"type\": \"string\"}}, \"additionalProperties\": false}"
      },
      "id": "pdfvector-extract",
      "name": "PDF Vector - Extract Meeting Info",
      "type": "n8n-nodes-pdfvector.pdfVector",
      "typeVersion": 2,
      "position": [
        580,
        340
      ],
      "credentials": {
        "pdfVectorApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const data = ($input.first().json?.data || $input.first().json) || {};\nconst fileName = $('Google Drive Trigger')?.item?.json?.name || 'Unknown';\nconst fileId   = $('Google Drive Trigger')?.item?.json?.id   || '';\n\nconst attendeeList  = data.attendeesList || 'Not specified';\nconst attendeeCount = attendeeList !== 'Not specified'\n  ? attendeeList.split(',').filter(a => a.trim()).length : 0;\n\nconst decisions = (data.decisionsList || '').split(';').map(d => d.trim()).filter(Boolean);\nconst decisionList  = decisions.map(d => `\u2713 ${d}`).join('\\n') || 'None recorded';\nconst decisionCount = decisions.length;\n\nconst actions = (data.actionItemsList || '').split(';').map(a => a.trim()).filter(Boolean);\nconst actionList = actions.map(a => {\n  const parts = a.split('|').map(p => p.trim());\n  return `\u25ab ${parts[0] || a} \u2192 ${parts[1] || 'TBD'} (Due: ${parts[2] || 'TBD'}) [${parts[3] || 'Medium'}]`;\n}).join('\\n') || 'None assigned';\nconst actionCount = actions.length;\nconst highPriorityCount = actions.filter(a => a.toLowerCase().includes('high')).length;\n\nreturn [{ json: {\n  meetingTitle:      data.meetingTitle      || 'Unknown Meeting',\n  meetingDate:       data.meetingDate       || 'N/A',\n  meetingDuration:   data.meetingDuration   || 'N/A',\n  attendeeList,\n  attendeeCount,\n  discussionSummary: data.discussionSummary || 'N/A',\n  decisionList,\n  decisionCount,\n  actionList,\n  actionCount,\n  highPriorityCount,\n  followUpDate:    data.followUpDate    || 'N/A',\n  followUpPurpose: data.followUpPurpose || 'N/A',\n  parkingLotList:  data.parkingLotList  || 'None',\n  fileName,\n  fileId,\n  processedAt: new Date().toISOString()\n}}];"
      },
      "id": "format-meeting",
      "name": "Format Meeting Data",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        780,
        340
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "list"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Meeting Title": "={{ $json.meetingTitle }}",
            "Date": "={{ $json.meetingDate || 'N/A' }}",
            "Duration": "={{ $json.meetingDuration || 'N/A' }}",
            "Attendees": "={{ $json.attendeeList }}",
            "Attendee Count": "={{ $json.attendeeCount }}",
            "Decisions Made": "={{ $json.decisionCount }}",
            "Action Items": "={{ $json.actionCount }}",
            "High Priority": "={{ $json.highPriorityCount }}",
            "Follow-up Date": "={{ $json.followUpDate }}",
            "Notes Link": "=https://drive.google.com/file/d/{{ $json.fileId }}/view",
            "Processed": "={{ $json.processedAt.split('T')[0] }}"
          }
        },
        "options": {}
      },
      "id": "sheets-log",
      "name": "Log Meeting Summary",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.4,
      "position": [
        980,
        340
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "YOUR_SLACK_CHANNEL_ID",
          "mode": "list"
        },
        "text": "=\ud83d\udccb *Meeting Summary: {{ $('Format Meeting Data').item.json.meetingTitle }}*\n\n\ud83d\udcc5 *Date:* {{ $('Format Meeting Data').item.json.meetingDate }}\n\u23f1 *Duration:* {{ $('Format Meeting Data').item.json.meetingDuration }}\n\ud83d\udc65 *Attendees:* {{ $('Format Meeting Data').item.json.attendeeList }}\n\n---\n\n\u2705 *Decisions Made ({{ $('Format Meeting Data').item.json.decisionCount }}):*\n{{ $('Format Meeting Data').item.json.decisionList }}\n\n---\n\n\ud83d\udccc *Action Items ({{ $('Format Meeting Data').item.json.actionCount }}):*\n{{ $('Format Meeting Data').item.json.actionList }}\n\n---\n\n{{ $('Format Meeting Data').item.json.followUpDate !== 'N/A' ? '\ud83d\udcc6 *Next Meeting:* ' + $('Format Meeting Data').item.json.followUpDate + ' \u2014 ' + $('Format Meeting Data').item.json.followUpPurpose : '' }}\n\n<https://drive.google.com/file/d/{{ $('Format Meeting Data').item.json.fileId }}/view|\ud83d\udcc4 View Full Notes>",
        "otherOptions": {}
      },
      "id": "slack-summary",
      "name": "Post Summary to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        1180,
        340
      ],
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Google Drive Trigger": {
      "main": [
        [
          {
            "node": "Download Notes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Notes": {
      "main": [
        [
          {
            "node": "PDF Vector - Extract Meeting Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PDF Vector - Extract Meeting Info": {
      "main": [
        [
          {
            "node": "Format Meeting Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Meeting Data": {
      "main": [
        [
          {
            "node": "Log Meeting Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Meeting Summary": {
      "main": [
        [
          {
            "node": "Post Summary to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": [
    {
      "name": "PDF Vector"
    },
    {
      "name": "Meetings"
    },
    {
      "name": "Productivity"
    }
  ],
  "meta": {
    "templateCredsSetupCompleted": false
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

W11 - Meeting Notes & Action Item Extractor. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 9 nodes.

Source: https://github.com/khanhduyvt0101/workflows/blob/0153ee2efc0f692c931b9bb4c2a04abf11756822/n8n-workflows/meeting-notes-extractor.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Extract title deed data and score risk factors with AI. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 10 nodes.

Google Drive Trigger, Google Drive, N8N Nodes Pdfvector +2
AI & RAG

Invoice Data Extraction Automation. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 8 nodes.

Google Drive Trigger, Google Drive, N8N Nodes Pdfvector +2
AI & RAG

Lease Agreement Analyzer for Renters. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 12 nodes.

Google Drive Trigger, Google Drive, N8N Nodes Pdfvector +2
AI & RAG

Expense Report Processor with AI Categorization. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 12 nodes.

Google Drive Trigger, Google Drive, N8N Nodes Pdfvector +2
AI & RAG

Financial Report Analyzer (10-K, 10-Q). Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 11 nodes.

Google Drive Trigger, Google Drive, N8N Nodes Pdfvector +2