Pricing

How to Connect Typeform to Google Sheets

TypeformSaved SearchDateDocumentAmount07/01INV-40214,280.0007/02INV-40221,860.5007/05INV-40239,140.0007/08INV-40242,375.2507/09INV-40256,902.7507/12INV-40263,118.40BrookedABCDateDocumentAmount123456707/01INV-40214,280.0007/02INV-40221,860.5007/05INV-40239,140.0007/08INV-40242,375.2507/09INV-40256,902.7507/12INV-40263,118.40Google SheetsTypeform report
JW
James Whitfield

Typeform's native Sheets integration only sends responses submitted after you switch it on. Here's how to backfill old responses and keep new ones flowing.

Typeform ships its own Google Sheets integration and it takes about two minutes to switch on. The catch, and the reason most people end up searching for this, is that it only sends responses submitted after you connect it. Every response collected before that moment stays behind in Typeform. This guide covers the native integration and where it runs out, the free Apps Script route that does pull your full history, and the trade-offs between them.

The native Typeform → Google Sheets integration

Open your form, go to the Connect panel, choose Integrations, and pick Google Sheets. Authorise the Google account, choose an existing spreadsheet or let Typeform create one, and map each question to a column. From then on every submission appends a row. It's free on all plans, including the free tier.

Three limits are worth knowing before you rely on it:

  • No backfill. Responses submitted before you connected the integration are never sent. This is not a bug you can configure away.
  • One form per sheet. Combining several forms into one table means several connections and manual consolidation.
  • Column mapping is positional. Reordering questions or inserting columns mid-range can misalign later submissions.

Honest take: if you're setting up a brand new form and only care about responses from today onward, stop here. The native integration is genuinely the fastest option and it costs nothing. The rest of this guide is for when you need history, multiple forms, or a refresh you control.

The two-minute backfill: CSV export

For a one-off, this beats writing any code. In your form go to Results → Responses, then Download responses and pick CSV. Import that file into a sheet via File → Import. You now have your history, and if you also switch on the native integration, new responses append below it.

The reason this isn't the whole answer: the CSV column order won't necessarily match the integration's column mapping, so the two halves of your table can disagree. Check the headers line up before you trust a combined sheet, and re-export rather than repeating this monthly.

Typeform to Google Sheets for free (Apps Script + Responses API)

The Responses API returns every response a form has ever collected, so this is the free route that solves the backfill problem properly. Create a personal access token under your account → Settings → Personal tokens, and grab the form ID from your form's URL (the string after /form/, for example https://admin.typeform.com/form/AbC12dEf/create).

Before the code, the part that trips most people up. A response's answers array only contains questions that were actually answered. Skipped questions, and anything behind unmet logic jumps, are simply absent. If you build each row by iterating that array, a respondent who skipped question three shifts every later value one column to the left, and your sheet quietly fills with misaligned data. The fix is to read the form definition first, build a fixed column order from its field references, and look up each answer by reference:

Code.gs
function importTypeformResponses() {  const TOKEN = "YOUR_PERSONAL_ACCESS_TOKEN";  const FORM_ID = "AbC12dEf";  const headers = { Authorization: "Bearer " + TOKEN };   // 1. Read the form definition so column order is fixed and complete,  //    independent of which questions any one respondent answered.  const form = JSON.parse(    UrlFetchApp.fetch("https://api.typeform.com/forms/" + FORM_ID, { headers })      .getContentText()  );  const fields = form.fields.map((f) => ({ ref: f.ref, title: f.title }));   // 2. Page through every response. Pagination is token-based: pass the  //    last response's token as "before" to walk backwards through history.  const rows = [];  let before = null;   while (true) {    let url =      "https://api.typeform.com/forms/" + FORM_ID + "/responses?page_size=1000";    if (before) url += "&before=" + before;     const page = JSON.parse(      UrlFetchApp.fetch(url, { headers }).getContentText()    );    if (!page.items || !page.items.length) break;     page.items.forEach((item) => {      // Index this response's answers by field ref.      const byRef = {};      (item.answers || []).forEach((a) => {        byRef[a.field.ref] = readAnswer(a);      });      rows.push([        item.response_id,        item.submitted_at,        ...fields.map((f) => byRef[f.ref] ?? ""), // blank, not shifted      ]);    });     if (page.items.length < 1000) break;    before = page.items[page.items.length - 1].token;    Utilities.sleep(600); // stay under ~2 requests/second  }   const sheet = SpreadsheetApp.getActiveSpreadsheet();  const tab = sheet.getSheetByName("Responses") || sheet.insertSheet("Responses");  tab.clearContents();  const header = ["response_id", "submitted_at", ...fields.map((f) => f.title)];  tab.getRange(1, 1, 1, header.length).setValues([header]);  if (rows.length) {    tab.getRange(2, 1, rows.length, header.length).setValues(rows);  }} // Each answer stores its value under a key named after its type.function readAnswer(a) {  switch (a.type) {    case "choice":  return a.choice.label || a.choice.other || "";    case "choices": return (a.choices.labels || []).join(", ");    case "payment": return a.payment.amount;    default:        return a[a.type]; // text, email, number, boolean, date, url…  }}

Run it once to authorise, then add a time-driven trigger under Triggers → Add Trigger → Time-driven to re-import on a schedule. Note that this rewrites the whole tab each run, which keeps things simple and idempotent but means anything you type into that tab gets erased. Put your own formulas on a separate sheet pointing at this one.

Limits: Apps Script caps execution at six minutes, so very large forms need the import split across runs. There's no write-back, no UI for choosing fields, and the script needs revisiting whenever you add questions.

Automation tools: Zapier, Make and n8n

All three have a Typeform trigger that fires on new submission (built on Typeform's webhooks, so it's near-instant) and a Google Sheets action to append a row. Setup is ten to twenty minutes of mapping fields.

Honest take: for Typeform-to-Sheets alone this is strictly worse than the native integration, it costs money at volume and does the same job with the same no-backfill limitation. It earns its place when the submission needs to do several things at once: post to Slack, create a CRM contact, and land in a sheet. Zapier's free tier allows 100 tasks a month, which one busy form will exhaust quickly.

The Brooked method

Brooked talks to the Responses API for you, so the first import brings the form's entire history rather than starting from zero, and handles the field-reference mapping described above so skipped questions leave blanks instead of shifting columns. Several forms can land in the same spreadsheet on one schedule.

Step 1: Install Brooked

Install Brooked from the Google Workspace Marketplace. Free tier includes 100 imports per month, no credit card required.

Step 2: Connect Typeform

Open Brooked in your sheet, choose Typeform, and paste a personal access token from Settings → Personal tokens in your Typeform account. Brooked lists the forms that token can see; pick one, choose whether you want every response or a date range, and import.

Step 3: Schedule the refresh

Set the import to re-run hourly, daily or weekly. Because it reads history rather than streaming submissions, a scheduled refresh also picks up anything that arrived while a webhook-based integration was failing, which is a quiet failure mode of every on-submit method here.

BrookedBrooked AI, Typeform
Live
Ask anything about your Typeform data…

Method comparison

MethodCostSetupRefreshTwo-wayBest for
Typeform native Sheets integrationFree (all plans)2 minOn submit (new responses only)NoOne form, going forward, no history needed
Apps Script + Responses APIFree20 to 30 minTime-driven triggerNoBackfilling history, custom column mapping
Zapier / Make / n8nFree tier limited · paid for volume10 to 20 minOn submit, via webhookNoFanning responses out to Slack, a CRM and Sheets at once
BrookedFree tier · Pro $29/user/mo~3 minScheduled (hourly, daily, weekly)YesFull history, multiple forms in one sheet, scheduled refresh

Common use cases

  • Lead capture: route form submissions into a sheet the sales team already works from, with scoring columns alongside
  • Survey analysis: pivot NPS or CSAT responses by segment without exporting a CSV every time
  • Drop-off analysis: compare landed_at against submitted_at to find where respondents abandon the form
  • Multi-form reporting: combine responses from several forms into one table with a form-name column
  • Enrichment: join responses against CRM or billing data already living in the spreadsheet

Troubleshooting common issues

Frequently asked questions

Why doesn't my Typeform Google Sheets integration show old responses?

This is by design, and it's the single most common complaint about the native integration. Typeform's Google Sheets connection starts streaming at the moment you enable it: it appends each new submission as a row, but it never backfills responses collected before that point. To get historical responses you have to either export a CSV from the Results panel and paste it in, or pull them through the Responses API, which returns every response the form has ever collected.

Can I connect Typeform to Google Sheets for free?

Yes, two ways. Typeform's own Google Sheets integration is available on every plan including the free one, and takes about two minutes to set up from the Connect panel, it just only handles responses going forward. The Apps Script method in this guide is also free and does handle history, at the cost of about half an hour of setup and a script you maintain yourself.

Does the Typeform integration break if I edit the spreadsheet?

It can. The native integration maps each question to a fixed column position when you connect it. Inserting or deleting columns in the sheet, or reordering questions in the form, can push values into the wrong columns on subsequent submissions. Add new columns to the right of the mapped range rather than in the middle of it, and reconnect the integration after any structural change to the form.

How do I get responses from multiple Typeforms into one sheet?

The native integration is one form to one sheet, so multiple forms means multiple connections and multiple tabs. If you want several forms landing in one combined table, pull them through the Responses API (each form has its own form ID) and write them into a shared sheet with a form-name column, or use a connector like Brooked that can import several forms into the same spreadsheet on one schedule.

What's the Typeform API rate limit?

The Typeform APIs allow roughly 2 requests per second. The Responses endpoint returns up to 1,000 responses per page, so even a form with tens of thousands of submissions only needs a handful of requests. Paginate with the returned token rather than an offset, and add a short sleep between pages if you're looping.

Can I write data back from Google Sheets into Typeform?

No, and this is a real limitation of every method here. Typeform's API is read-only for responses, you cannot edit a submitted response through it. What you can do is enrich responses on the Sheets side (scoring, categorising, adding CRM data alongside them) and push that enriched table onward to another system.

Connect Typeform to Google Sheets today.

Free tier: 100 imports per month, no credit card required. Or see the full Typeform integration details.

Install Brooked free →

Also in Forms & Surveys

More Forms & Surveys guides

Forms & Surveys

How to Connect SurveyMonkey to Google Sheets

Export SurveyMonkey responses to Google Sheets, including the nested answer IDs that hide your actual question text and the daily API cap on free apps.

JW
James Whitfield
Read

Get your spreadsheet hours back

Brooked sets up in seconds. Your team is querying live data before lunch.

Get started free