Build and Send a Slack Block Kit Message with Node.js
Learn how to construct a Block Kit payload, send it via the @slack/web-api SDK, and avoid common errors. Includes limits, a concrete example, and verification steps.
08 Oct 2026, 00:43 UTC

Key Takeaway
To reliably post a rich Slack message you must build a valid Block Kit JSON payload, use the @slack/web-api Node SDK to call chat.postMessage, and respect the platform’s limits. A common source of failures is duplicate block_id values or exceeding the 50‑block ceiling.
What is Block Kit?
Block Kit is Slack’s declarative UI framework for messages, modals, and home tabs. Each UI element is a block (e.g., section, image, actions, divider) described in JSON. The API validates the payload before rendering.
Crafting a Minimal Payload
Below is a minimal example that sends a section block with a button. Replace the placeholder <YOUR_BOT_TOKEN> with a bot token that has the chat:write scope.
// index.js
const { WebClient } = require('@slack/web-api');
const token = process.env.SLACK_BOT_TOKEN || '<YOUR_BOT_TOKEN>';
const client = new WebClient(token);
async function postBlockKit() {
const payload = {
channel: '<CHANNEL_ID>',
text: 'Fallback text', // appears if blocks fail to render
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: '*Hello from Block Kit!*'
}
},
{
type: 'actions',
block_id: 'action_section',
elements: [
{
type: 'button',
text: {
type: 'plain_text',
text: 'Click me'
},
action_id: 'button_click',
value: 'button_value'
}
]
}
]
};
const result = await client.chat.postMessage(payload);
console.log(result);
}
postBlockKit().catch(console.error);
Run with node index.js. The message should appear in <CHANNEL_ID> with a button that, when clicked, triggers an interactive message payload to your app.
Limits & Constraints
| Limit | Value |
|---|---|
| Maximum blocks per message | 50 |
| Maximum characters in all block text combined | 2,000 |
| Maximum actions per actions block | 10 |
| Maximum length of accessibility_label | 200 characters |
| Maximum block_id length | 255 characters |
Violating these limits returns a 400 error with details in the error field of the response.
Common Pitfalls
- Duplicate
block_idvalues in the same message prevent interactive components from working. Eachblock_idmust be unique. - Unescaped newlines or unsupported block types trigger
invalid_payloaderrors. - Missing
textfallback can cause a 400 if the blocks cannot render. - Exceeding the 2000‑character limit in combined text fields results in
message_too_long. - Using a user token with insufficient scopes (e.g., missing
chat:write) leads tonot_in_channelorinvalid_auth.
Verification Checklist
- Run the script and inspect the console for
ok: trueand noerrorfield. - Open the target channel and confirm the message renders with the expected blocks.
- Click the button to ensure an
interactive_messagepayload is sent to your app’s request URL. - Use Slack’s API tester to manually send the same payload and compare responses.
- Check the
chat.postMessageresponse forts(timestamp) to confirm the message was posted.
When to Rollback
Only change state if you alter message content or send new messages. If you need to delete or update a message, use chat.delete or chat.update with the message ts and channel ID.
Limitations & Future Changes
Slack occasionally updates Block Kit specifications. Always refer to the latest docs before deploying. Legacy workspace apps may require enabling Block Kit in the app settings.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.