Connecting Bubble to Slack is the easiest communication integration available — Slack's Incoming Webhooks need no Authorization header, just a POST with JSON to a URL you keep in a Private API Connector header. For posting to multiple channels, reading history, or sending Block Kit messages, use a Slack Bot token (xoxb-) in a Private Bearer header. Both paths are server-side in Bubble so credentials stay out of the browser.
| Fact | Value |
|---|---|
| Tool | Slack |
| Category | Communication |
| Method | Bubble API Connector |
| Difficulty | Beginner |
| Time required | 30–60 minutes |
| Last updated | July 2026 |
Two paths for Slack in Bubble — Incoming Webhooks vs. Bot Token
Slack is uniquely beginner-friendly in Bubble because its Incoming Webhook approach requires no Authorization header at all. The webhook URL (e.g., `https://hooks.slack.com/services/T.../B.../XXXX`) is itself the credential — a single POST with a JSON body `{"text": "your message"}` delivers a notification to the target channel. The 'Private' checkbox in Bubble's API Connector prevents this URL from appearing in browser network requests when the call runs from a Backend Workflow.
The more powerful path — posting to multiple channels dynamically, reading channel history, or sending interactive Block Kit messages with buttons — requires a Slack Bot token. You create a Slack App, add OAuth scopes, install it to your workspace, and copy the Bot User OAuth Token (xoxb-...). This token goes in the Authorization header of your Web API calls, marked Private.
Both paths are available on all Slack plans, including Slack Free. The complexity difference is significant: Incoming Webhooks take about 15 minutes to configure; the Bot token path takes 30–60 minutes including scope setup and app installation.
Integration method
Bubble API Connector with the Incoming Webhook URL stored in a Private header (for simple notifications) or a Slack Bot token (xoxb-) in a Private Bearer Authorization header (for multi-channel and interactive use cases).
Prerequisites
- A Slack workspace where you have admin rights or permission to create apps (slack.com/apps)
- The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → API Connector by Bubble)
- For the Bot token path or inbound webhooks: a Bubble paid plan (Starter or above) for Backend Workflows
Step-by-step guide
Create a Slack app and activate Incoming Webhooks
Go to api.slack.com/apps and click 'Create New App.' Choose 'From scratch,' give your app a name (like 'Bubble Alerts'), and select your Slack workspace. After the app is created, you land on the app dashboard. In the left sidebar, click 'Incoming Webhooks.' Toggle 'Activate Incoming Webhooks' to On. Scroll down and click 'Add New Webhook to Workspace.' Slack shows a channel picker — select the channel where you want messages delivered (e.g., #general or #notifications) and click 'Allow.' Slack generates a Webhook URL that looks like: `https://hooks.slack.com/services/T0XXXXXXX/B0XXXXXXX/XXXXXXXXXXXXXXXXXXXX` Copy this URL. This is the only credential you need for the Incoming Webhook path — treat it like a password. If it is compromised, anyone can post to your Slack channel. You can regenerate it from the Incoming Webhooks page if needed.
1// Slack Incoming Webhook URL format:2https://hooks.slack.com/services/T[WorkspaceID]/B[AppID]/[Secret]34// Test in browser DevTools console or curl:5// curl -X POST -H 'Content-Type: application/json' \6// --data '{"text":"Test from Bubble setup"}' \7// https://hooks.slack.com/services/T.../B.../XXXXPro tip: You can create multiple webhooks — one per Slack channel. If you need to notify different channels from different workflows, generate a webhook for each channel and store them as separate API Connector calls.
Expected result: Your Slack app is created, Incoming Webhooks is active, and you have a webhook URL for your chosen Slack channel.
Configure the Bubble API Connector for Slack Incoming Webhook
In your Bubble editor, go to Plugins → API Connector. Click 'Add another API' and name it 'Slack.' Under this API group, click 'Add another call' and name it 'Send Slack Message.' Set the method to POST. For the URL, you have two options: - Option A (simpler, one channel): paste the full webhook URL directly into the URL field. This hardcodes the channel. - Option B (more flexible): put just `https://hooks.slack.com/services/` in the URL field and use a shared header named `X-Webhook-Path` with the rest of the URL — but Bubble doesn't support URL concatenation this way cleanly. Simpler: put the full URL in the header's value and mark it Private. Best practice for Bubble: put the full webhook URL in the Base URL field of the entire Slack API group (not the individual call URL field). Mark the Base URL as Private. The individual call URL can then be empty or just `/`. This way the webhook URL never appears in the browser. Set the Content-Type header to `application/json`. In the body section, select 'JSON body' and add a single parameter `text` with type 'text' (dynamic). You can also add a `username` parameter (optional display name override) and `icon_emoji` for a custom bot avatar. Click 'Initialize call.' Enter a test message like 'Hello from Bubble setup' in the text field and run it. Check your Slack channel — the message should appear within seconds.
1// API Connector: Slack → Send Slack Message2// Method: POST3// URL: [Webhook URL — stored in Base URL field, marked Private]4//5// Headers:6// Content-Type: application/json7//8// Body (JSON):9{10 "text": "<dynamic_message_text>",11 "username": "Bubble App",12 "icon_emoji": ":bubble:"13}1415// Example with Block Kit (for richer messages):16{17 "text": "New signup: <dynamic_user_name>",18 "blocks": [19 {20 "type": "section",21 "text": {22 "type": "mrkdwn",23 "text": "*New user signed up*\nName: <dynamic_user_name>\nEmail: <dynamic_user_email>"24 }25 }26 ]27}Pro tip: If the Initialize call succeeds but you see no message in Slack, check that you selected the correct workspace and channel when generating the webhook. The Initialize call returns an HTTP 200 with body 'ok' on success — any other response indicates an error.
Expected result: The API Connector call initializes successfully (response body: 'ok') and a test message appears in your Slack channel within a few seconds.
Set up a Slack Bot token for multi-channel Web API access (advanced path)
If you need to post to multiple channels dynamically, read message history, or send interactive Block Kit components, use the Slack Web API with a Bot token instead of (or in addition to) Incoming Webhooks. In your Slack app at api.slack.com/apps, go to 'OAuth & Permissions' in the left sidebar. Scroll to 'Scopes' → 'Bot Token Scopes.' Click 'Add an OAuth Scope' and add: - `chat:write` — required to post messages - `channels:read` — to list public channels (optional) - `chat:write.public` — to post to channels the bot hasn't joined (optional) After adding scopes, scroll up and click 'Install to Workspace.' Slack shows an authorization screen — click 'Allow.' After installation, copy the 'Bot User OAuth Token' that starts with `xoxb-`. Back in Bubble's API Connector, add a second call under the Slack API group (or create a new API group). Name it 'Post to Channel.' Set method to POST, URL to `https://slack.com/api/chat.postMessage`. Add a header `Authorization: Bearer xoxb-...your-token...` and mark it Private. Add Content-Type: application/json. In the JSON body, add `channel` (dynamic — the channel name or ID like '#general' or 'C0XXXXXX') and `text` (dynamic message). Optionally add `blocks` for Block Kit. Click Initialize call — Bubble will need you to fill in a real channel value (like '#general') to get a valid response for schema detection.
1// API Connector: Slack → Post to Channel2// Method: POST3// URL: https://slack.com/api/chat.postMessage4//5// Headers:6// Authorization: Bearer xoxb-your-token-here // mark Private7// Content-Type: application/json8//9// Body (JSON):10{11 "channel": "<dynamic_channel_name_or_id>",12 "text": "<dynamic_message_text>",13 "blocks": [14 {15 "type": "section",16 "text": {17 "type": "mrkdwn",18 "text": "<dynamic_formatted_message>"19 }20 }21 ]22}Pro tip: Slack's Tier 3/4 endpoints (like chat.postMessage) allow ~50+ messages per minute per workspace. For high-volume apps, batch your Slack notifications rather than posting one per event. For reference: Tier 1 endpoints like channels.list allow only 1 request per minute.
Expected result: The chat.postMessage call initializes successfully. The response shows `{"ok": true, "channel": "C0XXXXXX", "ts": "..."}` and the test message appears in the specified Slack channel.
Build a Bubble workflow that sends a Slack message on trigger
Now connect your Slack API Connector call to a real Bubble workflow event. The most common pattern is notifying your team when something important happens in your app: a new user signs up, a payment is received, an order is placed, or a support request comes in. In the Bubble workflow editor, create or open a workflow with a triggering event. Common triggers: 'A new Thing is created' (choose your data type), 'Button is clicked' (for manual notification buttons), or 'A condition is true' (for event-based monitoring). Add an action: 'Plugins → API Connector - Slack - Send Slack Message' (or 'Post to Channel' for the Bot token path). In the text field, compose your message using dynamic expressions from the triggered data. For example: 'New signup: [User's name] ([User's email]) joined at [Current date/time formatted]'. For richer messages, use Slack's mrkdwn format (not HTML) in the text field — asterisks for bold (*bold*), underscores for italic (_italic_), backticks for code, and line breaks with \n. To run this securely server-side, wrap the Slack action in a Backend Workflow and trigger it with 'Schedule API Workflow' from the frontend. This ensures the webhook URL never appears in browser DevTools, even if you accidentally leave it non-private.
1// Workflow: Notify Slack on New User Signup2// Trigger: When User is created3// Action: Plugins → Slack → Send Slack Message4// text: "*New signup* \nName: " + User's name + "\nEmail: " + User's email5// + "\nSigned up at: " + Current date/time formatted as "MMM D, YYYY h:mm A"67// For Block Kit (richer formatting):8// text field: "New user: " + User's name9// blocks field (JSON):10[11 {12 "type": "section",13 "text": {14 "type": "mrkdwn",15 "text": "*New signup detected*\n*Name:* " + User's name + "\n*Email:* " + User's email16 }17 },18 {19 "type": "context",20 "elements": [{21 "type": "plain_text",22 "text": "Signed up " + Current date/time formatted23 }]24 }25]Pro tip: Use Bubble's 'Schedule API Workflow' (at 'Current date/time') to run Slack notifications as a Backend Workflow rather than a client-side action. This is more secure (webhook URL is truly server-side) and also more reliable — client-side actions can fail if the user closes the browser before the action completes.
Expected result: When the trigger event fires (new user created, button clicked, etc.), a formatted Slack message appears in your channel within a few seconds. The Bubble Logs tab → Workflow logs shows the API call completed successfully.
Enable inbound Slack events with Bubble Backend Workflows
To receive events FROM Slack (slash commands, button interactions, event subscriptions), you need to expose a public endpoint from Bubble and configure it in your Slack app. This requires a Bubble paid plan since Backend Workflows (API Workflows) are needed. In Bubble, go to Settings → API → check 'This app exposes a Workflow API.' Copy your app's API endpoint base URL (format: `https://appname.bubbleapps.io/api/1.1/wf/`). In the Backend Workflows section of your Bubble editor, click 'Add workflow' and name it `slack_event`. In the workflow, click 'Detect data' and Bubble will listen for the next incoming request to auto-detect the schema. At the same time, in your Slack app dashboard at api.slack.com/apps → Event Subscriptions (or Slash Commands), paste your Bubble Backend Workflow URL as the endpoint: `https://appname.bubbleapps.io/api/1.1/wf/slack_event`. Slack sends a one-time URL verification challenge: a POST with `{"type": "url_verification", "challenge": "somestring"}`. Your Backend Workflow must respond with the same challenge value. In Bubble, add a 'Return data from API' action in the workflow and map the `challenge` field from the detected request data to the response body. For slash command payloads: Slack sends `application/x-www-form-urlencoded` data (not JSON). The `payload` field for interactive components is also form-encoded. In your Backend Workflow, detect these as text fields and use Bubble's 'Detect data' to parse `command`, `text`, `user_id`, and `channel_id`. For interactive button payloads, the data arrives as a URL-encoded `payload` parameter containing a JSON string — use Bubble's JSON operator to parse it.
1// Bubble Backend Workflow URL format:2https://appname.bubbleapps.io/api/1.1/wf/slack_event34// Slack sends URL verification challenge (one-time, when you register the endpoint):5// POST body: {"type": "url_verification", "challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXToZi"}6// Your Backend Workflow must return: {"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXToZi"}78// Slash command POST body (form-encoded, not JSON):9// token=xxx&command=/create-task&text=Buy+groceries&user_id=U0XXXXXX&channel_id=C0XXXXXX1011// Detect fields in Backend Workflow:12// command: text13// text: text14// user_id: text15// channel_id: textPro tip: Interactive component payloads (button clicks in messages) arrive as a form-encoded `payload` parameter containing a JSON string — not as parsed JSON. In Bubble, detect it as a text field named `payload`, then use the JSON operator or a 'Detect data from text' approach to extract the nested fields like action_id, block_id, and the triggering user's information.
Expected result: Your Bubble Backend Workflow endpoint passes Slack's URL verification challenge. You can trigger the workflow by running a slash command in Slack and see the incoming data in Bubble's Backend Workflow run logs.
Test, secure, and monitor your Slack integration
Before shipping your Slack integration to production, run through this checklist: 1. Privacy verification: In Bubble's Logs tab → Network logs, check that the Slack webhook URL or xoxb- token does not appear in any browser-originated request. If you see it in the network tab, you have a client-side action that needs to be moved to a Backend Workflow or have the Private checkbox enabled. 2. Error handling: Add error handling to your Slack notification workflow. If the Slack API returns an error (non-200 response or `{"ok": false}`), Bubble can log the error to a Logs data type or send an internal alert. Common errors: `invalid_payload` (malformed JSON in the body), `channel_not_found` (wrong channel name), `not_in_channel` (Bot token not added to channel). 3. Channel membership for Bot tokens: If using the xoxb- Bot token path, invite your Slack bot to the channels it needs to post in by typing `/invite @your-bot-name` in each channel. Without this, chat.postMessage returns `not_in_channel` unless you have the `chat:write.public` scope. 4. Webhook URL rotation: If your Slack Incoming Webhook URL is ever exposed, regenerate it from api.slack.com/apps → Incoming Webhooks → Revoke and regenerate. Update the URL in Bubble's API Connector. The old URL stops working immediately. RapidDev's engineers have shipped Slack integrations across dozens of Bubble apps — for complex multi-workspace or Block Kit setups, reach out at rapidevelopers.com/contact.
1// Testing the Slack webhook from Bubble Logs:2// 1. Go to Bubble editor → Logs tab3// 2. Run a workflow that triggers your Slack action4// 3. In Logs → Workflow logs, find the API call entry5// 4. Verify the Status shows 200 and the response body shows 'ok'67// Bubble privacy check: open your deployed app in a browser8// → Open DevTools → Network tab9// → Trigger the Slack workflow from the frontend10// → Filter by 'hooks.slack.com' or 'slack.com/api'11// → If you see a request hitting Slack directly from the browser,12// your action is client-side — move it to a Backend WorkflowPro tip: Slack Incoming Webhooks are regenerated (not rotated) when you reinstall the Slack app or remove and re-add the app from the workspace. If your team ever uninstalls and reinstalls the Slack app, all existing webhook URLs break silently — your Bubble workflows will show HTTP 200 but messages stop appearing. Monitor this with periodic test pings or a webhook health-check workflow.
Expected result: Your Slack integration sends messages reliably. No Slack credentials appear in browser network requests. The Bubble Logs tab shows successful 200 responses for all Slack API calls. Your Slack channel receives formatted notifications from your Bubble app.
Common use cases
Instant Slack alerts for new form submissions or sign-ups
Notify your team's Slack channel every time a new user signs up, a form is submitted, or a payment is received. The workflow fires server-side in Bubble, posts a formatted message to your designated channel, and your team sees it in real time without leaving Slack.
When a new User record is created, trigger a Backend Workflow that POSTs to the Slack Incoming Webhook with the message 'New signup: [User's name] ([User's email]) at [Current date/time]'.
Copy this prompt to try it in Bubble
Dynamic multi-channel notifications based on record type
Route different app events to different Slack channels — support tickets to #support, sales leads to #sales, errors to #engineering. Using the Slack Web API's chat.postMessage with a Bot token, you can specify the channel dynamically per workflow run.
When a Support_Ticket record is created, POST to Slack chat.postMessage with channel='#support' and the ticket details. When a Lead record is created, POST to channel='#sales' with the lead's name, company, and score.
Copy this prompt to try it in Bubble
Receive Slack slash command inputs in Bubble
Let your team trigger Bubble workflows from Slack by creating a slash command that posts to your Bubble Backend Workflow endpoint. Users type /create-task in Slack and the payload arrives at your Bubble API, creating a Task record automatically.
Enable Bubble's Workflow API, set the endpoint as the slash command URL in your Slack app settings, and create a Backend Workflow that detects the 'text' field from the Slack payload and creates a Task with that text as the title.
Copy this prompt to try it in Bubble
Troubleshooting
Slack webhook returns HTTP 200 but no message appears in the channel
Cause: The webhook URL was regenerated after the Slack app was reinstalled, or it was revoked. The old URL still returns 200 (Slack acknowledges the request) but silently discards the message because the webhook is no longer valid.
Solution: Go to api.slack.com/apps → your app → Incoming Webhooks. Check if the webhook URL in Bubble matches the active webhook URL shown in the dashboard. If the app was reinstalled or the webhook was revoked, click 'Add New Webhook to Workspace' to generate a fresh URL and update it in Bubble's API Connector.
chat.postMessage returns {"ok": false, "error": "not_in_channel"}
Cause: The Slack bot (identified by the xoxb- token) has not been added as a member to the channel it is trying to post in. Without `chat:write.public` scope, bots must be channel members to post.
Solution: In the Slack channel where you want the bot to post, type `/invite @your-bot-name` to add the bot as a member. Alternatively, add the `chat:write.public` scope to your Slack app's Bot Token Scopes (OAuth & Permissions → Scopes), then reinstall the app to regenerate the token.
Bot token (xoxb-) is visible in browser DevTools network requests
Cause: The Slack Web API call is configured as a client-side Bubble action without the Authorization header marked Private, or the call is triggered directly from a client-side workflow rather than a Backend Workflow.
Solution: Open Bubble's API Connector → Slack → Post to Channel. Find the Authorization header and check the 'Private' checkbox. Then move the Slack action from a client-side workflow to a Backend Workflow (Bubble paid plan required). Trigger the Backend Workflow from the frontend using 'Schedule API Workflow' at 'Current date/time.'
Slack URL verification challenge fails — Slack keeps retrying and shows 'Your URL didn't respond with the value of the challenge parameter'
Cause: The Bubble Backend Workflow is not returning the challenge value in the response body, or the workflow is not deployed and active yet (Backend Workflows in draft state do not respond to external requests).
Solution: In the Backend Workflow, add a 'Return data from API' action. Map the `challenge` field from the workflow's detected incoming data to the response. Make sure the workflow is saved and the Bubble app is deployed (not just in development mode). The Workflow API endpoint only responds to external POSTs when the app is live.
Best practices
- Always mark the Slack Incoming Webhook URL 'Private' in the Bubble API Connector header or Base URL. Even though the webhook has no auth header, the URL itself is a credential — exposing it in browser DevTools lets anyone post to your Slack channel.
- Run Slack notification actions inside Backend Workflows rather than client-side actions. This keeps credentials server-side and ensures the action completes even if the user navigates away before the API call finishes.
- Store your Slack Bot token (xoxb-) only in the API Connector Authorization header marked Private — never in a Bubble database field or page state variable, where it could be read by other workflows or exposed via the Data API.
- Handle Slack's `not_in_channel` error proactively: invite your bot to every channel it needs to post in using `/invite @your-bot-name`, or add the `chat:write.public` scope if you need to post to channels dynamically.
- Use Block Kit for richer messages rather than plain text. Block Kit messages are easier to scan and support structured data like user names, amounts, timestamps, and action buttons. Build and test Block Kit JSON at api.slack.com/block-kit/building before embedding in Bubble.
- Monitor your Slack webhook health. If the Slack app is ever uninstalled and reinstalled, all Incoming Webhook URLs become invalid silently. Consider running a periodic Backend Workflow that sends a test ping and alerts your team if it fails.
- For inbound Slack events, always return HTTP 200 within 3 seconds — Slack retries timed-out webhooks up to 3 times and flags your endpoint as unreliable. If processing takes longer (e.g., creating database records), acknowledge immediately with a 200 response and queue the heavy work as a separate Backend Workflow.
Alternatives
Microsoft Teams uses a Workflows-app webhook (replacing deprecated Outlook Connectors) with a more complex Adaptive Card JSON format for messages. Slack's Incoming Webhook with a simple JSON text body is significantly easier to set up. Choose Teams if your organization mandates Microsoft 365 and users are not in Slack.
Twilio delivers notifications via SMS and WhatsApp to phone numbers rather than a team chat platform. Use Twilio when you need to reach external customers or users who are not in your Slack workspace. Slack is better for internal team alerts where all recipients have Slack accounts.
SendGrid delivers notifications via email, with richer formatting options and delivery tracking. Use SendGrid when you need an auditable email trail, delivery receipts, and the ability to reach users without Slack. Use Slack for instant team alerts where speed and channel-based routing matter more than email compliance features.
Frequently asked questions
Do I need a paid Slack plan for this integration?
No. Slack Incoming Webhooks and Bot tokens are available on all Slack plans including Slack Free. There is no per-message cost and no plan-gating on the API features described in this guide. The limitation is on the Bubble side: Backend Workflows (required for the most secure setup) need a Bubble paid plan.
What is the difference between Incoming Webhooks and the Slack Web API with a Bot token?
Incoming Webhooks are tied to a single channel and require only a URL to post — simple but inflexible. The Slack Web API with a Bot token lets you post to any channel dynamically, read message history, send interactive Block Kit messages with buttons, and access other Slack features. Use Incoming Webhooks for quick notification setups; use the Bot token when you need dynamic channel routing or user interactions.
How do I format text with bold, links, or line breaks in Slack messages?
Slack uses mrkdwn formatting (not HTML or Markdown). Use *text* for bold, _text_ for italic, ~text~ for strikethrough, `code` for inline code, and \n for line breaks. For hyperlinks, use <URL|display text>. In Bubble's dynamic text fields, escape the mrkdwn syntax carefully — Bubble does not process it, it just passes the string to Slack.
Can I post Slack messages from a free Bubble plan?
Yes, for client-side Bubble actions. You can trigger a Slack Incoming Webhook from a client-side workflow on Bubble Free. The limitation is security: without Backend Workflows (paid plan), the webhook URL can appear in browser network requests if the 'Private' checkbox is missed. For a secure production setup, use a Bubble paid plan and Backend Workflows.
My Slack messages are arriving but the timestamps show in UTC, not my local timezone. How do I fix this?
Slack displays timestamps in each user's local timezone automatically — you do not need to convert the timestamp. However, if you include a timestamp as plain text in the message body (e.g., from Bubble's 'formatted as' operator), format it server-side to a human-readable string like 'Jan 15, 2026 3:30 PM EST' using Bubble's date formatting operators before including it in the Slack message text.
Can I send Slack messages to a specific user (DM) instead of a channel?
Yes, using the Slack Web API's chat.postMessage endpoint with a Bot token. Instead of a channel name, pass the user's Slack Member ID (found in their Slack profile, format: U0XXXXXX) as the `channel` parameter. The bot must have the `im:write` scope to send DMs. Incoming Webhooks cannot send DMs — only the Web API supports direct messaging.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation