What this automation does
Every submission from every form lands in the right table, in the right format, exactly once, and if anything fails you know about it the same day.
- Receive. Typeform, Jotform and Tally send each submission by webhook. Google Forms posts through a short Apps Script or a linked Sheet trigger.
- Acknowledge quickly. The receiver returns success right away and processes the submission afterward, so the form provider never times out and resends.
- Validate and normalize. Code checks required fields and converts formats: lowercase emails, phone numbers in E.164 format, ISO dates, two-letter state codes, and multi-select answers as arrays.
- Map. Stable field identifiers, not question labels, map to database columns. Renaming a question on the form does not break the mapping.
- Upsert. The row is inserted or updated using the submission ID as a unique key. A contact table is matched on email so the same person submitting twice links to one record.
- Enrich (optional). A small model classifies free-text answers or pulls structured details out of long responses.
- Notify and reconcile. The right team gets a Slack or email alert. Failures go to a dead-letter table, and a daily job compares submission counts between the form and the database.
When it is worth building
This is worth doing when form data drives real work, such as applications, service requests, registrations or intake, and the current setup is a Google Sheet that several people edit, filter and occasionally break. It is also worth it when several forms describe the same kinds of records and you want them in one place, or when other systems need to read the data.
It is not worth building for a single low-volume form that a native integration already handles well. A one-step Zapier connection or the form tool’s own Airtable integration will do. Build when reliability matters, when there are several forms, or when the target is a relational database with constraints. If the job is really keeping two business apps in step with each other, our data sync guide is the closer match.
Architecture
| Layer | What we use | Why |
|---|---|---|
| Forms | Typeform, Jotform, Tally, Google Forms | Keep whatever form tool your team already likes |
| Receiver | n8n Webhook node, or a Supabase Edge Function for simple cases | A stable endpoint that answers quickly |
| Validation | Code with a schema per form | Bad data is rejected with a reason, not stored |
| Database | Postgres or Supabase for relational data, Airtable for editable views | Constraints, joins and history in one place |
| Dead-letter store | A failed submissions table with the raw payload | Nothing is lost, everything can be replayed |
| AI (optional) | Claude Haiku 5.5 | Fast, cheap classification of free-text answers |
| Reconciliation | Scheduled n8n job against each form’s API | Catches anything webhooks missed |
Choosing between Postgres and Airtable as the destination is covered in our Airtable vs Postgres comparison. If you prefer a managed Postgres with an admin UI, our Supabase notes explain the setup.
How to build it
- Design the data model first. Decide tables, column types and constraints before touching the forms. Model entities, such as contacts, organizations and requests, rather than one table per form.
- Use stable field identifiers. Map on field IDs or references, not question text. Typeform lets you set a custom reference on each question, which keeps mappings readable.
- Secure the webhook. Verify the payload signature where the provider supports one (Typeform does). Otherwise, include a long secret token in the webhook URL and reject requests without it.
- Write an idempotent upsert. In Postgres, use an insert with an on-conflict clause on the submission ID. Retries and replays then update the same row instead of adding a duplicate.
- Validate and route failures. Rejected submissions go to the dead-letter table with the raw payload and the reason. Someone reviews that table daily for the first month.
- Copy uploaded files. File links from form providers can expire or require a login. Download attachments to your own storage, such as Supabase Storage or S3, and store that path instead.
- Backfill history. Export past submissions through the form’s API and run them through the same pipeline, which doubles as a full test.
- Schedule reconciliation. Each night, compare counts and IDs for the last few days and insert anything missing.
The downloadable starter template below gives you the webhook receiver, validation and Postgres upsert to adapt to your forms.
What breaks in production
- Form edits. Someone adds a question, deletes one or changes a dropdown option, and data stops landing in the right column. Alert when a payload contains a field the mapping does not know.
- Duplicate rows. Webhook retries without a unique key create copies. The submission ID constraint is not optional.
- Junk submissions. Bots find public forms. Use the form tool’s spam protection and reject entries that fail basic validation.
- Type mismatches. “N/A” or “about 50” in a number field breaks inserts. Validate before writing and keep the original text alongside the parsed value.
- Missing hidden fields. UTM parameters and referral codes are only present when the link included them. Treat them as nullable.
- Sensitive data. Health, financial or identity information needs care. For healthcare data covered by HIPAA, every vendor that stores or processes it (form tool, automation host, database) must offer a BAA on the plan you use, or that data must not pass through them.
Timeline and cost
One to three forms writing into a single database typically take one to two weeks. Lumeor builds this in the range of $2,500 to $6,000. The upper end covers several forms, file handling, AI enrichment and reconciliation jobs. If you self-host n8n, our cloud vs self-hosted comparison covers the trade-offs, and running costs are mostly hosting.
How to measure success
- Submissions in the form tool versus rows in the database (these should match exactly)
- Minutes from submission to row available
- Failed submissions per week and time to replay them
- Duplicate records found in periodic audits
- Hours of manual copying and cleanup removed
- Share of rows passing validation on the first attempt