Turn a single Telegram message into a fully automated reminder system: saved, scheduled, and delivered without touching a server.
You’re in the middle of something and a task pops into your head. You don’t want to open a dedicated app, create an account, or navigate a dashboard; you just want to type it somewhere and know it won’t slip through the cracks. This workflow gives you exactly that: send Remind 14:30 Call the client to your Telegram bot, and it handles everything else. At exactly 14:30, your phone buzzes with the reminder.
In this guide, you’ll build a two-workflow n8n automation that uses Telegram as the input interface and Google Sheets as the brain. No coding, no monthly subscription, no app install. Just a bot that listens, stores, and delivers.
Prefer to skip the setup? Grab the ready-made template β and be up and running in under 10 minutes.
What You’ll Build
- You send a message to your Telegram bot:
Remind 14:30 Call the client - The bot validates the format, saves the reminder to a Google Sheet, and sends you a confirmation instantly.
- Every minute, a background workflow checks the sheet for due reminders.
- At exactly 14:30, your Telegram receives: π REMINDER: Task: Call the client
- The reminder is automatically marked as Done so it never fires twice.
How It Works: The Big Picture
The system is built from two separate n8n workflows that share a Google Sheet as their bridge. Workflow 1 handles input; Workflow 2 handles delivery.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WORKFLOW 1 - Reminder Creator β
β β
β [Telegram Trigger] -> [Parse Command] -> [Route / Switch] β
β β β β
β (valid)β (errorβ β
β β β β
β [Save to Sheet] [Send β
β β Info/Err] β
β β β
β [Send Confirmation] β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Shared Google Sheet ("Rappels" tab)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WORKFLOW 2 - Checker (runs every 1 minute) β
β β
β [Schedule Trigger] -> [Read Sheet] -> [Filter by Time] β
β β β
β (match)β β
β [Send Telegram Alert] β
β β β
β β β
β [Mark Row as Done] β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
What You’ll Need
- A free n8n account (cloud or self-hosted)
- A Telegram bot token; create one for free via @BotFather in 2 minutes
- A Google account with access to Google Sheets
- A Google Cloud Service Account for authentication (we’ll walk through it)
Estimated build time: 30-45 minutes from scratch, or under 10 minutes with the ready-made template.
Part 1: The Reminder Creator Workflow
This workflow lives at the input end of the system. It listens for Telegram messages, validates the format, stores valid reminders, and immediately confirms receipt.
1 Telegram Trigger
What it does: Listens continuously for any new message sent to your Telegram bot and fires the workflow the moment one arrives.
How to configure it:
- Add a Telegram Trigger node to a new workflow.
- Set Updates to Watch to
message. - Connect your Telegram bot credentials (the API token from BotFather).
- Click Test node, then send any message to your bot and you’ll see the raw data appear.
The raw data that flows out of this node looks like this:
{
"message": {
"message_id": 42,
"chat": {
"id": 123456789
},
"text": "Remind 14:30 Call the client"
}
}
Tip: Save the chat.id value from your test run, as you’ll need it later when configuring the Checker workflow to know where to send notifications.
2 Parse Command (Code Node)
What it does: Reads the message text, checks whether it starts with Remind, and extracts the time and task, or returns a clear error if the format is wrong.
How to configure it:
- Add a Code node after the Telegram Trigger.
- Set the language to JavaScript.
- Paste in the parsing logic (included in the template).
The code checks for the Remind prefix (case-insensitive), then extracts two pieces of information using a regular expression: the time in HH:MM format and everything after it as the task description. It returns one of three output types:
| Output type | When it’s returned |
|---|---|
remind | Valid format; time and task extracted, ready to save |
error | Started with “Remind” but time or task was missing or malformed |
chat | Message didn’t start with “Remind” at all |
For a valid input like Remind 14:30 Call the client, the output looks like this:
{
"type": "remind",
"tache": "Call the client",
"date_heure": "2026-03-14 14:30",
"raw_time": "14:30"
}
For an invalid input like Remind callmom, it returns:
{
"type": "error",
"message": "β Incorrect format\n\nExpected: Remind HH:MM Task\nExample: Remind 14:30 Call the client"
}
Tip: Want to use a different command keyword? Replace 'remind ' in the code with anything you like: 'task ', 'set ', or even your own name. Just make sure to match the character count in the substring() call that strips the prefix.
3 Route (Switch Node)
What it does: Acts as a traffic controller. Valid reminders go down one path; errors and help messages go down another.
How to configure it:
- Add a Switch node after Parse Command.
- Create two output routes:
- Route “reminder”: condition
{{ $json.type }}equalsremind - Route “info”: condition
{{ $json.type }}does not equalremind
- Route “reminder”: condition
This node is the guardian of your data. Nothing reaches the Google Sheet unless the format is clean.
4 Save to Sheet (Google Sheets)
What it does: Appends a new row to the Rappels tab in your Google Sheet, recording the task, scheduled time, and an initial status of “pending”.
How to configure it:
- Add a Google Sheets node on the “reminder” output of the Switch.
- Set the operation to Append row.
- Connect your Google Service Account credentials.
- Select your spreadsheet and the
Rappelssheet tab. - Map the columns as shown below.
| Sheet column | Value to map |
|---|---|
Tache | ={{ $json.tache }} |
Date_Heure | ={{ $json.date_heure }} |
Statut | En attente (hardcoded) |
Type | Reminder (hardcoded) |
5 Send Confirmation (Telegram)
What it does: Immediately sends a success message back to the user confirming that their reminder was saved.
How to configure it:
- Add a Telegram node after Save to Sheet.
- Set Chat ID to
={{ $('Telegram Trigger').item.json.message.chat.id }}; this dynamically targets the person who sent the original message. - Set the message text to something like:
β
REMINDER SAVED
π Task: {{ $json.Tache }}
β° Time: {{ $json.Date_Heure }}
I'll remind you at the scheduled time! π
Tip: Notice we reference $('Telegram Trigger') directly here; after the Google Sheets node, the original message data is no longer in the current item scope. Always pull chat.id from the trigger node by name.
There’s also a Send Info/Error node on the Switch’s second output. It simply sends back the message field from the Parse Command output, which is either a usage hint or a formatted error. No extra configuration needed beyond setting the chat ID the same way.
Part 2: The Checker Workflow
This second workflow runs silently in the background every minute, checking whether any saved reminder is due. When it finds one, it fires the notification and marks the row complete.
1 Schedule Trigger
What it does: Fires the workflow automatically every 60 seconds, regardless of user activity.
How to configure it:
- Create a new workflow and add a Schedule Trigger node.
- Set the interval to Every 1 minute.
Tip: Because the trigger runs every 60 seconds, reminders fire within a 1-minute window of their scheduled time. For most personal use cases this is perfectly fine. If you need exact-second precision you’d need a different approach, but the complexity isn’t worth it for a reminder bot.
2 Get Reminders (Google Sheets)
What it does: Reads all rows from the Rappels tab, every saved reminder whether pending or done.
How to configure it:
- Add a Google Sheets node set to Read rows.
- Connect to the same spreadsheet and
Rappelstab.
n8n automatically splits the sheet rows into individual items; each reminder becomes a separate item flowing through the rest of the workflow.
3 Check Time (Filter Node)
What it does: Keeps only the rows where the scheduled time matches right now. Everything else is silently dropped.
How to configure it:
- Add a Filter node.
- Set the condition:
{{ $json.Date_Heure }}contains={{ $now.format('yyyy-MM-dd H:mm') }}
The contains operator (rather than strict equality) is intentional; it makes the time comparison more resilient to minor formatting differences between the stored string and the current timestamp.
If no reminders match the current minute, the workflow ends here with zero items. This is normal. It runs every minute, so the vast majority of executions will simply do nothing. That’s by design.
4 Send Telegram Alert
What it does: Sends the reminder notification to your Telegram account.
How to configure it:
- Add a Telegram node.
- Set the Chat ID to your personal Telegram user ID (find it by messaging @userinfobot).
- Set the message text:
π REMINDER π
Task: {{ $json.Tache }}
Scheduled for: {{ $json.Date_Heure }}
5 Update Status (Google Sheets)
What it does: Marks the reminder row as Done so it never fires again.
How to configure it:
- Add a Google Sheets node set to Update row.
- Match on
row_number(n8n tracks this automatically when reading rows). - Set
Statut=Done.
This is the closing loop that keeps the system clean. Without this step, the same reminder would fire every minute for the rest of the day.
The Data Structure
Your Google Sheet is the shared brain between both workflows. It has one tab named Rappels with exactly four columns:
| Column | Type | Example | Description |
|---|---|---|---|
Tache |
Text | Call the client | The task description, extracted from the Telegram message |
Date_Heure |
Text | 2026-03-14 14:30 | Scheduled date and time in YYYY-MM-DD HH:MM format; must be exact |
Statut |
Text | En attente | Status flag; starts as En attente (pending), becomes Done after the reminder fires |
Type |
Text | Reminder | The reminder type; useful if you extend the system later with other types |
Here’s what the lifecycle of a row looks like, from creation to completion:
| Tache | Date_Heure | Statut | Type |
|---|---|---|---|
| Call the client | 2026-03-14 14:30 | En attente (just saved) |
Reminder |
| Call the client | 2026-03-14 14:30 | Done (after firing) |
Reminder |
Column names are case-sensitive. Create the sheet with the exact names shown above β Tache, Date_Heure, Statut, Type β before running the workflow for the first time. A mismatch will cause the Google Sheets node to fail silently.
Full System Flow
Here’s the entire journey, from the moment you type a message to the moment the reminder fires:
YOU ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β Send: "Remind 14:30 Call the client"
β
β
[Telegram Trigger]
β
β
[Parse Command] ββββββββββββββββββββββββββββββββββββββββββ
β β
β type: "remind" type: "error" or "chat"
β β
[Route / Switch] β
β [Send Info/Error -> YOU]
β
[Save to Sheet] ββββ Appends row to Google Sheets
β Tache | Date_Heure | Statut | Type
β ββββββββββββββββββββββββββββββββββββββββββββββ
β Task | 2026-03-14 14:30 | En attente | Reminder
β
[Send Confirmation -> YOU]
"β
REMINDER SAVED - I'll remind you at 14:30!"
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
(every minute, Workflow 2 runs in the background)
[Schedule Trigger]
β
β
[Read All Rows from Google Sheets]
β
β
[Filter: Date_Heure = now?] ββ (no match -> stop, wait 1 min)
β (match found)
β
[Send Telegram Alert -> YOU]
"π REMINDER: Task: Call the client"
β
β
[Update Row: Statut = "Done"] ββββ Row never fires again
Testing Your Workflow
Before activating both workflows, run through this test sequence:
- Activate Workflow 1 in n8n.
- Open your Telegram bot and send:
Remind 14:30 Test reminder - You should receive a confirmation message within 2-3 seconds.
- Open your Google Sheet; a new row should appear with
Statut = En attente. - Now create a reminder for 2 minutes from now:
Remind HH:MM Watch for this - Activate Workflow 2.
- Wait. The notification should arrive within 60 seconds of the scheduled time.
- Check the sheet; the row’s
Statutshould now beDone.
If something doesn’t work, here are the most common culprits:
| Problem | Likely Cause | Fix |
|---|---|---|
| No confirmation message after sending | Telegram credentials wrong or bot token expired | Re-enter the bot token from BotFather in your n8n credentials |
| Row not appearing in the sheet | Google Service Account lacks edit permission on the sheet | Share the sheet with the Service Account email address as Editor |
| Reminder never fires | Workflow 2 not activated, or wrong Chat ID in Send Message node | Activate Workflow 2; verify the Chat ID matches your Telegram user ID |
| Reminder fires repeatedly | Update Status node isn’t updating the correct row | Make sure the Update node matches on row_number, not a text field |
| Error: “Format incorrect” for valid input | Extra space or different capitalization in “Remind” | The parser is case-insensitive; check for hidden characters in the message |
Frequently Asked Questions
Can I set a reminder for a future date, not just today?
The current workflow automatically uses today’s date. To schedule for a future date, you’d modify the Parse Command node to accept an optional date before the time, for example Remind 2026-03-20 14:30 Pay invoice. The parsing logic in the Code node would need a small update to detect the date pattern.
What happens if n8n is offline when a reminder is due?
The reminder will be missed for that minute. If Workflow 2 is down and the minute passes, the row stays as En attente but the notification won’t fire, and the time filter won’t match again later. For critical reminders, self-hosting n8n on a reliable VPS or using n8n Cloud (which has uptime guarantees) is worth it.
Can multiple people use the same bot?
Workflow 1 already handles this; it captures each user’s chat.id dynamically and sends confirmation back to whoever sent the message. The challenge is in Workflow 2: the current version sends all notifications to a single hardcoded Chat ID. To support multiple users, you’d store each user’s chat.id in the sheet alongside the reminder and reference it in the Send Message node.
Can I change the “Remind” keyword to something else?
Yes, easily. In the Parse Command node, find the line text.toLowerCase().startsWith('remind ') and replace 'remind ' with your preferred keyword (keep the trailing space and use lowercase). The substring(7) call strips the prefix; if your new keyword has a different length, update that number to match.
Does this cost anything to run?
The n8n free tier covers this workflow comfortably; both workflows are lightweight and use no AI nodes. Telegram bots are completely free. Google Sheets API access via a Service Account is also free within Google’s generous limits. The only potential cost is hosting if you run n8n self-hosted on a VPS.
Can I add recurring reminders?
Not out of the box, but it’s a natural extension. After the reminder fires, instead of setting Statut = Done, you could update Date_Heure to the next occurrence (tomorrow, next week, etc.) and keep the status as En attente. You’d need a small logic layer to calculate the next date based on a recurrence rule stored in an extra column.
π Get the Telegram Reminder Bot Template
You’ve seen exactly how it works. The template gives you both workflows pre-wired, the Google Sheet structure ready to copy, and a step-by-step credential setup guide, so you go from zero to running bot in under 10 minutes.
Buy the template βInstant download Β· Works on n8n Cloud and self-hosted Β· One-time purchase
What’s Next?
Once your reminder bot is up and running, here are some natural directions to take it:
- Multi-user support: store each sender’s
chat.idin the sheet so the bot works for a whole team - Recurring reminders: add a recurrence column and auto-reschedule rows after they fire
- List your reminders: add a
Listcommand that reads pending rows and sends them back to Telegram as a summary - Calendar integration: connect Google Calendar to auto-create reminders from upcoming events without any manual input
- Priority levels: extend the command format to include urgency (
Remind 14:30 urgent Call the client) and style the notification differently