n8n recipe
n8n is the self-hostable alternative when you want Zapier-style flows without per-task pricing or a third party seeing your data. Cloud version exists too if you don't want to run it yourself.
Setup
1. Add a Webhook node
In your n8n workflow: Add node → Webhook.
- HTTP Method: POST
- Path: something unique like
formspring-contact - Response Mode: Immediately (respond 200 fast; do work after)
- Authentication: None (we'll do HMAC ourselves)
Save and execute the workflow once to get the test URL. For production, copy the production URL.
2. Verify the signature
Drop a Code node right after the Webhook node:
const crypto = require('crypto');
const sig = $input.first().json.headers['x-formspring-signature'];
const raw = $input.first().json.body; // raw body string
const secret = $env.FORMSPRING_SECRET;
const expected = crypto.createHmac('sha256', secret).update(raw).digest('hex');
if (
sig.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
) {
throw new Error('Invalid signature');
}
return [{ json: JSON.parse(raw) }];
For this to work, set the Webhook node's Raw Body option to true so body is the unparsed string. Without that, the JSON gets re-serialized and the HMAC won't match.
Store FORMSPRING_SECRET in n8n's environment (n8n cloud: workflow variables; self-hosted: .env).
3. Wire it up in Formspring
Webhooks → Add webhook → Generic. Paste the n8n production URL.
4. Build downstream steps
Common patterns:
- HTTP Request → forward to your API with auth.
- Set + Postgres/MySQL → insert into your DB directly.
- IF → branch on
body.type(created vs flagged) or onbody.payload.emaildomain. - Email → send a templated reply via SMTP/SendGrid/Postmark.
- AI → run the message through an LLM for classification, then route.
Self-hosted vs cloud
| Self-hosted | n8n cloud | |
|---|---|---|
| Per-execution cost | Free (your infra) | Metered |
| Data residency | Yours | n8n's |
| Setup effort | Docker + reverse proxy | Sign up |
| Best for | Sensitive data, high volume | Quick start, low ops |
For Formspring-style payloads on a moderately busy form, self-hosted on a small VM (1 vCPU, 2 GB RAM) handles thousands of submissions per day comfortably.
Idempotency
The Webhook node fires once per HTTP request. If a Formspring retry hits, you'll see the same submission_id again. Add an IF node early that queries your dedupe table (or a Redis SET NX) on body.submission_id and short-circuits if already processed.