Extract Action Items from Zoom Transcripts Using GPT

Getting a Zoom transcript into usable text

If you’ve used Zoom’s built-in transcription feature, you’ve probably seen that it generates these weird VTT files — basically text files with timecodes interwoven between every line. They’re readable by media players, sure, but for our purposes (like feeding to GPT), it’s a mess.

So the first part of this whole thing starts by actually cleaning that transcript.

I grab the VTT file from Zoom — usually emailed to me or downloadable from my meeting recordings. When I open it in VS Code or even just Notepad, it looks something like this:

“`
00:00:01.000 –> 00:00:02.000
Hey everyone, thanks for joining today.

00:00:03.000 –> 00:00:05.000
We’re going to go over the Q3 rollout.
“`

That’s not bad for humans, but GPT will just repeat the time stamps back to you if you feed it raw. So I either:
1. Do a quick find-and-replace with regex to strip timestamps (if in VS Code), or
2. Copy-paste the whole thing into a short Python script I wrote ages ago that just extracts only the spoken lines.

Just for sanity, I paste that cleaned output into GPT-4 and just ask: “Can you check if there’s any leftover timestamps?” because sometimes it’ll catch weird formatting leftovers I missed. ¯\_(ツ)_/¯

Prompting GPT for bullet action items

Now that I have that cleaned text, the next problem is figuring out the best way to yank out action items without GPT just summarizing the whole call. Most people ask something like “Can you provide action items from this meeting?” and unfortunately, GPT tends to respond with a generic list like,

– Follow up on project deadlines
– Schedule next team meeting

Super helpful 🙄

So instead I go with something like:

“Here is the transcript of a meeting. Please extract ONLY action items that include a clear task, assignee (if any), and any deadlines mentioned. Use bullet points. Do not rewrite or summarize. Just list each task verbatim if possible.”

That tends to steer it away from inventing stuff that wasn’t said. But even then… sometimes it hallucinated deadlines or incorrectly assigned tasks to the wrong person just based on names mentioned. So my more reliable version has become this prompt:

“Act as a meeting assistant. From the following transcript, copy out ONLY sentences that sound like action items. Do not interpret. Do not summarize. Just paste the whole sentence if it contains a task, request, or commitment.”

That gets me way closer to something I can build on. Then on a second pass, if I want structured outputs, I run:

“Turn these into structured action items in the format: Task / Assignee / Deadline (if any).”

Yes, it’s two steps instead of one, but it avoids GPT making up nonsense.

When Zapier OpenAI step randomly double runs

A thing I discovered the hard way: if you’re piping your cleaned transcript into a Zap that runs an OpenAI step (say, to auto-generate action items), sometimes the AI action runs twice and eats double your tokens. Not kidding. I looked at my OpenAI billing and thought I got hacked.

It turned out my Zap had this:
– Trigger: New File in Google Drive
– Delay: 1 minute
– Action: Extract text
– Action: Feed to OpenAI prompt

That worked most days. But if I uploaded two files close together, the trigger would sometimes queue both and accidentally retrigger the OpenAI step on the same file. I never added any repeating logic — it just misfired.

So the fix was super hacky but it worked 🙂 I added a Filter step that checked whether a hidden sheet (in Google Sheets) already had a row about this file. Basically a DIY deduplicator. I thought about using the Zapier Storage module for this too (like a little key-value log), but writing to Sheets makes it easier to debug.

Zapier should really have better retry controls… but here we are.

Why GPT sometimes misses super obvious tasks

I kept seeing GPT ignore really clear statements like:

“Can you send the proposal to Jane by Thursday?”

And I’d prompt it with regular variations of “extract tasks” and it would just… skip this. Over and over. Until I finally realized what it was doing — it only treated phrases with explicit responsibility wording like “I will” or “[Name] will” as action items.

Asking helped. I literally fed it a single line and said, “Is this an action item?” — and it said no, because the task was phrased as a question/request.

It doesn’t “understand” tone the way humans do.

So I updated my prompt to:

“Include both direct and indirect action items — including requests, suggestions, or questions that imply a task.”

Total game changer. It started pulling helpful stuff like:
– Can you loop in legal on that?
– Maybe worth getting a quote from Mike.
– Should we build a quick prototype?

These are all soft asks — but in real meetings, this is how most stuff gets assigned. Not with verbs, but offhand comments.

Putting the results into a Google Doc by Zap

After I get cleaned-up action items back from GPT, I usually want them auto-organized somewhere. Sending them as emails was fine for a while, but I kept getting lost when threads piled up. So I built a Zap that does:

– Trigger: File added to a transcript folder
– Action: Clean text (custom Python code)
– Action: Ask GPT to extract action items
– Action: Create a new Google Doc with the same filename, and paste results in

I format it like this:

“`
Meeting: Q3 Launch Review
Date: [today’s date]

Action Items:
– [output from GPT]
“`

What’s weird — and inconsistent — is that Zapier occasionally fails to create line breaks in the Google Doc if the GPT output has bullets. I had to add a Formatter step that replaces `\n` with actual breaks, or sometimes even double breaks to force it to render properly.

When in doubt: paste into Docs yourself and check how it behaves. The Zap preview isn’t always accurate.

Trimming irrelevant intro chatter automatically

The first few minutes of any Zoom call are usually trash. “Heyyy, how’s it going?” “Wait, I think you’re on mute.” — you get the vibe. GPT doesn’t know to skip this unless you cut it first.

So I started doing rough pre-cutting using basic keyword logic before feeding to GPT.

In the transcript cleaner script, I added: if a line contains:
– “thanks for joining”
– “can everyone hear me”
– “let’s give it a minute”

…then delete up to five lines before and after it. Not perfect. Super crude. But it dropped my irrelevant tokens by maybe a third. I pay less per month now for OpenAI with no quality drop 🙂

You can also add logic like, only include lines after the first mention of “agenda,” “project,” or a specific client name. Your calls probably have repeated patterns. Mine always do.

Building an internal database of all action items

Eventually I got sick of hunting different Docs for tasks and wanted all action items searchable in one dashboard.

So I pointed my Zapier flow to Google Sheets instead.

Each row holds:
– Meeting name
– Date
– Action item
– Assignee
– Deadline
– Source transcript (hyperlink to original file)

This sheet gets updated every time anyone drops a call recording into our shared folder. GPT pulls out assignments, and they just show up in this doc magically.

The only weird hiccup was sheet length. Google Sheets start to get laggy after a few thousands of rows — especially if you add formulas. So every month, I start a fresh tab.

There’s probably a more elegant way to later query this (maybe using Notion or even a lightweight SQL setup), but hey — the Sheet works. And my team actually checks it now.

Adding a Slack alert when new actions are found

Last thing — I added a Slack step to notify me when action items were generated. Sounds simple, but timing was tricky. If the GPT step failed (or was empty), I didn’t want a message screaming “Success!” with no result.

So I made it conditional. Filter step: Only continue if the GPT output includes a dash `- ` (which every bullet had). That way, the Slack alert only fires when real items were found. Message looks like:

“New action items from the Q4 Budget Call were added. Check the doc here: [link]”

Weirdly, Slack sometimes didn’t unfurl the document properly unless I added an extra space after the URL. Still don’t fully get that, but spacing it like:

“Check the doc here: [link]
Let me know if questions.”

…fixed the issue. Spacing bugs — gotta love ’em 😛

Leave a Comment