The problem is nearly always the same. Marketing wants leads in the CRM so sales can work them. Operations wants the same leads in a spreadsheet, because that is where the reporting, the pivot tables and the finance reconciliation already live. Doing both by hand means someone exports a CSV every week, and that person eventually forgets.
This guide covers every route honestly, including the free ones, and is written by people who sell one of the paid options. The bias is disclosed; the facts are checkable against the vendors' own pages.
Route 1: Google Forms plus an Apps Script trigger (free)
A Google Form already writes to a Google Sheet. To get the same submission into a CRM, you attach an Apps Script installable trigger on onFormSubmit and call the CRM's API with UrlFetchApp. This genuinely works, costs nothing, and for a low-volume form it is the right answer.
Where it breaks is the failure path. If the CRM is briefly unreachable, UrlFetchApp throws and the trigger execution fails. Google will retry the trigger, but you do not control the retry policy, and by default nobody is told. The spreadsheet row is already there, so nothing looks wrong; the lead simply never reaches sales. Teams usually discover this weeks later while reconciling.
The other constraint is quota. Apps Script has daily UrlFetch limits that vary by account type, and a consumer Gmail account has a lower ceiling than a Workspace one. A form that suddenly performs well is exactly when you hit it.
If you take this route, wrap the API call in a try/catch and write the error into a column on the same row. A failed CRM push that leaves a visible marker in the sheet is recoverable; a silent one is not.
Route 2: an automation platform (Zapier, Make, n8n)
Connect the form or the spreadsheet to an automation platform and let it push to the CRM. This is the most common setup in small teams, and it is a reasonable one: the mapping is visual, the platforms retry on your behalf, and their run history shows you what failed and why.
Two things to know before choosing it. First, if the automation is triggered by a new spreadsheet row rather than by the submission itself, it inherits the polling interval of that trigger, which on lower plans can be several minutes. For a lead who has just filled in a form and expects a call back, that delay is real. Second, the per-task pricing means cost scales with submissions, which is the opposite of what you want when a campaign performs.
Triggering the automation from a webhook rather than from a new row removes the polling delay entirely, because the form calls the platform the moment someone submits.
Route 3: a form that posts a webhook natively
The third option is a form that writes the spreadsheet row and fires the webhook itself, with no script and no intermediary. The submission is stored first, then both deliveries are attempted independently, so a CRM outage delays the CRM copy without touching the spreadsheet row.
This is how QR to Sheets Forms works. A submission writes a row to a Google Sheet you own, posts a signed JSON payload to any HTTPS endpoint you nominate, and optionally emails the person a confirmation with a unique QR code for later check-in. If the endpoint is unreachable, the webhook is retried automatically rather than dropped.
| Capability | Google Forms + Apps Script (DIY) | QR to Sheets |
|---|---|---|
| Cost | Free, within Apps Script quotas | Free for 10 trial submissions, then 7 USD per registered device per month |
| Time from submit to CRM | Seconds, when the trigger runs cleanly | Seconds, webhook fires on submission |
| When the CRM is down | Trigger fails; Google retries on its own schedule and nobody is notified | Retried automatically; the Sheet row and the confirmation email are unaffected |
| Setup | Write and maintain a script, handle auth and errors yourself | Paste the endpoint URL into the form settings |
| Spreadsheet row | Written by Google Forms directly | Written to a Sheet you own, timestamped in your workspace timezone |
| Per-person QR code | Not available without building it | Issued per submission and emailed, scannable at a door later |
| Respondent accounts | None required | None required |
The rule that matters more than the tool
Whichever route you pick, the submission must be stored durably before any external system is called. A lead that exists only inside an in-flight API request is a lead you lose when that request fails.
This is the single most common design mistake in form-to-CRM wiring. A form that posts straight to a CRM and nowhere else has no record of what it tried to send, so when the CRM rejects a malformed field or times out, the submission is simply gone and the person who filled it in has no idea. Write the row first, then deliver.
What a webhook payload should contain
Send the whole submission, including a stable identifier for the submission itself and the timestamp. A receiving system can ignore fields it does not need, but it cannot invent ones you left out, and changing the payload later means redeploying whatever consumes it.
- A unique submission id, so the receiver can detect a duplicate delivery.
- The submission timestamp, in a timezone you have stated explicitly.
- Every visible field, keyed by a stable name rather than by column position.
- The form's own identifier, so one endpoint can serve several forms.
A receiver that keys on the submission id can safely be called twice. That matters because any retrying sender will occasionally deliver the same event more than once, and a CRM that creates two contacts from one person is a worse outcome than a delayed one.
When you do not need any of this
If your leads arrive a few times a week and one person handles all of them, a Google Form writing to a Sheet is enough, and copying the occasional row into the CRM by hand costs less than any integration. Build the wiring when the manual step starts being skipped, not before.
Equally, if the CRM already offers a native hosted form and you do not need the spreadsheet copy, use it. The reason to run both is that the spreadsheet is where reporting and reconciliation happen, and exporting from a CRM on a schedule is the manual step this whole exercise exists to remove.
Step by step
- 1
Decide which system is the source of truth
The CRM and the spreadsheet will drift apart eventually. Pick one as authoritative before you build anything, because that decision determines which side you reconcile against when a number disagrees.
- 2
Write down the fields the CRM actually requires
Most CRMs reject a contact with no email, or silently create a duplicate when a field it dedupes on is missing. Confirm the required set before designing the form, not after the first lead is lost.
- 3
Build the form and point it at the Sheet
Collect only what a person will fill in on a phone. Every extra field costs you completions. The spreadsheet row is the durable copy, so it should be written first and independently of any CRM call.
- 4
Add the webhook to the CRM
Point it at the CRM's inbound endpoint, or at an automation platform such as Make or n8n that maps the payload for you. Send the whole submission, not a trimmed subset, so the mapping can change later without touching the form.
- 5
Test with a deliberately broken endpoint
Point the webhook at a URL that returns a 500, submit the form, and confirm the spreadsheet row still appears. If a CRM outage can lose a lead entirely, the wiring is wrong and you will find out during a campaign rather than a test.
- 6
Reconcile once before you rely on it
Count rows in the sheet against records in the CRM for the same period. They should match. If they do not, you have found the gap now rather than at the end of a quarter.
Frequently asked questions
Can a Google Form send data to a CRM without Apps Script?+
Not on its own. Google Forms has no native webhook or outbound HTTP feature, so reaching a CRM requires either an Apps Script trigger you write, or an automation platform such as Zapier, Make or n8n watching the linked spreadsheet or the form itself.
What happens to a submission if the CRM is down?+
That depends entirely on the design. With QR to Sheets Forms the submission is written to the database and the Google Sheet first, and the webhook is retried automatically, so the lead is never lost. With a naive direct-to-CRM form, the submission usually disappears.
Does the webhook cost extra?+
No. The webhook is part of the paid plan at 7 USD per registered device per month. There is no per-submission or per-task charge, which is the main cost difference against an automation platform priced by task volume.
Which CRMs does this work with?+
Any CRM that accepts an inbound HTTPS POST, either directly or through an automation platform such as Make or n8n that maps the payload. The webhook posts standard JSON to a URL you choose, so nothing depends on a specific vendor integration.
How many submissions can a form take?+
Submissions are unlimited on a paid plan when the confirmation email is switched off. When the confirmation email is on, sends draw on the workspace monthly email allowance of 2,000 plus 500 per extra registered device. Passing that allowance never rejects a response: the row, the Sheet write and the webhook all still happen, and only the confirmation email is held.
Can the same form also check people in on the day?+
Yes. Each submission can issue that person a unique QR code, delivered on the confirmation screen and by email, which is scanned later to record their arrival in the same spreadsheet.