Discord to X, approved tweets posted and tracked
Most “tweet workflows” fall apart in the same place. You generate a draft, you forget to post it, you post it twice, or you publish something that sounded clever at 11pm and regrettable at 8am.
This hits solo founders first. But marketing leads managing brand voice and agency operators juggling multiple clients feel the same Discord X automation pain: keeping a steady cadence without letting anything slip through.
This workflow turns messy drafting into a clean approval loop. You will see how it creates tweets in your style, checks for duplicates, sends them to Discord for a simple yes/no, then posts to X and logs everything to Google Sheets.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Discord to X, approved tweets posted and tracked
flowchart LR
subgraph sg0["When clicking ‘Test workflow’ Flow"]
direction LR
n0@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model", pos: "b", h: 48 }
n1@{ icon: "mdi:memory", form: "rounded", label: "Simple Memory", pos: "b", h: 48 }
n2@{ icon: "mdi:wrench", form: "rounded", label: "Get_Brand_Brief", pos: "b", h: 48 }
n3@{ icon: "mdi:wrench", form: "rounded", label: "Get_Content_Fedback", pos: "b", h: 48 }
n4@{ icon: "mdi:robot", form: "rounded", label: "AI Content creator", pos: "b", h: 48 }
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/discord.svg' width='40' height='40' /></div><br/>Discord confirm"]
n6@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If2", pos: "b", h: 48 }
n7@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If1", pos: "b", h: 48 }
n8@{ icon: "mdi:cog", form: "rounded", label: "Get Brief", pos: "b", h: 48 }
n9@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields", pos: "b", h: 48 }
n10@{ icon: "mdi:robot", form: "rounded", label: "Structured Output Parser", pos: "b", h: 48 }
n11@{ icon: "mdi:robot", form: "rounded", label: "Idea creator", pos: "b", h: 48 }
n12@{ icon: "mdi:play-circle", form: "rounded", label: "When clicking ‘Test workflow’", pos: "b", h: 48 }
n13@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model1", pos: "b", h: 48 }
n14@{ icon: "mdi:memory", form: "rounded", label: "Simple Memory1", pos: "b", h: 48 }
n15@{ icon: "mdi:database", form: "rounded", label: "Check History", pos: "b", h: 48 }
n16@{ icon: "mdi:database", form: "rounded", label: "Check Examples", pos: "b", h: 48 }
n17@{ icon: "mdi:robot", form: "rounded", label: "Rewriter", pos: "b", h: 48 }
n18["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/discord.svg' width='40' height='40' /></div><br/>Send post for approval"]
n19["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/discord.svg' width='40' height='40' /></div><br/>Try Again "]
n20["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/discord.svg' width='40' height='40' /></div><br/>End of work"]
n21["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/discord.svg' width='40' height='40' /></div><br/>Confirm of next try"]
n22["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/x.dark.svg' width='40' height='40' /></div><br/>Post on X"]
n23@{ icon: "mdi:database", form: "rounded", label: "Update history", pos: "b", h: 48 }
n24@{ icon: "mdi:database", form: "rounded", label: "Add post to examples", pos: "b", h: 48 }
n32@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model2", pos: "b", h: 48 }
n7 --> n21
n7 --> n20
n6 --> n22
n6 --> n19
n17 --> n18
n8 --> n11
n22 --> n24
n19 --> n7
n9 --> n4
n11 --> n9
n15 -.-> n4
n1 -.-> n4
n16 -.-> n17
n14 -.-> n17
n23 --> n5
n2 -.-> n4
n0 -.-> n4
n4 --> n17
n13 -.-> n17
n32 -.-> n11
n21 --> n4
n3 -.-> n4
n24 --> n23
n18 --> n6
n10 -.-> n11
n12 --> n8
end
subgraph sg1["When Executed by Another Workflow Flow"]
direction LR
n25@{ icon: "mdi:play-circle", form: "rounded", label: "When Executed by Another Wor..", pos: "b", h: 48 }
n26["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/notion.dark.svg' width='40' height='40' /></div><br/>Notion"]
n27@{ icon: "mdi:cog", form: "rounded", label: "Aggregate", pos: "b", h: 48 }
n28@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields1", pos: "b", h: 48 }
n26 --> n27
n27 --> n28
n25 --> n26
end
subgraph sg2["OpenAI Flow"]
direction LR
n29@{ icon: "mdi:cog", form: "rounded", label: "Get brand brief", pos: "b", h: 48 }
n30@{ icon: "mdi:robot", form: "rounded", label: "OpenAI", pos: "b", h: 48 }
n31@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields2", pos: "b", h: 48 }
n30 --> n31
n29 --> n30
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n12,n25 trigger
class n4,n10,n11,n17,n30 ai
class n0,n13,n32 aiModel
class n2,n3 ai
class n1,n14 ai
class n6,n7 decision
class n15,n16,n23,n24,n26 database
classDef customIcon fill:none,stroke:none
class n5,n18,n19,n20,n21,n22,n26 customIcon
The Problem: Tweet Drafts Don’t Turn Into Consistent Posts
You can have great ideas and still lose the game on execution. Drafts end up scattered across Notes apps, Slack threads, Notion pages, and half-finished “content calendars” that never get opened again. Then posting becomes a daily decision. What should I say. Is this on brand. Did I already post something like this last week. That mental load is the real tax, because it makes you procrastinate. And once you miss a few days, restarting feels weirdly hard.
It’s not one big failure. It’s dozens of small ones that pile up.
- You waste about 20 minutes per post rewriting the same idea because you cannot find the last version.
- Duplicates sneak in when you are moving fast, which makes your feed look repetitive.
- Approvals happen in DMs or random comments, so you lose the final “why we posted this” context.
- Your posting history is incomplete, so evaluating what worked turns into guesswork.
The Solution: Discord Approval, Automatic Posting, Clean Tracking
This workflow gives you a reliable loop: generate, refine, approve, publish, log. It starts by loading your brand brief (either from a sub-workflow or optional Notion blocks), then uses OpenAI to generate a tweet idea aligned with your tone. Before it writes a full post, it checks Google Sheets to confirm the idea hasn’t been used, which keeps repeats from creeping in as you scale. Next, it drafts the tweet, evaluates brand fit and quality, and rewrites if the score is too low. Finally, it sends the polished version into Discord for manual approval. When you approve, it posts to X and logs the final post to Google Sheets so you always have a clean history.
The flow begins with a manual trigger when you want fresh content. AI handles idea generation, style matching (based on your past writing stored in Sheets), and quality control. Discord is the gate, X is the destination, and Google Sheets becomes your source of truth.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you publish 2 tweets a day. Manually, you might spend 15 minutes drafting, 10 minutes second-guessing tone, and another 5 minutes logging what you posted, so roughly 1 hour daily. With this workflow, you trigger it, skim the draft in Discord, and hit approve, which is closer to 5 minutes of real effort per post (the AI processing happens in the background). That’s about 40 to 50 minutes back each day, while still keeping a human check before anything goes live.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Discord for the approval loop and notifications
- X (Twitter) account to publish via OAuth connection
- OpenAI API key (get it from your OpenAI dashboard)
Skill level: Intermediate. You’ll connect accounts, duplicate a Google Sheet template, and adjust a few prompts to match your voice.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
You trigger a new content run. In this version, it starts from an n8n manual trigger, which is perfect when you want to generate tweets in batches (or run it once per day on your schedule).
Your brand context gets loaded. A sub-workflow fetches your brand summary, and there’s an optional Notion fetch that can pull blocks and aggregate them into usable prompt text. The point is simple: the AI shouldn’t guess your POV every time.
AI writes, checks, and rewrites. The workflow generates an idea, looks at Google Sheets history to avoid duplicates, then drafts the tweet. It evaluates brand fit with a scoring step, and if the score is low, it loops back for a rewrite using your style examples as guidance.
Discord becomes the checkpoint, then Sheets becomes the archive. You get the final draft in Discord for approval. Approve it, and n8n publishes to X and appends the post to Google Sheets (History and Examples) so your future runs get smarter and your team has a clean record.
You can easily modify the approval rules to require a specific emoji reaction or a keyword, based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Manual Workflow Trigger
This workflow starts manually and immediately launches the idea-generation subworkflow.
- Add and open Manual Workflow Trigger to confirm it is the entry point.
- Verify that Manual Workflow Trigger connects directly to Run Sub-Workflow (Configure Required).
Step 2: Configure the Subworkflow and Idea Generation Chain
This section calls a subworkflow, generates topic ideas, parses them, and maps them for the composer.
- In Run Sub-Workflow (Configure Required), choose the correct Workflow to run (it is currently empty).
- Open Topic Idea Generator and set the Text prompt to the existing value, including the expression
{{ $json.content }}. - Ensure Structured Parse Output remains attached as the output parser for Topic Idea Generator with the JSON schema example provided.
- In Map Idea Fields, set Post Idea to
{{ $json.output.suggestions }}. - Confirm the execution flow: Run Sub-Workflow (Configure Required) → Topic Idea Generator → Map Idea Fields.
Step 3: Set Up the AI Composer and Tools
The composer uses OpenAI, memory, and tools to draft posts and check brand alignment and history.
- Open AI Post Composer and keep the Text value as
=Avalible idea for post: {{ $json['Post Idea'] }}. - Attach OpenAI Chat Engine as the language model for AI Post Composer and confirm the model
gpt-4.1-mini. - Confirm Session Memory Buffer, Fetch Brand Summary, and Retrieve Content Feedback are connected as AI tools/memory for AI Post Composer.
- Open Review Post History and set the Document and Sheet to your history sheet for duplicate checks.
- Ensure the flow continues: Map Idea Fields → AI Post Composer.
Credential Required: Connect your openAiApi credentials in OpenAI Chat Engine.
Credential Required: Connect your googleSheetsOAuth2Api credentials in Review Post History.
Step 4: Configure the Style Rewrite and Brand Fit Review
After composing, the post is rewritten in brand style and can be evaluated via a secondary subworkflow.
- Open Style Rewrite Agent and keep Text as
=Rewrite this post to my style: {{ $json.output }}. - Attach OpenAI Chat Engine B as the language model for Style Rewrite Agent.
- Connect Review Style Examples as an AI tool for Style Rewrite Agent, and confirm the sheet and document IDs.
- In Run Sub-Workflow (Configure Required) 2, select the evaluation workflow to enable brand-fit checks.
- Verify the brand evaluation path: Run Sub-Workflow (Configure Required) 2 → Evaluate Brand Fit → Extract Feedback Score.
Credential Required: Connect your openAiApi credentials in OpenAI Chat Engine B.
Credential Required: Connect your googleSheetsOAuth2Api credentials in Review Style Examples.
Credential Required: Connect your openAiApi credentials in Evaluate Brand Fit.
Step 5: Configure Notion Brand Brief Retrieval (Subworkflow)
The brand brief is pulled from Notion and aggregated into a single string for evaluation.
- In the subworkflow, set Subworkflow Trigger to Input Source
passthrough. - Open Fetch Notion Blocks and set the Block ID to your Notion page URL.
- Ensure Fetch Notion Blocks → Aggregate Content → Join Content Fields.
- In Join Content Fields, set content to
{{ $json.content.join() }}.
Credential Required: Connect your notionApi credentials in Fetch Notion Blocks.
Step 6: Configure Approval, Retry, and Publishing Flow
Posts go through approval in Discord and then publish to X, with retry logic handled by Discord approvals.
- In Send for Approval, set Message to
=Aprove this post: {{ $json.output }}and keep Operation as sendAndWait. - In Approval Check, confirm the condition uses
{{ $json.data.approved }}equalstrue. - For retries, keep Request Retry set to
=Try Again ?with sendAndWait, then ensure Retry Decision checks{{ $('Request Retry').item.json.data.approved }}. - Set Retry Confirmation to send
Let's try Againand verify it routes back to AI Post Composer. - In Publish to X, set Text to
{{ $('Style Rewrite Agent').item.json.output }}.
Credential Required: Connect your discordBotApi credentials to all Discord nodes (Send for Approval, Request Retry, Retry Confirmation, Completion Notice, Discord Publish Notice).
Credential Required: Connect your twitterOAuth2Api credentials in Publish to X.
Step 7: Configure History Logging and Notifications
Successful posts are stored in Google Sheets and announced in Discord.
- In Store Example Post, keep Operation as append and map Examples to
{{ $('AI Post Composer').item.json.output }}. - In Append History Log, keep Operation as append and map Post to
{{ $('AI Post Composer').item.json.output }}, Time to{{ $now }}, and Published toTRUE. - Confirm the flow: Publish to X → Store Example Post → Append History Log → Discord Publish Notice.
Credential Required: Connect your googleSheetsOAuth2Api credentials in Store Example Post and Append History Log.
Step 8: Test and Activate Your Workflow
Run a manual test to validate approvals, publishing, and logging.
- Click Execute Workflow on Manual Workflow Trigger to start a test run.
- Approve the post in Discord when Send for Approval prompts you; verify that Publish to X posts successfully.
- Check Google Sheets to confirm Store Example Post and Append History Log appended new rows.
- Verify the final Discord message from Discord Publish Notice shows the output text.
- Toggle the workflow to Active to enable production use.
Common Gotchas
- Discord credentials can expire or need specific permissions. If things break, check the n8n Discord credential and your channel access settings first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Default prompts in AI nodes are generic. Add your brand voice early or you’ll be editing outputs forever.
Frequently Asked Questions
About 45 minutes if you already have your accounts and Sheet ready.
No. You’ll mostly connect accounts and paste in prompts. The “hard part” is deciding what your brand voice should sound like.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in OpenAI API costs (often a few cents per batch of tweets).
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and it’s a common upgrade. You can route different “brand briefs” through the Fetch Brand Summary sub-workflow, then swap the Discord “Send for Approval” target channel based on brand name or client. Many teams also keep separate Google Sheets tabs per brand for History and Examples, so style learning doesn’t bleed across clients.
Usually it’s permissions. Make sure the Discord bot is invited to the right server, has access to the approval channel, and can read message content if your approval logic depends on it. If it used to work and suddenly doesn’t, reselect the Discord credential in n8n and send a test message from the node. Also double-check you didn’t delete or rename the channel that the node is pointing to.
A lot. On n8n Cloud, the limit is mainly your monthly executions, and on self-hosted there’s no hard cap besides your server. Practically, X rate limits and your own approval pace are the bottlenecks, not n8n.
Often, yes, if you care about the “loop” part: evaluate quality, rewrite, check Sheets history, then wait for a human approval in Discord. n8n handles branching and conditional logic without turning every path into a new paid step. It also makes it easier to keep your prompts, memory, and style examples in one place. Zapier or Make can still work if you only want “draft to Sheet to post,” but once you add scoring, retries, and dedupe checks, those builders get clunky (and pricey). Talk to an automation expert if you want a quick recommendation based on your posting volume.
Set this up once and your content engine stops relying on willpower. The workflow handles the repetitive parts, and you keep control where it matters: the final approval.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.