Connect Bubble to Typeform using two complementary methods: a Backend Workflow that receives new form submissions as real-time webhooks (no external proxy needed — Bubble is server-side by design), and an API Connector call that pulls historical responses via the Typeform REST API. The nested answers array in Typeform payloads requires deliberate field mapping. Backend Workflows require a paid Bubble plan.
| Fact | Value |
|---|---|
| Tool | Typeform |
| Category | Marketing |
| Method | Backend Workflow (Webhooks) |
| Difficulty | Intermediate |
| Time required | 2–3 hours |
| Last updated | July 2026 |
Typeform + Bubble: Real-Time Lead Capture and Response Management
Typeform and Bubble pair well because Bubble's server-side architecture eliminates the proxy problem that plagues client-side tools when receiving webhooks. When a user completes your Typeform, Typeform sends an HTTP POST to your Bubble Backend Workflow URL within seconds — Bubble receives it directly, parses the payload, and can immediately create records, send notifications, or trigger downstream workflows. No external service required.
The integration has two useful modes. The first is real-time webhook reception: new Typeform submissions arrive in Bubble immediately and get stored as 'ResponseSubmission' records in your Bubble database. This powers live lead dashboards, instant welcome emails triggered from Bubble, or CRM record creation in tools like HubSpot via a secondary API call.
The second mode is historical pull: the Typeform REST API at `https://api.typeform.com/forms/{form_id}/responses` lets you retrieve all past submissions. This is useful when building a response analytics dashboard or migrating existing Typeform data into Bubble on first setup.
The trickiest part of either mode is Typeform's answers structure. Unlike a flat JSON object, Typeform responses contain a list where each item has a `field` (question metadata) and a value that's stored in different keys depending on question type — `answer.text` for short text, `answer.email` for email fields, `answer.choice.label` for multiple choice. You'll need to handle this in your Bubble workflow's field mapping logic.
Integration method
Receive Typeform submissions instantly via Bubble's Backend Workflow webhook endpoint, while also pulling historical responses with an API Connector GET call to the Typeform REST API.
Prerequisites
- A Typeform account on a plan that supports webhooks (Basic, Plus, Business, or Enterprise — webhooks are not available on the free Typeform plan)
- A Bubble app on a paid plan (Starter or above) — Backend Workflows are not available on Bubble's free plan
- Your Typeform form ID, visible in the form's URL: app.typeform.com/to/FORM_ID or in the Typeform workspace under the form's settings
- A Typeform Personal Access Token, generated at app.typeform.com → Account settings → Personal tokens
- The API Connector plugin installed in your Bubble app for historical response pulls (Plugins tab → Add plugins → 'API Connector' by Bubble)
Step-by-step guide
Create the Bubble Backend Workflow webhook endpoint
In the Bubble editor, click 'Backend Workflows' in the left navigation panel (this option only appears on paid Bubble plans). If you don't see it, upgrade your Bubble plan first. Click 'Add another workflow'. Name the workflow 'typeform-webhook'. By default, new Backend Workflows use 'API' as the trigger type — leave this as-is. You'll see a 'Expose as a public API endpoint' toggle; make sure this is enabled (it should be on by default for API workflows). Look below the workflow name to find the endpoint URL — it will look like: `https://yourapp.bubbleapps.io/api/1.1/wf/typeform-webhook` Copy this URL. If your app is on a custom domain, replace `yourapp.bubbleapps.io` with your custom domain. This is the URL you'll paste into Typeform's webhook settings in the next step. Note the `/initialize` URL variant: Bubble also provides `https://yourapp.bubbleapps.io/api/1.1/wf/typeform-webhook/initialize` — this initialize endpoint is used only during Typeform's test payload delivery for schema detection. Your production webhook URL does NOT include `/initialize`. Never paste the initialize URL into Typeform's webhook panel as the active endpoint.
1// Bubble Backend Workflow endpoint URLs23// Production endpoint (paste into Typeform webhooks):4https://yourapp.bubbleapps.io/api/1.1/wf/typeform-webhook56// Schema detection endpoint (used once during setup only):7https://yourapp.bubbleapps.io/api/1.1/wf/typeform-webhook/initialize89// Note: Replace 'yourapp' with your actual Bubble app name10// If using custom domain: https://yourdomain.com/api/1.1/wf/typeform-webhookPro tip: Navigate to Bubble's Settings tab → API to confirm 'This app exposes a Workflow API' is enabled. If this toggle is off, your Backend Workflow URL will return 404 regardless of the workflow configuration.
Expected result: Backend Workflow 'typeform-webhook' is visible in the Backend Workflows section with 'Expose as public API endpoint' enabled. The endpoint URL is visible beneath the workflow name.
Register the endpoint in Typeform and capture the payload schema
Log into your Typeform account and open the form you want to connect to Bubble. Click 'Connect' in the top navigation, then find 'Webhooks' in the integration list. Click 'Add a webhook'. In the 'Destination URL' field, paste your Bubble Backend Workflow URL: `https://yourapp.bubbleapps.io/api/1.1/wf/typeform-webhook`. Leave Secret Token blank for now (you can add one later for webhook signature verification if needed). Click 'Save webhook'. Now trigger the Detect Data step. In Bubble's Backend Workflow editor, with the 'typeform-webhook' workflow open, click the trigger settings area and look for 'Detect Data' or 'Click here to detect data from the request'. This enables Bubble to learn the payload structure from an incoming request. Back in Typeform, find your webhook in the list and click 'Deliver sample payload' (sometimes labeled 'Test webhook' or 'Send test'). This sends a sample Typeform payload to your Bubble workflow URL. Return to Bubble. After the sample payload is received, Bubble's Detect Data step should populate with typed fields from the Typeform payload structure. You'll see fields like `form_response`, `form_response.answers`, `form_response.submitted_at`, and others. This detected schema is what you'll reference when building the workflow actions. IMPORTANT: Without clicking 'Deliver sample payload', Bubble's Detect Data step has no schema, and your workflow actions have no typed fields to reference. This step is mandatory before building the parsing logic.
1// Sample Typeform webhook payload structure2{3 "event_id": "01ABCD",4 "event_type": "form_response",5 "form_response": {6 "form_id": "FORM_ID",7 "token": "RESPONSE_TOKEN",8 "submitted_at": "2026-07-09T10:30:00Z",9 "answers": [10 {11 "field": { "id": "abc123", "type": "short_text", "ref": "name_question" },12 "type": "text",13 "text": "Jane Smith"14 },15 {16 "field": { "id": "def456", "type": "email", "ref": "email_question" },17 "type": "email",18 "email": "jane@example.com"19 },20 {21 "field": { "id": "ghi789", "type": "multiple_choice", "ref": "interest_question" },22 "type": "choice",23 "choice": { "label": "Product Demo" }24 }25 ]26 }27}Pro tip: If 'Deliver sample payload' doesn't trigger Bubble's Detect Data to populate, check that the Backend Workflow's API endpoint is enabled in Bubble Settings → API. Also confirm your Bubble app is deployed (not just in development) — Typeform cannot reach a localhost development URL.
Expected result: Typeform shows 'Webhook delivered successfully' after the test. In Bubble's Backend Workflow editor, the 'Detect Data' step now shows typed fields from the Typeform payload, including form_response, answers array, and submitted_at.
Create a Bubble data type and build the parsing workflow
Before adding workflow actions, create the Bubble data type to store parsed submissions. Go to Data tab → Data types → 'Create a new type' → name it 'TypeformResponse'. Add fields: respondent_email (text), respondent_name (text), form_id (text), response_token (text), submitted_at (date), raw_interest (text), notes (text). Add any additional fields that match the specific questions in your Typeform — one field per question you want to capture. Return to the Backend Workflow editor. In the 'typeform-webhook' workflow, add workflow actions: Action 1: 'Create a new TypeformResponse'. Set the field values by referencing the detected payload data: - submitted_at = trigger's form_response's submitted_at - form_id = trigger's form_response's form_id - response_token = trigger's form_response's token For the `answers` fields, you need to extract values from the answers array. Typeform's answers are heterogeneous — the value lives in different keys depending on question type. To extract a specific answer: - For text questions: trigger's form_response's answers filtered by field's ref = 'name_question': first item's text - For email questions: trigger's form_response's answers filtered by field's ref = 'email_question': first item's email - For choice questions: trigger's form_response's answers filtered by field's ref = 'interest_question': first item's choice's label The `field.ref` is the unique reference ID you set for each question in Typeform's question settings. In Typeform, open each question → Settings → Reference ID — use these refs to reliably identify answers regardless of question order. Set Privacy rules: go to Data tab → Privacy → TypeformResponse → restrict to logged-in users only. Typeform submission data including emails is personal data that should not be publicly readable.
1// Typeform answers parsing — extracting by field ref2// In Bubble workflow action 'Create a new TypeformResponse':34// respondent_name field:5// Source: trigger's form_response's answers6// Filter: field's ref = "name_question" (your question's ref ID)7// Extract: :first item's text89// respondent_email field:10// Source: trigger's form_response's answers11// Filter: field's ref = "email_question"12// Extract: :first item's email1314// multiple choice field:15// Source: trigger's form_response's answers16// Filter: field's ref = "interest_question"17// Extract: :first item's choice's label1819// number/rating field:20// Source: trigger's form_response's answers21// Filter: field's ref = "rating_question"22// Extract: :first item's number2324// date field:25// Source: trigger's form_response's answers26// Filter: field's ref = "date_question"27// Extract: :first item's datePro tip: Set descriptive Reference IDs in Typeform (question Settings → Reference) before building the Bubble parsing logic. Reference IDs like 'respondent_email' are more reliable than question positions, which change if you reorder questions in the form.
Expected result: When a Typeform is submitted, the Backend Workflow creates a TypeformResponse record in Bubble's database with the respondent's name, email, and other question answers correctly extracted from the nested answers array.
Configure API Connector for historical response pulls
For pulling existing Typeform responses (before the webhook was configured, or for bulk analytics), you need a separate API Connector call using your Typeform Personal Access Token. Click Plugins tab → API Connector → 'Add another API'. Name it 'Typeform API'. In the Shared headers section, click '+ Add a shared header'. Enter: name = `Authorization`, value = `Bearer YOUR_PERSONAL_ACCESS_TOKEN`. Enable the 'Private' checkbox on this header — the Personal Access Token grants read/write access to ALL forms in your Typeform account and must never reach the browser. Set the base URL to `https://api.typeform.com`. Click 'Add a call'. Name it 'Get Form Responses'. Set method to GET, path to `/forms/{{form_id}}/responses`. Add URL parameters: - `page_size` — value: `200` (maximum allowed by Typeform API) - `before` — leave empty (used for pagination; Typeform uses cursor-based pagination, not page numbers) The `before` parameter accepts the `token` value from the last response in a batch — to get the next page, pass that token as the `before` value. This is different from most APIs that use page numbers. Click 'Initialize call'. In the form_id test field, enter your actual Typeform form ID. Click 'Initialize'. Bubble detects the response structure from the Typeform API. Set 'Use as' to 'Data' to enable Repeating Group binding. IMPORTANT: The Personal Access Token grants full read/write access to all forms in your account. Use it only in API Connector shared headers with the Private checkbox enabled. Never reference it in client-side Bubble actions or expose it in workflows that non-admin users can trigger.
1// Typeform API Connector configuration2{3 "api_name": "Typeform API",4 "base_url": "https://api.typeform.com",5 "shared_headers": [6 {7 "name": "Authorization",8 "value": "Bearer <private: YOUR_PERSONAL_ACCESS_TOKEN>",9 "private": true10 }11 ],12 "calls": [13 {14 "name": "Get Form Responses",15 "method": "GET",16 "path": "/forms/{{form_id}}/responses",17 "params": [18 { "name": "page_size", "value": "200" },19 { "name": "before", "value": "" }20 ]21 }22 ]23}Pro tip: Typeform's API returns a maximum of 200 responses per call. For forms with more than 200 submissions, implement pagination by reading the last item's `token` field from the response and passing it as the `before` parameter in the next call. Bubble's 'Schedule API Workflow' with a running token value handles this loop.
Expected result: Initialize call returns HTTP 200 with a list of form responses. Bubble detects the response structure including items, total_items, and the nested answers array. 'Use as: Data' enables binding to Repeating Groups.
Build the Bubble response dashboard
Create a new Bubble page called 'typeform-responses'. This page will serve as the admin dashboard for managing Typeform submissions that have been received via webhook and stored in your TypeformResponse data type. Add a Repeating Group. Set its type to 'TypeformResponse'. Set the data source to 'Do a search for TypeformResponses' with Sort by = submitted_at descending. Set height to 60 pixels per row and add at least 3-4 columns showing: respondent_name, respondent_email, submitted_at (formatted as date), and the key question fields you captured (interest, notes, etc.). Add a search bar (Input element with a workflow that filters the Repeating Group) and a date range filter if needed. In each Repeating Group row, add a 'View Details' button that navigates to a single-response detail page or opens a popup showing all fields for the selected TypeformResponse. For bulk historical syncs, add a 'Sync from Typeform API' button on an admin page. Its workflow: call API Connector → Typeform API → Get Form Responses → for each response in the results, check if a TypeformResponse with that response_token already exists (search, count > 0), if not, create a new one. This prevents duplicate records when syncing. For WU efficiency: the webhook-driven workflow (step 3) processes one record at a time — very low WU cost. The bulk historical sync (this step) processes up to 200 records in a loop — higher WU consumption. Cache the last sync timestamp in an AppConfig field and only allow re-syncing after a defined interval (e.g., once per hour) to prevent accidental over-fetching. RapidDev's team frequently builds Typeform + Bubble intake systems and lead dashboards for clients — book a free scoping call at rapidevelopers.com/contact to discuss your specific form-to-app workflow.
1// Bubble data type: TypeformResponse2// respondent_name (text)3// respondent_email (text)4// form_id (text)5// response_token (text)6// submitted_at (date)7// raw_interest (text) [or your specific question fields]8// notes (text)9// synced_via (text) ["webhook" or "api"]1011// Repeating Group data source:12// Search for TypeformResponses13// Sort: submitted_at descending14// Constraints: [add search/date filters here]1516// Deduplication check in bulk sync workflow:17// Condition: Do a search for TypeformResponses18// constraint: response_token = current API result's token19// :count = 020// Then: Create a new TypeformResponsePro tip: Add a 'synced_via' text field (values: 'webhook' or 'api') to your TypeformResponse data type. This lets you see at a glance which records arrived in real time via webhook vs. which were backfilled from the API, useful for debugging gaps in your data.
Expected result: Admin dashboard page shows a Repeating Group listing all TypeformResponse records with respondent name, email, submission date, and key question answers. New submissions appear automatically after the webhook delivers them.
Common use cases
Real-Time Lead Capture into Bubble CRM
Embed a Typeform on your marketing site for lead capture (name, email, company, interest). When submitted, Typeform's webhook delivers the response to a Bubble Backend Workflow instantly. The workflow parses the answers, creates a 'Lead' record in Bubble's database, and can trigger a follow-up action like sending a welcome email via Mailchimp or adding the contact to a HubSpot pipeline.
Build a Bubble app that receives Typeform lead form submissions via webhook and creates a Lead record with name, email, company, and interest fields. Display the leads in an admin dashboard with a Repeating Group sorted by submission date descending.
Copy this prompt to try it in Bubble
Customer Survey Response Dashboard
Pull historical Typeform survey responses into a Bubble dashboard showing aggregated results: average ratings, most common multiple-choice answers, and open-text responses. Use the API Connector to fetch all responses and store them in a Bubble 'SurveyResponse' data type, then display results in charts and repeating groups for team analysis.
Create a Bubble dashboard showing aggregated results from a Typeform NPS survey. Display the average score, score distribution as a chart, and the last 50 written comments in a scrollable list. Include a 'Sync Latest Responses' button that fetches new submissions via the Typeform API.
Copy this prompt to try it in Bubble
Application or Intake Form Processing
Use Typeform's conversational interface to collect detailed application data (job applications, grant applications, client intake forms). When submitted, the webhook triggers a Bubble workflow that creates an 'Application' record, assigns it to a reviewer, and sends the applicant a confirmation. Admin users see a Bubble kanban board for application status management.
Build a Bubble intake system where Typeform submissions create Application records visible in an admin dashboard. Show applicant name, email, submission date, and a status dropdown (Pending, Reviewing, Approved, Rejected). Allow admins to add notes to each application.
Copy this prompt to try it in Bubble
Troubleshooting
Typeform webhook delivers successfully but Bubble's Detect Data step remains empty with no fields
Cause: Bubble's Detect Data step only populates when a webhook payload arrives while the Backend Workflow is in 'detecting' mode. If the 'Detect Data' click step is not active in the editor when Typeform sends the test payload, Bubble ignores the payload for schema detection purposes.
Solution: In Bubble's Backend Workflow editor, click the trigger/detect area to enable detection mode first, then return to Typeform and click 'Deliver sample payload' again within the same editing session. The Bubble editor must be open and actively waiting for the sample request.
Backend Workflow option is not visible in Bubble's left navigation
Cause: Backend Workflows (API Workflows) are only available on paid Bubble plans. The free plan does not show the Backend Workflows section.
Solution: Upgrade to Bubble's Starter plan or above. After upgrading, also verify that Settings → API → 'This app exposes a Workflow API' is toggled on — this must be enabled separately from the plan upgrade before Backend Workflow endpoints become active.
API Connector Initialize call returns 401 Unauthorized when testing the Typeform REST API
Cause: The Personal Access Token is either invalid, expired, or the Authorization header value is missing the 'Bearer ' prefix (with a trailing space before the token).
Solution: Go to app.typeform.com → Account settings → Personal tokens and verify the token is still active. In Bubble's API Connector, confirm the shared header value is formatted exactly as `Bearer YOUR_TOKEN` — the word 'Bearer' followed by a single space, then the token string. The 'There was an issue setting up your call' message in the Initialize step also indicates authentication failure.
Webhook receives submissions but the answers fields are all empty or null in the created TypeformResponse records
Cause: The field reference IDs in the Bubble workflow filter expressions do not match the actual Reference IDs set in Typeform's question settings, so the filter returns no matching answers.
Solution: In Typeform, open each question → click Settings → find the 'Reference' field and note the exact string. In Bubble's Backend Workflow, update the filter expressions to match these exact reference strings. If no Reference IDs were set in Typeform, they default to auto-generated strings — check the raw payload in Bubble's Logs tab to see the actual field ref values.
Best practices
- Use Typeform's Question Reference IDs (question Settings → Reference) to identify answers by stable IDs rather than array position. If you reorder Typeform questions, array-position-based parsing breaks; reference-based parsing does not.
- Enable Privacy rules on your TypeformResponse data type immediately after creating it. Typeform responses contain personal data (email addresses, names) that should never be publicly readable through Bubble's Data API.
- Add a `response_token` field (unique per Typeform submission) to your TypeformResponse data type and check for it before creating new records during bulk API syncs. This prevents duplicate records when the webhook and the historical API sync both capture the same submission.
- Avoid re-fetching all historical Typeform responses on every API sync. Store the last sync timestamp in an AppConfig data type and only request responses newer than that timestamp using Typeform's `since` parameter to minimize API calls and Workload Unit consumption.
- For complex forms with many question types, consider storing the full raw answers array as a JSON text field alongside the parsed individual fields. This gives you a fallback if your parsing logic misses a question type, and makes debugging easier by having the original data.
- Set a Typeform webhook Secret Token (in the webhook settings panel) and verify signatures in your Bubble Backend Workflow using a Toolbox Server Script action — this prevents unauthorized requests from creating records in your database if someone discovers your webhook URL.
- Test the entire pipeline end-to-end by submitting a real Typeform response (not just the 'Deliver sample payload' test) and verifying the record appears in Bubble's database with all fields populated correctly before going live.
Alternatives
SurveyMonkey uses OAuth 2.0 instead of Personal Access Tokens, requiring a more complex auth setup. SurveyMonkey is stronger for enterprise survey analytics with built-in reporting; Typeform is better for conversational lead capture forms where completion rate matters. Both support webhooks for real-time Bubble integration.
Google Analytics tracks form completion events on web pages but does not capture individual response data — it's a traffic analytics tool, not a form backend. Typeform stores each response with all answers. Choose Typeform when you need structured response data in Bubble; use Google Analytics separately to track form conversion rates.
HubSpot includes its own native forms feature that auto-creates CRM contacts on submission. If you're already using HubSpot for CRM, native HubSpot forms may be simpler than routing Typeform data through Bubble into HubSpot. Choose Typeform when you need the conversational one-question-at-a-time UX for higher completion rates on complex forms.
Frequently asked questions
Does Typeform webhook delivery work on Bubble's free plan?
No. Bubble's Backend Workflows (which receive incoming webhooks) require a paid Bubble plan. Additionally, Typeform webhooks themselves require a paid Typeform plan — they are not available on Typeform's free tier. Both tools need to be on paid plans for the webhook integration to work.
What is the difference between the webhook URL and the initialize URL in Bubble?
Bubble's Backend Workflow exposes two URLs: the main endpoint (`/api/1.1/wf/typeform-webhook`) for production webhook delivery, and an initialize endpoint (`/api/1.1/wf/typeform-webhook/initialize`) used only during setup to help Bubble detect the payload schema. Register ONLY the main endpoint URL in Typeform's webhook settings. Never use the initialize URL as your production webhook — it behaves differently and may not process data as expected.
How do I handle Typeform's cursor-based pagination when pulling historical responses?
Typeform uses token-based (cursor) pagination, not page numbers. The API returns up to 200 responses per call. If there are more, the last response in the batch has a `token` field value. To get the next page, pass that token as the `before` URL parameter in your next API call. In Bubble, implement this with a recursive Backend Workflow: call the API, save results, check if the result count equals page_size (meaning there may be more), then schedule another API Workflow run passing the last token as `before`.
Can I write data back to Typeform from Bubble — for example, pre-fill form answers?
Typeform supports URL-based pre-fill for known answer values using query parameters appended to the form URL (e.g., `https://yourform.typeform.com/to/FORM_ID#email=test@example.com`). You can generate these pre-filled URLs dynamically in Bubble by constructing text expressions. The Typeform REST API does not support programmatic response creation — you cannot submit answers on behalf of users via API.
How do I extract a multiple-choice answer from the Typeform answers array in Bubble?
For multiple-choice (single select) questions, the answer value is stored at `answer.choice.label`. In Bubble's workflow, filter the answers list by `field.ref = 'your_question_ref'`, take the first item, then access its `choice.label` sub-field. For multi-select questions, the values are in `answer.choices.labels` — an array of selected labels you'll need to handle as a list.
My Typeform webhook stopped delivering after a few days. What happened?
Typeform deactivates webhooks that repeatedly fail to deliver (if Bubble returns errors or timeouts). Check Bubble's Logs tab → Workflow logs to see if recent webhook calls resulted in errors. Common causes: Bubble's Workflow API setting was accidentally disabled (Settings → API), or a workflow action error causes the endpoint to return a non-200 status. Fix the underlying error, then re-enable the webhook in Typeform → Connect → Webhooks.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation