OpenClaw Slack Setup: Threads, Permissions, and Production-Safe Defaults

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?

Required Slack scopes (minimum set)

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:

Essential bot scopes

Scope
What breaks without it
Why it matters
chat:write
Bot can't send messages
Core functionality
channels:history
No context from public channels
Agent needs message history
groups:history
No context from private channels
Same as above
im:history
DM conversations fail
Required for direct messages
mpim:history
Group DMs don't work
Multi-party direct messages
users:read
Can't resolve @mentions
User lookup for routing
app_mentions:read
Misses @bot mentions
Trigger detection

According to Slack's OAuth documentation, these scopes follow the Conversations API pattern—you only need scopes for conversation types you'll touch.

Scopes you probably want

Scope
What it enables
Production impact
reactions:read + reactions:write
Ack reactions, user feedback
Visual confirmation
pins:read + pins:write
Pin important messages
Knowledge management
files:read + files:write
Handle attachments
Document workflows
emoji:read
Custom emoji context
Team culture awareness

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%.

What you can skip initially

  • groups:write — only needed if OpenClaw creates private channels (it doesn't by default)
  • channels:read — the wizard handles channel resolution at setup
  • chat:write.public — dangerous; lets bot post to channels it's not in

The Slack permissions reference details each scope's behavior. Cross-reference against OpenClaw's official Slack docs to avoid over-scoping.

Connect + verify events

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.

Socket Mode setup (step-by-step)

  1. Create app at api.slack.com/apps
  2. Basic InformationSocket Mode → toggle ON
  3. App-Level Tokens → Generate with connections:write scope
  4. Copy xapp-... token
  5. OAuth & Permissions → add bot scopes from table above
  6. Install to workspace → copy xoxb-... token

The xapp- token enables Socket Mode. The xoxb- token is your bot's identity. Slack's OAuth guide explains the token hierarchy.

Event subscription checklist

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.

Verification test

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:

  1. App Token has connections:write scope
  2. Socket Mode is toggled ON in app settings
  3. Firewall allows WebSocket connections
  4. OpenClaw has network access (check gateway/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.

User token (optional but powerful)

OpenClaw can use a user token (xoxp-...) for read operations. This is useful when you want the bot to:

  • Read message history from before it joined
  • Access private channels without explicit invitation
  • Search across workspace content

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.

Threading that works

This took me four days to stabilize. The docs say replyToMode controls threading. Reality: it's more nuanced.

The three threading modes

Mode
Behavior
Use case
off
Replies in main channel (unless message was already threaded)
Default; keeps visibility high
first
First reply threads, rest go to main channel
Balance context vs clutter
all
Everything threads
Contained conversations

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.

Per-chat-type threading (the fix)

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.

Manual threading tags

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."

Channel allowlist/denylist

Default behavior without explicit config: OpenClaw accepts messages from ALL channels where it's invited.

That's a production risk.

Lock it down

{
  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.

Channel-specific overrides

Per-channel config supports:

  • requireMention — bot only responds when @mentioned
  • users — allowlist specific users
  • tools — override tool policies (deny dangerous ones)
  • skills — filter which agent skills apply
  • systemPrompt — add channel-specific context

I use systemPrompt to inject channel norms: "This is #legal. Responses must cite sources and avoid speculation."

DM pairing (default security)

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.

Troubleshooting: missing replies, permission errors

Missing replies in DMs

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.

Thread replies go to main channel

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.

Permission denied on reactions

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.

Bot ignores mentions in private channels

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.

File uploads fail

Symptom: not_allowed_token_type

Fix: Add files:write to bot scopes. User tokens can't upload on behalf of bot.

Messages from other bots ignored

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.

History limit tuning

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.

Slash command conflicts

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.

DM threading still broken

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.

Hey, I’m Hanks — a workflow tinkerer and AI tool obsessive with over a decade of hands-on experience in automation, SaaS, and content creation. I spend my days testing tools so you don’t have to, breaking down complex processes into simple, actionable steps, and digging into the numbers behind “what actually works.”

Apply to become Macaron's first friends