Skip to main content

How to Migrate from Typeform to Formbricks in 2026

·OSSAlt Team
typeformformbricksmigrationsurveysguide
Share:

How to Migrate from Typeform to Formbricks in 2026

TL;DR

Typeform charges $25–83/month and caps responses on every plan. Formbricks is the open source alternative for in-app surveys, NPS, CSAT, and feedback collection — self-hosted, unlimited responses, and built specifically for product teams who want to survey users inside their app rather than redirect them to a separate form URL. This guide walks through the complete migration: deploying Formbricks, recreating your surveys, embedding the widget, configuring triggers, and connecting your data pipeline.

Key Takeaways

  • Typeform Basic ($25/month) limits you to 100 responses/month — Formbricks self-hosted is unlimited
  • Formbricks (AGPL-3.0, 9K+ stars) is built for in-app surveys — target specific users, trigger on events, show inside your product
  • Question type mapping is 1:1 for most types — NPS, rating, multiple choice, open text all exist in Formbricks
  • Webhooks let you pipe responses to Slack, Notion, Airtable, or your backend in real time
  • The key difference: Typeform creates standalone form pages; Formbricks creates embedded surveys that appear inside your app to specific user segments
  • Self-hosting on a $6/month VPS eliminates Typeform's $300–1,000/year bill

Why Teams Switch from Typeform

Typeform's pricing model has a fundamental mismatch for SaaS products. You pay per response — the more your product grows, the more you pay for user research. The tiers:

  • Free: 10 responses/month
  • Basic: $25/month — 100 responses/month
  • Plus: $50/month — 1,000 responses/month
  • Business: $83/month — 10,000 responses/month

A SaaS with 500 active users running a quarterly NPS survey needs 500 responses every 3 months (~170/month). That's the Plus plan at $50/month, $600/year — for surveys.

More critically, Typeform is designed for standalone form pages. Users leave your product, fill out a form on typeform.com, and return. For in-app NPS, post-feature surveys, or churn feedback modals, this creates friction. Formbricks solves both problems: no response limits, and surveys appear inside your product.


Step 1: Deploy Formbricks

# docker-compose.yml
services:
  postgres:
    image: postgres:15-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: formbricks
      POSTGRES_USER: formbricks
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data

  formbricks:
    image: ghcr.io/formbricks/formbricks:latest
    restart: unless-stopped
    ports:
      - "3000:3000"
    depends_on:
      - postgres
    environment:
      DATABASE_URL: postgresql://formbricks:password@postgres:5432/formbricks
      NEXTAUTH_SECRET: your-nextauth-secret-min-32-chars
      NEXTAUTH_URL: https://surveys.yourdomain.com
      NEXT_PUBLIC_WEBAPP_URL: https://surveys.yourdomain.com
      # SMTP for survey invitation emails
      MAIL_FROM: surveys@yourdomain.com
      SMTP_HOST: smtp.resend.com
      SMTP_PORT: 587
      SMTP_SECURE_ENABLED: "1"
      SMTP_USER: resend
      SMTP_PASSWORD: re_your_api_key
      # File uploads (local or S3)
      UPLOADS_DIR: /home/nextjs/apps/web/uploads
    volumes:
      - uploads:/home/nextjs/apps/web/uploads

volumes:
  postgres_data:
  uploads:
# Start Formbricks
docker compose up -d

# Check logs
docker compose logs -f formbricks

Option B: One-Line Docker (quick test)

docker run -d \
  --name formbricks \
  -p 3000:3000 \
  -v formbricks_data:/app/data \
  -e NEXTAUTH_SECRET=your-secret-min-32-chars \
  -e NEXTAUTH_URL=http://localhost:3000 \
  -e NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000 \
  ghcr.io/formbricks/formbricks:latest

Step 1b: Reverse Proxy with Caddy

# /etc/caddy/Caddyfile
surveys.yourdomain.com {
    reverse_proxy localhost:3000
}
sudo systemctl restart caddy
# Caddy auto-provisions SSL via Let's Encrypt

Step 1c: Create your account

Navigate to https://surveys.yourdomain.com and create your admin account. You'll land on the Formbricks dashboard where you can create your first environment.


Step 2: Understand the Typeform → Formbricks Mental Model

Before recreating surveys, understand the key conceptual difference:

Typeform: A form is a URL. You share the link or embed an iframe. Anyone with the link can fill it out.

Formbricks: A survey is attached to an environment. Your app connects to the environment, identifies users, and Formbricks decides who to show which survey based on targeting rules.

This means Formbricks surveys are:

  • Targeted — only specific users (new signups, churning users, power users) see specific surveys
  • Triggered — surveys appear at the right moment (after completing a feature, after X days, on exit intent)
  • Contextual — users fill them out without leaving your app

Step 3: Map and Recreate Your Surveys

Question Type Mapping

Typeform FeatureFormbricks EquivalentNotes
Welcome screenSurvey intro cardSame — configure in survey builder
Short textOpen text (short)Identical
Long textOpen text (long)Identical
Multiple choiceMultiple choiceIdentical, supports multi-select
Single choiceSingle choiceIdentical
Rating (stars)Rating (1–5)Same concept
Opinion scaleRating (1–10)Extended range available
NPSNPS question typeNative NPS with 0–10 scale
DropdownSingle choiceUse single choice with many options
DateOpen textNo native date picker
File uploadNot available — Typeform-only
PaymentNot available — Typeform-only
Thank you screenThank you cardSame
Logic jumpsSurvey logicAvailable via condition builder
Hidden fieldsHidden fieldsSupported for user attributes

Recreating an NPS Survey

In Typeform, NPS was a standalone form. In Formbricks, NPS is a first-class survey type:

  1. Create Survey → Select "NPS" template
  2. Set the question: "How likely are you to recommend [Product] to a friend?"
  3. Add follow-up text question (auto-branches based on score):
    • Score 0–6: "What's the main reason for your score?"
    • Score 7–8: "What could we improve?"
    • Score 9–10: "What do you love most?"
  4. Configure targeting: Run this survey every 90 days for active users

Recreating a Multi-Step Survey

Survey: Post-Onboarding Feedback (5 steps)

Step 1: Single choice
  "How did you find out about us?"
  Options: Search engine, Social media, Friend referral, Product Hunt, Other

Step 2: Rating (1–5)
  "How easy was your onboarding experience?"
  (Shows only if step 1 answer is NOT "Friend referral")

Step 3: Open text
  "What was the most helpful part of onboarding?"

Step 4: Open text
  "Is there anything that confused you?"

Step 5: Thank you card
  "Thanks for your feedback! It helps us improve."

Step 4: Embed the Formbricks Widget

This is the main integration step. Add the Formbricks SDK to your app — it connects to your environment, identifies users, and renders surveys when triggered.

JavaScript (Vanilla / CDN)

<!-- Add before </head> or before </body> -->
<script type="text/javascript">
  !function(){
    var apiHost = "https://surveys.yourdomain.com";
    var t = document.createElement("script");
    t.type = "text/javascript";
    t.async = true;
    t.src = apiHost + "/js/formbricks.umd.cjs";
    var e = document.getElementsByTagName("script")[0];
    e.parentNode.insertBefore(t, e);
    t.onload = function() {
      window.formbricks.init({
        environmentId: "your-environment-id",
        apiHost: apiHost,
        userId: "user_123",          // Your user's ID
        attributes: {
          email: "user@example.com",
          plan: "pro",
          daysActive: "45",
          hasCompletedOnboarding: "true",
        },
      });
    };
  }();
</script>

React / Next.js

npm install @formbricks/js
// app/providers.tsx (or your root layout)
'use client';

import { useEffect } from 'react';
import formbricks from '@formbricks/js/app';

interface FormbricksProviderProps {
  userId: string;
  userEmail: string;
  userPlan: string;
}

export function FormbricksProvider({ userId, userEmail, userPlan }: FormbricksProviderProps) {
  useEffect(() => {
    formbricks.init({
      environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENV_ID!,
      apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_HOST!,
      userId,
      attributes: {
        email: userEmail,
        plan: userPlan,
      },
    });
  }, [userId]);

  return null;
}
// app/layout.tsx
import { FormbricksProvider } from './providers';
import { auth } from '@/lib/auth';

export default async function RootLayout({ children }) {
  const session = await auth();

  return (
    <html>
      <body>
        {children}
        {session?.user && (
          <FormbricksProvider
            userId={session.user.id}
            userEmail={session.user.email}
            userPlan={session.user.plan}
          />
        )}
      </body>
    </html>
  );
}

Step 5: Configure Survey Triggers

Formbricks triggers replace Typeform's static URLs. Surveys appear automatically when conditions are met.

Trigger Types

Page visit: Show survey when user visits a specific URL path

// In Formbricks dashboard: Survey → Triggers → "Page URL"
// Condition: URL contains "/dashboard" and user hasn't seen this survey

Custom events: Trigger when user completes an action in your app

// Fire a custom event from your app
formbricks.track("completed_first_export");
formbricks.track("upgraded_to_pro");
formbricks.track("used_feature_X");

// In Formbricks dashboard: Survey → Triggers → "Code"
// Select: "completed_first_export"

Exit intent: Show survey when user is about to leave

// Configure in Formbricks dashboard:
// Survey → Triggers → "Exit Intent"
// Good for churn surveys on pricing or account pages

Targeting Filters (Audience)

// Show NPS survey only to:
// - Users with plan = "pro" OR "enterprise"
// - Who have been active for more than 30 days
// - Who haven't seen this survey in 90 days

// Set up via: Survey → Audience → Add Filter
// Attribute: "plan" equals "pro" OR "enterprise"
// Attribute: "daysActive" greater than "30"

Step 6: Set Up Webhooks

Pipe Formbricks responses to your existing data stack instead of logging into another dashboard.

// Formbricks webhook payload structure
{
  "event": "responseFinished",
  "data": {
    "id": "resp_abc123",
    "surveyId": "survey_xyz",
    "surveyName": "NPS Survey - Q1 2026",
    "personId": "person_user123",
    "data": {
      "nps_question": 9,
      "followup_text": "Love the export speed!"
    },
    "meta": {
      "userAgent": "...",
      "url": "https://app.yourdomain.com/dashboard"
    },
    "createdAt": "2026-03-15T10:23:00Z"
  }
}
// Next.js API route to receive Formbricks webhooks
// app/api/webhooks/formbricks/route.ts
import { NextRequest } from 'next/server';

export async function POST(req: NextRequest) {
  const payload = await req.json();

  if (payload.event === 'responseFinished') {
    const { surveyName, data, personId } = payload.data;

    // Log to your database
    await db.survey_responses.create({
      survey: surveyName,
      userId: personId,
      responses: data,
    });

    // Send NPS to Slack
    if (surveyName.includes('NPS') && data.nps_question <= 6) {
      await slack.postMessage({
        channel: '#product',
        text: `🚨 Detractor NPS (${data.nps_question}/10): "${data.followup_text}"`,
      });
    }
  }

  return new Response('ok');
}

Step 7: Cancel Typeform

  1. Export any historical response data from Typeform (Settings → Responses → Export CSV)
  2. Note all active form URLs and set up redirects if needed
  3. Cancel from Typeform Settings → Billing

What You Gain

  • Unlimited responses — no plan-based caps
  • In-app surveys — users never leave your product
  • User targeting — show surveys to specific segments
  • Event-based triggers — surveys appear at the right moment
  • Full data ownership — responses stay in your database
  • Webhook pipeline — real-time data to Slack, Notion, Airtable, your backend

What You Lose vs Typeform

  • Polished standalone form UX — Typeform's conversational one-question-at-a-time UI is better for public-facing forms
  • Advanced question types — file upload and payment collection aren't available
  • Public form pages — Formbricks is designed for in-app, not shareable URLs (though link surveys are available)
  • Non-technical setup — embedding the SDK requires adding code; Typeform is truly no-code

When to Keep Typeform

Formbricks is the right switch if you're running in-app surveys for your own product users. Typeform is better for:

  • Public-facing lead generation forms
  • External customer research (no app integration needed)
  • File upload collection
  • Beautiful branded form pages shared via URL

Cost Comparison

SolutionAnnual Cost
Typeform Basic (100 resp/mo)$300/year
Typeform Plus (1K resp/mo)$600/year
Typeform Business (10K resp/mo)$996/year
Formbricks Cloud (free tier)$0
Formbricks self-hosted (VPS)$60–120/year

What Typeform Features Don't Exist in Formbricks

Being clear about what you're giving up prevents post-migration regret. Formbricks is an excellent tool for its design intent (in-app product surveys), but it genuinely does not replicate every Typeform capability.

Typeform's one-question-at-a-time conversational format is its signature UX for external-facing forms. A beautifully designed Typeform with animated transitions, full-screen question layouts, and branded visual design delivers a polished form experience that external respondents notice and appreciate. Formbricks' link surveys (non-in-app forms shared via URL) use a more conventional multi-field layout. For public-facing lead generation or research surveys where brand presentation matters, Typeform's visual quality is a real differentiator that Formbricks' link surveys don't match.

File upload fields are available in Typeform but not in Formbricks as of early 2026. If your forms collect file submissions (resumes, design files, documentation), Formbricks is not a complete Typeform replacement for those workflows. Alternative: use a dedicated file collection tool (Heyform supports file uploads) or build a custom file upload step in your application before triggering the Formbricks survey.

Payment collection via Stripe is available in Typeform's Business and higher plans. This enables simple checkout flows within a form — collecting payment card details and charging for products or event registrations. Formbricks has no payment collection feature. If your Typeform forms collect payments, you need a separate checkout tool (Stripe Payment Links, Lemon Squeezy, or a custom implementation) before migrating to Formbricks.

Typeform's Calculator field performs mathematical operations across form responses (calculating scores, totals, or personalized values based on answers). Formbricks has no equivalent built-in calculation field. Complex scoring logic must move to webhook-based processing: receive the Formbricks response via webhook and calculate scores in your application backend.

Typeform also has stronger third-party native integrations in its marketplace — direct HubSpot, Salesforce, Mailchimp, and Google Sheets integrations without requiring Zapier as middleware. Formbricks' native integrations are more limited; the robust integration path is via webhooks to a middleware tool (n8n, Zapier, Make.com). This adds a dependency for teams that relied on Typeform's direct integrations.

Building Equivalent Workflows in Formbricks

The section above covers what you can't replicate. This section covers how to rebuild the workflows that Typeform was actually handling for most teams, because the majority of Typeform use cases map cleanly to Formbricks with modest configuration work.

NPS surveys are the canonical Formbricks use case. In Typeform, an NPS survey was either a link you sent via email or embedded in a page. In Formbricks, NPS runs as an in-app survey triggered 30 days after signup (or based on whatever behavioral trigger is appropriate). The Formbricks NPS template includes the 0–10 rating question and a follow-up open text question, pre-configured for NPS methodology. Set the display frequency (don't show more than once per quarter), configure the audience (show only to active users, not churned ones), and deploy via the JavaScript SDK. The survey appears contextually in your product rather than requiring a separate email send.

Lead qualification forms that were Typeform embeds on landing pages move to either Heyform (for traditional form layout) or Typebot (for conversational format). Both tools offer embeddable forms with the same embed code approach Typeform used. If the lead qualification logic is complex (show enterprise pricing options to companies with 100+ employees, show SMB options to smaller companies), Typebot's visual conditional branching is the cleanest way to implement that logic.

Contact forms and registration forms are simple enough that any tool handles them. The migration for a basic name-email-message contact form is 15 minutes: recreate the fields in Heyform, copy the embed code to your website, update your webhook endpoint.

The webhook pipeline for getting Formbricks responses into your data stack typically replaces Typeform's native integrations. A Zapier or n8n workflow that receives the Formbricks webhook payload and writes to Google Sheets, sends to HubSpot, or posts to Slack replicates what Typeform's integrations did directly. The n8n approach is self-hosted, keeping your response data from flowing through Zapier's servers — aligning with the privacy motivation for leaving Typeform in the first place.


Related: Best Open Source Form Builders 2026 · Best Open Source Typeform Alternatives 2026 · How to Self-Host Formbricks

See open source alternatives to Typeform on OSSAlt.

The SaaS-to-Self-Hosted Migration Guide (Free PDF)

Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.

Join 300+ self-hosters. Unsubscribe in one click.