Follow a complete create Slack bot build tutorial from app setup to deployment. Learn OAuth scopes, events, slash commands, modals, file uploads, and production hosting.
Slack App Foundations
A Slack app is the container for your bot, commands, and UI. It listens with the Events API and acts with the Web API. Use messages, modals, App Home, and interactive components to create complete workflows. For context on Slack features, see our guides on what Slack is, Slack AI, and omnichannel support.
Workflow Builder
- Fast automation
- Built in triggers
- Limited logic
Marketplace Apps
- Thousands of choices
- Two way sync
- Vendor limits
Custom App
- Full control
- Private data
- Dev effort
How To Create a Slack Bot Checklist
Plan scopes and features. Create the app in a dev workspace.
- Store secrets in environment variables.
- Add minimal bot token scopes.
- Install the app to get the xoxb token.
- Wire Events API and Interactivity to a public HTTPS URL.
- Implement app_mention and one helpful command.
- Add a modal for structured input.
- Upload a sample file.
- Deploy to Heroku or Lambda.
- Update URLs in the Slack dashboard and reinstall if scopes changed.
Create the App and Get Credentials
Register your app, then secure your tokens. You need the Client ID, Client Secret, and Signing Secret for OAuth and request verification.
Create the App
Go to the Slack API dashboard. Create a new app from scratch in a dev workspace. Name it clearly, for example support-bot.
Collect Credentials
Copy Client ID, Client Secret, and Signing Secret. Store them in environment variables, not in code.
Add Scopes
Under OAuth and Permissions, add bot token scopes like chat:write, app_mentions:read, and commands. Keep scopes minimal.
Install to Workspace
Click Install App to get your xoxb- bot token. Reinstall when you change scopes.
Initialize a Bolt Project
Use Bolt to handle signatures, OAuth, and event plumbing. Choose Node or Python.
Node.js Starter
Install dependencies and post a message.
npm init -y
npm install @slack/bolt dotenv
// app.js
require('dotenv').config();
const { App } = require('@slack/bolt');
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});
app.event('app_mention', async ({ event, say }) => {
await say(Hi <@${event.user}>);
});
(async () => {
await app.start(process.env.PORT || 3000);
console.log('⚡️ Bolt app running');
})();
Python Starter
Create a virtual env and reply to a mention.
python3 -m venv venv
source venv/bin/activate
pip install slack-bolt python-dotenv
app.py
import os
from dotenv import load_dotenv
from slack_bolt import App
load_dotenv()
app = App(token=os.environ["SLACK_BOT_TOKEN"],
signing_secret=os.environ["SLACK_SIGNING_SECRET"])
@app.event("app_mention")
def handle_mention(event, say):
say(f"Hi <@{event['user']}>")
if name == "main":
app.start(port=int(os.environ.get("PORT", 3000)))
Listen to Events and Add Slash Commands
Subscribe to app_mention and define a command like /echo.
// Node: simple /echo app.command('/echo', async ({ command, ack, say }) => { await ack(); await say(`You said: ${command.text}`); });
# Python: simple /echo @app.command("/echo") def echo(ack, say, command): ack() say(f"You said: {command['text']}")
Create Interactive Messages and Modals
Use Block Kit for buttons and menus. Open modals for structured input.
// Node: open a modal from a command app.command('/survey', async ({ ack, body, client }) => { await ack(); await client.views.open({ trigger_id: body.trigger_id, view: { type: 'modal', callback_id: 'survey_view', title: { type: 'plain_text', text: 'Feedback Survey' }, submit: { type: 'plain_text', text: 'Submit' }, blocks: [ { type: 'input', block_id: 'feedback_block', label: { type: 'plain_text', text: 'Your feedback' }, element: { type: 'plain_text_input', action_id: 'feedback_input', multiline: true } } ] } }); }); app.view('survey_view', async ({ ack, body }) => { await ack(); const user = body.user.id; const feedback = body.view.state.values.feedback_block.feedback_input.value; console.log(`Feedback from ${user}: ${feedback}`); });
Upload and Share Files
Use the modern upload flow or SDK helpers. Request files:write.
# Python SDK helper: files_upload_v2 from slack_sdk import WebClient client = WebClient(token=os.environ["SLACK_BOT_TOKEN"]) client.files_upload_v2( channel="C12345678", file="report.txt", title="Weekly Report", initial_comment="Here is the report" )
Deploy to Production
Choose Heroku for simplicity, AWS Lambda for serverless, or a VPS for full control. Always serve HTTPS.
Heroku
Add a Procfile and env vars. Push to the Heroku remote.
# Procfile (Node) web: node app.js # Procfile (Python) web: gunicorn app:app
AWS Lambda
Use AwsLambdaReceiver and API Gateway. Deploy with Serverless.
const { App, AwsLambdaReceiver } = require('@slack/bolt'); const receiver = new AwsLambdaReceiver({ signingSecret: process.env.SLACK_SIGNING_SECRET }); const app = new App({ token: process.env.SLACK_BOT_TOKEN, receiver }); module.exports.handler = async (event, context, callback) => { const handler = await receiver.start(); return handler(event, context, callback); };
VPS
Run Gunicorn behind Nginx with TLS from Let’s Encrypt.
server { listen 443 ssl; server_name your_domain.com; location / { include proxy_params; proxy_pass http://unix:/home/your_user/mybot.sock; } }
Troubleshooting Slack Bot Errors
If Slack shows a timeout, call ack sooner and send results later. If events do not arrive, verify the public URL and the signing secret. If messages fail, confirm chat.write scope and that the bot is in the channel. If modals fail to open, use the trigger_id within three seconds.
If uploads fail, enable files.write and try the SDK helper. Use logs and retry logic to handle transient errors.
Security and UX Best Practices
Protect tokens and design messages that help users act in place.
Security
- Use env vars for secrets
- Verify signatures on every request
- Request least privilege scopes
- Avoid broad legacy scopes
Reliability
- Ack fast then process
- Use retries and idempotency
- Log and alert failures
UX
- Keep it brief
- Use buttons not links out
- Use App Home for settings
Ship a Slack Native Ticketing Experience
Use Suptask to turn messages into tickets, assign owners, and resolve requests inside Slack. No context switching.
Used by growing teams • 14 day free trial • No credit card required
You Are Ready To Build
Start with events and a single command. Add interactivity and files. Deploy and iterate with tight feedback loops.