Guide · Flows
How to automate Discord without code (Flows + Google Sheets)
Build no-code Discord automations in a visual editor — log new members to Google Sheets, auto-reply to keywords and post on a schedule, step by step.
FlowsRemindersWelcome messages
On this page
Most Discord “automation” is a pile of single-purpose bots, each with its own dashboard. Flows lets you automate Discord without code in one visual editor: pick a trigger (a member joins, a message arrives, a schedule fires), add logic (If, Switch, Filter, Loop) and chain actions (send a message, give a role, write to Google Sheets, call a web API). This guide explains the building blocks and then walks through three real workflows you can copy.
What you need
- BotGG in your server (https://discord.com/oauth2/authorize?client_id=1553367772451446804&scope=bot%20applications.commands&permissions=282969912110295) and Manage Server permission.
- The web console at https://console.botgg.app → your server → Flows. Flows has no slash commands; everything is built in the console.
- For the Google Sheets example: a Google account and a few minutes in Google Cloud. Google Sheets and MySQL nodes, and webhook triggers, are part of Pro. Discord triggers, logic, Discord actions, schedules and HTTP requests work on the free plan (5 flows).
The building blocks
Every flow has exactly one trigger and any number of nodes connected by lines on a canvas.
| Group | Nodes |
|---|---|
| Triggers | Member joined, Member left, New message, Reaction added, Member roles changed, Voice activity, Button clicked, Schedule, Webhook, Manual trigger |
| Logic | If (true/false), Switch (several routes + fallback), Filter (stop when false), Loop, Wait, Stop |
| Data | Set fields, Date & time, Text (templates, regex), JSON |
| Discord actions | Send message (with embed builder and buttons), Send DM, Reply to message, Add reaction, Add/Remove role, Timeout, Kick, Ban, Create thread, Edit channel, Get member |
| Integrations | HTTP request, Google Sheets, MySQL |
Expressions: inserting data with {{ }}
Any text field can contain expressions in double curly braces. The variable picker in the node panel inserts them for you, so you rarely type them by hand:
{{ $trigger.user.username }}— data from the trigger (here: who joined).{{ $trigger.message.content | lower }}— the message text, lower-cased with a filter.{{ $node["Google Sheets"].updatedRows }}— output of an earlier node, by its name.{{ $now | date('YYYY-MM-DD HH:mm', 'Europe/London') }}— the current time, formatted in a time zone (UTC if you leave the zone out).{{ $guild.name }},{{ $vars.counter }},{{ $json.field }}— server, workflow variables, current item.
Filters are chained with |: upper, lower, trim, default('none'), replace(a,b), split, join, round(2), date(format) and more. There is no code execution — expressions only read data, and comparisons live in If, Filter and Switch.
Example 1: Log new members to a Google Sheet
A member list with join dates you can sort, filter and share with your team.
1. Create a service account in Google Cloud. In the Google Cloud console create (or choose) a project, enable the Google Sheets API, then go to IAM & Admin → Service accounts → create one. Open it → Keys → Add key → JSON. A JSON key file downloads.
2. Add the credential in BotGG. In Flows open Credentials → New credential, choose the Google service account type and paste the whole JSON key. Click Save & test. The key is encrypted at rest and never shown back to the browser.
3. Share the spreadsheet. Create a Google Sheet, then share it (Editor) with the service account’s e-mail — the client_email value from the JSON, ending in iam.gserviceaccount.com. This is the step people forget.
4. Build the flow. Create a flow (or start from the Log messages to Google Sheets template and swap the trigger):
- Trigger: Member joined, with “Ignore bots” on.
- Action: Google Sheets → operation Append, paste the spreadsheet URL, sheet name
Sheet1, values mode Columns. - Map columns (header → value): -
Username→{{ $trigger.user.username }}-User ID→{{ $trigger.user.id }}-Joined→{{ $now | date('YYYY-MM-DD HH:mm', 'Europe/London') }}-Account created→{{ $trigger.user.createdAt | date('YYYY-MM-DD') }}
Column names match the header row case-insensitively; if the sheet is empty, the first append writes the header row for you. Click Test flow to run it with sample data, check the new row, then switch the flow on and save.
Want departures too? Duplicate the flow, change the trigger to Member left and use Update with lookup column User ID to fill a “Left” column instead of adding a row.
Example 2: Keyword auto-reply in a help channel
Answer the same question for the hundredth time without typing it.
- Trigger: New message, channels
#help, “Ignore bots” on, match contains, patternserver ip. - Action: Reply to message with the answer — for example
Hi {{ $trigger.user.displayName }}, the IP is play.example.net. Rules are in #rules.
Need several answers? Keep the trigger on any message and add a Switch node with value {{ $trigger.message.content | lower }}. Add routes such as contains ip, contains apply, contains rules, each connected to its own Reply to message node, and leave fallback unconnected so other messages are ignored. To skip staff, put a Filter before the Switch: {{ $trigger.member.roles }} does not contain your staff role’s ID.
Example 3: A scheduled weekly message
- Trigger: Schedule → type Cron, expression
0 18 * * 5(Fridays at 18:00). Schedules use the server time zone from the console settings; the editor shows the next runs so you can check. - Optional: HTTP request (GET) to a public API — say, your game server’s status endpoint — and use
{{ $node["HTTP request"].body.players }}in the message. - Action: Send message to
#announcementswith the embed builder: titleWeekend raid night, descriptionRaid night for the week of {{ $now | date('D MMMM') }}: sign-ups are open., plus a button if you want a click to start another flow via the Button clicked trigger.
For simple one-off reminders and recurring announcements without logic, Reminders is quicker; use Flows when the post needs data, conditions or follow-up actions.
Recommended practice
| Tip | Why |
|---|---|
| Name nodes clearly (“Log join”, “Help reply”) | Expressions reference nodes by name |
| Test with Discord actions disabled first | Test runs really send messages and change roles |
| Turn on “Continue on fail” or retries for HTTP/Sheets nodes | A slow API won’t break the whole flow |
| Use Filter early | Stops the flow before it does work it doesn’t need |
| Check Executions after changes | Every run shows each node’s input, output and errors |
Troubleshooting
- The flow never runs. Both the flow and the Flows feature must be enabled. Saved changes reach Discord triggers within about a minute.
- Keyword filters never match. Text matching depends on Discord’s Message Content access for the bot; without it, message text arrives empty.
- Google Sheets returns 403 or “not found”. The sheet isn’t shared with the service-account e-mail, or the Google Sheets API isn’t enabled in that Cloud project.
- Times are a few hours off. The
datefilter formats in UTC unless you pass a zone as the second argument, e.g.date('HH:mm', 'America/New_York'). - “Add role” fails. BotGG’s role must be above the role it assigns, and actions only work on this server’s channels, roles and members.
- The flow reacts to its own messages. It doesn’t — BotGG’s own messages and reactions never trigger flows, so you can’t create an accidental loop.
Once your flows run, look at welcome messages and the verification guide for built-in features you don’t need to rebuild, and the commands list for everything else.
FAQ
Is Flows like Zapier or n8n for Discord?
Yes, in the same spirit: a visual canvas with triggers, logic and actions — but built into a Discord bot, so Discord events and actions work without webhooks or API keys.
Do I need to know how to code?
No. Nodes are configured through forms and pickers; expressions are inserted from a variable picker. There is no code node at all.
Can Flows write to Google Sheets on the free plan?
Google Sheets and MySQL nodes and webhook triggers are Pro features. Discord actions, logic, schedules and HTTP requests are free. See pricing.
Can I send data from a website or form into Discord?
Yes, with a Webhook trigger (Pro): each flow gets its own secret URL, and whatever you POST to it is available as {{ $trigger.body }}.