Register your interest: Tag @Cody, get an agent
BlogResources

How to connect Typeform to Google Sheets so an edit does not break it

Editing a form changes the response shape, and a spreadsheet built on column position breaks silently. Matching on field identifiers, logic jumps, and what to do with partial responses.

Rithul PalazhiRithul Palazhi11 min read

Summarize with AI

How to connect Typeform to Google Sheets so an edit does not break it
On this page

Form-to-spreadsheet integrations break for one reason above all others: somebody edited the form. A question was reworded, a new one was added in the middle, a choice was removed — and the spreadsheet that has been collecting responses for six months starts putting answers in the wrong columns without any error.

Typeform's conditional logic makes it worse, because different respondents answer different questions, so a response is not a fixed row even before anybody edits anything.

What we'll cover

Why the sheet drifts

Five ways a form edit corrupts a spreadsheet, none of which produces an error.

A question added in the middle shifts every column after it, so historical rows and new rows disagree about what column seven means.

A question reworded breaks anything matching on the question text, which is what most simple integrations do.

A question deleted leaves a column that is populated for old responses and empty for new ones.

A choice removed from a multiple choice means old responses hold a value the form no longer offers.

A question type changed — a text field becoming a dropdown — changes the shape of the answer for everything after the change.

The common thread: the spreadsheet is a fixed rectangle and the form is not. Something has to reconcile them, and the reconciliation has to be explicit.

Identifiers, not titles or positions

The single decision that makes this durable.

Every field has a stable identifier that survives rewording. Match on it.

Also record a reference where your form uses them, since a readable key is easier to maintain than an opaque identifier.

Map identifiers to columns explicitly, in a mapping you control, rather than letting column order follow question order.

Append new columns at the end, never in the middle, when a question is added — so historical rows stay valid.

Keep the mapping visible. A hidden mapping inside an automation is something nobody can check when a column looks wrong.

Report unmapped fields rather than dropping them, because that is how a new question's answers silently go nowhere.

Building it with CodeWords

CodeWords connects to more than 3,000 integrations, and the connection is made once and reused.

  1. Open CodeWords and start a new automation.
  2. Describe what should happen in plain language to Cody, the automation builder: which form, which fields, and which sheet they land in.
  3. Authorize the connection to Typeform, and grant access to the target spreadsheet.
  4. Describe the exceptions: a field that is not in your mapping, a response that skipped a question through logic, a partial submission.
  5. Submit test responses covering each logic branch and check where each answer lands before the form goes live.

You describe the outcome; Cody builds it, connects it, and deploys it. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.

Logic jumps and the ragged response

Typeform's conditional logic is the reason people choose it and the reason the data is awkward.

Different respondents answer different questions, so no single row shape fits every response.

A blank cell is ambiguous. It can mean "skipped by logic", "left empty", or "not asked because this question did not exist yet", and those are three different facts.

Distinguish them explicitly. Use a marker for "not asked" rather than leaving the cell blank, or every analysis over that column is wrong.

Record the path where branches matter — which route the respondent took — as a column of its own, since it is frequently more informative than the individual answers.

Test every branch before going live. A branch nobody tested is a branch whose answers land in the wrong column, and it is discovered after the responses have arrived.

Partial responses, which are data too

Often ignored, and they say something the completed responses do not.

Typeform records responses that were started and not submitted, depending on your configuration, and these are available separately.

Where people stop is a finding. A question that consistently precedes abandonment is a question worth rewriting.

Decide whether partials belong in the same sheet. Mixing them with completions without a flag means every count is wrong.

Flag them clearly if you include them, in a column, so a filter is one click.

Report the abandonment point periodically, since it is the most actionable thing a form produces and almost nobody looks at it.

Field types that need handling

Multiple selection answers hold several values, which need joining into one cell with a separator or splitting into columns per option — and the second is more useful for counting.

File uploads arrive as links, and those links may require authentication, so a sheet full of them is not self-contained.

Payment fields carry transaction detail that generally should not sit in a shared spreadsheet.

Ratings and opinion scales are numbers with a scale, and a sheet that loses the scale makes a four uninterpretable.

Dates arrive in the form's configured format, and a spreadsheet will helpfully reinterpret them according to its own locale, which is a classic source of days and months swapping.

Hidden fields carry the context — campaign, referrer, user identifier — and are usually the most useful columns in the sheet.

Validating the form before you trust the sheet

A short check worth running on a schedule.

Compare the form's current fields against your mapping, and report anything new, missing, or changed.

Alert when a field is added, since that is the moment to decide which column it belongs in rather than discovering later.

Alert when responses stop arriving. A form that has gone quiet is either genuinely quiet or broken, and the two look identical in a spreadsheet.

Check the response count against Typeform's own, periodically, to catch anything the integration dropped.

Report all of it to whoever owns the form, since they are the person who edited it.

What happens after the row is written

A sheet is rarely the end of the journey, and deciding what happens next is worth doing at the same time.

The row is a record, not an action. Somebody submitting a form usually expects something to happen, and a row appearing in a spreadsheet is not it.

Route from the same automation that writes the row — a record in the CRM, a ticket, a task — rather than building a second process that reads the sheet.

Do not make the sheet the trigger. Reading a spreadsheet to detect new rows is fragile, slow, and breaks when somebody sorts the sheet.

Acknowledge the respondent with what happens next and roughly when, which removes the follow-up email from somebody unsure the form worked.

Keep the sheet as the log, which is what it is good at: a durable, readable record anybody can filter without needing access to anything else.

Send the acknowledgement after the downstream record exists, so nobody is told their submission was received when the part that mattered failed.

Making it survive

Make it idempotent, keyed on the response identifier, since webhooks are at-least-once and duplicate rows are the commonest complaint.

Append rather than replace for a response log, and never reorder existing rows.

Write the response identifier and the submission timestamp as the first columns, in text format.

Handle the unmapped field by reporting it rather than dropping it.

Report the outcome. Responses written, duplicates skipped, and fields that could not be mapped.

Limits worth knowing about

Rate limits apply to the responses API, so bulk retrieval needs pagination and pacing.

Webhook delivery is at-least-once, which is why idempotency matters.

File upload links can expire or require authentication, so a sheet of links is not a durable archive.

Sheets has a cell limit, which a long-running form with many questions will eventually reach.

Response retention depends on your plan, so a full re-fetch may not reach as far back as you expect.

What to set up first

The explicit field mapping, with responses appended and the response identifier written as the first column. It is the foundation for everything else here, and retrofitting it after six months of responses have landed in position-based columns is considerably more work than doing it first.

Two habits make the difference. Match on field identifiers rather than question text, since rewording a question is the single most common thing anybody does to a form. And add the scheduled check comparing the form's fields against your mapping, because the failure you are guarding against produces no error at all.

Frequently asked questions

Why did my spreadsheet columns stop lining up?

Somebody edited the form — most often adding a question in the middle, which shifts every column after it. Map fields by identifier to named columns rather than relying on order, and append new columns at the end.

What does a blank cell mean?

It is ambiguous, which is the problem. It can mean skipped by logic, left empty, or not asked because the question did not exist then. Use an explicit marker for "not asked" or analysis over that column will be wrong.

Should partial responses go in the same sheet?

Only with a flag column, or every count is wrong. They are worth collecting separately regardless — where people abandon a form is the most actionable thing it tells you and almost nobody looks.

How should multiple selection answers be stored?

One column per option with a true or false, if you want to count them. A single cell with joined values is readable and painful to analyse, which is what people usually discover afterwards.

Why are dates wrong in the sheet?

The spreadsheet reinterpreted them according to its locale, which is the classic day and month swap. Write dates in an unambiguous format, or as text, and state the format in the sheet.

Why are there duplicate rows?

Webhook delivery is at-least-once. Key on the response identifier and skip anything already written — this is the most common complaint about form-to-sheet integrations and it is entirely preventable.

How do I know the form is still collecting?

Alert when responses stop arriving for longer than usual. A broken form and a quiet week look identical in a spreadsheet, and the difference is expensive.

Should another process read the sheet?

No — route from the same automation that writes the row. Watching a spreadsheet for new rows is fragile, slow, and breaks the moment somebody sorts or filters it. Keep the sheet as the readable log.

What should the respondent receive?

A confirmation saying what happens next and roughly when, sent after the downstream record exists rather than on submission. "We received your response" tells somebody nothing they did not already know.

Does Typeform's own Google Sheets connector do this?

It writes responses to a sheet with no building, which is right for a stable form. The reasons to build are an explicit field mapping that survives edits, partial responses, routing to other systems, and validation that the form still matches what the sheet expects.

Get started today

Your first workflow is free to build.

Describe what you need. Cody handles the build, the connections, and the deployment.