Automate Transcribing Voice Notes in Notion with Zapier

Imagine you can drag and drop voice notes directly from your voice notes app to Notion and get a transcript of your note. Well now you can. We can harness the power of Zapier, Notion, and Steamship to automatically transcribe voice notes.

In this post we’ll cover:

  • A Brief Introduction to Zapier
  • Transcribing Notion MP3s with Steamship
    • Notion Related Functions
    • Changes to Our API
  • Putting it all Together
    • Triggering on a New Notion Database Item
    • Take Action with the Steamship Integration
  • Summary of Using Zapier to Automate Transcribing Notion Voice Notes

A Brief Introduction to Zapier

Zapier is an “if this then that” (IFTTT) low code automation tool. It contains integrations to many tools such as Slack, Notion, Google Docs, etc. Zapier works by sending HTTP web requests like GET, POST, or PATCH requests. You can even create your own Zapier integrations like Steamship did. For this tutorial, we’ll be using the Notion and Steamship Zapier integrations to create our own Zap.

Transcribing Notion MP3s with Steamship

Last month we looked at how to automatically transcribe a Notion mp3 file. This tutorial is an extension of that project. There are some minor code changes to adjust the project from automatically transcribing a specific MP3 file to automating the transcription of any MP3 file in a Notion database using Zapier. You can find the code on GitHub.

Notion Related Functions

The transcribe piece of the puzzle doesn’t change, but the way the api is set up and the notion functions do. Let’s start by taking a look at the file related to Notion functions. There are two new functions here to be aware of: notion_block_to_audio_url and notion_page_to_audio_url. There are also two constants, PageId, and AudioUrl, to be aware of. These constants are for representing the types of return values from our new functions

We start with a function to turn a Notion block into an audio URL. This function takes a notion block, represented as a dictionary. From this block, we extract the audio URL and the page ID as a dictionary. Then we return these two as a tuple. 

PageId = str
AudioUrl = str
def notion_block_to_audio_url(block: dict) -> (PageId, AudioUrl):
   """Get the audio url from the notion block json."""
   audio_url = block["audio"]["file"]["url"]
   page_id = block["parent"]["page_id"]
   return (page_id, audio_url)

Next, we create a function to extract the audio URL from a Notion page. This function requires two parameters – the page URL and the Notion API key. In our prior example, we simply passed the URL to the audio block to extract our audio URL. Zapier does not pass block URLs, only whole Notion page URLs. Notice that this function includes the same function we created in the last tutorial if the URL includes a “#”, which lets the function know we’ve passed a block URL.

The part after the else statement is where we handle the Zapier integration. We have to get the block ID from the URL through two different splits. First we split on the front slash and grab the last element. Second we split again on the dash and grab the last element again. Now that we have the block ID, we need to put it into the UUID format that the Notion API requires. Once we have the block ID in the right format, we use the notion_get function we created before to get the children on the page and pass the results to our notion_block_to_audio_url function to get the page ID and the audio URL.

def notion_page_to_audio_url(url: str, api_key: str) -> (PageId, AudioUrl):
   """Get the audio url from the notion page url."""
   if "#" in url:
       # We assume someone has copied the block.
       block_id = url.split("#")[1]
       block = notion_get(f"blocks/{block_id}", api_key)
       return notion_block_to_audio_url(block)
       # This is what the incoming Zapier page reference will look like.
       # from:
       # to: Creating-Page-Sample-ee18b8779ae54f358b09221d6665ee15
       block_id = url.split("/")[-1]
       # from: Creating-Page-Sample-ee18b8779ae54f358b09221d6665ee15
       # to: ee18b8779ae54f358b09221d6665ee15
       block_id = block_id.split("-")[-1]
       # This is necessary because the URL doesn't have the hyphens in 8-4-4-4-12 format, but the API requires it
       block_uuid = uuid.UUID(block_id)
       notion_page_children = notion_get(f"blocks/{block_uuid}/children", api_key)
       return notion_block_to_audio_url(notion_page_children["results"][0])

Changes to Our API

Now that we’ve made our Notion function changes, we need to make a few changes to our API file. There are two main changes to be aware of here. First, we import a different function from our Notion package. We import notion_page_to_audio_url instead of notion_get. We’ve abstracted out the GET-ing of the audio URL from Notion in the Notion functions we edited above. 

The second change we make to our API file is in the transcribe function of NotionAutoTranscribe class. We moved the extracting of the block into the Notion functions and now use the function notion_page_to_audio_url to get the page ID and audio URL. The rest of the transcribe function does the same thing – we simply call Steamship to transcribe our audio file.

from typing import Type
from steamship.invocable import Config, PackageService, create_handler, post
# NOTE: It should be `notion` not `src.notion` here.
from notion import add_markdown, notion_page_to_audio_url
# NOTE: It should be `transcribe` not `src.transcribe` here.
from transcribe import transcribe_audio
class NotionAutoTranscribe(PackageService):
   """Example steamship Package."""
   config: NotionAutoTranscribeConfig
   def config_cls(self) -> Type[Config]:
       """Return the Configuration class."""
       return NotionAutoTranscribeConfig
   def transcribe(self, url: str = None) -> str:
       """Transcribe the audio in the first Notion block of the page at `url` and append to the page.
       This uses the API Key provided at configuration time to fetch the Notion Page, transcribe the
       attached audio file, and then post the transcription results back to Notion as Markdown Text.
       page_id, audio_url = notion_page_to_audio_url(url, self.config.notion_key)
       print(f"Audio url: {audio_url}")
       print(f"Page ID: {page_id}")
       # Transcribe the file into Markdown
       markdown = transcribe_audio(audio_url, self.client)
       print(f"Markdown: {markdown}")
       # Add it to Notion
       res_json = add_markdown(page_id, markdown, self.config.notion_key)
       print(f"Res JSON: {res_json}")
       return res_json

Putting it All Together in Zapier

Our Steamship package is now ready to use to create a fully automated Notion MP3 transcription tool. Now that we have made all the necessary code changes, all we have to do is create our Zap. Once you’ve signed up for a Zapier account, you should see something like the image below as your homepage. Hit the Create button to create a new Zap.

Triggering on a New Notion Database Item

On the next page, select Notion as your trigger. Zapier only offers one option for integrating with Notion – it triggers on a new database item. Follow the steps as shown in the images below. Select your account. Set up a trigger and select which database you want to trigger on. Finally, test your trigger and ensure that it succeeds

Take Action with the Steamship Integration

The second part of creating a Zap is to create an Action. With our Notion trigger completed, we create an action using the Steamship Integration. Steamship is currently by invite only to get an invite. Choose a Steamship event. Like Notion, there’s only one option here for the moment – running a package method. Then, choose a Steamship account to use.

Now we set up our package method. Steamship packages are much like NPM packages. There are some that are on the site already, but you can also create your own. In the prior tutorial, we created our own package to automatically transcribe MP3 files in Notion. This is the package we edited up above.

For this example, we’ll use that package. It’s called notion-auto-transcribe. Specify your package version, for this tutorial we use version 1.1.8. We also need to specify any configuration variables. In this case, we need a Notion API key, which we also created in the previous tutorial. Specify an instance handle if you have a specific instance in mind. Otherwise, leave it blank to automatically create a new instance. The only method argument we need is the URL of the Notion page. Now, we’re ready to test our action and publish the Zap.


In this tutorial, we extended a previous tutorial on how to automatically transcribe an MP3 file in Notion. That tutorial required us to drop a link to a block in Notion. This time, we’ve included Zapie. We created a Zap that automates transcriptions every time a new MP3 file is added to a database in Notion.

We made a few changes to the previous code. These changes mainly reside in three functions. We added two Notion related functions. One to get the audio URL from a Notion block, which we were doing in the API transcribe function before, and another to get the page ID and audio URL from a Notion URL. These functions are necessary to integrate with Zapier. The third function we changed was under the API functions, and this was simply a refactor that moved the logic from the API transcribe function to the Notion function.

Finally, we looked at how to actually create a Zap that automates our entire workflow. We created a two part Zap. The first part of the Zap is the trigger. In this case, an addition of a new item to the Notion database. The second part of the Zap is the action. We use the Zapier Steamship integration to call a Steamship package method – in this case the transcription. That’s all there is to automatically transcribing an MP3 file in Notion.

I run this site to help you and others like you find cool projects and practice software skills. If this is helpful for you and you enjoy your ad free site, please help fund this site by donating below! If you can’t donate right now, please think of us next time.

Yujian Tang

Leave a Reply

%d bloggers like this: