teachyou.ai academy
← All posts
Workflow Automationn8nSlackAI AgentsAutomation

Building a Slack AI Bot with n8n

Pramod Dutta · Jun 25, 2026 · 10 min read

Building an n8n Slack bot is one of the fastest ways to put an AI assistant in front of a team that already lives in Slack. Instead of standing up a bot server, managing the Slack Events API yourself, and hosting an LLM client, n8n gives you a trigger, a model node, and an output node, wired together in a canvas you can edit live. This guide walks through a working n8n Slack bot from scratch: the Slack app setup, the workflow nodes, tool calling, thread memory, and the deployment details that trip people up.

By the end you will have a bot that listens for mentions or direct messages in Slack, sends the message to an LLM with memory and tools attached, and replies in the same thread. The same pattern extends to ticket lookups, internal doc search, or triggering other workflows from chat.

Why n8n for a Slack AI bot

n8n is a node-based workflow automation tool, similar in spirit to Zapier or Make, but self-hostable and built for more complex branching logic. For a Slack AI bot specifically, three things make it a good fit:

  • Native Slack trigger and Slack node. You do not write Slack SDK code; n8n handles the OAuth token and API calls behind a form.
  • First-class AI nodes. n8n ships an AI Agent node, chat model nodes for the major providers, memory nodes, and a tool-calling framework, so "LLM with tools" is a drag-and-drop pattern, not custom orchestration code.
  • Visibility and control. Every run is logged with the exact input and output of each node, which matters a lot once the bot is doing more than echoing a prompt back.

The tradeoff: n8n workflows can get messy in Slack's threaded, event-heavy world if you do not plan for deduplication and thread context up front. We will handle both.

Prerequisites

  • An n8n instance, self-hosted (Docker or npm) or n8n Cloud. Self-hosting is fine for this; a Slack bot's traffic is low volume.
  • A Slack workspace where you can create an app (workspace admin, or a sandbox workspace for testing).
  • An API key for your LLM provider of choice, wired into n8n as credentials.
  • Optionally, a webhook-reachable n8n URL. If you are self-hosting locally during development, use a tunnel tool (n8n bundles support for this, or use your own) so Slack's Events API can reach your instance.

Step 1: Create the Slack app

Go to api.slack.com, create a new app "from scratch," and configure these pieces before touching n8n:

  1. OAuth scopes (under OAuth & Permissions -> Bot Token Scopes): add app_mentions:read, chat:write, channels:history, groups:history, im:history, im:read, and users:read. Add chat:write.public if you want the bot to post in channels it has not been invited to yet.
  2. Event Subscriptions: turn this on. You will fill in the Request URL after you build the n8n trigger, since Slack verifies that URL before saving it.
  3. Subscribe to bot events: add app_mention and, if you want DMs to work, message.im.
  4. Install the app to your workspace and copy the Bot User OAuth Token (xoxb-...).
  5. Copy the Signing Secret from Basic Information; n8n's Slack trigger node uses it to verify incoming events.

Keep this tab open. You will come back to paste in the Request URL once n8n gives you one.

Step 2: Add Slack credentials in n8n

In n8n, go to Credentials -> New -> Slack. Choose OAuth2 or the simpler "Access Token" option depending on your n8n version, and paste the bot token. Test the credential; n8n will confirm it can call auth.test.

Step 3: Build the trigger

Create a new workflow and add a Slack Trigger node. Configure it to watch for the events you subscribed to in Slack: message posted, app mentioned, or both. When you save this node, n8n generates a webhook URL, something like:

https://your-n8n-host/webhook/<workflow-id>/slack

Copy that URL into the Slack app's Event Subscriptions "Request URL" field. Slack sends a verification handshake; n8n's Slack Trigger answers it automatically as long as the workflow is active (not just saved, but toggled on).

Deduplication note: Slack retries event delivery if your endpoint does not respond fast enough, which can fire your workflow two or three times for one message. Add a Filter or a small Code node right after the trigger that checks the X-Slack-Retry-Num header (available in the trigger's raw headers output) and stops the run if it is a retry:

const retryNum = $input.first().json.headers['x-slack-retry-num'];
if (retryNum) {
  return [];
}
return $input.all();

Step 4: Filter out the bot's own messages

Without a guard here, your bot will see its own replies as new messages and can loop. Add an IF node right after the dedup filter that checks the event's bot_id field is empty, or that user does not equal your bot's own user ID (grab that once from the Slack app's Basic Information page or via an auth.test call).

// IF node condition (expression mode)
{{ $json.event.bot_id === undefined }}

Step 5: Wire up the AI Agent node

This is the core of the n8n Slack bot. Add an AI Agent node (n8n's LangChain-based agent node) after your filters. It needs three connections:

  1. Chat Model: attach a chat model node for your provider (OpenAI, Anthropic, or whichever you have credentials for). Point it at a current general-purpose model; do not hardcode a specific version string into your prompt, set it in the model node's dropdown so upgrades are a one-click change.
  2. Memory: attach a Window Buffer Memory node (or Postgres/Redis-backed memory for production) so the bot remembers earlier turns in the same thread. Set the session key to the Slack thread timestamp so each thread gets its own memory:
{{ $json.event.thread_ts || $json.event.ts }}
  1. Tools (optional but recommended): attach tool nodes such as an HTTP Request tool for hitting an internal API, a Vector Store tool for RAG over your docs, or a Workflow tool that calls another n8n workflow. Each tool needs a clear name and description; the agent decides when to call it based on that description, so be specific ("Look up an order by ID in the billing system" beats "billing tool").

In the AI Agent node's prompt field, map the incoming Slack text, stripping the <@BOTID> mention tag:

{{ $json.event.text.replace(/<@[A-Z0-9]+>/g, '').trim() }}

Set a system message that defines the bot's role, tone, and any hard boundaries ("only answer questions about X, say you don't know rather than guessing").

Step 6: Post the reply back to Slack

Add a Slack node (not the trigger) after the AI Agent, set to "Send a Message." Configure:

  • Channel: {{ $json.event.channel }}
  • Text: {{ $json.output }} (the AI Agent node's output field)
  • Thread timestamp: {{ $json.event.thread_ts || $json.event.ts }} so the reply lands in the thread instead of the main channel

This last part matters for usability: replying in-thread keeps busy channels readable and is what makes the bot feel like a teammate instead of noise.

Step 7: Handle long-running responses

Slack expects an HTTP 200 within three seconds of an event, but an LLM call plus tool calls can take longer. n8n's Slack Trigger already acknowledges the event immediately and processes the rest of the workflow asynchronously, so this is usually not a problem out of the box. If you see "This app took too long to respond" in the channel, check that your Slack Trigger node is set to respond immediately rather than waiting on the workflow's last node, this is a toggle in the node's response settings.

For a nicer UX during long tool calls, add an early Slack node that posts a placeholder ("Looking into that...") and later a "Update a Message" call to replace it with the final answer using the returned message ts.

Step 8: Test and activate

  1. Toggle the workflow Active.
  2. In Slack, @mention the bot in a channel it has been invited to, or DM it directly.
  3. Watch the n8n Executions panel; each Slack event should produce one execution (confirming your dedup filter works), passing cleanly through the AI Agent node, and ending with a posted Slack message.
  4. Check that a second message in the same thread gets a reply that shows awareness of the first message, confirming memory is wired to the thread key correctly.

Adding tools: a practical example

A common first tool is a knowledge-base lookup. Add an HTTP Request tool node connected to the AI Agent, configured to call your internal search API or a vector database's query endpoint. Give it a tool description like: "Search the internal knowledge base for a query string and return the top matching documents." The agent will call this automatically when a user asks something that looks like a documentation question, and skip it for small talk. Test this by asking a question you know is in the knowledge base and one you know is not; the agent should call the tool for the first and answer directly (or say it does not know) for the second.

A second common tool is "escalate to a human," implemented as a Slack node that posts into a specific ops channel with the original question and thread link. Give the agent a clear rule in the system prompt for when to use it, for example, when the user explicitly asks for a human, or after it has failed twice to answer confidently.

Production considerations

  • Rate limits: Slack's chat.postMessage has per-workspace rate limits. If your bot handles high-traffic channels, batch or debounce rather than posting on every single event.
  • Error handling: add an Error Trigger workflow that catches failures in the main bot workflow and posts a fallback message ("Something went wrong, retrying...") instead of leaving the user with silence.
  • Memory backend: window buffer memory is fine for testing, but for production, back it with Postgres or Redis so context survives an n8n restart and you can inspect conversation history for debugging.
  • Secrets: store the Slack bot token, signing secret, and LLM API key as n8n credentials, never as plain text in node parameters, so they do not leak into workflow exports.
  • Access control: if the bot has tools that touch internal systems, restrict which Slack channels or users can trigger those tools, either in the IF node logic or inside the tool's own backend.

FAQ

Does the n8n Slack bot need a public server? Yes, Slack's Events API needs to reach your n8n webhook URL over HTTPS. n8n Cloud gives you this automatically. Self-hosted, you need a reachable domain with a valid certificate, or a tunnel for local development.

Can I use a slash command instead of mentions? Yes. Add a Slack Trigger configured for slash commands (or a plain Webhook node pointed at the slash command's request URL), then feed the command text into the same AI Agent setup. Slash commands are synchronous by default, so you generally need to acknowledge immediately and send the real answer via a follow-up response_url call.

How do I stop the bot from replying to every message in a channel? Only subscribe to app_mention and message.im events rather than message.channels. That way the bot only fires when directly addressed or DMed, not on every message in a channel it belongs to.

Which LLM should I use for the chat model node? Any provider n8n supports will work with this pattern; the workflow structure does not change. Pick based on the tool-calling reliability and context window your use case needs, and keep the model choice in the chat model node's dropdown so you can swap it without editing the rest of the workflow.

How do I keep conversation memory from growing unbounded? Use a Window Buffer Memory with a fixed turn count (for example, the last 10 exchanges) rather than unbounded memory, and key it by thread timestamp so old threads do not bleed into new ones. For long-lived support-style bots, pair this with a summarization step that condenses older turns instead of dropping them outright.

Can the same workflow support multiple Slack workspaces? Yes, if you use Slack's OAuth flow to install the app per workspace and store the resulting bot token per team ID, then look up the right credential dynamically in the workflow using the team_id field from the incoming event. For a single internal bot, a single hardcoded credential is simpler and sufficient.