Slack AI Chatbot: Enterprise Integration Guide
Add an AI assistant to your Slack workspace with the Bolt SDK. Thread support, slash commands, and enterprise features.
Molted Team
Molted.cloud
Slack is where work happens. Adding an AI assistant directly in Slack means your team can get answers, generate content, and automate tasks without leaving their workflow. This guide covers building a Slack AI bot with the Bolt SDK and deploying it for your workspace.
Why Slack AI bots matter for teams
- Context where you work - No switching to ChatGPT or Claude web
- Team-wide access - Everyone can use it, not just those with AI subscriptions
- Channel-specific assistants - Different bots for engineering, sales, support
- Integration potential - Connect to your internal tools and data
- Audit trail - All interactions logged in Slack
Create a Slack app
- Go to api.slack.com/apps
- Click "Create New App" → "From scratch"
- Name it and select your workspace
Configure OAuth scopes
Go to OAuth & Permissions → Scopes → Bot Token Scopes. Add:
app_mentions:read- Know when mentionedchat:write- Send messagesim:history- Read DM historyim:read- Access DMsim:write- Send DMs
Enable Socket Mode
Socket Mode lets you run the bot locally without a public URL. Go to Socket Mode → Enable. Generate an app-level token with connections:write scope.
Subscribe to events
Go to Event Subscriptions → Enable. Subscribe to bot events:
app_mentionmessage.im
Install to workspace
Go to Install App → Install to Workspace. Copy the Bot User OAuth Token.
Project setup with Bolt
mkdir slack-ai-bot
cd slack-ai-bot
npm init -y
npm install @slack/bolt @anthropic-ai/sdk dotenvCreate .env:
SLACK_BOT_TOKEN=xoxb-your-bot-token
SLACK_APP_TOKEN=xapp-your-app-token
ANTHROPIC_API_KEY=your-anthropic-keyBasic Slack AI bot
require('dotenv').config();
const { App } = require('@slack/bolt');
const Anthropic = require('@anthropic-ai/sdk');
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
appToken: process.env.SLACK_APP_TOKEN,
socketMode: true,
});
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
// Store conversations per channel/DM
const conversations = new Map();
// Handle mentions in channels
app.event('app_mention', async ({ event, say }) => {
const channelId = event.channel;
const text = event.text.replace(/<@[A-Z0-9]+>/g, '').trim();
if (!text) {
await say('How can I help you?');
return;
}
await handleMessage(channelId, text, say);
});
// Handle DMs
app.event('message', async ({ event, say }) => {
// Only handle DMs, not channel messages
if (event.channel_type !== 'im') return;
// Ignore bot messages
if (event.bot_id) return;
const channelId = event.channel;
const text = event.text;
await handleMessage(channelId, text, say);
});
async function handleMessage(channelId, text, say) {
// Get or create conversation
if (!conversations.has(channelId)) {
conversations.set(channelId, []);
}
const history = conversations.get(channelId);
// Add user message
history.push({ role: 'user', content: text });
// Trim history
if (history.length > 20) {
history.splice(0, history.length - 20);
}
try {
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
system: `You are a helpful assistant in a Slack workspace.
Keep responses professional and concise.
Use Slack formatting: *bold*, _italic_, \`code\`, \`\`\`code blocks\`\`\`.`,
messages: history,
});
const reply = response.content[0].text;
history.push({ role: 'assistant', content: reply });
await say(reply);
} catch (error) {
console.error('Error:', error);
await say('Sorry, I encountered an error. Please try again.');
}
}
(async () => {
await app.start();
console.log('Slack bot is running!');
})();Enterprise-ready Slack AI
OpenClaw includes Slack integration with SSO and admin controls.
Start free trialThread support
Slack threads are essential for organized conversations:
app.event('app_mention', async ({ event, say, client }) => {
const threadTs = event.thread_ts || event.ts;
const channelId = event.channel;
// Use thread ID for conversation context
const contextId = `${channelId}-${threadTs}`;
if (!conversations.has(contextId)) {
conversations.set(contextId, []);
}
const history = conversations.get(contextId);
const text = event.text.replace(/<@[A-Z0-9]+>/g, '').trim();
history.push({ role: 'user', content: text });
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: history,
});
const reply = response.content[0].text;
history.push({ role: 'assistant', content: reply });
// Reply in thread
await client.chat.postMessage({
channel: channelId,
thread_ts: threadTs,
text: reply,
});
});Slash commands
Add slash commands for specific actions. In your Slack app settings, go to Slash Commands → Create New Command.
// /ask command for quick questions
app.command('/ask', async ({ command, ack, respond }) => {
await ack();
const question = command.text;
if (!question) {
await respond('Usage: /ask <your question>');
return;
}
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{ role: 'user', content: question }],
});
await respond({
response_type: 'in_channel', // visible to everyone
text: response.content[0].text,
});
});
// /summarize command for channel summaries
app.command('/summarize', async ({ command, ack, respond, client }) => {
await ack();
// Get recent messages from channel
const result = await client.conversations.history({
channel: command.channel_id,
limit: 50,
});
const messages = result.messages
.filter(m => !m.bot_id)
.map(m => m.text)
.reverse()
.join('\n');
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{
role: 'user',
content: `Summarize these Slack messages in bullet points:\n\n${messages}`,
}],
});
await respond(response.content[0].text);
});Interactive messages
app.event('app_mention', async ({ event, client }) => {
await client.chat.postMessage({
channel: event.channel,
text: 'How can I help?',
blocks: [
{
type: 'section',
text: { type: 'mrkdwn', text: 'What would you like to do?' },
},
{
type: 'actions',
elements: [
{
type: 'button',
text: { type: 'plain_text', text: 'Summarize channel' },
action_id: 'summarize_channel',
},
{
type: 'button',
text: { type: 'plain_text', text: 'Generate report' },
action_id: 'generate_report',
},
],
},
],
});
});
app.action('summarize_channel', async ({ ack, body, client }) => {
await ack();
// ... summarization logic
});Slack AI without the setup
Molted deploys OpenClaw with Slack ready. OAuth install, done.
Webhook deployment (production)
For production without Socket Mode:
const { App, ExpressReceiver } = require('@slack/bolt');
const receiver = new ExpressReceiver({
signingSecret: process.env.SLACK_SIGNING_SECRET,
});
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
receiver,
});
// Your event handlers...
(async () => {
await app.start(process.env.PORT || 3000);
console.log('Slack bot running on port 3000');
})();Set the Request URL in Event Subscriptions to https://your-domain.com/slack/events.
Security best practices
- Verify requests - Bolt does this automatically with signing secret
- Limit permissions - Only request scopes you need
- Rate limit users - Prevent API cost abuse
- Audit logging - Log all AI interactions for compliance
OpenClaw for Slack
OpenClaw supports Slack via the Bolt SDK internally. Benefits over DIY:
- OAuth flow handled - Users install via button click
- Multi-workspace support - One deployment, many workspaces
- Admin dashboard - See usage, manage access
- Model switching - Change between Claude/GPT without code
Related guides
- Discord Bot with AI - For community servers
- Microsoft Teams AI Bot - Enterprise Teams integration
- Self-Hosted AI Guide - All channel options compared
Slack AI for your team
OpenClaw on Molted. Install to Slack in one click. 24-hour free trial.
24-hour free trial · No credit card required · Cancel anytime