How to Build an AI Social Media Manager Bot with n8n

How to Build an AI Social Media Manager Bot with n8n (Powered by Telegram)

Keeping your social media channels active is a full-time job — and most founders, creators, and small teams simply don’t have the bandwidth to do it consistently. What if you could send a voice note, a document, or a quick text to a Telegram bot and have it draft, get your approval, and publish a polished post to X and LinkedIn automatically?

That’s exactly what this n8n workflow builds: your own AI-powered social media manager, running 24/7 inside Telegram, connected to Google Gemini for smart content generation, and wired directly to your X (Twitter) and LinkedIn profiles.

Prefer to skip the setup? Grab the ready-made template → and be up and running in under 10 minutes.

What You’ll Build

  1. Send a text, voice note, or document to your Telegram bot — the AI understands all three formats
  2. The agent drafts a platform-appropriate post, respecting X’s 280-character limit and LinkedIn’s professional tone
  3. You review the draft in Telegram and approve it — nothing gets published without your explicit say-so
  4. With your approval, the bot publishes instantly to X (Twitter) and/or LinkedIn
  5. The bot remembers your brand voice, company details, and preferences over time — you stop repeating yourself in every session

How It Works — The Big Picture

The workflow uses a Telegram bot as the command center. Every incoming message is classified by type — text, document, voice, or button tap — and routed through the right processing pipeline before reaching a Google Gemini-powered AI Agent. The agent drafts posts, manages both short- and long-term memory, and uses LinkedIn and X tools to publish only after you approve.

┌──────────────────────────────────────────────────────────────────────┐
│  AI SMM MANAGER                                                      │
│                                                                      │
│  [Telegram Trigger] → [Set Context] → [Input Type Switch]            │
│                                              │                       │
│         ┌────────────────────────────────────┼────────────────┐      │
│         ↓                ↓                   ↓                ↓      │
│     [Text]          [Document]            [Voice]        [Callback]  │
│         │           ↓ Download           ↓ Download           │      │
│         │           ↓ Encode             ↓ Encode        [If cm?]   │
│         │           ↓ Gemini OCR         ↓ Transcribe   ↓       ↓   │
│         │           ↓ Doc Prompt         ↓ Audio Prompt [Clear] [✗]  │
│         └───────────┴────────────────────┘                          │
│                               ↓                                      │
│                         [AI Agent] ←── [Gemini LLM]                 │
│                    ↑   ↑   ↑   ↑      [Short-term Memory]           │
│                    │   │   │   └── [Retrieve Knowledge (vector)]     │
│                    │   │   └──── [Save Knowledge (sub-workflow)]     │
│                    │   └──────── [Create X (Twitter) Post]           │
│                    └──────────── [Create LinkedIn Post]              │
│                               ↓                                      │
│                    [Split Response] → [Split Out]                    │
│                               ↓                                      │
│                    [Send Response via Telegram]                      │
└──────────────────────────────────────────────────────────────────────┘
  

What You’ll Need

  • n8n (cloud or self-hosted, version 1.0+)
  • Telegram Bot API key — create one for free via @BotFather in Telegram
  • Google AI Studio API key — free at aistudio.google.com (powers Gemini 2.0 Flash)
  • X (Twitter) Developer API — free developer account at developer.x.com
  • LinkedIn OAuth credentials — create an app at the LinkedIn Developer Portal
  • A companion n8n sub-workflow — “Save Vector Store Record” (included in the template pack) for long-term memory storage

Estimated build time: 45–60 minutes from scratch, or under 10 minutes with the template.


Part 1 — Bot Entrance and Input Preprocessing

1 Telegram Trigger (telegramTrigger)

This is the entry point. The Telegram Trigger node opens a webhook that listens for all incoming events from your bot — text messages, documents, voice notes, and inline button taps.

Configuration:

  1. Open the node and click “Credential for Telegram API”
  2. Paste your BotFather token and save
  3. Under “Updates”, enable: message, callback_query, inline_query, and *
{
  "message": {
    "chat": { "id": 198472651, "type": "private", "first_name": "Sarah" },
    "text": "Write a LinkedIn post about our product launch next Tuesday",
    "message_id": 142
  },
  "update_id": 553043001
}
💡

Tip: Add a “Restrict to chat IDs” filter so only your account can trigger the bot. Find your personal chat ID by messaging @userinfobot on Telegram.

2 Set Input Context (set)

This node normalizes the raw Telegram payload into clean, consistently named fields — regardless of whether the input is a text message, a file, or a voice note.

FieldWhat it capturesExample
chat_idSender’s chat ID (from message or callback)198472651
message_textText content of the message"Write a post about our launch"
update_typeDetected type: text, document, voice, callback"text"
file_idDocument file ID (if document sent)"BQACAgIA..."
file_mime_typeMIME type of document"application/pdf"
file_captionCaption text sent with the document"Our company overview"
voice_file_idVoice note file ID"AwACAgIA..."

3 Input Type Switch (switch)

Routes execution to the correct processing branch based on update_type:

  • text → straight to AI Agent via Text Prompt
  • document → Download → Encode → Gemini OCR → Document Prompt → AI Agent
  • voice → Download → Encode → Gemini Transcribe → Audio Prompt → AI Agent
  • callback → If node (checks whether it’s a memory-clear command)

Part 2 — Document and Audio Processing

4 Document Branch (Download → Encode → Describe)

When a user sends a PDF, presentation, or any file, three nodes work in sequence. Download document fetches the raw binary from Telegram using the file_id. Encode document converts the binary to base64. Describe document sends it to Gemini 2.0 Flash via HTTP POST:

{
  "contents": [{
    "parts": [
      { "text": "Extract all the information about the company or product from this document" },
      {
        "inline_data": {
          "mime_type": "application/pdf",
          "data": "JVBERi0xLjQgJeL..."
        }
      }
    ]
  }]
}

Gemini returns a structured extraction of all company and product details, which gets injected into the AI Agent prompt alongside the document’s caption.

💡

Tip: This works with PDFs, HTML files, Word docs, and most common formats. The mime_type is pulled automatically from Telegram’s download metadata.

5 Voice Branch (Download → Encode → Transcribe)

Voice messages follow the same pattern — Download Audio → Encode Audio → call Gemini with “Generate a transcript of the speech.” The transcript becomes the chatInput field, so the agent processes it exactly like a typed message.

📌

Note: Telegram encodes all voice messages as OGG files. The workflow hardcodes "mime_type": "audio/ogg" in the Gemini request — do not change this value.


Part 3 — The AI Agent

6 AI Agent (agent)

The brain of the entire operation. The agent receives the normalized user input and decides autonomously what to do next: ask clarifying questions if context is missing, draft a post tailored to the target platform, send it to you for review, publish after your explicit approval, or save brand information to long-term memory.

The system message enforces a strict rule: nothing gets published without the user’s explicit “approved” signal. This is the safety net that keeps the bot from acting without consent.

ToolPurpose
Retrieve knowledgeFetches relevant brand context from the vector store
Save knowledgeCalls the sub-workflow to save new information to vector memory
Create X (Twitter) postPosts to X; enforces the 280-character limit
Create post in LinkedIn as a personPosts from your personal LinkedIn profile
Create post in LinkedIn as a companyPosts from a company/organization page

7 Google Gemini Chat Model + Memory

The agent is powered by Google Gemini via the lmChatGoogleGemini node. Two memory systems work in parallel:

Short-term memory (Buffer Window Memory): Keyed to the chat_id, this stores recent conversation history so the agent maintains context within a single Telegram session.

Long-term memory (In-Memory Vector Store + Gemini Embeddings): Powered by the embedding-001 model, this lets the agent remember brand voice, company info, and preferences across completely separate sessions.

💡

Tip: The in-memory vector store resets when n8n restarts. For production use, replace it with a persistent store like Pinecone, Supabase pgvector, or Qdrant.

8 Memory Clear Callback

When a user taps an inline Telegram button with callback data "cm", the workflow routes to the If node, clears all buffer window memory via Chat Memory Manager, and sends a “Memory is cleaned” confirmation back to Telegram. Handy for switching between clients or starting fresh on a new campaign.


Part 4 — Response Delivery

9 Split + Send (code + telegram)

Telegram enforces a 4,096-character limit per message. The Split agent’s response node uses JavaScript to break the AI output into 3,000-character chunks, and Split Out iterates over each chunk. Every chunk is sent as a separate Telegram message so nothing is ever truncated.

function splitString(str, size) {
  let result = [];
  for (let i = 0; i < str.length; i += size) {
    result.push(str.slice(i, i + size));
  }
  return result;
}

for (const item of $input.all()) {
  const parts = splitString(item.json.output, 3000);
  item.json.parts = parts;
}

return $input.all();

Full System Flow

User sends message (text / voice / document) to Telegram bot
                          │
                          ▼
              [Telegram Trigger] → [Set Input Context]
                                            │
               ┌────────────────────────────┼───────────────────┐
               ▼                            ▼                   ▼
         [text route]               [document route]     [voice route]
               │                    ↓ Download            ↓ Download
               │                    ↓ Encode (base64)     ↓ Encode (base64)
               │                    ↓ Gemini OCR           ↓ Gemini Transcribe
               │                    ↓ Document Prompt      ↓ Audio Prompt
               └────────────────────┴──────────────────────┘
                                            │
                                            ▼
                                      [AI Agent]
                            ┌─────────────────────────┐
                            ↓                         ↓
                    [X & LinkedIn Tools]    [Memory: Save + Retrieve]
                            └─────────────────────────┘
                                            │
                                            ▼
                              [Split Response (3,000 chars)]
                                            │
                                            ▼
                              [Send each chunk via Telegram]
                                            │
                                            ▼
                                      User gets reply ✓
  

Testing Your Workflow

  1. Import the JSON and attach all credentials (see the Credentials Guide PDF)
  2. Activate the workflow — n8n registers the Telegram webhook automatically
  3. Open Telegram, find your bot, and send: "Write a LinkedIn post about how AI is changing small business marketing"
  4. Confirm the bot replies with a draft and asks for your approval
  5. Reply "approved" — check your LinkedIn profile for the published post
  6. Test a voice note: record 10 seconds describing a product feature and send it to the bot
  7. Test document processing: send a PDF of your company overview and ask the bot to write a post about it
ProblemLikely CauseFix
Bot doesn't respond at allWorkflow not activeToggle the Active switch in n8n
"Forbidden" error posting to XTweet exceeds 280 charactersThe agent handles this — rephrase your brief to be shorter
Document not processedUnsupported mime typeStick to PDF, HTML, or DOCX formats
Memory lost after restartIn-memory vector store clearedSwitch to Pinecone or Qdrant for persistent memory
LinkedIn post failsOAuth token expiredRe-authorize LinkedIn credentials in n8n settings
No response from botGemini API quota exceededCheck your AI Studio usage dashboard and upgrade if needed

Frequently Asked Questions

Can I add more platforms like Instagram or Facebook?

Yes — n8n has native nodes for Facebook Pages and Instagram Business. Add them as additional tool nodes attached to the AI Agent, following the same pattern as the X and LinkedIn tools already in this workflow.

Does the bot ever post without my approval?

Never. The system message explicitly instructs the agent to always get explicit user approval before posting anything. The draft is always sent to Telegram first, and you can review, edit, or reject it before anything goes live.

Can I use this for multiple clients or brands?

The workflow is keyed by chat_id, so each Telegram conversation has separate memory. For multiple brands, create separate Telegram bots and run separate workflow instances — or extend the memory key to include a brand identifier prefix.

What happens if Gemini is unavailable?

The AI Agent node will throw an error and n8n will log it. For production use, add a retry setting (3 attempts, 5-second delay) on the AI Agent node and an error handler that sends you a fallback Telegram message so you know something went wrong.

Is my document content safe when processed through Gemini?

Your document data is sent to Google's API for processing. Review Google AI Studio's data usage policy at aistudio.google.com if confidentiality is a concern. For sensitive documents, consider replacing the Gemini HTTP calls with a self-hosted model via Ollama.

How do I teach the bot my brand voice?

Just tell it in plain language: "My company is Acme Corp, we sell B2B SaaS to HR teams, and our tone is professional but approachable." The Save Knowledge tool stores this automatically and the bot recalls it in all future sessions without you needing to repeat it.

🚀 Get the AI SMM Manager Template

Everything you need to deploy your own Telegram-powered social media bot: ready-to-import workflow JSON, Setup Guide PDF, and full Credentials Guide PDF — go from download to live bot in under 10 minutes.

Get the Template →

Instant download · Works on n8n Cloud and self-hosted

What's Next?

  • Add Instagram support via the Instagram Graph API as a new tool on the AI Agent node
  • Schedule posts by connecting a Google Sheets queue and a Schedule Trigger to batch-publish at optimal times
  • Add AI image generation using DALL-E or Flux to auto-create visuals for each post before publishing
  • Multi-language support — instruct the agent to detect the user's language and draft posts in the same language automatically
  • Analytics tracking — connect a Google Sheets node to log every post with timestamps so you can track what's performing
n8n Telegram Google Gemini LinkedIn Twitter / X AI Agent Social Media automation

Facebook Ads Spy Agent

How to Build a Facebook Ads Spy Agent with n8n (AI-Powered Competitor Analysis)

Running Facebook ads without knowing what your competitors are doing is like showing up to a poker game blindfolded. The Facebook Ads Library is completely public — but manually trawling through it for every competitor, every week, is nobody’s idea of a good time. This n8n workflow fixes that: you enter a competitor’s Facebook Page URL, and an AI agent automatically scrapes their active ads, analyzes each one with Google Gemini, rewrites the copy for your own inspiration, and logs everything to a Google Sheet — hands-free.

Prefer to skip the setup? Grab the ready-made template → and be up and running in under 10 minutes.

What You’ll Build

  1. You open a simple web form and paste a competitor’s Facebook Page URL, choose how many ads to pull, pick a country, and select a date range.
  2. The workflow scrapes that page’s active ads from the Facebook Ads Library using Apify’s actor — no API key from Meta required.
  3. Each ad is classified automatically as a Video, Image, or Text ad, and routed into its own analysis branch.
  4. Google Gemini AI analyzes video and image ads visually — extracting hooks, CTAs, emotional triggers, and conversion insights.
  5. An OpenRouter AI agent writes a full marketing summary and a rewritten version of the ad copy for each ad, then saves everything to your Google Sheet.

How It Works — The Big Picture

This workflow is a single pipeline that fans out into three parallel branches based on ad type, then converges in a shared Google Sheet.

┌────────────────────────────────────────────────────────────────────────────┐
│  FACEBOOK ADS SPY — n8n AI AGENT                                           │
│                                                                             │
│  [Form Trigger]                                                             │
│       │  URL, count, country, period                                        │
│       ▼                                                                     │
│  [Apify Scraper]  ← Facebook Ads Library Scraper actor                     │
│       │  Array of active ads                                                │
│       ▼                                                                     │
│  [Filter: 1,000+ page likes]                                                │
│       │  Quality-filtered ads                                               │
│       ▼                                                                     │
│  [Switch: Ad Type]                                                          │
│       │                                                                     │
│       ├──── Video Ad ────► [Loop] → [Download Video] → [Gemini Analyze]    │
│       │                        → [AI Agent: Summarize + Rewrite]           │
│       │                        → [Google Sheets Append] → [Loop back]      │
│       │                                                                     │
│       ├──── Image Ad ────► [Loop] → [Download Image] → [Gemini Analyze]    │
│       │                        → [AI Agent: Summarize + Rewrite]           │
│       │                        → [Google Sheets Append] → [Loop back]      │
│       │                                                                     │
│       └──── Text Ad ─────► [Loop] → [AI Agent: Summarize + Rewrite]        │
│                                → [Google Sheets Append] → [Loop back]      │
│                                                                             │
│                   ↓↓↓ ALL BRANCHES WRITE TO ↓↓↓                             │
│               [Google Sheet: Facebook Ad Spy]                               │
└────────────────────────────────────────────────────────────────────────────┘
  

What You’ll Need

  • n8n — cloud or self-hosted (v1.0+)
  • Apify account — free tier works; you’ll use the Facebook Ads Library Scraper actor
  • Google account — for Google Sheets (OAuth2)
  • Google Gemini API key — free tier available at Google AI Studio
  • OpenRouter account — pay-per-use; costs pennies per workflow run
  • A Google Sheet set up with the right column headers (schema below)

Estimated build time: 45–60 minutes from scratch, or under 10 minutes with the template.


Part 1 — Scraping Phase

1 On form submission (Form Trigger)

This is the entry point — a hosted web form n8n generates for you automatically. No coding required. Users fill it in and hit Submit.

How to configure it:

  1. Add an n8n Form Trigger node.
  2. Set the Form Title to Facebook Ad Spy.
  3. Add four fields: Ad URL (Text), Ad Count (Number), country (Text), and Ad Period (Dropdown with options: last24h, last7d, last14d, last30d).

What the data looks like after this node:

{
  "Ad URL": "https://www.facebook.com/nike/",
  "Ad Count": 20,
  "country": "US",
  "Ad Period": "last30d"
}
💡

Tip: The Form Trigger gives you a public URL you can bookmark and share with your team. No one else needs to touch n8n — they just open the form in a browser.

2 Run an Actor and get dataset (Apify)

This node calls Apify’s Facebook Ads Library Scraper and returns all active ads for the target page.

How to configure it:

  1. Add an Apify node. Set operation to Run actor and get dataset.
  2. Select actor ID XtaWFhbtfxyzqrFmd (Facebook Ads Library Scraper).
  3. In Custom Body, reference the form fields using n8n expressions to pass count, countryCode, period, and the target url dynamically.
  4. Set Memory to 512 MB and attach your Apify credential.

What each ad object looks like:

{
  "ad_archive_id": "1027384950617283",
  "start_date_formatted": "2026-02-14",
  "advertiser": {
    "ad_library_page_info": {
      "page_info": { "page_name": "Nike", "likes": 34200000 }
    }
  },
  "snapshot": {
    "page_profile_uri": "https://www.facebook.com/nike/",
    "videos": [{ "video_hd_url": "https://cdn.fbcdn.net/.../video.mp4" }],
    "cards": [],
    "body": { "message": "Just Do It. New Spring Collection." }
  }
}
💡

Tip: Apify’s free tier includes $5 in monthly credits — enough to run this workflow dozens of times. A typical 20-ad run costs roughly $0.05–$0.15.

3 Filter (1,000+ Page Likes)

This Filter node drops ads from tiny pages. If a page has fewer than 1,000 likes, the advertiser likely isn’t spending enough to produce tested creative worth analyzing. Configure the condition to check advertiser.ad_library_page_info.page_info.likes is greater than 1000. You can raise this to 10,000 or 100,000 to focus on larger brands.


Part 2 — Routing by Ad Type

4 Switch (Ad Type Router)

This Switch node forks the workflow into three branches based on the type of media in each ad.

  1. Output 0 — Video Ad: checks if snapshot.videos[0].video_hd_url exists.
  2. Output 1 — Image Ad: checks if snapshot.cards[0].original_image_url exists.
  3. Fallback — Text Ad: catches everything else (copy-only ads).
💡

Tip: Order matters — video is checked first. If an ad contains both video and images (carousel), it routes to the Video branch.


Part 3 — Video Ad Branch

5 Loop Over Items (Video)

A SplitInBatches node processes one video ad at a time, preventing Gemini from being overwhelmed with concurrent requests. Connect its output back from the Sheets append node to complete the loop.

6 Download Video (HTTP Request)

Downloads the raw .mp4 file from snapshot.videos[0].video_hd_url as binary data so Gemini can analyze it visually. Set response format to File / Binary.

7 Analyze Video (Google Gemini)

Gemini watches the ad video and extracts 10 marketing data points. Set the resource to Video, model to models/gemini-2.5-flash, and input type to Binary. Use this analysis prompt:

You are a direct response marketing expert.

Analyze this Facebook ad video and extract:
1. Hook (first 3 seconds message)
2. Main problem presented
3. Main solution offered
4. Target audience (who is this ad for)
5. Emotional triggers used
6. Offer details (discount, bonus, urgency)
7. Call to action
8. Video structure breakdown (scene by scene summary)
9. Why this ad might be converting
10. Suggestions to improve this ad

Be concise and structured. Focus only on marketing insights.

8 AI Agent + OpenRouter (Video)

The AI Agent takes the Gemini analysis and the raw ad JSON to produce a structured marketing summary and a rewritten version of the ad copy. Configure the agent prompt to include both the JSON scrape and the Gemini video description. Connect a Structured Output Parser with this schema:

{ "summary": "", "rewrittenAdCopy": "" }

Connect an OpenRouter Chat Model as the language model sub-node. Sample output:

{
  "summary": "Nike targets value-conscious runners with a durability-first message. Hook leads with pain point (shoes falling apart), transitions to stress-test product demo, closes with 30-day return guarantee. High conversion probability due to specific claim + risk reversal combo.",
  "rewrittenAdCopy": "Your running shoes should outlast your excuses. Our React Infinity handles 500 miles of punishment — guaranteed. Try them free for 30 days or your money back."
}

9 Append Row in Sheet (Video)

Saves the full result to your Google Sheet. Map these columns:

Sheet ColumnValue / Expression
ad_archive_idLoop Over Items → ad_archive_id
page_nameadvertiser.ad_library_page_info.page_info.page_name
page_profile_urisnapshot.page_profile_uri
ad typeHardcoded: Video
ad Datestart_date_formatted formatted as yyyy-MM-dd
Summary$json.output.summary
RewrittenAdCopy$json.output.rewrittenAdCopy

Connect the output back to Loop Over Items (port 0) to continue processing the next ad.


Part 4 — Image Ad Branch

The image branch is nearly identical to the video branch, with two key differences:

  1. Download Image — the HTTP Request uses snapshot.cards[0].original_image_url.
  2. Analyze Image (Gemini) — set resource to Image and tailor the prompt to ask for visual structure analysis (headline placement, design elements, layout) instead of scene-by-scene breakdown.

The loop, AI Agent, Structured Output Parser, OpenRouter model, and Sheets append are all configured identically to the video branch.


Part 5 — Text Ad Branch

Text ads contain no video or image, so Gemini isn’t needed here. The loop goes straight to the AI Agent, which analyzes the raw ad JSON (body copy, headline, CTA text) and produces the same summary + rewrittenAdCopy output. The agent works purely from the structured ad data — no media description step required.


The Data Structure

Every branch writes to the same Google Sheet. Create a sheet named Sheet1 with these columns in row 1:

ColumnTypeExampleDescription
ad_archive_idText1027384950617283Unique Facebook ad ID — useful for deduplication
page_nameTextNikeThe advertiser’s Facebook Page name
page_profile_uriTexthttps://facebook.com/nike/Link back to the advertiser’s page
ad typeTextVideoOne of: Video, Image, Text
ad DateDate2026-02-14When the ad started running
SummaryText (long)AI marketing analysis…Gemini + OpenRouter combined analysis
RewrittenAdCopyText (long)Rewritten copy…Swiped and repurposed ad copy

Sample rows:

ad_archive_idpage_namead typead DateSummary (excerpt)
1027384950617283NikeVideo2026-02-14Hook leads with pain point, strong risk reversal…
9182736450192837AdidasImage2026-02-10Bold visual with product closeup, seasonal urgency…
4561728394017263Under ArmourText2026-01-30Copy-heavy, targets gym-goers, performance focus…
📌

Important: Column names must match exactly — including capitalization and spaces. The workflow maps to these exact headers. If you rename any column, update the corresponding expression in the Google Sheets node for that branch.


Full System Flow

┌───────────────────────────────────────────────────────────────────────────┐
│  USER INPUT                                                                  │
│  Form → { url, count: 20, country: "US", period: "last30d" }               │
└─────────────────────────────────┴──────────────────────────────────────────┘
                                 │
                                 ▼
┌───────────────────────────────────────────────────────────────────────────┐
│  SCRAPING                                                                    │
│  Apify Actor → 20 active ad objects from Facebook Ads Library               │
│  Filter → drops pages with < 1,000 likes                                   │
└─────────────────────────────────┴──────────────────────────────────────────┘
                                 │
                                 ▼
┌───────────────────────────────────────────────────────────────────────────┐
│  ROUTING (Switch by ad type)                                                 │
│    ├── Video → Loop → Download MP4 → Gemini vision → AI Agent             │
│    ├── Image → Loop → Download JPG → Gemini vision → AI Agent             │
│    └── Text  → Loop ───────────────────→ AI Agent             │
└─────────────────────────────────┴──────────────────────────────────────────┘
                                 │
                                 ▼
┌───────────────────────────────────────────────────────────────────────────┐
│  OUTPUT                                                                      │
│  Google Sheets row per ad: metadata + AI summary + rewritten copy            │
└───────────────────────────────────────────────────────────────────────────┘
  

Testing Your Workflow

  1. Open the Form Trigger URL in a browser (find it under the node settings → Test URL).
  2. Enter a well-known brand URL such as https://www.facebook.com/nike/, set Ad Count to 3, country to US, and Ad Period to last30d.
  3. Submit the form and watch the n8n execution log in real time.
  4. After it completes, open your Google Sheet and check for new rows.
  5. Confirm all 7 columns have data — especially Summary and RewrittenAdCopy.
ProblemLikely CauseFix
Apify returns 0 adsPage URL is wrong or page has no active adsVerify the URL; try a large brand page
All ads filtered outPage has < 1,000 likesLower the Filter threshold to 100
Gemini error on videoVideo URL expired or isn’t a direct MP4Re-run the workflow; Apify CDN URLs can expire
output.summary is emptyStructured Output Parser failedCheck that OpenRouter model is connected to AI Agent
Google Sheets auth errorOAuth token expiredRe-connect your Google credential in n8n
ad Date shows wrong formatn8n date expression issueConfirm start_date_formatted is a date string, not a timestamp

Frequently Asked Questions

Do I need a Facebook API key or special access from Meta?

No. The workflow uses Apify’s Facebook Ads Library Scraper, which pulls from Meta’s publicly available Ads Library. You don’t need any developer credentials from Facebook or Meta — just an Apify account.

How much does it cost to run?

The main cost is Apify (roughly $0.05–$0.15 per run for 20 ads) and OpenRouter (fractions of a cent per AI call). Google Gemini has a generous free tier. A typical 20-ad run costs less than $0.25 total.

Can I spy on multiple competitors in one run?

The current workflow processes one Facebook Page URL per form submission. For multiple competitors, run the form once per URL — results accumulate in the same Sheet. You could also modify the Apify node to accept an array of URLs.

What if an ad has both a video and images (carousel)?

The Switch node checks for a video URL first. If snapshot.videos[0].video_hd_url exists, the ad routes to the Video branch regardless of whether images are also present. Carousel-only ads (no video) hit the Image branch via cards[0].original_image_url.

Can I change the AI model?

Yes — the OpenRouter node accepts any model on openrouter.ai. Swap in anthropic/claude-3-haiku or openai/gpt-4o-mini for different speed/quality trade-offs. The Gemini vision nodes are fixed to Gemini for multimodal analysis, but the text generation step is fully swappable.

Can I run this automatically on a schedule?

Absolutely. Replace the Form Trigger with a Schedule Trigger, hardcode the competitor URL and settings in the Apify node, and set it to run weekly. You’ll have a fully automated competitor monitoring system that updates your Sheet every seven days without any manual input.


🚀 Get the Facebook Ads Spy Agent Template

Import the workflow, add your credentials, and start pulling AI-analyzed competitor ads into your Google Sheet in under 10 minutes — no build time required.

Get the Template →

Instant download · Works on n8n Cloud and self-hosted

What’s Next?

  • Add a Slack or email notification when the workflow finishes — get a digest of the top 3 most interesting ads delivered straight to your inbox.
  • Add a deduplication step before the Sheets append to check ad_archive_id against existing rows, preventing duplicates when re-running the same competitor.
  • Schedule it weekly per competitor and track which ads are still running after 30+ days — longevity is the strongest signal of a high-converting creative.
  • Add a sentiment scoring node to automatically flag ads using high-urgency language or deep discounts — a sign your competitor may be pushing hard on a particular angle.
  • Store in Airtable instead of Google Sheets for richer filtering, gallery views, and team collaboration on creative insights.
n8n Facebook Ads Apify Google Gemini OpenRouter Google Sheets AI Agent marketing automation competitor research ad spy

Shopify Ai voice store manager n8n 

Managing a Shopify store means checking the dashboard, hunting for order IDs, editing products one by one, and emailing customers manually. Every one of those tasks takes you away from actually growing the business. This n8n Shopify AI agent changes that completely. First, you send a voice note or text message on WhatsApp. Next, the AI understands your command, queries your live store, and takes action — updating orders, managing products, sending customer emails, and logging everything to Google Sheets. As a result, your entire store becomes controllable from your phone, hands-free, in English, Arabic, or French.

Prefer to skip the build? Grab the ready-made template → and be managing your Shopify store by voice in under 20 minutes.

What You’ll Build

  1. You send a WhatsApp text or voice note to your business number — “How many orders came in today?” or “Update the price of the blue hoodie to $49.”
  2. If it’s a voice note, ElevenLabs transcribes the audio to text automatically before passing it to the AI.
  3. The AI agent reads your command, calls the right Shopify tool — get orders, update a product, create a listing, delete a variant — and executes it against your live store.
  4. Order data is written to a Google Sheet for tracking, and customer emails are sent via Gmail when you ask.
  5. The AI replies back to WhatsApp: text if you typed, a voice note in the same Charlie voice if you spoke.
  6. Every conversation is remembered per WhatsApp contact, so context carries forward across messages.

How This n8n Shopify AI Agent Works — The Big Picture

The workflow has two entry paths that merge at the AI agent, and two exit paths that split again based on whether the original message was text or audio. In between, the AI has six Shopify tools it can call autonomously, plus Google Sheets and Gmail. Here is the full picture:

┌──────────────────────────────────────────────────────────────────────────────┐
│  N8N SHOPIFY AI AGENT — WHATSAPP VOICE STORE MANAGER                        │
│                                                                              │
│  [WhatsApp Trigger]                                                          │
│          │                                                                   │
│          ▼                                                                   │
│  [Switch: text or audio?]                                                    │
│     │ text                   │ audio                                         │
│     ▼                        ▼                                               │
│  (straight to          [Get Media URL]                                       │
│   AI Agent)            [Download Audio Binary]                               │
│                        [ElevenLabs: Speech-to-Text]                         │
│                              │                                               │
│                    ──────────┘                                               │
│                    ▼                                                         │
│           [AI Agent — Store Manager]                                         │
│            │  Tools available:                                               │
│            ├─ [Shopify: Get Orders]                                          │
│            ├─ [Shopify: Get Products]                                        │
│            ├─ [Shopify: Update Order]                                        │
│            ├─ [Shopify: Create Product]                                      │
│            ├─ [Shopify: Update Product]                                      │
│            ├─ [Shopify: Delete Product]                                      │
│            ├─ [Google Sheets: database (append/update)]                      │
│            └─ [Gmail: Send Email]                                            │
│            │  Memory: Simple Memory (per WhatsApp contact)                  │
│            │  Model:  OpenRouter Chat Model                                  │
│                    │                                                         │
│                    ▼                                                         │
│           [Switch1: was original text or audio?]                             │
│             │ text                    │ audio                                │
│             ▼                         ▼                                      │
│    [WhatsApp: Send text]    [ElevenLabs: Text-to-Speech]                    │
│                             [Code: Set MIME → audio/mpeg]                   │
│                             [WhatsApp: Send voice note]                     │
└──────────────────────────────────────────────────────────────────────────────┘

What You’ll Need

  • n8n — self-hosted or n8n Cloud (v1.30+). See the n8n hosting documentation for setup options.
  • WhatsApp Business API — a verified Meta business phone number with a permanent access token. See the WhatsApp Cloud API getting-started guide.
  • Shopify store — with a private app or OAuth app that has read/write access to Orders and Products.
  • ElevenLabs account — free tier works for testing; choose any voice from your library.
  • OpenRouter account — to power the AI agent; Claude, GPT-4o, or Llama 3 all work.
  • Google Sheets — one spreadsheet with an “orders” tab containing the 14-column schema shown below.
  • Gmail account — connected via OAuth2 in n8n for sending customer emails.

Estimated build time: 60–90 minutes from scratch, or under 20 minutes with the ready-made template.

Part 1 — Receiving the WhatsApp Message

1 WhatsApp Trigger

This node opens a webhook endpoint that Meta’s WhatsApp Cloud API calls every time a message arrives on your business number. It listens for the messages event type, which covers both text messages and media (audio, images, documents). Every incoming message delivers a payload with two fields the rest of the workflow relies on: messages[0].type (either text or audio) and contacts[0].wa_id (the sender’s phone number, used as the session key for memory).

// Incoming WhatsApp payload — text message example
{
  "messages": [
    {
      "type": "text",
      "text": { "body": "How many orders are pending today?" }
    }
  ],
  "contacts": [
    { "wa_id": "15551234567", "profile": { "name": "Sarah Thompson" } }
  ]
}
📌

Note: Your WhatsApp webhook must be registered in the Meta Developer Console pointing to your n8n webhook URL. The verification token is set in the WhatsApp Trigger node credentials. Make sure your n8n instance is publicly reachable — it cannot run on localhost.

2 Switch — Text or Audio?

First, the Switch node reads $json.messages[0].type. If it equals text, the message goes directly to the AI Agent. If it equals audio, the message takes a detour through three nodes to transcribe the voice note before the AI sees it. This routing is what makes the workflow truly voice-native — the AI always receives clean text, regardless of how the user communicated.

// Switch routing logic
{
  "route_text":  "messages[0].type === 'text'",
  "route_audio": "messages[0].type === 'audio'"
}

Part 2 — Transcribing Voice Messages

3 Download Media (WhatsApp)

When the message is audio, this node calls the WhatsApp media endpoint to get the audio file’s download URL. It passes $json.messages[0].audio.id — the media ID from the trigger payload — and receives back a temporary URL that expires after a few minutes.

4 Download Audio (HTTP Request)

Next, this HTTP Request node fetches the actual audio binary from the URL returned by the previous step. It uses the WhatsApp API credentials for authentication, since Meta’s media URLs require a valid access token in the request headers. The output is a binary file that ElevenLabs can process.

5 Transcribe Audio (ElevenLabs)

ElevenLabs Speech-to-Text converts the audio binary into plain text with high accuracy, including for Arabic and French — matching the multilingual capability of the AI agent. The transcribed text arrives as $json.text, which the AI Agent reads via its Audio input: {{ $json.text }} prompt field.

💡

Tip: ElevenLabs handles background noise, accents, and mixed-language voice notes well. For store managers recording quick commands while walking around a warehouse, this reliability is critical. If you want to reduce API costs, you can swap ElevenLabs for OpenAI’s Whisper node, which is cheaper for high-volume transcription.

Part 3 — The AI Store Manager Agent

6 AI Agent — Store Manager

This is the brain of the entire workflow. The AI Agent node receives either the text body or the transcribed audio, then decides which tools to call and in what order to fulfill the command. Its system prompt defines its role as a Shopify store manager, its available tools, its language capabilities, and one important rule: always call Get orders before updating an order, to retrieve the order ID first.

The agent prompt sets the behavior clearly. For example, the current system prompt instructs:

role: You are a smart AI voice Store Manager for my Shopify Store.
tasks:
- Always use 'Get orders' to get order/sales details
- Before you update orders, always get the order ID first from 'Get orders'
tools: shopify tool, Google Sheets 'database', Gmail
languages: English, Arabic (Modern Standard Arabic), French
💡

Tip: The system prompt mentions “Pet_shop” as the Gmail sender name — update this to your actual store name in both the AI Agent system prompt and the Gmail Tool node’s senderName field before going live.

7 OpenRouter Chat Model

The AI Agent is powered by OpenRouter, which gives you access to 100+ language models through a single API key. The default model is not hardcoded — you choose it in the OpenRouter Chat Model node’s dropdown. For store management commands (structured data retrieval, product updates), Claude 3.5 Sonnet or GPT-4o Mini deliver excellent results at low cost. Switch models any time without touching the rest of the workflow.

8 Simple Memory

The memory node gives the agent a 20-message conversation window, keyed to each contact’s WhatsApp phone number (wa_id). This means when a user follows up with “Actually, add a note to that order saying urgent delivery,” the agent remembers which order they were discussing without being told again. Each WhatsApp contact gets a fully isolated conversation context — 50 customers messaging simultaneously creates 50 separate memory streams.

Part 4 — Shopify Tools the Agent Can Use

The AI agent has six Shopify tools available. It calls them autonomously — you never have to specify which tool to use in your WhatsApp message. Just describe what you want in plain language, and the agent decides.

ToolWhat it doesExample command that triggers it
Get Orders Fetches all orders from Shopify. The agent controls returnAll and limit via $fromAI() based on your request. “Show me today’s orders” / “How many pending orders do we have?”
Get Products Fetches all products from the catalog. Returns titles, prices, variants, and inventory levels. “List all products under $30” / “Do we still have the red sneakers in stock?”
Update an Order Updates an order by ID. First calls Get Orders to find the correct ID, then applies changes like notes or tags. “Add a note to order #1023 saying the customer requested gift wrapping.”
Create a Product Creates a new product with a title and optional additional fields (description, price, images). “Create a new product called Summer Linen Tote Bag at $24.99.”
Update a Product Updates a product’s title and HTML body description by product ID. First calls Get Products to find the ID. “Update the Blue Hoodie description to add washing instructions.”
Delete a Product Permanently deletes a product from Shopify by product ID. “Remove the discontinued Winter Scarf from the catalog.”
📌

Important: The Delete a product tool is permanent. There is no confirmation step — if the AI identifies the product and you asked it to delete, it will. Add a safety confirmation step (an IF node or a WhatsApp confirmation reply) if you want to prevent accidental deletions in production.

Part 5 — Database and Email Tools

9 Google Sheets — Database Tool

Every time the agent retrieves or acts on an order, it can write the data to your Google Sheet using the appendOrUpdate operation. The Order ID column is the matching key — so re-running a command on the same order updates the existing row rather than duplicating it. All 14 fields are populated via $fromAI() expressions, meaning the agent extracts each value from the Shopify response and maps it automatically.

10 Gmail — Send Email Tool

When you ask the agent to email a customer, it calls this tool, filling the To, Subject, and Message fields via $fromAI(). The sender name is set to your store name. For example, you can say: “Email james.carter@gmail.com and tell him his order shipped today” — and the agent writes and sends the email entirely on its own.

Part 6 — Sending the Reply

11 Switch1 — Reply in Text or Voice?

After the AI agent finishes, a second Switch node checks the original message type again. If you sent text, you get a text reply. If you sent a voice note, the agent converts its response to speech and sends a voice note back. The reply always matches the input format — a voice conversation stays a voice conversation.

12 Convert Text to Speech (ElevenLabs)

For audio replies, this node sends the AI agent’s text output to ElevenLabs using the “Charlie — Deep, Confident, Energetic” voice. The settings are configured for natural, professional delivery: stability at 1.0, similarity boost at 1.0, and speed at 0.82 (slightly slower than default, which works better for information-dense store management replies). The output format is MP3 at 22050 Hz.

13 Convert to MPEG (Code Node)

WhatsApp’s API is strict about audio MIME types. This Code node sets mimeType to audio/mpeg and renames the file to voice.mp3 — without this step, WhatsApp rejects the audio upload and the voice reply fails silently.

for (const item of $input.all()) {
  if (item.binary && item.binary.data) {
    item.binary.data.mimeType = 'audio/mpeg'
    item.binary.data.fileName = 'voice.mp3'
  }
}
return $input.all();

14 Send Message / Send Message1 (WhatsApp)

Two WhatsApp send nodes handle the two reply paths. Send message1 (text path) sends the AI output as a plain text body. Send message (audio path) sends the MPEG binary as an audio message. Both always reply to the original sender using $('WhatsApp Trigger').item.json.contacts[0].wa_id.

The Data Structure — Google Sheets Order Database

Create a Google Sheet with one tab named orders. The column names below are case-sensitive — the agent uses them as keys when writing rows via $fromAI().

Column NameTypeExample ValueDescription
Order IDText5678901234Shopify order ID — used as the matching key to prevent duplicate rows
Order NameText#1023Human-readable order name shown in the Shopify dashboard
Order DateTextMarch 18, 2026Date the order was placed
Customer NameTextJames CarterFull name from the Shopify order
Customer EmailTextjames.carter@gmail.comUsed when sending confirmation emails via Gmail
Customer PhoneText(555) 867-5309Contact number from the order
Product TitleTextBlue Hoodie — Size MProduct name and variant from the order line item
QuantityText2Number of units ordered
Product PriceText$49.00Unit price at time of order
Total Order AmountText$98.00Full order total including all line items
CurrencyTextUSDCurrency code from the Shopify order
Payment StatusTextpaidShopify financial status: paid, pending, refunded
SourceTextonline_storeOrder source channel from Shopify
Agent NoteTextCustomer requested express shippingAI-generated note about the order based on conversation context
📌

Setup step: Create the sheet with these exact headers before activating the workflow. The Order ID column is the matching key — a second write with the same ID updates the existing row instead of creating a duplicate. Name the tab exactly orders (lowercase) to match the workflow configuration.

Full System Flow — n8n Shopify AI Agent End to End

You send a WhatsApp message: "Update the Blue Hoodie price to $44"
          │
          ▼
[WhatsApp Trigger] → { messages[0].type: "text", text.body: "Update the Blue Hoodie price to $44" }
          │
          ▼
[Switch: type = "text"] → routes to AI Agent directly
          │
          ▼
[AI Agent — Store Manager]
  → calls [Get Products] → finds Blue Hoodie, product_id: 7890123456
  → calls [Update a Product] → sets title + new price on Shopify
  → calls [Google Sheets database] → logs order/product change
  → generates reply: "Done! Blue Hoodie updated to $44.00 in your store."
          │
          ▼
[Switch1: original type = "text"]
          │
          ▼
[WhatsApp: Send text reply] → "Done! Blue Hoodie updated to $44.00 in your store."

────────────────────────────────────────────────────────────

You send a WhatsApp voice note: "Send an email to James about his order"
          │
          ▼
[WhatsApp Trigger] → { messages[0].type: "audio", audio.id: "media_id_xyz" }
          │
          ▼
[Switch: type = "audio"] → routes to audio transcription path
          │
[Download Media URL] → { url: "https://lookaside.fbsbx.com/..." }
[Download Audio Binary] → binary MP3 file
[ElevenLabs: Speech-to-Text] → { text: "Send an email to James about his order" }
          │
          ▼
[AI Agent — Store Manager]
  → calls [Get Orders] → finds James Carter, order #1023, james.carter@gmail.com
  → calls [Gmail: Send Email] → sends order update email to james.carter@gmail.com
  → generates reply: "Email sent to James Carter at james.carter@gmail.com for order #1023."
          │
          ▼
[Switch1: original type = "audio"]
          │
[ElevenLabs: Text-to-Speech] → MP3 audio of reply in Charlie voice
[Code: Set mimeType = audio/mpeg]
[WhatsApp: Send voice note] → 🔊 Voice reply delivered to sender

Testing Your n8n Shopify AI Agent

  1. In n8n, activate the workflow and copy the WhatsApp webhook URL. Register it in the Meta Developer Console under your app’s webhook settings.
  2. Send a text message to your WhatsApp business number: “List all products.” Confirm the AI responds with your actual Shopify catalog.
  3. Send a voice note saying: “How many orders do we have this week?” Confirm the audio is transcribed, the AI calls Get Orders, and you receive a voice reply with the count.
  4. Send: “Create a test product called Test Widget at $9.99.” Check your Shopify Products dashboard to confirm it appeared.
  5. Send: “Delete the Test Widget product.” Confirm it’s removed from Shopify. Then send the same command again — the AI should respond that the product no longer exists, demonstrating it uses Get Products before acting.
  6. Send: “Email emily.rodriguez@outlook.com and tell her order #1001 has shipped.” Check your Gmail Sent folder to confirm the email was sent with the correct content.
  7. Open your Google Sheet and confirm order rows are being written or updated correctly.
ProblemLikely CauseFix
Webhook not receiving messages n8n URL not registered in Meta Developer Console, or instance not publicly accessible Verify the webhook URL and token in Meta Developer Console → WhatsApp → Configuration. Use ngrok for local testing.
Voice reply fails — audio not delivered Missing MIME type fix or wrong phone number ID Confirm the “Convert to mpeg” Code node runs before the send node. Replace YOUR_WHATSAPP_PHONE_NUMBER_ID with your actual Phone Number ID from the Meta console.
AI says “I can’t find that product” but it exists Agent is not calling Get Products before Update Product Add an explicit instruction to the system prompt: “Always call Get Products before updating or deleting any product.”
Google Sheet not updating Column names don’t match exactly (case-sensitive) Compare sheet headers character-by-character against the schema table above. Make sure the tab is named orders.
Gmail not sending OAuth2 token expired or incorrect sender name Reconnect the Gmail OAuth2 credential in n8n. Update senderName in the Gmail Tool node from “Pet_shop” to your store name.
AI responds in the wrong language Language detection relies on user input — mixed messages can confuse it Update the system prompt to specify a default language: “If the language is unclear, respond in English.”

Frequently Asked Questions

Does this n8n Shopify AI agent work with Shopify Basic, Grow, or Advanced plans?

Yes. The workflow uses the Shopify REST API via n8n’s native Shopify nodes, which are available on all paid Shopify plans. You need to create a custom app in your Shopify admin under Settings → Apps → Develop apps and grant it read/write access to Orders and Products. The API credentials generated there connect directly to the Shopify nodes in the workflow.

Can multiple team members use the same WhatsApp number to control the store?

Yes. The Simple Memory node isolates each conversation by WhatsApp phone number, so two managers messaging the same business number get completely separate conversation contexts. There is no cross-contamination — one manager asking about orders does not affect the other’s session. For team use, consider adding an authorization check at the start of the workflow to restrict commands to known wa_id numbers.

Which AI model should I use with OpenRouter for best results?

For store management tasks — structured queries, product lookups, order updates — Claude 3.5 Sonnet or GPT-4o Mini both perform excellently. Claude handles Arabic and French more naturally, making it the better choice if your team works in multiple languages. For pure speed and lowest cost, GPT-4o Mini is the most efficient. Avoid smaller models (7B parameters or less) as they tend to mis-call tools on complex multi-step commands.

Can I add more Shopify actions beyond what’s included?

Absolutely. n8n’s Shopify Tool node supports many additional operations: creating customers, managing fulfillments, updating inventory levels, and more. To add a new capability, duplicate one of the existing Shopify Tool nodes, change the operation, connect it to the AI Agent’s tools input, and add a brief description of what the tool does in the node’s description field — the AI will use it automatically when appropriate.

What happens if the AI tries to delete the wrong product?

By design, the agent calls Get Products first to look up the product ID before deleting. However, there is no confirmation step in the base workflow. For production use, it is strongly recommended to add a safety layer: before the Delete node fires, send a WhatsApp message asking “Are you sure you want to delete [product name]? Reply YES to confirm.” Then use a Wait node and a conditional check on the reply before proceeding.

Can I connect this to a customer-facing WhatsApp number instead of an internal one?

The workflow as built is designed for internal store manager use. Connecting it to a customer-facing number would require a completely different system prompt and much stricter guardrails — the current prompt gives full write access to products and orders, which customers must never have. For a customer-facing chatbot, see our separate AI WooCommerce Chatbot guide which is designed specifically for that use case.

🚀 Get the n8n Shopify AI Agent Template

Download the ready-to-import workflow JSON, the Google Sheets order database template with all 14 columns pre-configured, and a step-by-step credential setup guide — so you can manage your Shopify store by WhatsApp voice in under 20 minutes.

Get the Template →

Instant download · Works on n8n Cloud and self-hosted

What’s Next?

  • Add a daily sales report — wire a Schedule Trigger that fires every morning and sends you a voice note summarizing the previous day’s orders, revenue, and top-selling products.
  • Add inventory alerts — extend the Get Products tool call to check stock levels and automatically send a WhatsApp alert when any product drops below a minimum quantity you define.
  • Connect Telegram as a second channel — duplicate the WhatsApp input/output nodes and replace them with Telegram nodes so the same AI agent is accessible from both apps with shared memory.
  • Add a safety confirmation step — before any destructive action (delete product, cancel order), add a WhatsApp reply asking for confirmation, then a Wait node and an IF check on the response.
  • Browse all our automation guides on the EasyWorkflows n8n blog →

How to Automate Social Media Posting Across Instagram, Facebook & YouTube with n8n

How to Automate Social Media Posting Across Instagram, Facebook & YouTube with n8n

One workflow, one Google Drive folder, four platforms. Drop a video, walk away — n8n handles the AI caption, the upload, the publish, and the status tracking automatically.

If you’re posting the same video to Instagram Reels, Facebook Reels, YouTube, and TikTok, you already know the drill: download, re-upload, write a caption, find the right tags, publish, check the status, repeat — four times, for every single video. It’s not a content problem. It’s a logistics problem. And logistics problems are exactly what n8n was built to solve.

This workflow watches a Google Drive folder, picks up the next unprocessed video, uses an AI model via OpenRouter to generate a platform-optimized caption with hashtags, uploads the video to Cloudinary as a CDN host, then simultaneously publishes it as a Reel on Instagram, a Reel on Facebook, and a video on YouTube — while staging the data for TikTok in a separate sheet. Every step is tracked in a Google Sheet so your team always knows what’s been published and what’s still pending. When everything is done, the original file is moved to an archive folder so it doesn’t get picked up again.

Prefer to skip the setup? Grab the ready-made template → and be publishing cross-platform in under 20 minutes.

What You’ll Build

  1. A daily schedule trigger (fires at 6 PM) scans your Google Drive folder for the next video waiting to be published.
  2. A Code node strips the file extension and normalizes the filename into a clean public ID (spaces become underscores for Cloudinary).
  3. The video is uploaded to Cloudinary, which provides a stable public CDN URL that all four platforms can download from.
  4. An AI call to OpenRouter (Claude 3.7 Sonnet) reads the filename as a keyword and writes a Facebook-optimized caption with five hashtags — no manual copywriting needed.
  5. The Cloudinary URL and AI caption are written back to your Google Sheet tracking row.
  6. The video is published as a Reel on Facebook (via the Facebook Graph API) and simultaneously as a Reel on Instagram — with 30-second waits built in between API calls to respect rate limits.
  7. The same video is uploaded to YouTube with the AI caption as the description, then added to a playlist.
  8. A separate Google Sheets tab gets a row appended for your TikTok queue (ready for the next manual step or a future TikTok automation).
  9. The main tracking sheet updates the row status to “Video Shared”, and the original Drive file is moved to your archive folder.

How It Works — The Big Picture

┌──────────────────────────────────────────────────────────────────────────────┐
│  SOCIAL MEDIA AUTOMATION (n8n)                                               │
│                                                                              │
│  [Schedule Trigger 6PM] ──► [Google Drive: Search Folder]                   │
│                                        │                                     │
│                                        ▼                                     │
│                              [Code: Clean Filename]                          │
│                                        │                                     │
│                                        ▼                                     │
│                              [Cloudinary: Upload Video]                      │
│                                        │                                     │
│                                        ▼                                     │
│                          [Sheets: Get Pending Row]                           │
│                                        │                                     │
│                                        ▼                                     │
│                         [OpenRouter AI: Generate Caption]                    │
│                                        │                                     │
│                                        ▼                                     │
│                         [Sheets: Write URL + Caption]                        │
│                                        │                                     │
│               ┌────────────────────────┤                                     │
│               │                        │                                     │
│               ▼                        ▼                                     │
│  ── FACEBOOK REELS ──       ── INSTAGRAM REELS ──                           │
│  [Init Upload Session]       [Post Container]                               │
│  [Upload Hosted File]        [Wait 30s]                                     │
│  [Publish Reel]              [Publish to Instagram]                         │
│  [Get Upload Status]         [Wait 30s]                                     │
│  [Wait 30s]                  [HTTP: Fetch Video]                            │
│               │                        │                                     │
│               └────────────────────────┘                                     │
│                                        │                                     │
│                                        ▼                                     │
│                         ── YOUTUBE ──                                        │
│                         [Upload Video]                                       │
│                         [Wait 10s]                                           │
│                         [Add to Playlist]                                    │
│                         [Wait 10s]                                           │
│                         [Sheets: Append TikTok Row]                         │
│                                        │                                     │
│                                        ▼                                     │
│                         [Sheets: Update Status → "Video Shared"]            │
│                         [Google Drive: Move to Archive Folder]              │
└──────────────────────────────────────────────────────────────────────────────┘

What You’ll Need

  • n8n — self-hosted or n8n Cloud (v1.30+)
  • Google Drive — one folder for new videos, one for archived videos
  • Cloudinary account — free tier is sufficient; the Social_Media folder will be created automatically
  • OpenRouter account — free tier works; Claude 3.7 Sonnet is configured by default (swap to any model you prefer)
  • Meta Developer App — with a Facebook Page token and an Instagram Business account linked to that page
  • YouTube Data API v3 — OAuth2 credentials connected in n8n; a playlist ID to post into
  • Google Sheets — one spreadsheet with two tabs: one for Instagram/Facebook/YouTube tracking, one for TikTok queue

Estimated build time: 90–120 minutes from scratch. Under 20 minutes with the template.

Part 1 — Picking Up the Video

1 Schedule Trigger

The workflow fires once a day at 6 PM. You can change this to any hour — just edit the Trigger At Hour field in the Schedule Trigger node. If you want to post multiple times a day, duplicate the trigger or switch to an interval-based schedule.

// Schedule Trigger output (no data — just fires the workflow)
{}
💡

Tip: To publish a different video every day, just make sure your Drive folder always has the next video waiting before 6 PM. The workflow picks up the first file it finds, processes it, and archives it — so the order files appear in Drive determines your posting schedule.

2 Search Files and Folders (Google Drive)

This node lists files inside your designated Google Drive folder, returning the first result it finds (limit: 1). It fetches all fields, including webContentLink — a direct download URL that Cloudinary will use to pull the video.

// Google Drive file output
{
  "id": "1aBcDeFgHiJkLmNoPqRsTuV",
  "name": "Summer Sale Promo.mp4",
  "webContentLink": "https://drive.google.com/uc?id=1aBcDeFgHiJkLmNoPqRsTuV&export=download",
  "mimeType": "video/mp4",
  "size": "48234567"
}
📌

Important: Set the folder ID to your “pending videos” folder in the Google Drive node. Leave the archive folder ID empty for now — you’ll fill it into the Move file1 node at the end of the workflow.

3 Remove Space & Extensions (Code Node)

Platform APIs and CDNs don’t love filenames with spaces or extensions. This Code node strips the .mp4 (or any extension) from the filename and produces two variants: one with underscores (for Cloudinary’s public_id) and one with the original spaces preserved (for YouTube’s video title, which looks better with natural spacing).

const baseName = $json["name"]
  .replace(/\s*\.[^/.]+$/, "")  // remove file extension
  .trim();

const public_id_underscores = baseName.replace(/\s+/g, "_"); // spaces → underscores
const public_id_no_underscores = baseName;                    // natural spacing

return [{ json: { public_id_underscores, public_id_no_underscores } }];
// Output
{
  "public_id_underscores": "Summer_Sale_Promo",
  "public_id_no_underscores": "Summer Sale Promo"
}

Part 2 — Uploading to Cloudinary

4 Upload an Asset from URL (Cloudinary)

Rather than downloading the video to n8n’s memory and re-uploading it, this node passes Cloudinary the Google Drive download link directly. Cloudinary fetches it server-to-server, transcodes it if needed, and stores it in your Social_Media folder with the underscore-normalized name as the public ID. In return, Cloudinary hands you a secure_url — the stable CDN link that all four platforms will pull from.

// Cloudinary upload output (key fields)
{
  "public_id": "Social_Media/Summer_Sale_Promo",
  "secure_url": "https://res.cloudinary.com/your-cloud/video/upload/Social_Media/Summer_Sale_Promo.mp4",
  "resource_type": "video",
  "format": "mp4",
  "duration": 28.4,
  "bytes": 48234567
}
💡

Tip: Cloudinary’s free tier gives you 25 GB of storage and 25 GB of monthly bandwidth — more than enough to test with. Videos are stored permanently so you can reuse the same CDN URL if you ever need to repost.

Part 3 — AI Caption Generation

5 Get Row(s) in Sheet (Google Sheets)

This node looks up the first row in your tracking sheet where the Status column is set to pending. It returns all columns for that row, including its row_number — which is used later to update the same row in place rather than creating a duplicate.

// Google Sheets row output
{
  "row_number": 4,
  "video_url": "",
  "Video Caption": "",
  "Status": "pending"
}

6 Video Caption (OpenRouter AI)

This HTTP Request node calls the OpenRouter API, sending the cleaned filename as the keyword. The system prompt tells Claude 3.7 Sonnet to act as a Facebook copywriter and return a Reel title (max 46 characters) followed by five relevant hashtags — no labels, no emojis, no markdown bold formatting. Clean, ready-to-paste copy every time.

// Request body (simplified)
{
  "model": "anthropic/claude-3.7-sonnet",
  "messages": [
    {
      "role": "system",
      "content": "You are a facebook copywriter expert. Follow formatting rules exactly."
    },
    {
      "role": "user",
      "content": "based on this keyword Summer Sale Promo Write an optimized facebook Reel title (max 46 characters), use 5 related hashtags, Do NOT include labels like (Video Reel Title, Hashtags) no emojis, don't use ** in title."
    }
  ]
}
// OpenRouter response
{
  "choices": [
    {
      "message": {
        "content": "Summer Sale — Shop the Best Deals Now\n#SummerSale #ShopNow #SaleAlert #BestDeals #LimitedTime"
      }
    }
  ]
}
💡

Tip: You can swap Claude 3.7 Sonnet for any model on OpenRouter — GPT-4o Mini, Mistral, or Llama 3 all work. For pure caption writing, GPT-4o Mini costs a fraction of a cent per request and produces great results.

7 Update Caption & Video URL (Google Sheets)

Once the AI returns the caption and Cloudinary returns the CDN URL, this node writes both values back to the pending row — matching by row_number. From this point on, every downstream node references these two fields using $('Update caption & vid url').item.json.video_url and $('Update caption & vid url').item.json['Video Caption'].

// Updated row in Google Sheets
{
  "row_number": 4,
  "video_url": "https://res.cloudinary.com/your-cloud/video/upload/Social_Media/Summer_Sale_Promo.mp4",
  "Video Caption": "Summer Sale — Shop the Best Deals Now\n#SummerSale #ShopNow #SaleAlert #BestDeals #LimitedTime",
  "Status": "pending"
}

Part 4 — Publishing to Facebook Reels

Facebook’s Reels API uses a three-step upload protocol: initialize a session, upload the file, then publish. n8n handles all three calls in sequence with a 30-second wait before the publish check — giving Facebook’s servers time to process the video before you query the status.

8 Initialize an Upload Session (Facebook Graph API)

Sends a POST to your Facebook Page’s video_reels edge with upload_phase=start and the Cloudinary video URL. Facebook returns a video_id and an upload_url that the next node uses.

// Facebook API response
{
  "video_id": "740128398210437",
  "upload_url": "https://rupload.facebook.com/video-upload/v23.0/740128398210437"
}

9 Upload a Hosted File (HTTP Request)

Posts to the upload_url from the previous step, passing the Cloudinary URL in a custom file_url header. Facebook fetches the video directly from Cloudinary — no binary upload, no memory usage in n8n.

10 Publish The Reel (Facebook Graph API)

Sends the finish signal: upload_phase=finish, video_state=PUBLISHED, the AI-generated description, and the video_id. This is the moment the Reel goes live on your Facebook Page.

11 Get the Upload Status + Wait 30s

Queries the Facebook Graph API to confirm the video’s status field. The 30-second Wait node before Instagram publishing gives Facebook time to fully process the reel and updates internal state before the workflow moves on.

Part 5 — Publishing to Instagram Reels

12 Post Container (Facebook Graph API — Instagram)

Instagram’s publishing API (also part of the Facebook Graph API) requires a two-step process. First, create a media container by posting the video URL, caption, and media_type=REELS to your Instagram Business account’s media edge. This returns a container id.

13 Wait 30s → Publish to Instagram

The 30-second wait is mandatory — Instagram needs time to process the video before you can publish the container. After the wait, a second API call to the media_publish edge with the creation_id makes the Reel visible on your Instagram profile.

📌

Note: You need a Facebook Page and an Instagram Business account connected to it under the same Meta Developer App. Personal Instagram accounts cannot use the Reels API.

Part 6 — Publishing to YouTube

14 HTTP Request — Fetch Video Binary

This node downloads the video binary from the Cloudinary URL. YouTube’s n8n node expects a binary input (unlike the Facebook API which accepts a URL), so this step bridges the gap — the response body becomes the binary data that the YouTube Upload node reads.

15 Upload a Video (YouTube)

Uploads the binary to YouTube. The title uses the un-modified filename (public_id_no_underscores — natural spaces), the description gets the AI-generated caption, and the video is published as public with notifySubscribers: true. Category 22 is “People & Blogs” — change this to match your niche.

// YouTube upload output (key fields)
{
  "uploadId": "abc123XYZ_youTubeVideoId",
  "status": { "privacyStatus": "public", "uploadStatus": "uploaded" },
  "snippet": { "title": "Summer Sale Promo", "categoryId": "22" }
}

16 Add to Playlist (YouTube)

After a 10-second wait (gives YouTube time to finish processing the upload), this node adds the video to your designated playlist using the uploadId from the previous step. Set your playlist ID in the node parameters.

Part 7 — Tracking and Cleanup

17 Append Row to TikTok Sheet (Google Sheets)

After a second 10-second wait, this node appends a new row to a separate “TikTok” tab in your spreadsheet with the video URL and caption — ready for you to post manually or wire up to a future TikTok API automation.

18 Update Row Status (Google Sheets)

Updates the original tracking row from pending to Video Shared, matched by row_number. This prevents the same video from being picked up again on the next trigger run.

19 Move File to Archive (Google Drive)

Moves the original video file from your “pending” folder to your “archive” folder. The file ID comes from the very first node (Search files and folders). Set your archive folder ID in this node’s parameters.

💡

Tip: If you’d rather delete the file from Drive than archive it, swap this node for a Google Drive Delete node. Archiving is recommended so you have a record of what was posted and can repost if needed.

The Data Structure

Your Google Sheet needs two tabs with these exact column names. The workflow uses string matching on column headers, so capitalization and spacing matter.

Tab 1: instagram / Facebook / Youtube

Column NameTypeExample ValueDescription
video_urlTexthttps://res.cloudinary.com/…/Summer_Sale_Promo.mp4Filled automatically by the workflow after Cloudinary upload
Video CaptionTextSummer Sale — Shop the Best Deals Now
#SummerSale #ShopNow…
AI-generated caption; filled automatically by the workflow
StatusTextpendingVideo SharedSet to “pending” manually when you add a video; updated to “Video Shared” after publishing

Tab 2: Tiktok

Column NameTypeExample ValueDescription
video_urlTexthttps://res.cloudinary.com/…/Summer_Sale_Promo.mp4Same Cloudinary URL — ready for TikTok posting
Video CaptionTextSummer Sale — Shop the Best Deals Now
#SummerSale…
Same AI caption — TikTok hashtag format works identically
📌

Setup step: Before activating the workflow, add one row to Tab 1 with Status = pending and leave video_url and Video Caption blank — the workflow fills those in automatically. Make sure the video file is already in your Google Drive folder.

Full System Flow

New video dropped into Google Drive "Pending" folder
          │
          ▼
[Schedule Trigger: 6PM daily]
          │
          ▼
[Google Drive: Search Folder] → { name: "Summer Sale Promo.mp4", webContentLink: "..." }
          │
          ▼
[Code: Clean Filename] → { public_id_underscores: "Summer_Sale_Promo",
                            public_id_no_underscores: "Summer Sale Promo" }
          │
          ▼
[Cloudinary: Upload Video] → { secure_url: "https://res.cloudinary.com/.../Summer_Sale_Promo.mp4" }
          │
          ▼
[Sheets: Get Pending Row] → { row_number: 4, Status: "pending" }
          │
          ▼
[OpenRouter AI: Generate Caption] → "Summer Sale — Shop the Best Deals Now\n#SummerSale..."
          │
          ▼
[Sheets: Write URL + Caption to Row 4]
          │
    ┌─────┴──────────────────────────────────┐
    ▼                                        ▼
── FACEBOOK ──                       ── INSTAGRAM ──
[Init Upload Session]                [Post Container] → { id: "17867..." }
[Upload Hosted File]                 [Wait 30s]
[Publish Reel]                       [Publish to Instagram]
[Get Upload Status]                  [Wait 30s]
[Wait 30s]                           [Fetch Video Binary (HTTP)]
    │                                        │
    └──────────────────┬─────────────────────┘
                       ▼
                 ── YOUTUBE ──
                 [Upload Video] → { uploadId: "abc123..." }
                 [Wait 10s]
                 [Add to Playlist]
                 [Wait 10s]
                 [Sheets: Append TikTok Row]
                       │
                       ▼
                 [Sheets: Update Status → "Video Shared"]
                 [Google Drive: Move to Archive Folder]
                       │
                       ▼
            ✅ Video live on Facebook, Instagram & YouTube
               TikTok row ready in queue sheet

Testing Your Workflow

  1. Add a short test video (under 60 seconds) to your Google Drive “pending” folder.
  2. Add a row to Tab 1 of your Google Sheet with Status = pending, leave other fields blank.
  3. In n8n, click Test workflow. Watch the execution — look for green checks on each node.
  4. Confirm the Code node output shows both public_id_underscores and public_id_no_underscores.
  5. Check your Cloudinary account to verify the video was uploaded to the Social_Media folder.
  6. Confirm the Google Sheet row now has a video_url and Video Caption filled in.
  7. Check your Facebook Page and Instagram profile for the new Reel (allow 2–3 minutes for processing).
  8. Check your YouTube channel for the new video and confirm it was added to the correct playlist.
  9. Verify the TikTok sheet has a new row appended.
  10. Confirm the original Google Drive file has been moved to the archive folder.
ProblemLikely CauseFix
Google Drive returns no files Folder ID is empty or incorrect in the Search node Open the Google Drive node → Filter → Folder ID and enter your “pending” folder’s ID (copy from the Drive URL)
Cloudinary upload fails Google Drive webContentLink requires authentication Make sure the file in Drive is shared as “Anyone with the link can view” — Cloudinary needs a public download URL
OpenRouter returns an error Invalid or expired API key in the HTTP Header credential Check your OpenRouter API key at openrouter.ai/keys and update the n8n credential
Facebook Reel fails: “Invalid node” Facebook Page ID is still the placeholder Replace YOUR_FACEBOOK_PAGE_ID in the Facebook Graph API nodes with your actual Page ID (found in Meta Business Suite → Settings → Page Info)
Instagram publish fails: “The media container is not ready” 30-second wait wasn’t long enough for processing Increase the Wait node before “Upload to instagram” to 60 seconds for larger videos
YouTube upload returns 403 OAuth token expired or insufficient scopes Reconnect the YouTube OAuth2 credential in n8n, ensuring the youtube.upload scope is granted
Google Sheet not updating Column name mismatch (case-sensitive) Confirm your sheet headers match exactly: video_url, Video Caption, Status

Frequently Asked Questions

Do I need a paid Cloudinary plan for this to work?

No — Cloudinary’s free tier supports up to 25 GB of storage and 25 GB monthly bandwidth, which is plenty for most small to medium posting schedules. If you’re posting long-form videos or several per day, upgrade to a paid plan. The secure_url generated for each upload never expires, so your CDN links remain valid indefinitely.

Can I change the AI model that generates captions?

Yes. The “video Caption” node is a standard HTTP Request to OpenRouter. Change the model field in the JSON body to any OpenRouter-supported model — for example, openai/gpt-4o-mini for lower cost or meta-llama/llama-3-70b-instruct for an open-source option. The system prompt and output format stay the same regardless of model.

Why does the workflow use Cloudinary instead of uploading directly from Drive?

Facebook and Instagram’s APIs require a publicly accessible video URL that their servers can download. Google Drive download links require authentication and have rate limits. Cloudinary solves both problems: it fetches the file from Drive during upload and serves it via a clean, public CDN URL that all four platforms can reliably access. It also handles transcoding and format compatibility automatically.

Can this post to TikTok automatically too?

The workflow currently stages TikTok data in a separate sheet tab (video URL + caption) but doesn’t publish directly, because TikTok’s Content Posting API requires business account approval and has stricter OAuth flows. The staged row is ready to wire into a TikTok API node once you have access — or you can use a tool like Buffer or Later to pick up from that sheet.

What happens if the workflow runs and there’s no video in the Drive folder?

The Google Drive “Search files and folders” node will return an empty result set, and the workflow will stop at that point with no error — it simply has nothing to process. No rows will be updated, no API calls will be made. You can optionally add an IF node after the Drive search to send yourself a Telegram or email notification when no videos are found.

Can I post to multiple Facebook Pages or Instagram accounts?

Yes, but you’ll need a separate set of Facebook Graph API nodes for each page or account, each with its own credential. The cleanest approach is to duplicate the Facebook and Instagram sections of the workflow and swap the Page ID and Instagram User ID in the cloned nodes. One n8n workflow can handle multiple accounts in parallel using a Split In Batches node at the top.

🚀 Get the Social Media Automation Template

Download the ready-to-import workflow JSON, the Google Sheets setup template with both tabs pre-configured, and a step-by-step credential guide — everything you need to go from zero to cross-platform posting in under 20 minutes.

Get the Template →

Instant download · Works on n8n Cloud and self-hosted

What’s Next?

  • Add a Telegram alert — wire a Telegram node at the very end to send yourself a confirmation message with the video title and publish status every time a video goes live.
  • Schedule multiple posts per day — duplicate the workflow and set one trigger for 9 AM and another for 6 PM to double your daily output without any extra manual work.
  • Auto-generate video thumbnails — add a Cloudinary transformation step that extracts a frame from the uploaded video and creates a custom thumbnail you can use as the YouTube cover image.
  • Connect a content calendar — replace the manual “add a file to Drive” step with a Notion or Airtable database where you queue up video ideas, titles, and target dates, and let the workflow pick the next scheduled entry automatically.
  • Add TikTok direct posting — once your TikTok Content Posting API access is approved, add a TikTok node after the “Append row in sheet” step and close the loop on all five platforms in a single run.
n8n Social Media Automation Instagram Reels Facebook Reels YouTube Automation Cloudinary Google Drive OpenRouter AI Caption Generator No Code

How to Build a Telegram Reminder Bot with n8n

ai-smm-manager-n8n

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

  1. You send a message to your Telegram bot: Remind 14:30 Call the client
  2. The bot validates the format, saves the reminder to a Google Sheet, and sends you a confirmation instantly.
  3. Every minute, a background workflow checks the sheet for due reminders.
  4. At exactly 14:30, your Telegram receives: 🔔 REMINDER: Task: Call the client
  5. 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:

  1. Add a Telegram Trigger node to a new workflow.
  2. Set Updates to Watch to message.
  3. Connect your Telegram bot credentials (the API token from BotFather).
  4. 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:

  1. Add a Code node after the Telegram Trigger.
  2. Set the language to JavaScript.
  3. 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 typeWhen it’s returned
remindValid format; time and task extracted, ready to save
errorStarted with “Remind” but time or task was missing or malformed
chatMessage 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:

  1. Add a Switch node after Parse Command.
  2. Create two output routes:
    • Route “reminder”: condition {{ $json.type }} equals remind
    • Route “info”: condition {{ $json.type }} does not equal remind

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:

  1. Add a Google Sheets node on the “reminder” output of the Switch.
  2. Set the operation to Append row.
  3. Connect your Google Service Account credentials.
  4. Select your spreadsheet and the Rappels sheet tab.
  5. Map the columns as shown below.
Sheet columnValue to map
Tache={{ $json.tache }}
Date_Heure={{ $json.date_heure }}
StatutEn attente (hardcoded)
TypeReminder (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:

  1. Add a Telegram node after Save to Sheet.
  2. Set Chat ID to ={{ $('Telegram Trigger').item.json.message.chat.id }}; this dynamically targets the person who sent the original message.
  3. 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:

  1. Create a new workflow and add a Schedule Trigger node.
  2. 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:

  1. Add a Google Sheets node set to Read rows.
  2. Connect to the same spreadsheet and Rappels tab.

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:

  1. Add a Filter node.
  2. 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:

  1. Add a Telegram node.
  2. Set the Chat ID to your personal Telegram user ID (find it by messaging @userinfobot).
  3. 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:

  1. Add a Google Sheets node set to Update row.
  2. Match on row_number (n8n tracks this automatically when reading rows).
  3. 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:

ColumnTypeExampleDescription
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:

TacheDate_HeureStatutType
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:

  1. Activate Workflow 1 in n8n.
  2. Open your Telegram bot and send: Remind 14:30 Test reminder
  3. You should receive a confirmation message within 2-3 seconds.
  4. Open your Google Sheet; a new row should appear with Statut = En attente.
  5. Now create a reminder for 2 minutes from now: Remind HH:MM Watch for this
  6. Activate Workflow 2.
  7. Wait. The notification should arrive within 60 seconds of the scheduled time.
  8. Check the sheet; the row’s Statut should now be Done.

If something doesn’t work, here are the most common culprits:

ProblemLikely CauseFix
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.id in 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 List command 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
n8n Telegram Google Sheets automation reminder bot no-code productivity