Why send forms to Slack
For an agency, a B2B SaaS team, or any business that runs in Slack all day, every email notification is a context switch. The lead goes to your inbox, you forward it to the team channel, someone responds 20 minutes later. By then the prospect has already filled out the same form on a competitor's site.
Slack-native delivery cuts that loop to seconds. The notification lands in #leads with the prospect's name, email, message, source, and a button to reply. Your team responds in-thread, marks it with a reaction when handled, and the channel becomes a working pipeline. splitforms ships Slack-formatted messages out of the box — no custom payload required.
Step 1 — Create the Slack webhook
Slack split webhooks into "Apps" in 2020, so the path is two steps deep but still under three minutes:
- Go to
api.slack.com/appsand click Create New App → From scratch. - Name it (e.g. "splitforms"), pick your workspace, click Create.
- In the left sidebar click Incoming Webhooks, toggle Activate Incoming Webhooks to On.
- Scroll down, click Add New Webhook to Workspace.
- Pick the destination channel (e.g.
#leads) and click Allow. - Copy the webhook URL. It looks like
https://hooks.slack.com/services/T0/B0/abcXYZ....
That URL is the only credential you need. Anyone holding it can post to the channel as your app — store it as a secret. If it leaks you can rotate by clicking the trash icon next to the webhook in the same screen and adding a new one.
Step 2 — Connect it to splitforms
In your splitforms dashboard open the form, click Webhooks → Add, choose the Slack integration type, and paste the URL.
Webhook URL: https://hooks.slack.com/services/T0/B0/abcXYZ...
Type: Slack (auto-formats as Block Kit)
Events: submission.createdClick Send test event. A formatted message lands in the channel within ~250ms with header, sender info, and message body. Submit a real form to confirm end-to-end.
Wiring it programmatically (Terraform, CI, an admin script) hits the same endpoint:
curl -X POST https://splitforms.com/api/forms/frm_5fK9.../webhooks \
-H "Authorization: Bearer YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.slack.com/services/T0/B0/abcXYZ",
"type": "slack",
"events": ["submission.created"]
}'Block Kit: the Slack payload, explained
Slack's message format is called Block Kit. A "message" is a top-level text string (used as the notification preview and as accessibility fallback) plus a blocks array of layout blocks. The blocks you care about for form notifications are header, section, divider, and context.
POST https://hooks.slack.com/services/T0/B0/...
Content-Type: application/json
{
"text": "New submission from Ada Lovelace",
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "📬 New contact form submission" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*Name:*\nAda Lovelace" },
{ "type": "mrkdwn", "text": "*Email:*\n<mailto:ada@example.com|ada@example.com>" },
{ "type": "mrkdwn", "text": "*Source:*\nhomepage" },
{ "type": "mrkdwn", "text": "*Spam score:*\n0.02" }
]
},
{
"type": "section",
"text": { "type": "mrkdwn", "text": "*Message*\n>>> Hi — testing the Slack pipeline." }
},
{
"type": "context",
"elements": [
{ "type": "mrkdwn", "text": "<https://splitforms.com/dashboard/submissions/sub_abc|Open in splitforms ↗>" }
]
}
]
}splitforms generates this automatically when you pick the Slack type. The section-with-fields pattern renders as a two-column grid on desktop and stacks on mobile — perfect for form fields. The >>>at the start of the message body is Slack's blockquote markdown, which makes long submissions render with a colored left border.
Want a different layout? splitforms accepts a custom Block Kit template per webhook, with the same {{ fields.name }} Mustache syntax used elsewhere in the dashboard. Build the layout with Slack's Block Kit Builder at app.slack.com/block-kit-builder, paste the JSON in, and replace literal values with template variables.
Channel routing: one form, many channels
Real teams want different forms — or different submissions to the same form — going to different channels. Three common patterns:
- One form, multiple channels. Add multiple Slack webhooks to the form. Each posts in parallel. Common for fan-out:
#leadsfor the team,#auditfor the archive,#urgentif a priority field is set. - Conditional routing by field. Set a webhook condition like
fields.deal_size == "enterprise"in the splitforms dashboard. Only matching submissions trigger that delivery. Pair with a second condition forfields.deal_size != "enterprise"to split the firehose. - Form per channel. If the forms are genuinely different (sales contact vs support ticket vs careers), create separate splitforms forms with separate access keys, each with its own Slack webhook. Cleaner audit trail and you can scope spam settings per form.
See the lead notifications use case for the conditional routing config and the splitforms docs for the full Block Kit template reference.
Cost comparison vs Zapier and Make
The reason this post exists at all is that "Webhook → Slack" is a $50/mo line item if you go via a no-code tool. Here's the math at 2,000 form submissions per month — a realistic volume for a modest B2B contact form:
| Tool | Monthly cost | Setup time | Reliability |
|---|---|---|---|
| splitforms (native) | $5/mo Pro | 5 min | 1 hop, HMAC, 24h retries |
| Zapier (Webhook → Slack) | $49/mo Pro (2k tasks) | 10 min | 2 hops, occasional task delays |
| Make / Integromat | $29/mo Core (10k ops) | 15 min | 2 hops, 5-min batched runs |
| n8n self-hosted | $5/mo VPS + your time | 1–2 hr | 1 hop, you maintain it |
At 2k submissions/month splitforms native is $44/mo cheaper than Zapier and significantly faster (one HTTP hop instead of two). The splitforms 4-year plan ($59 one-time, 15,000 submissions/month for 48 months) makes the math even better at higher volume — Zapier still scales linearly with task count.
The Zapier path makes sense if you already have a complex Zap with branching logic. For straight "form to Slack", native is the obviously correct choice. See pricing for the full tier breakdown.
Mentions, threads, and reactions
For a high-priority form (sales demo request, support escalation), an inline @-mention in the Block Kit message gets a real human attention faster than a notification badge:
{
"text": "Sales demo requested",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<!subteam^S012ABCDEF> demo request from {{ fields.company }}"
}
},
{ /* ...rest of the form fields... */ }
]
}S012ABCDEF is the user-group ID for, say, @sales-team. Get it from Slack → People & user groups → user group → Copy member ID. For an individual person use <@U01ABCD2EFG>with the user's member ID.
Two team conventions worth adopting:
- Reply in-thread, not in the channel.Slack's threading keeps the form's "conversation" (your reply, internal discussion, "closed: customer churned") attached to the original submission. The channel stays scannable.
- Use a reaction emoji to mark handled. 👀 = looking at it, ✅ = responded, 🗄️ = archived. Cheap, visible, no separate tool.
For more advanced workflows — auto-creating a thread per submission, tagging by source, posting to a private channel and a public one in parallel — see the webhook reference.
Tech support and troubleshooting
The five Slack webhook issues we see most often:
- Slack returns invalid_payload — JSON shape is malformed or a block is missing a required field. Validate the payload in Block Kit Builder first, then re-paste into splitforms.
- channel_not_found — The webhook channel was archived or the app was removed. Recreate the webhook from api.slack.com/apps and update the URL.
- @mentions render as plain text — Slack expects user IDs (<@U01...>) and group IDs (<!subteam^S01...>), not handles. Right-click in Slack > Copy member ID for the correct format.
- Message arrives slowly — Slack rate-limits ~1 msg/sec per webhook. splitforms backs off automatically; if you're hammering it, fan out to additional webhooks instead of one.
- Free workspace history disappears — Slack free workspaces hide messages older than 90 days. Add a second destination (email, Notion, Google Sheets) for long-term archive.
The full webhook spec, retry policy, and HMAC signature are in the splitforms docs and the API reference. Plan and billing questions live in the splitforms FAQ.
FAQ
Why use Slack for form notifications instead of email?
For B2B teams that already live in Slack, every email notification adds inbox noise and round-trip latency. A Block Kit message in #leads or #sales lands inside the same client your team checks every minute, lets you reply in-thread, assign with reactions, and resolve without leaving the channel. The integration takes about five minutes.
Do I need a Slack paid plan to use Incoming Webhooks?
No. Incoming Webhooks work on every Slack plan including the free tier. The only caveat is that on free workspaces messages older than 90 days disappear from the visible history — but they still trigger notifications when posted. For long-term archive, also send to email or a database.
Can I post to multiple Slack channels from one form?
Yes. Add multiple webhooks to the same form, each created against a different channel. Useful for an agency posting client form leads into both an internal #ops channel and a private client-shared channel, or for routing a single form to #sales-large-deals and a backup #all-leads.
How does this compare to Zapier or Make for Slack notifications?
Zapier's 'Webhook to Slack' Zap is roughly $50/mo on the Pro tier once you cross 750 tasks/month — and every form submission is one task. splitforms ships native Slack delivery for $0 on the free tier (1,000 submissions/month) and $5/mo on the Pro tier. Same outcome, identical latency, no third-party SaaS in the middle, and no audit-log paperwork to add another vendor.
Can I @mention a person or group in the Slack message?
Yes — use the user/group ID, not the @-handle. The syntax is <@U01ABCD2EFG> for a user and <!subteam^S012ABCDEF> for a user group. Find the IDs by right-clicking the user/group → 'Copy member ID'. Mentions work in both plain content and inside Block Kit section blocks.
What's the rate limit on Slack Incoming Webhooks?
Slack documents 'roughly one message per second' per webhook with short bursts allowed. For a contact form that's effectively unlimited. splitforms automatically backs off and retries if Slack returns 429 (rate limited).
Will the Slack message look different on mobile vs desktop?
Block Kit renders consistently across desktop, mobile, and the web client. The main difference is that very wide tables wrap on mobile — keep field values short, and rely on the section block's inline fields layout rather than ASCII tables.
Next steps
- Add a Discord destination beside Slack — Send form submissions to Discord.
- Persist leads to a database — Airtable or Notion.
- Sign every webhook with HMAC — webhook security guide.
- Compare splitforms vs the legacy options — splitforms vs Formspree.