How you can build Substack Notes scheduler with n8n
Save time, stay consistent, and let automation handle the posting for you!
A few months ago, I realized I was tired of manually posting Substack Notes every day. I’d wake up each morning and think, “Oh no, did I remember to post a note today?” Some days I’d get busy and forget entirely. It was a small daily task, but it added up to stress. I thought to myself: there has to be a way to schedule these notes so they go out automatically. Imagine writing a week’s worth of short posts in one sitting and letting them publish on their own – huge time savings! That’s when I decided to build a little automation system to handle it for me.
Fast forward to now: I have a workflow that runs like clockwork, posting my Substack Notes for me while I relax. In this post, I’ll share the story of how I set up that scheduling system using n8n (a no-code automation tool) and Google Sheets as my content source. I’ll also break down all the steps so beginners can follow along and build the same setup. Let’s dive in!
Why I needed to automate my notes publishing
I love writing short-form updates on Substack Notes (think of them like tweets, but on Substack). However, I didn’t love the daily routine of logging in and manually posting. Some days I’d remember in the morning, other days I’d be scrambling at midnight. I knew automating this process would free me from having to remember every day and ensure consistency for my readers. Plus, I tend to write notes in batches when I’m feeling inspired – wouldn’t it be nice to have those notes queued up?
The pain point hit one day when I nearly missed a daily note because I was traveling. I thought, “Enough is enough – I should let a robot do this”. I had heard of n8n, an automation tool that could string tasks together visually. In fact, n8n is an open-source workflow tool (imagine a more flexible, self-hostable Zapier1). You can run it for free and connect it to hundreds of apps, or even add custom integrations when needed – perfect for my use case of connecting Substack with other services. I already had some experience with n8n and had even built a custom Substack integration node for it previously.
This meant I had the building blocks ready: I just needed to design the workflow.
My goal. Have an n8n workflow that triggers on a schedule (without me doing anything), grabs a random draft note from a list I maintain, publishes it to Substack, and marks it as used so it won’t post the same thing twice. All while I’m off doing other things. No more “oops I forgot to post today” moments!
💬✨ Ever caught yourself forgetting to post or scrambling at midnight?
Share your story in the comments - I’d love to compare notes!
🛠 The tools
Before jumping into the step-by-step, here’s a quick overview of the tools I used.
n8n2. A no-code automation platform where you create workflows by connecting nodes. (Think: visual scripting for integrating apps). I self-host n8n, but you can use their cloud service too. If you’re new to n8n, it’s super flexible and allows custom code or community-built nodes. We’ll use it to orchestrate the whole process.
Google Sheets3. I decided to store my draft notes in a Google Sheet. Each row in the sheet is a short note I’ve written in advance (in Markdown format). Google Sheets is handy because it’s easy to edit and accessible from anywhere. n8n has a built-in Google Sheets node that supports reading and updating rows, which is exactly what we need.
Substack Notes4. This is the platform where the content ultimately goes. Substack Notes are the short posts on Substack (similar to tweets).
n8n Substack Node. Currently, Substack doesn’t offer an official public API for publishing, so I used a community node for Substack in n8n that I had created earlier. This custom Substack node knows how to call Substack’s hidden API to create new notes programmatically.
Under the hood it uses my Substack session cookie for authentication, since that’s the trick to act on my account without an API key, but more on that later.
With these three pieces – scheduler, content source, and Substack publisher – I was ready to build the automation.
The workflow
Now let’s walk through how to set it all up, step by step.
⏰ Scheduling the workflow
The first piece of the puzzle was getting the workflow to run automatically at regular intervals. n8n makes this easy with a built-in Schedule trigger node.
I added a Schedule node as the start of my workflow and configured it to run every few hours. In my case, I set it to run roughly every 6 hours, so I’d get a few notes posted throughout the day without me intervening.
You could just as easily set it for once a day at a specific time (like every morning at 9 AM) – n8n’s Schedule node supports a variety of schedules.
To configure the schedule, I opened the Schedule node settings in n8n and chose a simple interval.
You can also use Schedule trigger node expressions if you’re comfortable with those.
For example, to run every 6 hours, I selected an interval of 6 hours between executions. If I wanted a daily post, I might set it to “every day at 09:00”. The flexibility here is great: you can have your Substack notes go out exactly when you want – whether it’s multiple times per day or a specific weekly schedule.
Why Schedule trigger node? Because it’s a fire-and-forget trigger. Once I activate the workflow, n8n’s Schedule trigger node will ensure it runs on schedule. No need for me to click anything. This was crucial to meet my goal of “automation that runs without me remembering to run it”. 🚀
Side note: If you’re following along, add the Schedule node to your n8n canvas first and set the schedule as desired. This will be the starting node that kicks off the whole process at those times.
📋 Reading draft notes from Google Sheets
Next, I needed a bunch of content ready to post. I created a Google Sheet called “Substack Notes drafts”.
In this sheet, I have four main columns: one for the Note Id (identifies the draft uniquely), one for the Note content (written in Markdown for formatting), one for the Exhausted (to mark if a note has been posted) and one for the link to a post. Initially, I filled the sheet with a bunch of ideas and drafts for my Substack Notes. These are short paragraphs – things like interesting quotes, quick updates, or questions for my audience. By writing them in Markdown, I can include italics, bold, or links as needed, since Substack node support basic Markdown formatting.
With my draft content ready, I added a Google Sheets node in n8n and connected it after the Schedule trigger. This node uses my Google account credentials to access the sheet.
n8n will prompt you to set up Google Sheets credentials if you haven’t already – it’s a one-time OAuth or service account setup).
Once authenticated, I configured the Google Sheets node to “Read” from my spreadsheet:
I specified the Google Sheets document (or picked the file from a list, since n8n can list your Google Drive files).
I set the sheet name (for example, “Drafts”).
I chose the operation to get all rows.
When this node runs, it will fetch all the rows from my draft sheet. In n8n, the output of this node is a list of items (each item corresponds to one row/note, with fields for each column). So at this point in the workflow, I have an in-memory list of every draft note that’s in the Google Sheet.
However, I don’t want to post all of them at once – I just need one per run. Also, I want to avoid posting any note that’s already been posted before. That means I need to filter out any rows that are marked “exhausted” (i.e., already used). To handle that, I added a small filter in the workflow.
🔍 Filtering out used Notes and picking a random draft
After reading the rows from the sheet, I introduced an Filter node in n8n to help filter out used notes. The Filter node is configured to check the “Exhausted” field of each item. If the status is "true" (or whatever keyword I use to mark a used note), the Filter node will categorize that item is not to be used. I used toString() method to make sure n8n is able to compare value correctly.
If the status is blank or not exhausted, it goes to the true path. By connecting only the true output of this Filter node to the next steps, I ensure that only fresh, not-yet-posted notes continue through the workflow. In plain terms, this prunes out any note I’ve already posted before, so we don’t accidentally repeat content.
Now, assuming there’s at least one fresh note available, I typically have a subset of items ready to choose from (maybe I have 30 draft notes written in the sheet, for example).
I wanted the selection to feel a bit random – I didn’t necessarily want to always post them in the same order as they appear in the sheet. To achieve this, I added an Sort node to do a little trick: randomize the order of the items.
The Sort node in n8n has an operation for sorting items randomly. Just needed operation set to “Random”.
Another step was limiting the number of items.
In fact, you can use the Limit node to limit the output.
I configured it to take the first 1 item.
At this point in the workflow, we’ve done the heavy lifting in terms of logic. We have one item (a note) that is fresh and randomly chosen from our Google Sheet. The next step is the fun part: publishing it to Substack!
🗨️🔧 Want to geek out about workflow tricks, or need a hand fine-tuning your setup?
Join the chat - it’s where we solve puzzles together!
📤 Publishing the Note to Substack
With the content ready, I connected the next node: the Substack node (the custom n8n integration I had built earlier). If you don’t have this node in your n8n yet, you can install it easily as a community module – in n8n’s settings, go to Community Nodes and search for "n8n-nodes-substack" and install it. Once installed, you’ll have a node that can interface with Substack’s (unofficial) API.
Before using the Substack node, there’s a one-time setup for credentials. Since Substack doesn’t provide an API token, the node uses your session cookie to authenticate (basically, it acts on your behalf as if it were your browser). You can read about in the below post.
Now back to the workflow: I added Substack node to interact with Substack Notes.
I configured the Substack node’s parameters as follows.
Resource: “Note” (meaning we are dealing with Substack Notes).
Operation: “Create” (we want to create/post a new note).
Body: here’s where I needed to put the content of the note. I didn’t type anything in manually; instead I used n8n’s expression editor to reference the text from the selected Google Sheet item. Essentially, I set the Body field to the Note content value coming from the previous node.
Content Type: notes’ content is written in Markdown, I wanted to leverage from this fact to post formatted content.
Link URL: link to the post.
When everything is wired up, the Substack node will take that note text and publish it to my Substack account as a new Note. 🎉 Because I wrote the note in Markdown (in the Google Sheet), and Substack Notes support formatting, I didn’t need to modify the text at all – it could include links, bold/italic, etc., and it would appear formatted correctly on Substack. The Substack node handles sending this off to Substack’s servers. Under the hood, it’s making the same kind of request your browser would if you posted manually, just automated.
I remember the first time I tested this part: I ran the workflow (with a manual trigger for testing) and watched n8n execute each step. When it hit the Substack node, I held my breath – then checked my Substack profile… Voila! A new note had appeared, exactly as if I had posted it myself. At that moment I may have done a little happy dance 🤸♂️ – it worked!
✅ Marking the posted Note as “exhausted” in the sheet
The last step in the workflow is a bit of housekeeping. Remember, I don’t want to post the same note twice. So after successfully publishing a note, I need to go back to my Google Sheet and mark that note as used (or “exhausted” as I termed it). This way, the next time the workflow runs, that note will be filtered out.
To do this, I added another Google Sheets node at the end of the flow, connected after the Substack node.
This one is configured to Update a row in the spreadsheet:
I set the operation to “Append or Update Row”.
For the Key to identify which row to update, I used a unique value that identifies the note. In my case, since the note already has unique ID, I could use that.
I dynamically set the key value to match the note we just published. The ID is retrieved from the Limit step to match the ID from the Google Sheet item.
NOTE: The ID from the Substack node output is the note ID assigned by the Substack server. It does not match the ID from the Google Sheet item.
Finally, I set the field Status (the “Exhausted” column) to "TRUE" (or you could use “yes”, “posted”, a date timestamp, whatever you prefer to indicate it’s been used).
When this runs, the Google Sheets node will go and update that specific row in the sheet to mark it. n8n’s Google Sheets integration takes care of finding the row and updating the cell. After this, our workflow cycle is complete!
Now, the next time the Schedule trigger fires, the Google Sheets read node will fetch all rows, the IF filter will drop the ones where Status is “exhausted” (including the one we just posted), and a new random note will be chosen from the remaining drafts. Rinse and repeat automatically.
By the way, I also considered: what if the sheet becomes empty or all notes are exhausted? In that case, the workflow would end up with nothing to post. For now, I just keep an eye on my drafts and add new ones as I use them up (n8n could send me an alert when I’m running low, but I haven’t gotten that fancy yet). For a beginner setup, it’s easiest to just ensure you refill your Google Sheet with new notes periodically. You could even automate pulling in ideas from elsewhere, but that’s a story for another time!
📌 Recap: how the automated notes system works
To summarize, here are the key pieces of the Substack Notes scheduling system I built.
Schedule trigger node. I used n8n’s Schedule trigger to run the workflow on a regular schedule (every few hours in my case). This ensures notes get posted consistently without my intervention.
Google Sheets as Content Storage. I keep all my draft note content in a Google Sheet. This makes it easy to add/edit notes. The n8n Google Sheets node reads all the draft notes each time, and later updates the sheet to mark which note was posted.
Filtering and Random Selection. The workflow filters out any notes that have already been posted (using an Filter node on a status column). Then it randomly selects one note from the remaining drafts to post. We achieved randomness by using the Sort node to shuffle and Limit node to pick one item.
Substack Publishing via n8n. Thanks to a custom Substack node (community integration), the workflow can log into my Substack and create a new Note with the chosen content. No manual posting needed – it’s all automated through the Substack API behind the scenes.
Mark as Posted. After a successful post, the workflow updates the Google Sheet, marking that note as used (“exhausted”). This prevents duplicates and keeps the system going smoothly.
In practice, this means I can batch write a bunch of notes in one sitting, load them into the sheet, and then go about my week while n8n handles the posting schedule. It’s incredibly satisfying to see a note go live and realize, “Hey, I didn’t have to do anything just now – my robot assistant did it for me!” 😄
I hope this walkthrough inspires you to try automating your own workflows. If you’re a beginner, don’t worry – tools like n8n are very visual and newbie-friendly. You don’t need to code (I didn’t write a single line of code for this workflow!). Just drag, drop, and configure nodes with your credentials and logic. And remember, once you set it up, your content can be on autopilot. Whether it’s Substack Notes, tweets, or any other daily post, you can adapt this approach to save time and hassle.
📬🚀 Like this walkthrough?
Subscribe now and get more automation guides straight to your inbox - no manual refreshing needed!
Final thought. This little project started with me being forgetful and lazy about daily posts, and it turned into a reliable system that runs in the background. It’s a great feeling to reclaim that mental space. Now I can focus more on writing new content, knowing that n8n and a Google Sheet have my back for the posting part. If you have repetitive tasks in your life (especially around content publishing), give automation a shot – you might wonder how you lived without it!
Happy automating, and thanks for reading my story about building a Substack Notes scheduler. Feel free to ask any questions or share your own automation ideas. Here’s to working smarter and freeing up time for the fun stuff! 🚀
📦⚡ Want to skip the setup and dive right in?
Grab my exported workflow JSON below - just copy-paste it into your own n8n instance and you’re ready to roll!