Formbricks
Integrate Formbricks open-source surveys for in-app, website, and link-based
You are an expert at integrating Formbricks, the open-source survey platform, into web applications. You configure in-app surveys triggered by user actions, collect website feedback via no-code widgets, and manage response data through the REST API. ## Key Points - **Showing surveys without event triggers** — random pop-ups annoy users and tank completion rates. - **Forgetting to call `formbricks.logout()`** on sign-out — the next user inherits the previous user's identity and attributes. - **Not setting user attributes** — you lose the ability to target surveys by plan, role, or tenure. - **Running the JS SDK in SSR** — Formbricks requires `window`. Initialize only on the client side inside `useEffect`. - Collecting in-app feedback triggered by specific user actions (post-onboarding, feature usage, churn signals). - Running NPS or CSAT surveys inside your product without redirecting users externally. - Self-hosting a survey platform for GDPR compliance and full data ownership. - A/B testing onboarding flows by surveying different user segments. - Building product analytics feedback loops where survey data feeds into your data warehouse. ## Quick Example ```bash NEXT_PUBLIC_FORMBRICKS_ENV_ID=clu... NEXT_PUBLIC_FORMBRICKS_API_HOST=https://app.formbricks.com FORMBRICKS_API_KEY=fb_... ```
skilldb get form-survey-services-skills/FormbricksFull skill: 247 linesFormbricks Skill
You are an expert at integrating Formbricks, the open-source survey platform, into web applications. You configure in-app surveys triggered by user actions, collect website feedback via no-code widgets, and manage response data through the REST API.
Core Philosophy
Event-Triggered Surveys
Formbricks excels at showing the right survey at the right moment. Trigger surveys based on user actions (e.g., completed onboarding, clicked upgrade, visited pricing page) rather than showing them randomly. Use the track() method to fire custom events and tie them to survey display rules.
Privacy-First Data Collection
Formbricks is self-hostable and GDPR-friendly by design. When self-hosting, all data stays on your infrastructure. Use the userId parameter to associate responses with known users without leaking PII to third parties. For anonymous surveys, omit userId entirely.
Progressive Survey Delivery
Avoid survey fatigue by using Formbricks' built-in targeting: show surveys only to specific user segments, limit display frequency, and stop showing a survey once a user has responded. Configure these rules in the dashboard or via API attributes.
Setup
Install the JavaScript SDK for in-app surveys:
// npm install @formbricks/js
import formbricks from "@formbricks/js";
formbricks.init({
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENV_ID!,
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST!, // https://app.formbricks.com or self-hosted URL
userId: currentUser?.id, // optional: for identified users
attributes: { // optional: for targeting
plan: currentUser?.plan,
role: currentUser?.role,
},
});
For the REST API:
const FB_API_HOST = process.env.FORMBRICKS_API_HOST;
const FB_API_KEY = process.env.FORMBRICKS_API_KEY;
async function fbFetch<T>(path: string, init?: RequestInit): Promise<T> {
const res = await fetch(`${FB_API_HOST}/api/v1${path}`, {
...init,
headers: {
"x-api-key": FB_API_KEY!,
"Content-Type": "application/json",
...init?.headers,
},
});
if (!res.ok) throw new Error(`Formbricks ${res.status}: ${await res.text()}`);
const json = await res.json();
return json.data as T;
}
Environment variables:
NEXT_PUBLIC_FORMBRICKS_ENV_ID=clu...
NEXT_PUBLIC_FORMBRICKS_API_HOST=https://app.formbricks.com
FORMBRICKS_API_KEY=fb_...
Key Patterns
Track Custom Events for Survey Triggers
Do this — fire events that trigger contextual surveys:
// Track when a user completes onboarding
async function completeOnboarding(userId: string) {
await saveOnboardingComplete(userId);
formbricks.track("onboarding_completed");
}
// Track when a user hits a feature wall
function handleFeatureGate(feature: string) {
formbricks.track("feature_gate_hit", { feature });
showUpgradeModal();
}
// Track page-specific events
function ProductPage() {
useEffect(() => {
formbricks.track("viewed_pricing_page");
}, []);
return <PricingContent />;
}
Not this — showing surveys on every page load without any targeting or event context.
Set User Attributes for Targeting
Do this — update attributes so surveys reach the right segments:
// Set attributes when user context changes
async function onPlanUpgrade(newPlan: string) {
formbricks.setAttribute("plan", newPlan);
formbricks.setAttribute("upgraded_at", new Date().toISOString());
}
// Set attributes on login
function onUserLogin(user: { id: string; plan: string; role: string; createdAt: string }) {
formbricks.setUserId(user.id);
formbricks.setAttribute("plan", user.plan);
formbricks.setAttribute("role", user.role);
formbricks.setAttribute("signup_date", user.createdAt);
}
// Reset on logout
function onLogout() {
formbricks.logout();
}
Not this — showing every survey to every user without segmentation, causing survey fatigue.
Fetch and Analyze Responses via API
Do this — retrieve responses with typed interfaces:
interface FormbricksResponse {
id: string;
surveyId: string;
finished: boolean;
createdAt: string;
updatedAt: string;
person: { id: string; attributes: Record<string, string> } | null;
data: Record<string, string | number | string[]>;
}
async function getSurveyResponses(surveyId: string): Promise<FormbricksResponse[]> {
return fbFetch<FormbricksResponse[]>(`/management/responses?surveyId=${surveyId}`);
}
// Calculate NPS from responses
function calculateNPS(responses: FormbricksResponse[], questionId: string): number {
const scores = responses
.map((r) => Number(r.data[questionId]))
.filter((n) => !isNaN(n));
const promoters = scores.filter((s) => s >= 9).length;
const detractors = scores.filter((s) => s <= 6).length;
return Math.round(((promoters - detractors) / scores.length) * 100);
}
Not this — exporting CSV manually from the dashboard for every analysis run.
Common Patterns
Create a Survey via API
interface CreateSurveyPayload {
name: string;
type: "app" | "website" | "link";
questions: Array<{
type: "openText" | "multipleChoiceSingle" | "multipleChoiceMulti" | "rating" | "nps" | "cta";
headline: string;
required: boolean;
choices?: Array<{ label: string }>;
scale?: "number" | "star" | "smiley";
range?: 5 | 10;
}>;
}
const survey = await fbFetch<{ id: string }>("/management/surveys", {
method: "POST",
body: JSON.stringify({
name: "Feature Feedback",
type: "app",
questions: [
{ type: "rating", headline: "How useful is this feature?", required: true, scale: "star", range: 5 },
{ type: "openText", headline: "Any suggestions?", required: false },
],
} satisfies CreateSurveyPayload),
});
React Integration with Next.js App Router
// app/providers.tsx
"use client";
import { useEffect } from "react";
import formbricks from "@formbricks/js";
export function FormbricksProvider({ userId, attributes }: { userId?: string; attributes?: Record<string, string> }) {
useEffect(() => {
formbricks.init({
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENV_ID!,
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST!,
...(userId ? { userId } : {}),
...(attributes ? { attributes } : {}),
});
}, [userId]);
return null;
}
Webhook Integration
// Formbricks sends webhooks for response events
interface FormbricksWebhookPayload {
event: "responseCreated" | "responseUpdated" | "responseFinished";
data: FormbricksResponse;
}
app.post("/webhooks/formbricks", async (req, res) => {
const payload = req.body as FormbricksWebhookPayload;
if (payload.event === "responseFinished") {
await syncToAnalytics(payload.data);
}
res.status(200).send("OK");
});
Anti-Patterns
- Showing surveys without event triggers — random pop-ups annoy users and tank completion rates.
- Forgetting to call
formbricks.logout()on sign-out — the next user inherits the previous user's identity and attributes. - Not setting user attributes — you lose the ability to target surveys by plan, role, or tenure.
- Running the JS SDK in SSR — Formbricks requires
window. Initialize only on the client side insideuseEffect.
When to Use
- Collecting in-app feedback triggered by specific user actions (post-onboarding, feature usage, churn signals).
- Running NPS or CSAT surveys inside your product without redirecting users externally.
- Self-hosting a survey platform for GDPR compliance and full data ownership.
- A/B testing onboarding flows by surveying different user segments.
- Building product analytics feedback loops where survey data feeds into your data warehouse.
Install this skill directly: skilldb add form-survey-services-skills
Related Skills
Formik
Build React forms with Formik using useFormik hook, Field components, and
Jotform
Integrate JotForm's REST API to create forms, retrieve submissions, process
React Hook Form
Build performant React forms with React Hook Form using register, validation,
Surveymonkey
Integrate SurveyMonkey's REST API to create surveys, collect responses via
Tally
Integrate Tally forms via its API and embed SDK to handle submissions, configure
Typeform
Integrate Typeform APIs to create forms, retrieve responses, configure webhooks,