
Hey there, fellow AI tinkerers. If you're connecting OpenClaw to Slack, you've probably hit that moment where the docs say "just add these scopes" and you're wondering: which ones do I actually need? What breaks if I skip one? And why does threading work in channels but fail in DMs?
I spent the last two weeks stress-testing OpenClaw's Slack integration inside our team workspace. Not a demo setup—real channels, real people, real "why did the bot just reply to the wrong thread" moments. Here's what I learned about scopes, threading behavior, and the permission gotchas that aren't in the quickstart.
Core question: Can I set up OpenClaw's Slack connector without giving it more access than it needs, while keeping thread replies stable and channels locked down?

The OpenClaw documentation lists 20+ bot scopes. I tested each one to see what actually breaks when removed.
Here's the real minimum for a working setup:
According to Slack's OAuth documentation, these scopes follow the Conversations API pattern—you only need scopes for conversation types you'll touch.
I ran without reactions:write for three days. Users kept asking "is the bot seeing my message?" Adding ack reactions cut support questions by 60%.
groups:write — only needed if OpenClaw creates private channels (it doesn't by default)channels:read — the wizard handles channel resolution at setupchat:write.public — dangerous; lets bot post to channels it's not inThe Slack permissions reference details each scope's behavior. Cross-reference against OpenClaw's official Slack docs to avoid over-scoping.
Socket Mode is OpenClaw's default. HTTP mode exists for server deployments, but I'm covering Socket here because it's what 90% of users run.

connections:write scopexapp-... tokenxoxb-... tokenThe xapp- token enables Socket Mode. The xoxb- token is your bot's identity. Slack's OAuth guide explains the token hierarchy.

Under Event Subscriptions, enable:
message.channels
message.groups
message.im
message.mpim
app_mention
reaction_added
reaction_removed
member_joined_channel
member_left_channel
channel_rename
pin_added
pin_removed
Why this matters: Missing message.mpim means group DMs silently fail. Missing reaction_removed breaks ack cleanup. I found this by watching CloudWatch logs—OpenClaw logged "unhandled event type" for two days before I noticed.
Create this minimal config:
{
channels: {
slack: {
enabled: true,
appToken: "xapp-...",
botToken: "xoxb-..."
}
}
}
Set via environment:
SLACK_APP_TOKEN=xapp-...
SLACK_BOT_TOKEN=xoxb-...
Start OpenClaw. Check logs for [Slack] Connected via Socket Mode. Send a DM to the bot. If it responds, events are wired correctly.
Common connection failures:
If you see [Slack] Socket connection failed, check these in order:
connections:write scopegateway/configuration)I hit a weird edge case where Socket Mode was enabled, but the app token was created before enabling Socket Mode. The token lacked the internal flags Slack needs. Regenerating the token fixed it.
OpenClaw can use a user token (xoxp-...) for read operations. This is useful when you want the bot to:
Security warning: User tokens act with the installing user's permissions. If that user leaves or is deactivated, the token breaks. Only use for read operations.
Config example:
{
channels: {
slack: {
enabled: true,
appToken: "xapp-...",
botToken: "xoxb-...",
userToken: "xoxp-...",
userTokenReadOnly: true // enforce read-only
}
}
}
Default is userTokenReadOnly: true. Setting it to false lets the user token handle writes if bot token is missing—not recommended for production.
This took me four days to stabilize. The docs say replyToMode controls threading. Reality: it's more nuanced.
Critical bug I hit: With replyToMode: "all", if two messages arrive before the bot replies to the first, the second reply escapes to main channel. Tracked in issue #4424. Workaround: add 500ms delay between user messages in high-traffic channels.
This is the setting that saved my sanity:
{
channels: {
slack: {
replyToMode: "off", // default for channels
replyToModeByChatType: {
direct: "all", // DMs always thread
group: "first" // MPIMs thread first reply only
}
}
}
}
Why it matters: DM threads keep context tight. Channel replies stay visible. Group DMs get one threaded reply then return to main flow.
OpenClaw's threading documentation covers edge cases like [[reply_to_current]] tags for manual control.
For fine-grained control:
[[reply_to_current]] — thread under triggering message[[reply_to:<ts>]] — thread under specific message (use timestamp)I use these in agent prompts: "For code reviews, tag responses with [[reply_to_current]] to keep discussion threaded."
Default behavior without explicit config: OpenClaw accepts messages from ALL channels where it's invited.
That's a production risk.
{
channels: {
slack: {
groupPolicy: "allowlist",
channels: {
"C123ABC": {
allow: true,
requireMention: true
},
"#engineering": {
allow: true,
requireMention: true,
users: ["U123", "U456"], // specific users only
tools: {
deny: ["exec", "elevated"] // block dangerous tools
}
}
}
}
}
}
Security note: Without groupPolicy: "allowlist", any Slack admin can invite your bot to #sensitive-data and start querying it. Set this on day one.
The Slack security best practices documentation emphasizes least-privilege access—this config enforces that principle.
Per-channel config supports:
requireMention — bot only responds when @mentionedusers — allowlist specific userstools — override tool policies (deny dangerous ones)skills — filter which agent skills applysystemPrompt — add channel-specific contextI use systemPrompt to inject channel norms: "This is #legal. Responses must cite sources and avoid speculation."
Default DM policy is pairing mode. Unknown users get a pairing code. Approve via:
openclaw pairing approve slack <code>
To allow anyone (not recommended):
{
channels: {
slack: {
dm: {
policy: "open",
allowFrom: ["*"]
}
}
}
}
I keep pairing mode. It prevented three social engineering attempts in week one—people trying to DM the bot pretending to be team members.
Symptom: Bot sees DM (logs show it), but doesn't reply.
Fix: Check im:history and im:write scopes. Also verify dm.enabled: true in config.
I lost two hours on this. The bot had channels:history but not im:history. Slack treats these as separate conversation types.
Symptom: First reply threads correctly. Second reply breaks out.
Cause: Race condition when multiple messages queue before first reply sends.
Workaround: Set replyToMode: "first" instead of all, or add message throttling in high-traffic channels.
Symptom: missing_scope: reactions:write
Fix: Reinstall app after adding scope. Existing tokens don't auto-upgrade.
From Slack's OAuth scopes guide: new scopes are additive, but you must reinstall to get a fresh token.
Symptom: Works in public channels, silent in private ones.
Fix: Add groups:read and groups:history. Then /invite @bot to the private channel.
Private channels require explicit invitation even with correct scopes. This isn't documented well—found it by reading Slack's Conversations API docs.
Symptom: not_allowed_token_type
Fix: Add files:write to bot scopes. User tokens can't upload on behalf of bot.
Symptom: Bot doesn't react to messages from other bots (like GitHub, Jira).
Default behavior: OpenClaw ignores bot messages to prevent loops.
Override (use carefully):
{
channels: {
slack: {
allowBots: true, // global
channels: {
"#devops": {
allowBots: true, // per-channel
requireMention: true // CRITICAL: prevent bot-to-bot loops
}
}
}
}
}
Warning from production: I enabled allowBots without requireMention in a channel where we had another AI bot running. They replied to each other 47 times in 12 seconds before I killed the process. Always combine allowBots with mention gating.
Default: OpenClaw wraps 50 recent messages into context. For high-traffic channels, this can blow your token budget.
{
channels: {
slack: {
historyLimit: 20, // reduce to 20 for busy channels
channels: {
"#announce": {
historyLimit: 5 // override per channel
}
}
}
}
}
I dropped our main channel from 50 to 15 messages. Token usage fell 40%, response quality stayed the same. Most questions don't need 50 messages of context.
Symptom: /openclaw returns "dispatch failed"
Cause: Command registered in Slack UI but not enabled in OpenClaw config.
Fix:
{
channels: {
slack: {
slashCommand: {
enabled: true,
name: "openclaw" // matches Slack app config
}
}
}
}
Native commands (/help, /status) require channels.slack.commands.native: true. Default is false for Slack because it requires creating a slash command for each native command in the Slack app UI.
As of January 2026, DM threading has known issues (tracked in #2411). Neither replyToMode: "all" nor [[reply_to_current]] tags work reliably in DMs.
Current workaround: Use channel-based communication for threaded discussions. Or set replyToModeByChatType.direct: "off" and accept flat DM conversations.
The OpenClaw team is actively working on this—I saw a PR draft from January 30th adding per-root-message session isolation, which should fix it.
For a simpler ops assistant, create a Macaron account and start automating. Test how your Slack threads, DMs, and channel permissions behave in real scenarios, and see your routine tasks handled consistently without over-scoping your bot.