Why send forms to Discord
Email is fine. Discord is faster. For a community admin, gaming clan, indie game studio, or freelance dev whose project lives in a Discord server, an inbound contact form posting to #leads or #contactmeans the entire team sees it the moment it arrives — no inbox triage, no "did you see that email" back-and-forth, and no $50/mo Zapier subscription routing what is fundamentally a single HTTP POST.
Discord webhooks are free, unlimited (30/min per URL is the only cap), and accept rich embeds with colored sidebars, fields, timestamps, and clickable links. splitforms ships a Discord preset that maps your form fields to embed fields automatically — no custom payload required for the common case. Below covers the full setup including embed customization and multi-server routing.
Step 1 — Create the Discord webhook
In any server you own (or have Manage Webhooks permission on):
- Click the server name at the top → Server Settings.
- Scroll down the left sidebar to Integrations.
- Click Webhooks → New Webhook.
- Set the name (e.g. "splitforms"), pick the destination channel (e.g.
#leads), optionally upload an avatar. - Click Copy Webhook URL. It looks like
https://discord.com/api/webhooks/123.../abc.... - Click Save Changes.
Treat the URL as a secret. Anyone who has it can post to that channel as "splitforms" with no further authentication. If it leaks, hit Delete Webhookin the same screen and create a new one — the URLs are not recoverable but they're also disposable.
Step 2 — Connect it to splitforms
In your splitforms dashboard open the form, click Webhooks → Add, and choose the Discord integration type. Paste the URL and save.
Webhook URL: https://discord.com/api/webhooks/123456789/abc-token...
Type: Discord (auto-formats as embed)
Events: submission.createdClick Send test event. A formatted message appears in the channel within about 250ms.
If you'd rather wire it from code (Terraform, GitHub Actions, an internal admin script), the API is symmetric:
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://discord.com/api/webhooks/123/abc",
"type": "discord",
"events": ["submission.created"]
}'The Discord payload, explained
Discord expects JSON in a specific shape. The two top-level fields you care about for form notifications are content (plain text, supports markdown and mentions) and embeds (an array of rich cards).
POST https://discord.com/api/webhooks/.../...
Content-Type: application/json
{
"username": "splitforms",
"avatar_url": "https://splitforms.com/icon.png",
"content": "New submission",
"embeds": [
{
"title": "Contact form",
"description": "From your homepage",
"color": 5814783,
"timestamp": "2026-05-02T12:00:00.000Z",
"fields": [
{ "name": "Name", "value": "Ada Lovelace", "inline": true },
{ "name": "Email", "value": "ada@example.com", "inline": true },
{ "name": "Message", "value": "Hi — testing.", "inline": false }
],
"footer": { "text": "splitforms · spam score 0.02" }
}
]
}splitforms generates this payload automatically when you pick the Discord type. The color field is a decimal RGB integer (5814783 is hex #58B5FF — a nice cool blue). Discord will reject the request silently if the embed exceeds 6,000 characters total or if any field value is over 1,024 characters; splitforms truncates oversized values to keep the post live.
Custom embed formatting
The default mapping is "every form field becomes an embed field, in submission order". If you want different — title from the message, color based on a priority field, footer with a CRM link — splitforms supports a Mustache-style template you paste into the webhook config.
{
"username": "Splitforms",
"embeds": [{
"title": "{{ fields.subject | default: 'New contact form submission' }}",
"description": "{{ fields.message }}",
"color": {{ fields.priority == "high" ? 16711680 : 5814783 }},
"url": "https://splitforms.com/dashboard/submissions/{{ id }}",
"fields": [
{ "name": "From", "value": "{{ fields.name }} <{{ fields.email }}>", "inline": false },
{ "name": "Source","value": "{{ fields.source | default: 'web' }}", "inline": true },
{ "name": "Spam", "value": "{{ spam_score }}", "inline": true }
],
"timestamp": "{{ submitted_at }}",
"footer": { "text": "Open in dashboard ↗" }
}]
}The url on the embed makes the title clickable, which is by far the highest-leverage thing you can do — one click and you're in the splitforms dashboard with the full submission, attachments, and reply form. Add the same template to your contact form template if you maintain shared snippets across projects.
Pick the embed color thoughtfully. Red (16711680 / #FF0000) for high-priority forms, green (5763719 / #57F287) for newsletter signups, blue for the default. Color is the fastest visual signal in a busy channel.
Role pings and thread routing
For an "a human must respond now" form (sales, support, refund), an embed alone gets ignored. Mention a role in content:
{
"content": "<@&987654321098765432> new high-priority lead",
"allowed_mentions": { "parse": ["roles"] },
"embeds": [ /* ... */ ]
}The role ID comes from Server Settings → Roles → right-click → Copy ID (Developer Mode in your Discord settings → Advanced must be enabled). The allowed_mentions.parse: ["roles"] guard prevents accidental @everyone or @here pings if a user happens to put one in their form message — a small detail that has saved more than one community admin from server-wide chaos.
To keep the channel tidy, post each submission into its own thread. Append ?thread_id=... to the webhook URL, or include thread_id in the JSON body, or use thread_name to auto-create a new thread per post:
// Auto-create a thread named after the submitter
{
"thread_name": "{{ fields.name }} — {{ submitted_at | date: '%b %d' }}",
"embeds": [ /* ... */ ]
}This pattern works really well for support: every contact form opens a thread, the team replies in-thread, and the channel itself stays scannable. Pair with the lead notifications use case for the full routing playbook.
Multiple servers, one form
Add as many webhooks as you like to one form. Each delivery is independent — splitforms posts in parallel and retries each one on its own schedule.
# Same form, three Discord destinations
Webhook 1: agency-internal server, #leads
Webhook 2: client A's community server, #contact-form
Webhook 3: archive-only server, #all-forms (private, audit log)
# Plus an email destination, plus a webhook to your CRM.
# splitforms fans out automatically.For agencies running multiple Discord communities this is the cheapest possible "multi-tenant inbound" setup. There's no per-destination cost — the splitforms free tiercovers 1,000 submissions per month with unlimited webhooks. Compare to Zapier's "one Zap per destination" pricing model and the math gets ugly fast.
See the full webhook payload spec, retry policy, and HMAC verification details in the splitforms docs.
Tech support and troubleshooting
Five issues cover almost every Discord webhook headache:
- 401 Unauthorized from Discord — The webhook URL was deleted or rotated. Recreate it under Server Settings > Integrations > Webhooks and paste the new URL into splitforms.
- Message looks like raw JSON — The payload type was set to Generic JSON instead of Discord. Switch the integration type to Discord so splitforms formats it as an embed.
- Role @mention shows as plain text — Discord requires the literal <@&ROLE_ID> syntax (with ampersand) and Developer Mode enabled to copy the role ID. Verify the ID is numeric, not the role name.
- Embed truncates with ... — You hit Discord's 1,024-char per-field or 6,000-char total limit. Shorten field templates or move long content into a clickable url back to the dashboard.
- Test event silently disappears — Either the channel was deleted, the bot lacks Send Messages permission, or the webhook URL is malformed. Re-test with a curl POST to isolate.
For HMAC verification, retry policy, and the full event schema, jump to the splitforms docs or the API reference. Account questions go in the splitforms FAQ.
FAQ
Why route form submissions to Discord instead of email?
If your community already lives in Discord — gaming clan, indie studio, open-source project, agency — keeping inbound leads in the same client your team checks all day means faster response times. Discord embeds also render structured fields better than plain-text email, and you can @ping the right person without forwarding.
Do I need a Discord bot, or is a webhook enough?
A webhook is enough for one-way posting from a form. Webhooks don't require a bot account, don't need OAuth, and ship in two minutes. You'd only need a full bot if you wanted the form responder to read replies, manage roles, or interact with users in DMs — none of which a contact form does.
Can I send to multiple Discord servers from one form?
Yes. Add multiple webhooks to the same form in splitforms, each pointing at a different server's channel. Every submission fans out to all of them. Useful for agencies that staff multiple client servers, or for backing up to a private 'archive' server while a public server gets the same alerts.
How do I @mention a role when a form submits?
Discord webhooks support role pings via the content field with the syntax <@&ROLE_ID>. Right-click the role in server settings → Copy ID (developer mode must be on). To prevent accidental @everyone or @here pings, set the allowed_mentions field on the webhook payload to { parse: ['roles'] } so only role mentions are honored.
Can I post submissions to a specific thread instead of the channel?
Yes — append ?thread_id=THREAD_ID to the webhook URL or include thread_id in the JSON body. This is great for keeping each new lead in its own thread so replies stay scoped instead of cluttering the main channel.
What's the rate limit on Discord webhooks?
30 requests per minute per webhook URL. For a contact form that's effectively unlimited — you'd need 30 submissions per minute to hit it. If you do, splitforms automatically batches and retries with backoff.
Will Discord show form data inline or as a downloadable file?
Inline as a rich embed when you stay under Discord's limits: 6,000 total characters per embed, 1,024 per field value, max 25 fields. splitforms truncates oversized values with an ellipsis and adds a link to the full submission in the dashboard.
Next steps
- Add Slack notifications side-by-side: Send form submissions to Slack.
- Push the same lead into a database: Airtable or Notion.
- Cut bot traffic before it hits Discord: stop contact form spam.
- Compare splitforms vs Web3Forms on webhook depth: splitforms vs Web3Forms.