Typeform logo Google Sheets logo

How to Integrate Typeform with Google Sheets

Native vs Make vs n8n vs Relay — setup time, cost & field mapping

Integration Status

Typeform makes it easy to collect clean, high-quality responses — but that data needs somewhere to live and be acted on. Connecting Typeform to Google Sheets means every submission is instantly appended as a new row, creating a live, collaborative dataset that your team can filter, analyze, and share without ever touching an export button. Marketers use it for lead capture, HR teams for applications, researchers for survey aggregation, and ops teams for intake forms. It's a lightweight but reliable data pipeline that turns form responses into real-time inputs for dashboards, downstream automations, and team workflows — all inside Google Workspace.

Note: We've identified 2 known limitations with this integration. See known limitations below for details.

Data Flow Architecture

Typeform Typeform
→ One-Way
Near real-time via webhook.
Google Sheets Google Sheets
API Tier
REST API v3
Auth Method
OAuth 2.0
Rate Limits
Standard SaaS Limits

Integration Overview

Connect Typeform to Google Sheets with seamless data sync and automate workflows. Eliminate manual entry and boost productivity with our integration.

Primary Use Case

Sync Typeform responses to Google Sheets for real-time customer data and automated workflows.

Setup Complexity

medium

Typical Setup Time

15 minutes

💰 Cost Estimator

Calculate your monthly automation cost based on data volume

Records per month
10,000
0 10,000 15,000+

💡 Tip: Make is best for complex logic and data transformations. n8n is great if you need privacy and self-hosted control. Relay adds manager approval gates—perfect for sensitive financial or legal data transfers. Pabbly Connect offers unlimited tasks at a flat rate—ideal for high-volume workflows on a budget.

Known Limitations & Errors

criticalHigh
Typeform responses aren't syncing to Google Sheets
View Fix →
highModerate
Single Typeform response creates multiple Google Sheets rows
View Fix →

Recommended Integration Path

Typeform to Google Sheets is a setup workflow.

This pair usually requires custom mapping (Raw Data Collection), so an automation layer is needed between Typeform and Google Sheets.

Primary Recommendation: Make for Fast Automation

Make is the fastest way to map fields and automate Typeform -> Google Sheets without custom code.

  • Visual scenarios with branch logic and filters
  • Strong data mapping and transformation controls
  • Reliable fallback path when native sync is limited
Start with Make

Budget Alternative: Pabbly Connect

Pabbly Connect is a one-time payment automation tool — ideal for Typeform → Google Sheets workflows without monthly fees.

  • One-time pricing with unlimited tasks
  • 1,000+ app integrations including most SaaS tools
  • Good fit for teams on tight automation budgets
Try Pabbly Connect

Integration Solutions

Choose the right tool for your requirements:

Platform Cost
🔗
Native
Free
Free
Included
Make
$9–99/mo
Budget-Friendly
Start Free
✨ Fastest to Deploy

Use Make to get running in 15–45 minutes. Map fields, transform data, and connect dozens of apps without touching code. Best for startups and fast iterations.

👤 Require Human Sign-Off

Add Relay on top of any solution to require approval before syncing. Perfect for finance, legal, or compliance—let humans make the final call before data moves.

🔐 Maximum Control

Deploy n8n on your own servers for zero cloud dependencies. Full data residency, unlimited customization, and complete audit trails—essential for healthcare, finance, and GDPR compliance.

Ready to automate? We have a template for you.

Real workflow

Send appointment SMS follow-ups with Typeform, Twilio, and Google Sheets — copy this blueprint, open n8n, paste it in, and your workflow is live.

n8n
typeform-google-sheets-blueprint.json
{
  "id": "XMQU1Cl3DrsiwDR3",
  "meta": {
    "instanceId": "b885fa0491017e0f6687232e04426db63e8f57901aff19cf5dd8c38e246e1f20",
    "aiBuilderAssisted": true,
    "templateCredsSetupCompleted": true
  },
  "name": "New Appointment → Welcome SMS",
  "tags": [
    {
      "id": "ApCZ67ZDQCOdgYND",
      "name": "submitted",
      "createdAt": "2026-05-18T04:04:59.119Z",
      "updatedAt": "2026-05-18T04:04:59.119Z"
    }
  ],
  "nodes": [
    {
      "id": "cd874ec6-ca9f-40c2-a2c0-eaec9d2dd5fe",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        64,
        928
      ],
      "parameters": {
        "color": "#FBF9CB",
        "width": 544,
        "height": 576,
        "content": "## New Appointment → Welcome SMS\n\n### How it works\n\n1. Sends an instant welcome SMS when a Typeform submission arrives.\n2. Logs the customer to a Google Sheet for follow-up tracking.\n3. Sends up to 2 nudge SMS every 24 hours if the customer doesn't reply.\n4. Stops nudging the moment the customer replies to any message.\n\n### Setup steps\n\n- [ ] Connect Typeform to \"When Form Submitted\" and select the form.\n- [ ] Connect Twilio to \"Send Welcome SMS\" and \"Send Nudge SMS\" with your From number.\n- [ ] Connect Google Sheets to the four sheet nodes (one tracking sheet with columns: customerName, customerPhone, submittedAt, repliedAt, nudgeCount, lastNudgeAt).\n- [ ] Send a test submission, confirm SMS + sheet row, then toggle Active.\n\n### Customization\n\n- Tweak nudge cadence in \"If Time For Next Nudge\" (default: 24h apart, max 2).\n- A2P 10DLC registration is required for Twilio SMS in the US — check Twilio's docs.\n\n### Learn more at [SMB Excel](https://www.smbexcel.com)"
      },
      "typeVersion": 1
    },
    {
      "id": "b991fd68-6ee2-4a36-a23c-47e655b47ad9",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        928
      ],
      "parameters": {
        "color": 7,
        "width": 1536,
        "height": 480,
        "content": "## Welcome and track new submission\n\nReceives the Typeform submission, extracts name and phone, sends the welcome SMS via Twilio, and appends the customer to the tracking sheet."
      },
      "typeVersion": 1
    },
    {
      "id": "fe2fe082-0c91-4035-affa-8c2f513aae9d",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        1456
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 400,
        "content": "## Query for non-responders\n\nRuns every 6 hours, reads the tracking sheet, and splits the list into individual customer items for evaluation."
      },
      "typeVersion": 1
    },
    {
      "id": "a881781c-bf3e-46d0-8e07-ff5f142023e7",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1312,
        1456
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 400,
        "content": "## Send and update nudge\n\nChecks the nudge cadence, sends the next nudge SMS via Twilio, and updates the customer's nudge count and timestamp in the tracking sheet."
      },
      "typeVersion": 1
    },
    {
      "id": "48ddbe99-afa5-4597-8eb2-37cdc2d57484",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        1904
      ],
      "parameters": {
        "color": 7,
        "width": 1536,
        "height": 336,
        "content": "## Handle inbound SMS replies\n\nListens for inbound SMS, marks the customer as replied in the tracking sheet, and stops all future nudges."
      },
      "typeVersion": 1
    },
    {
      "id": "ae3961ab-4419-40ce-b15f-cb3f834307ef",
      "name": "When Form Submitted",
      "type": "n8n-nodes-base.typeformTrigger",
      "position": [
        688,
        1104
      ],
      "webhookId": "98d75651-3404-4780-ac4b-aab6fe802b00",
      "parameters": {
        "formId": "<__PLACEHOLDER_VALUE__Select your Typeform form from the dropdown__>",
        "onlyAnswers": false
      },
      "typeVersion": 1.1
    },
    {
      "id": "d6ebf391-5429-4f37-887f-dcf0c199b2d3",
      "name": "Extract Name and Phone",
      "type": "n8n-nodes-base.set",
      "position": [
        912,
        1104
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "field-name",
              "name": "customerName",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "field-phone",
              "name": "customerPhone",
              "type": "string",
              "value": "={{ $json.phone }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "50ab91eb-5a90-4ffb-a6ae-3143b734a924",
      "name": "Send Welcome SMS",
      "type": "n8n-nodes-base.twilio",
      "position": [
        1136,
        1008
      ],
      "parameters": {
        "to": "={{ $json.customerPhone }}",
        "from": "<__PLACEHOLDER_VALUE__Your Twilio phone number e.g. +1234567890__>",
        "message": "=Hi {{ $json.customerName }}, thanks for booking with us! We look forward to seeing you soon. Reply STOP to opt out.",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "9ce4b364-0cf9-4b85-8485-4bdb876b0d4d",
      "name": "Prepare Tracking Row",
      "type": "n8n-nodes-base.set",
      "position": [
        1136,
        1200
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "customerName",
              "type": "string",
              "value": "={{ $json.customerName }}"
            },
            {
              "id": "id-2",
              "name": "customerPhone",
              "type": "string",
              "value": "={{ $json.customerPhone }}"
            },
            {
              "id": "id-3",
              "name": "submittedAt",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "id-4",
              "name": "repliedAt",
              "type": "string",
              "value": ""
            },
            {
              "id": "id-5",
              "name": "nudgeCount",
              "type": "number",
              "value": 0
            },
            {
              "id": "id-6",
              "name": "lastNudgeAt",
              "type": "string",
              "value": ""
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "88a91ebe-a0a4-4f93-adf6-d0d79fe07872",
      "name": "Append Submission to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1360,
        1200
      ],
      "parameters": {
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "credential-id",
          "name": "Google Sheets OAuth2 API"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "778e8849-21c6-4f9e-bec3-69272b5f3f55",
      "name": "Every 6 Hours",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        688,
        1616
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "cf9785e7-6c20-46cc-b791-cb776c9cb037",
      "name": "Read Non-Responders from Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        912,
        1616
      ],
      "parameters": {
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "0aaa3ada-da21-42f0-b592-bd1bb88f3409",
      "name": "Split Non-Responder List",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1136,
        1616
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "4db8717d-b50e-4286-ac14-023b4993ab21",
      "name": "If Time For Next Nudge",
      "type": "n8n-nodes-base.if",
      "position": [
        1360,
        1616
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "id-1",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ ($json.nudgeCount === 0 && $now.diff(DateTime.fromISO($json.submittedAt), 'hours').hours >= 24) || ($json.nudgeCount === 1 && $json.lastNudgeAt && $now.diff(DateTime.fromISO($json.lastNudgeAt), 'hours').hours >= 24) }}"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "3e6ba7a1-e4fe-4d47-9f20-db9f24da8d17",
      "name": "Send Nudge SMS",
      "type": "n8n-nodes-base.twilio",
      "position": [
        1584,
        1616
      ],
      "parameters": {
        "to": "={{ $json.customerPhone }}",
        "from": "<__PLACEHOLDER_VALUE__Your Twilio phone number e.g. +1234567890__>",
        "message": "=Hi {{ $json.customerName }}, just checking in! We're looking forward to your appointment. Reply anytime if you have questions. Reply STOP to opt out.",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "f9e70770-22ce-4e81-b2f8-c7a806de4694",
      "name": "Prepare Nudge Update",
      "type": "n8n-nodes-base.set",
      "position": [
        1808,
        1616
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "nudgeCount",
              "type": "number",
              "value": "={{ $json.nudgeCount + 1 }}"
            },
            {
              "id": "id-2",
              "name": "lastNudgeAt",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b0a9a630-1837-4aa0-977f-7ab7d68c9cec",
      "name": "Update Nudge Count in Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2032,
        1616
      ],
      "parameters": {
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "620f2403-4873-45c5-9efb-60f14e472bbc",
      "name": "When SMS Reply Received",
      "type": "n8n-nodes-base.twilioTrigger",
      "position": [
        704,
        2032
      ],
      "webhookId": "0707c593-569a-499c-94d4-fb98e2cb4eff",
      "parameters": {
        "updates": [
          "com.twilio.messaging.inbound-message.received"
        ]
      },
      "typeVersion": 1
    },
    {
      "id": "8b854678-928d-4039-adcb-a85d7f18a82c",
      "name": "Prepare Reply Update",
      "type": "n8n-nodes-base.set",
      "position": [
        928,
        2032
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "repliedAt",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "fe3802d1-8161-476f-a2d5-59106397bb10",
      "name": "Update Replied in Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1152,
        2032
      ],
      "parameters": {
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "credential-id",
          "name": "Google Sheets OAuth2 API"
        }
      },
      "typeVersion": 4.7
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "99aa2fe2-0590-4649-aaf3-7f0f05b8a956",
  "connections": {
    "Every 6 Hours": {
      "main": [
        [
          {
            "node": "Read Non-Responders from Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Nudge SMS": {
      "main": [
        [
          {
            "node": "Prepare Nudge Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Form Submitted": {
      "main": [
        [
          {
            "node": "Extract Name and Phone",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Nudge Update": {
      "main": [
        [
          {
            "node": "Update Nudge Count in Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Reply Update": {
      "main": [
        [
          {
            "node": "Update Replied in Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Tracking Row": {
      "main": [
        [
          {
            "node": "Append Submission to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Name and Phone": {
      "main": [
        [
          {
            "node": "Send Welcome SMS",
            "type": "main",
            "index": 0
          },
          {
            "node": "Prepare Tracking Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Time For Next Nudge": {
      "main": [
        [
          {
            "node": "Send Nudge SMS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When SMS Reply Received": {
      "main": [
        [
          {
            "node": "Prepare Reply Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Non-Responder List": {
      "main": [
        [
          {
            "node": "If Time For Next Nudge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Non-Responders from Sheets": {
      "main": [
        [
          {
            "node": "Split Non-Responder List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Field Mappings

Detailed mapping of how fields sync between systems.

responses

Source FieldTypeTarget FieldDirectionNotes
tokenstringvalues.0unidirectional
submitted_atstringvalues.1unidirectional

Frequently Asked Questions

Does Typeform integrate directly with Google Sheets?

Yes, Typeform has a native integration with Google Sheets. It is available directly within the Typeform app marketplace.

Is the connection between Typeform and Google Sheets secure?

Yes. This integration typically uses OAuth 2.0, meaning you grant permission via a secure login window. You do not need to share your raw password, and you can revoke access at any time from your Typeform security settings.

Is the sync one-way or two-way?

This is typically a one-way sync: Typeform → Google Sheets. Changes in Google Sheets do not sync back to Typeform.

Will existing data in Typeform sync to Google Sheets?

Usually, no. Most native integrations are "forward-looking," meaning they only sync data created or updated *after* you activate the connection. To move historical data, you will likely need to perform a one-time CSV export/import manually.

Why does Typeform responses aren't syncing to Google Sheets?

This is a known issue (~60% of users). Common cause: Form Field Mismatch. Typical fix time: 10 minutes. Many teams solve this with Make's visual mapping tools or n8n for self-hosted control.

Automating Typeform → Google Sheets

Automation & webhook questions

How do I automatically send Typeform responses to Google Sheets?

Typeform has a native Google Sheets integration that appends a new row for each response — it covers the basic case well. For anything more complex (filtering responses, routing to multiple sheets, combining Typeform with Gmail or Airtable in the same flow), use Make instead.

Can I send Typeform data to Google Sheets and Gmail at the same time?

Yes. In Make, one Typeform trigger runs both actions: append the response to Google Sheets and send a Gmail notification (to the respondent, your team, or both). You can personalise the email using the Typeform answer fields — e.g., address the respondent by name from their form answer.

How do I connect Typeform, Google Sheets, and Airtable in one workflow?

Use Make with a single Typeform trigger and three downstream actions: add a row to Google Sheets (for reporting), create a record in Airtable (for project tracking or CRM), and optionally post a Slack notification. All three run on every submission without needing separate automations.

Using Typeform and Google Sheets with other tools?

Build your full stack map — see all connections and gaps at once.

See your full stack →