# How to Integrate Lovable with Typeform

- Tool: Lovable
- Difficulty: Intermediate
- Time required: 30 minutes
- Last updated: March 2026

## TL;DR

Integrate Typeform with a Lovable app by embedding forms using the @typeform/embed-react SDK for conversational survey experiences, and creating a Supabase Edge Function that handles Typeform response webhooks and queries the Typeform API with a Personal Access Token stored in Cloud → Secrets. Typeform's conversational UI achieves significantly higher completion rates than traditional survey forms.

## Integrating Typeform Conversational Forms into Your Lovable App

Typeform's defining characteristic is completion rate — its one-question-at-a-time conversational interface achieves completion rates of 57% versus the industry average of 14% for traditional multi-question forms. For Lovable app builders, this means an in-app NPS survey, onboarding questionnaire, or feedback form is significantly more likely to be completed when implemented with Typeform's conversational format rather than a traditional multi-field form. The psychological principle is simple: a single question feels manageable where a page of questions feels like work.

Typeform integrates with Lovable through two complementary paths. The @typeform/embed-react SDK provides a native React embedding experience with popup, slider, and full-page display modes — the form renders as an overlay within your Lovable app, not in a separate browser window. This SDK is the recommended approach for in-app use, providing smooth animations, mobile-responsive behavior, and event callbacks for completion detection. The second path is the Typeform API — a REST API that provides programmatic access to forms, responses, and webhook configurations using a Personal Access Token.

Response data in Typeform flows through webhooks — Typeform POSTs a JSON payload to your Edge Function URL when each form is submitted, delivering the response within seconds. Your Edge Function parses the response, extracts answers and hidden field values, stores the structured data in Supabase, and triggers any follow-up actions. This real-time webhook pattern is more reliable than polling the API for new responses. Lovable's security infrastructure blocks approximately 1,200 hardcoded API keys daily and holds SOC 2 Type II certification. Your Typeform Personal Access Token must live in Cloud → Secrets and be accessed only from Edge Functions via Deno.env.get().

## Before you start

- A Lovable account with an existing project that has Supabase and user authentication configured
- A Typeform account — free plan includes 10 responses per month; paid plans start at $25/month for unlimited responses
- At least one Typeform form created and published, with its Form ID copied from the form's Share → Embed settings
- A Typeform Personal Access Token from My Account → Personal Tokens (required for API access and webhook configuration)
- Basic understanding of Typeform's response data structure — answers are keyed by question ID (ref field), not by question text

## Step-by-step guide

### 1. Create a Typeform form and get your Personal Access Token

Before embedding Typeform in your Lovable app, create the form you want to embed and gather the credentials needed for API access. Log in to your Typeform account at typeform.com. Click 'Create typeform' and select the type of form you want: a survey, quiz, or blank form. For NPS surveys, Typeform has a built-in NPS template — search 'NPS' in the templates gallery. For onboarding questionnaires, the blank form gives you the most flexibility.

When building the form, add hidden fields for user identification. Hidden fields store values passed from your Lovable app alongside each response without displaying them to the respondent. Go to your form's Logic section → Hidden Fields and add a field named 'user_id' (you can also add 'user_email', 'user_plan', or any other context you want to pass). These field names will be used as URL parameters when embedding the form.

To get your Form ID for embedding, click the Share button in the form editor header. Under 'Share link', the URL will look like https://yourname.typeform.com/to/XXXXXXXX — the alphanumeric string after '/to/' is your Form ID. Copy this for use as VITE_TYPEFORM_FORM_ID.

For API access and webhook management, generate a Personal Access Token. Go to your Typeform account by clicking your profile picture → My Account → Personal Tokens → Generate a new token. Give it a name like 'Lovable Integration', select the scopes you need (at minimum: forms:read and responses:read for reading data; webhooks:write for creating webhooks), and click Generate Token. Copy the token immediately — you will only see it once. Go to your Lovable project, open the Cloud tab, click Secrets, and add TYPEFORM_ACCESS_TOKEN with your token value. Also add VITE_TYPEFORM_FORM_ID with your form ID for the frontend.

**Expected result:** Your Typeform form is created and published with hidden fields configured. TYPEFORM_ACCESS_TOKEN and VITE_TYPEFORM_FORM_ID are stored in Lovable Cloud Secrets. The form's Share → Embed section shows the Form ID in the embed URL.

### 2. Install @typeform/embed-react and create the Typeform embed component

Install the @typeform/embed-react npm package and create a React component that embeds your Typeform form. The embed SDK provides several display modes: widget (inline, renders within the page layout), popup (modal overlay), slider (slides in from side or bottom), and side-tab (a tab that opens from the edge of the screen). For most in-app feedback use cases, popup or slider works best — they appear on demand without taking over the page.

The @typeform/embed-react package provides typed React components for each embed mode: PopupButton, SliderButton, Widget, and PopupModal. Each component accepts a formId prop (your Typeform form ID), a hidden prop for hidden field values, onSubmit and onClose callbacks, and mode-specific styling props.

The hidden prop is the key to user identification — pass an object with your hidden field names and values. For example: hidden={{ user_id: currentUserId, user_plan: currentPlan }}. Typeform URL-encodes these values and passes them to the form via query parameters, which your Edge Function webhook handler then reads from the response payload. This links every Typeform response back to the corresponding Supabase user without asking users for their email address in the form itself.

For the onSubmit callback, Typeform calls this function when the form is successfully submitted. Use it to close the modal if using PopupButton, update the user's Supabase profile to mark the form as submitted (preventing repeat displays), and optionally show a thank-you message. The onSubmit callback receives a response_id that you can store for later lookup.

For conditional display — showing the form only to users who have not already seen it — check a survey_completed field in the user's Supabase profile before rendering the Typeform component. Gate the form display with a useEffect that checks this field after authentication.

```
// src/components/TypeformSurvey.tsx
import { useEffect, useState } from 'react';
import { PopupButton } from '@typeform/embed-react';
import { supabase } from '@/integrations/supabase/client';
import { useToast } from '@/hooks/use-toast';

interface TypeformSurveyProps {
  userId: string;
  triggerLabel?: string;
  autoOpen?: boolean;
}

const FORM_ID = import.meta.env.VITE_TYPEFORM_FORM_ID;

export function TypeformSurvey({
  userId,
  triggerLabel = 'Share Feedback',
  autoOpen = false,
}: TypeformSurveyProps) {
  const { toast } = useToast();
  const [completed, setCompleted] = useState(false);

  useEffect(() => {
    // Check if user has already completed the survey
    async function checkStatus() {
      const { data } = await supabase
        .from('profiles')
        .select('typeform_survey_completed')
        .eq('id', userId)
        .single();
      if (data?.typeform_survey_completed) setCompleted(true);
    }
    checkStatus();
  }, [userId]);

  const handleSubmit = async ({ responseId }: { responseId: string }) => {
    await supabase
      .from('profiles')
      .update({ typeform_survey_completed: true, typeform_response_id: responseId })
      .eq('id', userId);
    setCompleted(true);
    toast({ title: 'Thank you for your feedback!', description: 'Your response has been recorded.' });
  };

  if (!FORM_ID || completed) return null;

  return (
    <PopupButton
      id={FORM_ID}
      hidden={{ user_id: userId }}
      onSubmit={handleSubmit}
      autoClose={3}
      size={75}
      className="px-4 py-2 bg-primary text-primary-foreground rounded-md text-sm font-medium"
      open={autoOpen ? 'load' : undefined}
    >
      {triggerLabel}
    </PopupButton>
  );
}
```

**Expected result:** The TypeformSurvey component renders a button that opens the Typeform form as a popup. The form displays correctly with one-question-at-a-time navigation. Completing the form closes the popup and updates the user's profile. The component does not render for users who have already completed the survey.

### 3. Create a webhook receiver Edge Function for real-time responses

Typeform webhooks deliver response data to your Edge Function URL within seconds of form submission, enabling immediate follow-up actions and real-time dashboards. Before creating the Edge Function, understand Typeform's webhook payload structure — it differs from other webhook systems in how answers are structured.

A Typeform webhook payload is a JSON object with a form_response top-level key. Inside form_response, the key fields are: form_id, event_id (a unique webhook delivery ID), submitted_at (ISO timestamp), hidden (an object containing the hidden field values you passed during embedding — like { user_id: 'abc123' }), calculated (aggregate scores if configured), and answers (an array of answer objects).

Each answer object has a field key identifying which question was answered (using the question's ref), a type indicating the answer format (number, text, choice, etc.), and a value key containing the actual answer. Answers with type 'number' contain the numeric value (for NPS scores, a number from 0-10). Answers with type 'text' or 'long_text' contain the verbatim string. Answers with type 'choice' contain a { label, ref } object.

To set up the webhook in Typeform, go to your form → Connect → Webhooks → Add Webhook. Enter your Edge Function URL (https://[project-ref].supabase.co/functions/v1/typeform-webhook) and enable the webhook. Typeform will POST to this URL when each form is submitted. Typeform also supports webhook signature verification using an HMAC secret — if you enable this in Typeform's webhook settings, your Edge Function should verify the signature before processing the payload.

In the Edge Function, extract the answers from the payload, parse the NPS score (from the question with ref 'nps_score'), the verbatim feedback (from the question with ref 'verbatim_feedback'), and the hidden user_id. Store the structured data in your Supabase database. Add business logic for follow-up actions: create support tickets for detractors, send thank-you messages to promoters, or update the user's profile with their NPS score.

```
// supabase/functions/typeform-webhook/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};

function getAnswerValue(answers: Array<{ field: { ref: string }; type: string; number?: number; text?: string; long_text?: string }>, ref: string) {
  const answer = answers.find(a => a.field?.ref === ref);
  if (!answer) return null;
  if (answer.type === 'number') return answer.number;
  if (answer.type === 'text') return answer.text;
  if (answer.type === 'long_text') return answer.long_text;
  return null;
}

serve(async (req) => {
  if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders });
  if (req.method !== 'POST') return new Response('Method not allowed', { status: 405 });

  try {
    const supabase = createClient(
      Deno.env.get('SUPABASE_URL') ?? '',
      Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
    );

    const body = await req.json();
    const formResponse = body.form_response;

    if (!formResponse) {
      return new Response(JSON.stringify({ error: 'Invalid Typeform payload' }), {
        status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    }

    const answers = formResponse.answers ?? [];
    const hidden = formResponse.hidden ?? {};
    const npsScore = getAnswerValue(answers, 'nps_score') as number | null;
    const verbatim = getAnswerValue(answers, 'verbatim_feedback') as string | null;
    const userId = hidden.user_id ?? null;

    const { error } = await supabase.from('nps_responses').upsert({
      response_id: formResponse.event_id,
      form_id: formResponse.form_id,
      user_id: userId,
      nps_score: npsScore,
      verbatim_feedback: verbatim,
      submitted_at: formResponse.submitted_at,
      raw_answers: answers,
    }, { onConflict: 'response_id' });

    if (error) console.error('DB insert error:', error);

    if (npsScore !== null && npsScore < 7) {
      await supabase.from('follow_up_queue').insert({
        user_id: userId,
        response_id: formResponse.event_id,
        nps_score: npsScore,
        status: 'pending',
        priority: npsScore <= 3 ? 'high' : 'medium',
      });
    }

    return new Response(JSON.stringify({ success: true }), {
      headers: { ...corsHeaders, 'Content-Type': 'application/json' },
    });
  } catch (error) {
    console.error('Webhook error:', error);
    return new Response(JSON.stringify({ error: String(error) }), {
      status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' },
    });
  }
});
```

**Expected result:** The typeform-webhook Edge Function is deployed and its URL is registered in Typeform's webhook settings. Submitting the form creates a new row in the nps_responses Supabase table within seconds. The user_id from the hidden field is correctly captured in the response record.

### 4. Fetch form responses via the Typeform API for analytics

Build a Supabase Edge Function that fetches form responses from the Typeform API for building analytics dashboards. While the webhook approach handles real-time processing of individual responses, the API is useful for fetching all historical responses for analysis, building summary statistics, and populating dashboards with aggregate data.

Typeform's API responses endpoint is GET https://api.typeform.com/forms/{form_id}/responses. Authentication uses the Authorization header with 'Bearer [personal_access_token]'. The endpoint accepts pagination parameters (page_size, before, after) and filters (completed for only completed responses, since and until for date filtering). Responses are paginated — each page returns up to 1,000 responses by default.

Create a proxy Edge Function that accepts a form_id parameter, fetches responses from the Typeform API using the TYPEFORM_ACCESS_TOKEN secret, and optionally stores the aggregate statistics in your Supabase database for fast dashboard rendering. For NPS dashboards, calculate the NPS score from the responses: (promoters% - detractors%) where promoters are scores 9-10 and detractors are scores 0-6.

To display Typeform analytics inside your Lovable app, create a React component that calls the proxy Edge Function and renders summary statistics — total responses, NPS score trend over time, answer distribution for each question, and a feed of recent verbatim comments. For complex Typeform analytics implementations including multi-form dashboards and respondent segmentation, RapidDev's team can help build the data pipeline and visualization components.

```
// supabase/functions/typeform-proxy/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};

serve(async (req) => {
  if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders });

  try {
    const token = Deno.env.get('TYPEFORM_ACCESS_TOKEN');
    if (!token) {
      return new Response(JSON.stringify({ error: 'TYPEFORM_ACCESS_TOKEN not configured' }), {
        status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    }

    const { form_id, date_from, date_to, nps_question_ref = 'nps_score' } = await req.json();
    if (!form_id) {
      return new Response(JSON.stringify({ error: 'form_id required' }), {
        status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    }

    let url = `https://api.typeform.com/forms/${form_id}/responses?page_size=200&completed=true`;
    if (date_from) url += `&since=${date_from}`;
    if (date_to) url += `&until=${date_to}`;

    const response = await fetch(url, {
      headers: { 'Authorization': `Bearer ${token}` },
    });

    if (!response.ok) {
      const err = await response.text();
      return new Response(JSON.stringify({ error: `Typeform API: ${response.status}`, detail: err }), {
        status: response.status, headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      });
    }

    const data = await response.json();
    const responses = data.items ?? [];

    // Calculate NPS stats
    const npsAnswers: number[] = responses.flatMap((r: { answers: Array<{ field: { ref: string }; type: string; number?: number }> }) =>
      (r.answers ?? [])
        .filter((a) => a.field?.ref === nps_question_ref && a.type === 'number')
        .map((a) => a.number ?? 0)
    );

    const promoters = npsAnswers.filter(s => s >= 9).length;
    const detractors = npsAnswers.filter(s => s <= 6).length;
    const total = npsAnswers.length;
    const npsScore = total > 0
      ? Math.round(((promoters - detractors) / total) * 100)
      : null;

    return new Response(JSON.stringify({
      total_responses: responses.length,
      nps_stats: { total, promoters, passives: total - promoters - detractors, detractors, nps_score: npsScore },
      responses: responses.slice(0, 50), // Return first 50 for display
    }), {
      headers: { ...corsHeaders, 'Content-Type': 'application/json' },
    });
  } catch (error) {
    return new Response(JSON.stringify({ error: String(error) }), {
      status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' },
    });
  }
});
```

**Expected result:** The typeform-proxy Edge Function fetches form responses and returns NPS statistics including total responses, promoter/detractor counts, and the calculated NPS score. Calling it with a valid form_id returns the aggregate data for use in dashboard components.

## Best practices

- Always set meaningful question refs in Typeform (Logic → question Settings → Reference) before deploying — auto-generated refs like 'abc123' make webhook payload parsing opaque and difficult to maintain when the form changes.
- Pass the Supabase user ID as a hidden field in every Typeform embed so all responses are linked to specific users in your database — this enables personalized follow-up and prevents orphaned response records.
- Implement upsert with response_id as the unique key in your Supabase nps_responses table — Typeform may deliver duplicate webhook events for the same response in rare cases, and upsert prevents duplicate rows.
- Store the raw answers JSONB alongside extracted structured fields in your database — Typeform question structures change when forms are edited, and raw data preservation allows re-extraction of additional fields later without re-fetching from the API.
- Trigger Typeform surveys at high-intent moments — after a successful purchase, after completing onboarding, or after a user has been active for 30 days — rather than on every page load. High-intent timing dramatically improves completion rates.
- Use Typeform's logic jumps to show different follow-up questions based on the NPS score — ask detractors 'What could we improve?' and ask promoters 'What would you tell a friend about us?' This personalizes the survey experience and collects more actionable feedback.
- Rate-limit survey display using the typeform_survey_completed and typeform_survey_dismissed fields in user profiles — do not show the same survey again to users who have already responded or explicitly dismissed it.

## Use cases

### Collect onboarding information with a conversational form

Replace a multi-field signup form with a Typeform conversational questionnaire that collects the user's role, team size, use case, and goals one question at a time. The higher completion rate ensures more users complete onboarding setup, improving activation. Pass the user's Supabase ID as a hidden field so responses can be matched to the correct user profile.

Prompt example:

```
Create an OnboardingForm component using @typeform/embed-react that shows a Typeform form as a popup after signup. Use the form ID from VITE_TYPEFORM_ONBOARDING_ID. Pass the user's Supabase user ID as a hidden field named 'user_id'. On form submission (onSubmit callback), update the user's Supabase profile to set onboarding_completed: true and close the popup. Use the SliderButton embed mode so the form opens smoothly from the bottom of the screen.
```

### Run an in-app NPS survey via conversational form

Deploy a quarterly NPS survey using a Typeform form embedded as a popup that appears after users have been active for 30 days. The conversational format (score question, then follow-up 'why' question) collects both the numeric NPS score and qualitative verbatim feedback in a single form that takes under 60 seconds to complete. Webhook processing stores results in Supabase and triggers follow-up workflows.

Prompt example:

```
Create a Supabase Edge Function called 'typeform-webhook' that receives Typeform response webhooks for the NPS form. Extract the hidden user_id field, the NPS score answer, and the verbatim feedback answer from the response payload. Store in a 'nps_responses' Supabase table with columns: response_id, user_id, nps_score, verbatim, submitted_at. For NPS scores below 7, also insert a row into 'support_follow_ups' with status 'pending' and priority 'high'.
```

### Build a form response analytics dashboard

Create an in-app dashboard that fetches Typeform response data via the Typeform API and displays aggregate analytics — response counts over time, answer distribution for each question, average NPS score trend, and verbatim response feed. This gives team members a self-serve analytics view without requiring Typeform account access.

Prompt example:

```
Create a TypeformAnalytics page that fetches form responses from the Typeform API via a Supabase Edge Function called 'typeform-proxy'. For a specific form ID (from VITE_TYPEFORM_NPS_ID), display: total responses this month, NPS score distribution as a bar chart (0-10), a feed of the 10 most recent verbatim comments, and a weekly response count trend chart. Fetch from the Typeform API responses endpoint and store in Supabase for caching.
```

## Troubleshooting

### The Typeform popup does not open when the PopupButton is clicked

Cause: The form ID is undefined (VITE_TYPEFORM_FORM_ID is not set as a build environment variable), the @typeform/embed-react CSS is not loaded, or a Content Security Policy is blocking the Typeform script loading.

Solution: Check that VITE_TYPEFORM_FORM_ID is set in Lovable's environment configuration as a build variable, not just in Cloud Secrets. In the browser console, check for errors related to typeform.com being blocked. Import the embed CSS in your main.tsx or App.tsx: import '@typeform/embed-react/build/css/popup.css'. Verify the Form ID is the alphanumeric string from the Typeform share URL, not the full URL.

```
// Add to src/main.tsx or src/App.tsx:
import '@typeform/embed-react/build/css/popup.css';
```

### Hidden fields are not appearing in Typeform webhook responses — the hidden object is empty

Cause: The hidden fields are not defined in the Typeform form's Logic → Hidden Fields section, the field names in the hidden prop do not exactly match the field names configured in Typeform, or the form was embedded without the hidden prop.

Solution: Log in to Typeform, open the form editor, go to Logic → Hidden Fields and verify that fields named 'user_id' (and any others you are passing) are listed there. The field names are case-sensitive and must exactly match the keys in the hidden prop object passed to the React embed component. After adding hidden fields in Typeform, test by submitting a new response and checking the webhook payload in Cloud Logs.

### Typeform API returns 401 when called from the Edge Function

Cause: The TYPEFORM_ACCESS_TOKEN secret is missing from Cloud Secrets, has expired, or the token scopes do not include the 'responses:read' permission needed to access form responses.

Solution: Go to Cloud → Secrets and verify TYPEFORM_ACCESS_TOKEN is present. In your Typeform account, go to My Account → Personal Tokens and check that the token still exists and has responses:read scope. If the token was recently regenerated, update the Cloud Secret with the new value and redeploy the Edge Function. Typeform Personal Access Tokens do not expire automatically but can be revoked.

### Webhook events arrive but the NPS score is null in the Supabase table

Cause: The question ref used in getAnswerValue() does not match the actual ref set in Typeform for the NPS question — either the question ref was not customized and uses an auto-generated value, or a typo exists between the Edge Function code and the Typeform form configuration.

Solution: Log the full answers array from the webhook payload in Cloud Logs to see the actual field refs: console.log('Answers:', JSON.stringify(formResponse.answers)). Compare the field.ref values in the log output against what your Edge Function expects. Update either the form's question refs in Typeform (Logic → Hidden Fields, then each question's Settings → Reference) or the Edge Function code to use the correct ref value.

```
// Add to Edge Function to debug answer refs:
console.log('Answer refs:', JSON.stringify(answers.map((a: { field: { ref: string }; type: string }) => ({ ref: a.field?.ref, type: a.type }))));
```

## Frequently asked questions

### Is Typeform free to use with a Lovable app?

Typeform's free plan includes 10 responses per month, which is useful for initial testing but insufficient for production use. The Basic plan ($29/month) allows 100 responses per month, while the Plus plan ($59/month) is unlimited. The @typeform/embed-react SDK is free to use regardless of plan. API access for webhook configuration and programmatic response retrieval is available on all paid plans.

### What is the difference between Typeform and SurveyMonkey for in-app forms?

Typeform displays one question at a time in a conversational flow, with animations and progress indicators that feel more like an app than a form — this achieves completion rates of 50-60% compared to 14-20% for traditional multi-question surveys. SurveyMonkey displays all questions on a page in a traditional survey format, which is familiar to enterprise users and better for long, structured surveys. Choose Typeform for short (under 10 questions) customer-facing feedback forms where completion rate matters most.

### How do I match Typeform responses back to specific users in my Supabase database?

Pass the Supabase user's UUID as a hidden field in the Typeform embed using the hidden prop: hidden={{ user_id: userId }}. First, define a hidden field named 'user_id' in Typeform's Logic → Hidden Fields section. When the form is submitted, the webhook payload includes this value in formResponse.hidden.user_id. Store this user_id in your Supabase table to link responses to specific user profiles.

### Can I trigger a Typeform form automatically without the user clicking a button?

Yes. The @typeform/embed-react PopupButton component accepts an open prop — set it to 'load' to open the form immediately when the component mounts, or set it to 'time' with an openValue in milliseconds for a delayed auto-open. The PopupModal component (different from PopupButton) can also be controlled programmatically using a ref and calling the .open() method to trigger the form in response to any application event.

### How secure is Typeform webhook data — should I verify webhook signatures?

Typeform supports webhook signature verification using HMAC-SHA256. Configure a webhook secret in Typeform's webhook settings, then verify the Typeform-Signature header in your Edge Function by computing HMAC-SHA256 of the raw request body and comparing it to the header value. This prevents malicious actors from sending fake form submission data to your webhook URL. For production applications handling sensitive data (like NPS responses with user identity), webhook signature verification is strongly recommended.

### Can I show different questions to different users in a Typeform form?

Yes, using Typeform's Logic Jumps feature. Define conditions in the Logic panel that skip or show questions based on previous answers or hidden field values. For example, show a follow-up question only to users who give an NPS score below 7 — this is configured in Typeform's interface without any changes to your Lovable app code. Hidden fields (passed from your app) can also be used in logic conditions to personalize the question flow based on the user's profile data.

---

Source: https://www.rapidevelopers.com/lovable-integration/typeform
© RapidDev — https://www.rapidevelopers.com/lovable-integration/typeform
