All docs
2 min read

Discord recipe

Two ways: native Discord integration (no code) or a generic webhook to a Discord channel webhook URL.

Option A — Native Discord integration

  1. In Discord: Channel settings → Integrations → Webhooks → New webhook. Name it, copy the URL.
  2. In Formspring: Webhooks → Add integration → Discord.
  3. Paste the URL. Save.

We render submissions as a Discord embed: form name as title, key fields as embed fields, a small footer with the timestamp and a link back to the submission in your dashboard.

Channel mentions: prefix the form name with @here or @channel-id and we'll respect the mention in the embed's content. Use sparingly.

Option B — Generic webhook through your own handler

Use this when you want to format embeds yourself, route to different channels by field value, or filter what gets posted.

  1. In Discord, create a channel webhook. Copy the URL.
  2. In Formspring, Webhooks → Add webhook → Generic. Use your handler's URL. Save the signing secret.
  3. In your handler: verify, transform, POST to Discord.
// Cloudflare Worker / Lambda / etc.
import { createHmac, timingSafeEqual } from 'node:crypto';

export default {
  async fetch(req, env) {
    const sig = req.headers.get('x-formspring-signature') ?? '';
    const raw = await req.text();
    const expected = createHmac('sha256', env.FORMSPRING_SECRET)
      .update(raw)
      .digest('hex');

    if (
      sig.length !== expected.length ||
      !timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
    ) {
      return new Response('unauthorized', { status: 401 });
    }

    const body = JSON.parse(raw);
    const fields = Object.entries(body.payload).map(([name, value]) => ({
      name,
      value: String(value).slice(0, 1024),
      inline: name.length < 16,
    }));

    await fetch(env.DISCORD_WEBHOOK_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        username: 'Formspring',
        embeds: [
          {
            title: `New submission — ${body.form_name}`,
            url: `https://app.formspring.io/submissions/${body.submission_id}`,
            color: 0x5865f2,
            fields,
            footer: { text: body.submission_id },
            timestamp: body.received_at,
          },
        ],
      }),
    });

    return new Response('ok');
  },
};

Notes

  • Discord's embed limits: 25 fields, 1024 chars per field value, 6000 chars total. Truncate generously.
  • Replies don't loop back to Formspring — Discord webhooks are one-way.
  • Rotate the Discord webhook URL if it leaks; Discord treats it as a secret.

What's next