Every form tool promises "connect to Google Sheets" â and then charges you $30/month for it. n8n does the same thing in about 15 minutes, free, and you actually own the automation.
Here's how to build a workflow that:
- Receives any form submission via webhook
- Appends a timestamped row to a Google Sheet
- (Optional) fires a Slack alert so your team sees it instantly
Works with Tally, Typeform, Jotform, and plain HTML tags.
Why webhook-based form handling beats native integrations
Native "Sheets integrations" inside form tools are convenient until they're not:
- They break when the form tool updates their API
- They don't let you transform or filter the data before it hits the sheet
- They can't send a Slack alert at the same time
- They cost money
With n8n you get one webhook URL that handles everything, and you can add more steps (CRM write, email confirmation, Slack DM) without rebuilding from scratch.
The workflow
Three steps in a straight line:
Webhook -> Normalise payload -> [Google Sheets append]
\ [Build Slack message -> Slack post]
The Normalise node handles the fact that Tally, Typeform, and raw POST bodies all structure their payloads differently.
Step-by-step setup
1. Create the workflow in n8n
Add a Webhook trigger node:
- Method: POST
- Path: form-submit
- Response mode: Immediately (no waiting)
This gives you a URL like https://your-n8n-instance.com/webhook/form-submit.
2. Add a Function node - normalise the payload
Different form tools send different shapes:
- Tally sends { body: [{ label: "Name", value: "Alice" }, ...] }
- Typeform sends { formResponse: { answers: [...] } }
- Plain HTML POS sends a flat object directly
const raw = $input.first().json;
let fields = raw.body ?? raw.formResponse?.answers ?? raw.data?.fields ?? raw;
if (Array.isArray(fields)) {
const flat = {};
for (const f of fields) {
const key = (f.label || f.field?.title || f.key || '').trim();
const val = f.value ?? f.answer?.text ?? f.answer?.label ?? '';
if (key) flat[key] = val;
}
fields = flat;
}
const now = new Date().toISOString();
return [{ json: { ...fields, _submittedAt: now } }];
3. Google Sheets - Append Row
Add a Google Sheets node:
- Operation: Append
- Document: your sheet ID (from the URL: docs.google.com/spreadsheets/d/THIS_PART/)
- Sheet tab: Responses
- Column mapping: Auto-map input data
You'll need to connect Google Sheets OAuth2 credentials once - n8n walks you through it.
4. (Optional) Slack alert
const data = $json;
const lines = Object.entries(data)
.filter(([k]) => !k.startsWith('_'))
.map(([k, v]) => k + ': ' + String(v).trim());
return [{ json: { blocks: [
{ type: 'header', text: { type: 'plain_text', text: 'New form submission' } },
{ type: 'section', text: { type: 'mrkdwn', text: lines.join('\n') } },
{ type: 'context', elements: [{ type: 'mrkdwn', text: 'Submitted at ' + data._submittedAt }] }
] } }];
5. Configure your form tool
- Tally: Settings -> Integrations -> Webhooks
- Typeform: Connect -> Webhooks
- Plain HTML: set your form action attribute to the webhook URL
6. Test it
Submit a test entry through your form. You should see:
- A new row in your Google Sheet with all fields + a timestamp column
- A Slack message in your chosen channel
What this handles that native integrations don't
- Multi-form fan-out: route different forms to different sheets with an IF node
- Data cleaning: strip whitespace, capitalise names, mask PII in the Function node
- Error alerting: wire error output to Slack
- Chaining: add more steps (Airtable, confirmation email, Trello) without rebuilding
Get the ready-to-import JSON
I'll drop the complete workflow JSON in the comments - import it into n8n and you're five minutes from live.
If you want all three production-ready workflows (this one + a Stripe payment receipt sender + a lead capture/welcome email flow) as a single pack, I keep them at pirateprentice.gumroad.com/l/sxcoe for $29.
Drop a comment if you hit any issues with the Google Sheets OAuth or the payload normaliser - I'm watching.
Top comments (1)
Here is the workflow JSON as promised. Import into n8n via Settings -> Import workflow.
Variables to set: FORM_SHEET_ID (your Google Sheet ID from the URL), SLACK_CHANNEL (#leads or similar). Remove the Slack nodes if you only need Sheets.
Credentials needed: Google Sheets OAuth2 + Slack Bot Token with chat:write scope.
Full JSON in next comment (splitting due to length).