Despite their technical power, Notion and WebHooks can rapidly become unmanageable. This article outlines the problems and gives a path forward that makes it easier to use Notion’s WebHooks effectively.
For background, a Notion WebHooks lets us wake up external programs (Make.com, Zapier, N8N, Relay, PipeDream, etc) in response to native events in Notion. We can also pass individual properties to WebHooks as parameters, such as the ID of a database record that triggered the event. Other authors [links] have already created content on how they work and how to use them from Notion. I’m not going to rehash those ideas here.
Instead, let’s start by identifying the pitfalls of Notion WebHooks so that the solution makes sense.
What’s Wrong With Notion WebHooks?
- Calls to Notion WebHooks are not logged. We don’t have a record of which outbound calls were made, when, from where, or in response to which events. So, if you call the same WebHook from more than one location, or in response to more than one event, you have to manage all logging on the receiving end of the WebHook.
- Calls are not validated for success or failure. The results or return values from your WebHooks are lost. Technically, you could push the results back into Notion, but capturing and storing results would need to be done for every WebHook call you make.
- Templates with Notion WebHooks are a nightmare to deploy. When we distribute a template with native automation, everything goes with the template. However, everybody will have unique URLs for external automation for their WebHooks. So, if your template fires WebHooks from multiple locations, your customers need to update (or enter) their custom URLs throughout your Notion application. There is not yet a way to update automation parameters using the API, so it has to be done manually.
- Notion WebHooks are difficult to find. Cataloging all the places in Notion where you added automation is already challenging. On top of that, you would have to look at every database and button to inspect what the automations do just to locate where the WebHook calls are being made. It’s somewhat manageable when developing a bespoke solution, but this also adds to deployment challenges (for you) and maintenance challenges (for your customers) if a WebHook is updated to a new URL.
- Notion WebHooks are difficult to document. Unlike YourDomain.com/path, WebHooks are usually a long series of characters without much meaning to humans. It’s challenging to look at one and know what is listening on the other end. You need to develop an approach to documentation for all of your Notion Webhooks, where they are used, and what they do.
- There is no visible connection between your WebHook and where it is implemented. Even if you know where your external programs that listen to WebHooks are located, you cannot look at the URL and know which Scenario or Zap is responsible for implementation. If you fire Notion WebHooks to multiple systems, this problem gets even worse.
- A failed webhook may halt subsequent executions. Most low-code tools will retain WebHook calls to be processed later. However, if your call has a problem, such as a missing or malformed parameter, and your WebHook fails to process, then your automation may pause without notice. If WebHooks are distributed throughout your Notion application, you may have to review them all to ensure they are still active.
- Errors from race conditions. If you have automation that changes a record in one DB and then makes an update in a second DB, where both DBs make WebHook calls, you are not guaranteed that the first WebHook will execute (or finish) before the second. Even if you serialize each WebHook independently, you can’t serialize different WebHooks. So, anything that is sequence-dependent becomes unreliable.
- Duplicate calls can be highly inefficient. Sometimes, every change to a row should trigger an action on the changed row. Other times, in response to a bulk update, for example, it would be better for your WebHook to grab all the work to perform and do it in one pass. While you can implement these rules in the code behind your WebHooks, you’ll still be processing extra calls from Notion.
- You cannot tell when a Notion WebHook is actively processing your data. You cannot see when it fires, when it is processing data, when it finishes, or what the result (logging) is. If you need to re-execute a given Notion WebHook without re-triggering the original conditions, you must find the URL and manually enter it into a browser.
How To Fix the Problems With Notion WebHooks
There are three keys to solving the problems listed above.
- A centralized catalog of your WebHooks, what they do, and how to update them.
- A single point for requesting external execution
- An external Launcher that responds to requests and serves as the dispatcher for the WebHooks in your catalog.
1. A Central Catalog of External Automation
To catalog your Notion WebHooks, use a Notion database to hold information about all external automation (mine is PM Scenarios). It stores the scenario’s name (script, app, Zap, etc.), URLs, and a quick way to fire the WebHook for testing. It also lets us turn various automation scripts on or off from a central location. Most importantly, however, this allows us to select the WebHooks we want to fire by selecting their Scenario Name in a dropdown menu from native Notion automation.
G:\My Drive\Blogging\WebHooks-01
2. A Single Launch Point for Requesting External Execution
Whenever we want to fire an external automation, we add a record to an execution queue. This is the only DB that fires WebHooks directly. The Notion WebHook it calls will fire the Launcher script that provides the brains for the whole system.
One of the benefits of this approach is that we have a clean interface for making automation requests anywhere within our Notion application.
3. A Launcher Script to Respond to All Automation Requests.
The Launcher scenario handles the following:
- Serialization of all WebHook requests.
- Tracking the progress (Requested, Processing, Done) of requests
- Saving the results of WebHook calls back into Notion
- Eliminating duplicate requests from bulk updates.
What Does The Launcher Do?
The launcher is the Brain of the Operation.
We’re about to get deep into the weeds here. I’m using Make.com for my implementation, but you can do the same thing in other low-code tools. Below, I’ll cover steps in the process so that you can replicate it, or you can get the databases and scenarios as a package here.
- We start with a WebHook listener. This gives you the URL you need to fire from your Execution Queue.
- We read the Execution Queue database, which was sorted in date order, with the oldest requests first. We’re looking for any records in the “request” state.
- We only move forward with the first (oldest) requests.
- We check if the requested scenario is still turned off since we have control of all scenarios at once in Notion.
- If the scenario is off, we will update the request’s status, and we’re done.
- We confirm the scenario is turned on.
- Before doing the actual work, we update the status to indicate that we are processing it.
- If we run into an error updating the status, work continues, but we ignore the error.
- We’re only going to work on the first request we have. Subsequent requests would have their own webhook.
- Here, we are firing the WebHook of the individual scenario that was requested.
- If we get an error that the WebHook was not listening…
- We will update the request’s status by reporting that it was not running.
- Default path after our WebHook completes.
- We update that our request is completed.
- Did we have multiple requests pending?
- Fire the launcher again. This is a safety measure to ensure we don’t miss anything.
- Should we remove duplicate requests?
- Find all identical requests that follow the one we just processed
- Any found?
- Delete them
- Was there no work to do in step 2?
- Update that there was nothing to do