Merge branch 'main' into shubham/saturn-integration-v2

This commit is contained in:
Shubham Palriwala
2024-05-07 11:26:56 +05:30
committed by GitHub
521 changed files with 15811 additions and 14771 deletions

View File

@@ -173,6 +173,9 @@ ENTERPRISE_LICENSE_KEY=
# OpenTelemetry URL for tracing
# OPENTELEMETRY_LISTENER_URL=http://localhost:4318/v1/traces
# Unsplash API Key
UNSPLASH_ACCESS_KEY=
# The below is used for Next Caching (uses In-Memory from Next Cache if not provided)
# REDIS_URL:

View File

@@ -1,11 +1,12 @@
name: Cron - Report usage to Stripe
on:
workflow_dispatch:
# "Scheduled workflows run on the latest commit on the default or base branch."
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
schedule:
# This will run the job at 20:00 UTC every day of every month.
- cron: "0 20 * * *"
# schedule:
# This will run the job at 20:00 UTC every day of every month.
# - cron: "0 20 * * *"
jobs:
cron-reportUsageToStripe:
env:

View File

@@ -1,11 +1,12 @@
name: Cron - Survey status update
on:
workflow_dispatch:
# "Scheduled workflows run on the latest commit on the default or base branch."
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
schedule:
# Runs “At 00:00.” (see https://crontab.guru)
- cron: "0 0 * * *"
# schedule:
# Runs “At 00:00.” (see https://crontab.guru)
# - cron: "0 0 * * *"
jobs:
cron-weeklySummary:
env:

View File

@@ -1,11 +1,12 @@
name: Cron - Weekly summary
on:
workflow_dispatch:
# "Scheduled workflows run on the latest commit on the default or base branch."
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
schedule:
# Runs “At 08:00 on Monday.” (see https://crontab.guru)
- cron: "0 8 * * 1"
# schedule:
# Runs “At 08:00 on Monday.” (see https://crontab.guru)
# - cron: "0 8 * * 1"
jobs:
cron-weeklySummary:
env:

View File

@@ -81,6 +81,7 @@ jobs:
DB_USER: ${{ secrets.DB_USER }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
DB_NAME: ${{ secrets.DB_NAME }}
REDIS_URL: ${{ secrets.REDIS_URL }}
steps:
- name: Checkout code

View File

@@ -78,6 +78,7 @@ jobs:
DB_USER: ${{ secrets.DB_USER }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
DB_NAME: ${{ secrets.DB_NAME }}
REDIS_URL: ${{ secrets.REDIS_URL }}
steps:
- name: Checkout code

View File

@@ -1,4 +1,3 @@
import { classNames } from "@/lib/utils";
import {
ClockIcon,
CogIcon,
@@ -11,6 +10,8 @@ import {
UsersIcon,
} from "lucide-react";
import { classNames } from "../lib/utils";
const navigation = [
{ name: "Home", href: "#", icon: HomeIcon, current: true },
{ name: "History", href: "#", icon: ClockIcon, current: false },

View File

@@ -0,0 +1,25 @@
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@formbricks/ui/Select";
interface SurveySwitchProps {
value: "website" | "app";
formbricks: any;
}
export const SurveySwitch = ({ value, formbricks }: SurveySwitchProps) => {
return (
<Select
value={value}
onValueChange={(v) => {
formbricks.logout();
window.location.href = `/${v}`;
}}>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Theme" />
</SelectTrigger>
<SelectContent>
<SelectItem value="website">Website Surveys</SelectItem>
<SelectItem value="app">App Surveys</SelectItem>
</SelectContent>
</Select>
);
};

View File

@@ -1,6 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
transpilePackages: ["@formbricks/ui"],
async redirects() {
return [
{

View File

@@ -12,12 +12,14 @@
},
"dependencies": {
"@formbricks/js": "workspace:*",
"lucide-react": "^0.365.0",
"next": "14.1.4",
"@formbricks/ui": "workspace:*",
"lucide-react": "^0.373.0",
"next": "14.2.3",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"eslint-config-formbricks": "workspace:*"
"eslint-config-formbricks": "workspace:*",
"@formbricks/tsconfig": "workspace:*"
}
}

View File

@@ -2,8 +2,9 @@ import Image from "next/image";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import formbricks from "@formbricks/js";
import formbricks from "@formbricks/js/app";
import { SurveySwitch } from "../../components/SurveySwitch";
import fbsetup from "../../public/fb-setup.png";
declare const window: any;
@@ -30,22 +31,18 @@ export default function AppPage({}) {
window.history.replaceState({}, "", newUrl);
}
};
addFormbricksDebugParam();
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
const isUserId = window.location.href.includes("userId=true");
const defaultAttributes = {
language: "gu",
};
const userInitAttributes = { "Init Attribute 1": "eight", "Init Attribute 2": "two" };
const userId = "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING";
const userInitAttributes = { language: "de", "Init Attribute 1": "eight", "Init Attribute 2": "two" };
const attributes = isUserId ? { ...defaultAttributes, ...userInitAttributes } : defaultAttributes;
const userId = isUserId ? "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING" : undefined;
formbricks.init({
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
userId,
attributes,
attributes: userInitAttributes,
});
}
@@ -63,15 +60,19 @@ export default function AppPage({}) {
return (
<div className="h-screen bg-white px-12 py-6 dark:bg-slate-800">
<div className="flex flex-col justify-between md:flex-row">
<div>
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
Formbricks In-product Survey Demo App
</h1>
<p className="text-slate-700 dark:text-slate-300">
This app helps you test your in-app surveys. You can create and test user actions, create and
update user attributes, etc.
</p>
<div className="flex items-center gap-2">
<SurveySwitch value="app" formbricks={formbricks} />
<div>
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
Formbricks In-product Survey Demo App
</h1>
<p className="text-slate-700 dark:text-slate-300">
This app helps you test your app surveys. You can create and test user actions, create and
update user attributes, etc.
</p>
</div>
</div>
<button
className="mt-2 rounded-lg bg-slate-200 px-6 py-1 dark:bg-slate-700 dark:text-slate-100"
onClick={() => setDarkMode(!darkMode)}>
@@ -249,41 +250,6 @@ export default function AppPage({}) {
</p>
</div>
</div>
<div className="p-6">
{router.query.userId === "true" ? (
<div>
<button
onClick={() => {
window.location.href = "/app";
}}
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
Deactivate User Identification
</button>
</div>
) : (
<div>
<button
onClick={() => {
window.location.href = "/app?userId=true";
}}
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
Activate User Identification
</button>
</div>
)}
<div>
<p className="text-xs text-slate-700 dark:text-slate-300">
This button activates/deactivates{" "}
<a
href="https://formbricks.com/docs/attributes/identify-users"
target="_blank"
className="underline dark:text-blue-500">
user identification
</a>{" "}
with the userId &apos;THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING&apos;
</p>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,196 @@
import Image from "next/image";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import formbricks from "@formbricks/js/website";
import { SurveySwitch } from "../../components/SurveySwitch";
import fbsetup from "../../public/fb-setup.png";
declare const window: any;
export default function AppPage({}) {
const [darkMode, setDarkMode] = useState(false);
const router = useRouter();
useEffect(() => {
if (darkMode) {
document.body.classList.add("dark");
} else {
document.body.classList.remove("dark");
}
}, [darkMode]);
useEffect(() => {
// enable Formbricks debug mode by adding formbricksDebug=true GET parameter
const addFormbricksDebugParam = () => {
const urlParams = new URLSearchParams(window.location.search);
if (!urlParams.has("formbricksDebug")) {
urlParams.set("formbricksDebug", "true");
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
window.history.replaceState({}, "", newUrl);
}
};
addFormbricksDebugParam();
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
const defaultAttributes = {
language: "de",
};
formbricks.init({
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
attributes: defaultAttributes,
});
}
// Connect next.js router to Formbricks
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
const handleRouteChange = formbricks?.registerRouteChange;
router.events.on("routeChangeComplete", handleRouteChange);
return () => {
router.events.off("routeChangeComplete", handleRouteChange);
};
}
});
return (
<div className="h-screen bg-white px-12 py-6 dark:bg-slate-800">
<div className="flex flex-col items-center justify-between md:flex-row">
<div className="flex items-center gap-2">
<SurveySwitch value="website" formbricks={formbricks} />
<div>
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
Formbricks Website Survey Demo App
</h1>
<p className="text-slate-700 dark:text-slate-300">
This app helps you test your app surveys. You can create and test user actions, create and
update user attributes, etc.
</p>
</div>
</div>
<button
className="mt-2 rounded-lg bg-slate-200 px-6 py-1 dark:bg-slate-700 dark:text-slate-100"
onClick={() => setDarkMode(!darkMode)}>
{darkMode ? "Toggle Light Mode" : "Toggle Dark Mode"}
</button>
</div>
<div className="my-4 grid grid-cols-1 gap-6 md:grid-cols-2">
<div>
<div className="rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-900">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">1. Setup .env</h3>
<p className="text-slate-700 dark:text-slate-300">
Copy the environment ID of your Formbricks app to the env variable in /apps/demo/.env
</p>
<Image src={fbsetup} alt="fb setup" className="mt-4 rounded" priority />
<div className="mt-4 flex-col items-start text-sm text-slate-700 sm:flex sm:items-center sm:text-base dark:text-slate-300">
<p className="mb-1 sm:mb-0 sm:mr-2">You&apos;re connected with env:</p>
<div className="flex items-center">
<strong className="w-32 truncate sm:w-auto">
{process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID}
</strong>
<span className="relative ml-2 flex h-3 w-3">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-500 opacity-75"></span>
<span className="relative inline-flex h-3 w-3 rounded-full bg-green-500"></span>
</span>
</div>
</div>
</div>
<div className="mt-4 rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-900">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">2. Widget Logs</h3>
<p className="text-slate-700 dark:text-slate-300">
Look at the logs to understand how the widget works.{" "}
<strong className="dark:text-white">Open your browser console</strong> to see the logs.
</p>
{/* <div className="max-h-[40vh] overflow-y-auto py-4">
<LogsContainer />
</div> */}
</div>
</div>
<div className="md:grid md:grid-cols-3">
<div className="col-span-3 rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-800">
<h3 className="text-lg font-semibold dark:text-white">
Reset person / pull data from Formbricks app
</h3>
<p className="text-slate-700 dark:text-slate-300">
On formbricks.reset() the local state will <strong>be deleted</strong> and formbricks gets{" "}
<strong>reinitialized</strong>.
</p>
<button
className="my-4 rounded-lg bg-slate-500 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
onClick={() => {
formbricks.reset();
}}>
Reset
</button>
<p className="text-xs text-slate-700 dark:text-slate-300">
If you made a change in Formbricks app and it does not seem to work, hit &apos;Reset&apos; and
try again.
</p>
</div>
<div className="pt-6">
<div>
<button
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
onClick={() => {
formbricks.track("New Session");
}}>
Track New Session
</button>
</div>
<div>
<p className="text-xs text-slate-700 dark:text-slate-300">
This button sends an Action to the Formbricks API called &apos;New Session&apos;. You will
find it in the Actions Tab.
</p>
</div>
</div>
<div className="pt-6">
<div>
<button
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
onClick={() => {
formbricks.track("Exit Intent");
}}>
Track Exit Intent
</button>
</div>
<div>
<p className="text-xs text-slate-700 dark:text-slate-300">
This button sends an Action to the Formbricks API called &apos;Exit Intent&apos;. You can also
move your mouse to the top of the browser to trigger the exit intent.
</p>
</div>
</div>
<div className="pt-6">
<div>
<button
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
onClick={() => {
formbricks.track("50% Scroll");
}}>
Track 50% Scroll
</button>
</div>
<div>
<p className="text-xs text-slate-700 dark:text-slate-300">
This button sends an Action to the Formbricks API called &apos;50% Scroll&apos;. You can also
scroll down to trigger the 50% scroll.
</p>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@@ -1,23 +1,5 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"paths": {
"@/*": ["./*"]
}
},
"extends": "@formbricks/tsconfig/nextjs.json",
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,5 @@
export async function GET(_: Request, { params }: { params: { surveyId: string } }) {
const surveyId = params.surveyId;
// redirect to Formbricks Cloud
return Response.redirect(`https://app.formbricks.com/s/${surveyId}`, 301);
}

View File

@@ -0,0 +1,137 @@
import { MdxImage } from "@/components/shared/MdxImage";
import AddApiKey from "./add-api-key.webp";
import ApiKeySecret from "./api-key-secret.webp";
export const metadata = {
title: "Formbricks API Overview: Public Client & Management API Breakdown",
description:
"Formbricks provides a powerful API to manage your surveys, responses, users, displays, actions, attributes & webhooks programmatically. Get a detailed understanding of Formbricks' dual API offerings: the unauthenticated Public Client API optimized for client-side tasks and the secured Management API for advanced account operations. Choose the perfect fit for your integration needs and ensure robust data handling",
};
#### API
# API Overview
Formbricks offers two types of APIs: the **Public Client API** and the **Management API**. Each API serves a different purpose, has different authentication requirements, and provides access to different data and settings.
View our [API Documentation](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh) in more than 30 frameworks and languages. Or directly try out our APIs in Postman by clicking the button below:
<div className="max-w-full sm:max-w-3xl">
<a target="_blank" href="https://formbricks.postman.co/collection/11026000-927c954f-85a9-4f8f-b0ec-14191b903737?source=rip_html">
<img alt="Run in Postman" src="https://run.pstmn.io/button.svg"/>
</a>
</div>
## Public Client API
The [Public Client API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#5c981d9e-5e7d-455d-9795-b9c45bc2f930) is designed for our SDKs and **does not require authentication**. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
We currently have the following Client API methods exposed and below is their documentation attached in Postman:
- [Actions API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#b8f3a10e-1642-4d82-a629-fef0a8c6c86c) - Create actions for a Person
- [Displays API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#949272bf-daec-4d72-9b52-47af3d74a62c) - Mark Survey as Displayed or Update an existing Display by linking it with a Response for a Person
- [People API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#ee3d2188-4253-4bca-9238-6b76455805a9) - Create & Update a Person (e.g. attributes, email, userId, etc)
- [Responses API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#8c773032-536c-483c-a237-c7697347946e) - Create & Update a Response for a Survey
## Management API
The [Management API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#98fce5a1-1365-4125-8de1-acdb28206766) provides access to all data and settings that your account has access to in the Formbricks app. This API **requires a personal API Key** for authentication, which can be generated in the Settings section of the Formbricks app. Checkout the [API Key Setup](#how-to-generate-an-api-key) below to generate & manage API Keys.
We currently have the following Management API methods exposed and below is their documentation attached in Postman:
- [Action Class API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#81947f69-99fc-41c9-a184-f3260e02be48) - Create, List, and Delete Action Classes
- [Attribute Class API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#31089010-d468-4a7c-943e-8ebe71b9a36e) - Create, List, and Delete Attribute Classes
- [Me API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#79e08365-641d-4b2d-aea2-9a855e0438ec) - Retrieve Account Information
- [People API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#cffc27a6-dafb-428f-8ea7-5165bedb911e) - List and Delete People
- [Response API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#e544ec0d-8b30-4e33-8d35-2441cb40d676) - List, List by Survey, Update, and Delete Responses
- [Survey API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#953189b2-37b5-4429-a7bd-f4d01ceae242) - List, Create, Update, and Delete Surveys
- [Webhook API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#62e6ec65-021b-42a4-ac93-d1434b393c6c) - List, Create, and Delete Webhooks
## How to Generate an API key
The API requests are authorized with a personal API key. This API key gives you the same rights as if you were logged in at formbricks.com - **don't share it around!**
1. Go to your settings on [app.formbricks.com](https://app.formbricks.com).
2. Go to page “API keys”
<MdxImage src={AddApiKey} alt="Add API Key" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
3. Create a key for the development or production environment.
4. Copy the key immediately. You wont be able to see it again.
<MdxImage
src={ApiKeySecret}
alt="API Key Secret"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
<Note>
### Store API key safely!
Anyone who has your API key has full control over your account. For security reasons, you cannot view the API key again.
</Note>
### Test your API Key
Hit the below request to verify that you are authenticated with your API Key and the server is responding.
## Get My Profile {{ tag: 'GET', label: '/api/v1/me' }}
<Row>
<Col>
Get the product details and environment type of your account.
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
### Delete a personal API key
1. Go to settings on [app.formbricks.com](https://app.formbricks.com/).
2. Go to page “API keys”.
3. Find the key you wish to revoke and select “Delete”.
4. Your API key will stop working immediately.
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/me">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/me' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"id": "cll2m30r70004mx0huqkitgqv",
"createdAt": "2023-08-08T18:04:59.922Z",
"updatedAt": "2023-08-08T18:04:59.922Z",
"type": "production",
"product": {
"id": "cll2m30r60003mx0hnemjfckr",
"name": "My Product"
},
"widgetSetupCompleted": false
}
```
```json {{ title: '401 Not Authenticated' }}
Not authenticated
```
</CodeGroup>
</Col>
</Row>
Cant figure it out? Join our [Discord](https://discord.com/invite/3YFcABF2Ts) and we'd be glad to assist you!
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -0,0 +1,67 @@
import { TellaVideo } from "@/components/docs/TellaVideo";
import { MdxImage } from "@/components/shared/MdxImage";
import Filters from "./filters.webp";
import MetadataCard from "./metadata-card.webp";
export const metadata = {
title: "User Metadata | Formbricks",
description:
"Understand the metadata of your users when they fill a Formbricks survey (both in-app & link). We currently capture the user's source information, URL, browser, and device details, along with the country & the action that triggered.",
};
#### Additional Features
# User Metadata
Formbricks captures metadata of your users for you when they fill a survey.
This metadata is useful for understanding the context in which the user filled the survey. For example, if you are running a marketing campaign, you can understand which source is driving the most responses. Or if you are running a survey on a specific page, you can understand the user's behavior on that page.
<TellaVideo tellaVideoIdentifier="clvdr5lv300u90fjq7fmnhs0k" />
## Metadata Captured
- **Source**: The source from where the user filled the survey. This could be an App, Link, or a Webpage.
- **URL**: The URL of the page where the user filled the survey.
- **Browser**: The browser used by the user to fill the survey.
- **OS**: The operating system of the device used by the user to fill the survey.
- **Device**: The device used by the user to fill the survey.
- **Country**: The country of the user.
- **Action**: The action that triggered the survey. This is only available for App surveys.
## View Response Metadata
1. Go to the Responses tab of your survey.
2. Hover over the profile icon of the user on the response card & you should see a tooltip opening up with the metadata details.
<MdxImage
src={MetadataCard}
alt="Metadata Card on Response Tab"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
## Filter Responses by Metadata
1. Go to the Responses tab of your survey.
2. Click on the Filter button.
3. Scroll down & Select the metadata field you want to filter by.
4. Select the condition & the value you want to filter by.
<MdxImage
src={Filters}
alt="Apply Filters on Metadata"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
5. Now you should see the responses filtered based on the metadata you selected. If you want to see a walkthrough, view the video above to see how you can view & filter responses by metadata.
## Export Metadata
You can export the metadata of your responses along with the response data. When you export responses, you will see the metadata fields in the exported CSV file.
---
Cant figure it out? Join our [Discord](https://discord.com/invite/3YFcABF2Ts)!

View File

@@ -1,85 +0,0 @@
import { Fence } from "@/components/shared/Fence";
export const metadata = {
title: "Formbricks Actions API Documentation - Manage Your Survey Data Seamlessly",
description:
"Unlock the full potential of Formbricks' Client Actions API. Create Actions right from the API.",
};
#### Client API
# Actions API
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
This API can be used to:
- [Add Action for User](#add-action-for-user)
---
## Add Action for User {{ tag: 'POST', label: '/api/v1/client/<environment-id>/actions' }}
Adds an Actions for a given User by their User ID
<Row>
<Col>
### Mandatory Body Fields
<Properties>
<Property name="userId" type="string">
The id of the user for whom the action is being created.
</Property>
<Property name="name" type="string">
The name of the Action being created.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/api/v1/client/<environment-id>/actions">
```bash {{ title: 'cURL' }}
curl --location --request POST 'https://app.formbricks.com/api/v1/client/<environment-id>/actions' \
--data-raw '{
"userId": "1",
"name": "new_action_v2"
}'
```
```json {{ title: 'Example Request Body' }}
{
"userId": "1",
"name": "new_action_v3"
}
```
</CodeGroup>
<CodeGroup title="Response">
```json {{ title: '200 Success' }}
{
"data": {}
}
```
```json {{ title: '400 Bad Request' }}
{
"code": "bad_request",
"message": "Fields are missing or incorrectly formatted",
"details": {
"name": "Required"
}
}
```
</CodeGroup>
</Col>
</Row>
---

View File

@@ -1,145 +0,0 @@
import { Fence } from "@/components/shared/Fence";
export const metadata = {
title: "Formbricks Public Client API Guide: Manage Survey Displays & Responses",
description:
"Dive deep into Formbricks' Public Client API designed for customisation. This comprehensive guide provides detailed instructions on how to mark create and update survey displays for users.",
};
#### Client API
# Displays API
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
This set of API can be used to
- [Create Display](#create-display)
- [Update Display](#update-display)
---
## Create Display {{ tag: 'POST', label: '/api/v1/client/<environment-id>/diplays' }}
<Row>
<Col>
Create Display of survey for a user
### Mandatory Request Body JSON Keys
<Properties>
<Property name="surveyId" type="string">
Survey ID to mark as viewed for a person
</Property>
</Properties>
### Optional Request Body JSON Keys
<Properties>
<Property name="userId" type="string">
Already existing user's ID to mark as viewed for a survey
</Property>
<Property name="responseId" type="string">
Already existing response's ID to link with this new Display
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/api/v1/client/<environment-id>/displays">
```bash {{ title: 'cURL' }}
curl -X POST \
'https://app.formbricks.com/api/v1/client/displays' \
-H 'Content-Type: application/json' \
-d '{
"surveyId":"<survey-id>",
"userId":"<user-id>"
}'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "clphzz6oo00083zdmc7e0nwzi"
}
}
```
```json {{ title: '400 Bad Request' }}
{
"code": "bad_request",
"message": "Fields are missing or incorrectly formatted",
"details": {
"surveyId": "Required"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Update Display {{ tag: 'PUT', label: '/api/v1/client/<environment-id>/diplays/<display-id>' }}
<Row>
<Col>
Update a display by it's ID
### Optional Request Body JSON Keys
<Properties>
<Property name="userId" type="string">
Already existing user's ID to mark as viewed for a survey
</Property>
<Property name="responseId" type="string">
Already existing response's ID to link with this new Display
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="PUT" label="/api/v1/client/<environment-id>/displays/<display-id>">
```bash {{ title: 'cURL' }}
curl -X POST \
'https://app.formbricks.com/api/v1/client/<environment-id>/displays/<display-id>' \
-H 'Content-Type: application/json' \
-d '{
"userId":"<user-id>"
}'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {}
}
```
```json {{ title: '400 Bad Request' }}
{
"code": "bad_request",
"message": "Fields are missing or incorrectly formatted",
"details": {
"surveyId": "Required"
}
}
```
</CodeGroup>
</Col>
</Row>
---

View File

@@ -1,47 +0,0 @@
export const metadata = {
title: "Formbricks API Overview: Public Client & Management API Breakdown",
description:
"Get a detailed understanding of Formbricks' dual API offerings: the unauthenticated Public Client API optimized for client-side tasks and the secured Management API for advanced account operations. Choose the perfect fit for your integration needs and ensure robust data handling",
};
#### API
# API Overview
Formbricks offers two types of APIs: the **Public Client API** and the **Management API**. Each API serves a different purpose, has different authentication requirements, and provides access to different data and settings.
Checkout the [API Key Setup](/docs/api/management/api-key-setup) - to generate, store, or delete API Keys.
## Public Client API
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
- [Actions API](/docs/api/client/actions) - Create actions for a person
- [Displays API](/docs/api/client/displays) - Mark Survey as Displayed or Responded for a Person
- [People API](/docs/api/client/people) - Create & update people (e.g. attributes)
- [Responses API](/docs/api/client/responses) - Create & update responses for a survey
## Management API
The Management API provides access to all data and settings that are visible in the Formbricks App. This API requires a personal API Key for authentication, which can be generated in the Settings section of the Formbricks App. With the Management API, you can manage your Formbricks account programmatically, accessing and modifying data and settings as needed.
**Auth:** Personal API Key
API requests made to the Management API are authorized using a personal API key. This key grants the same rights and access as if you were logged in at formbricks.com. It's essential to keep your API key secure and not share it with others.
To generate, store, or delete an API key, follow the instructions provided on the following page [API Key](/docs/api/management/api-key-setup).
- [Action Class API](/docs/api/management/action-classes) - Create, Update, and Delete Action Classes
- [Attribute Class API](/docs/api/management/attribute-classes) - Create, Update, and Delete Attribute Classes
- [Me API](/docs/api/management/me) - Retrieve Account Information
- [People API](/docs/api/management/people) - Create, Update, and Delete People
- [Responses API](/docs/api/management/responses) - Create, Update, and Delete Responses
- [Surveys API](/docs/api/management/surveys) - Create, Update, and Delete Surveys
- [Webhook API](/docs/api/management/webhooks) - Create, Update, and Delete Webhooks
<Note>
By understanding the differences between these two APIs, you can choose the appropriate one for your needs,
ensuring a secure and efficient integration with the Formbricks platform.
</Note>
---

View File

@@ -1,130 +0,0 @@
import { Fence } from "@/components/shared/Fence";
export const metadata = {
title: "Formbricks Public Client API Guide: Manage Users",
description:
"Dive deep into Formbricks' Public Client API designed for customisation. This comprehensive guide provides detailed instructions on creating and updating users to help in user identification.",
};
#### Client API
# People API
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
This set of API can be used to
- [Create Person](#create-person)
- [Update Person](#update-person)
---
## Create Person {{ tag: 'POST', label: '/api/v1/client/<environment-id>/people' }}
<Row>
<Col>
Create User with your own User ID
### Mandatory Request Body JSON Keys
<Properties>
<Property name="userId" type="string">
User ID which you would like to identify the person with
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/api/v1/client/<environment-id>/people">
```bash {{ title: 'cURL' }}
curl -X POST \
'https://app.formbricks.com/api/v1/client/<environment-id>/people' \
-H 'Content-Type: application/json' \
-d '{
"userId":"docs_user"
}'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"userId": "docs_user"
}
}
```
```json {{ title: '400 Bad Request' }}
{
"code": "bad_request",
"message": "Fields are missing or incorrectly formatted",
"details": {
"surveyId": "Required"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Update Person {{ tag: 'POST', label: '/api/v1/client/<environment-id>/people/<user-id>' }}
<Row>
<Col>
Update Person by their User ID
### Mandatory Request Body JSON Keys
<Properties>
<Property name="attributes" type="JSON">
Key Value pairs of attributes to add to the user
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/api/v1/client/<environment-id>/people/<user-id>">
```bash {{ title: 'cURL' }}
curl -X POST \
--location \
'https://app.formbricks.com/api/v1/client/<environment-id>/people/<user-id>'
-H 'Content-Type: application/json' \
-d '{
"attributes":{
"welcome_to":"formbricks"
}
}'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {}
}
```
```json {{ title: '500 Internal Server Error' }}
{
"code": "internal_server_error",
"message": "Database operation failed",
"details": {}
}
```
</CodeGroup>
</Col>
</Row>
---

View File

@@ -1,200 +0,0 @@
import { Fence } from "@/components/shared/Fence";
export const metadata = {
title: "Formbricks Responses API Documentation - Manage Your Survey Data Seamlessly",
description:
"Unlock the full potential of Formbricks' Responses API. From fetching to updating survey responses, our comprehensive guide helps you integrate and manage survey data efficiently without compromising security. Ideal for client-side interactions.",
};
#### Client API
# Responses API
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
This set of API can be used to
- [Create Response](#create-response)
- [Update Response](#update-response)
---
## Create Response {{ tag: 'POST', label: '/api/v1/client/<environment-id>/responses' }}
Add a new response to a survey.
<Row>
<Col>
### Mandatory Body Fields
<Properties>
<Property name="surveyId" type="string">
The id of the survey the response belongs to.
</Property>
<Property name="finished" type="boolean">
Marks whether the response is complete or not.
</Property>
<Property name="data" type="string">
The data of the response as JSON object (key: questionId, value: answer).
</Property>
</Properties>
### Optional Body Fields
<Properties>
<Property name="userId" type="string" required>
Pre-existing User ID to identify the user sending the response
</Property>
</Properties>
### Parameters Explained
| field name | required | default | description |
| ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| data | yes | - | The response data object (answers to the survey). In this object the key is the questionId, the value the answer of the user to this question. |
| userId | no | - | The person this response is connected to. |
| surveyId | yes | - | The survey this response is connected to. |
| finished | yes | false | Mark a response as complete to be able to filter accordingly. |
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/api/v1/client/<environment-id>/responses">
```bash {{ title: 'cURL' }}
curl --location --request POST 'https://app.formbricks.com/api/v1/client/<environment-id>/responses' \
--data-raw '{
"surveyId":"cloqzeuu70000z8khcirufo60",
"userId": "1",
"finished": true,
"data": {
"clfqjny0v0003yzgscnog1j9i": 10,
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
}
}'
```
```json {{ title: 'Example Request Body' }}
{
"userId": "1",
"surveyId": "cloqzeuu70000z8khcirufo60",
"finished": true,
"data": {
"clfqjny0v0003yzgscnog1j9i": 10,
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
}
}
```
</CodeGroup>
<CodeGroup title="Response">
```json {{ title: '200 Success' }}
{
"data": {
"id": "clp84xdld0002px36fkgue5ka",
}
}
```
```json {{ title: '400 Bad Request' }}
{
"code": "bad_request",
"message": "surveyId was not provided.",
"details": {
"surveyId": "This field is required."
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Update Response {{ tag: 'PUT', label: '/api/v1/client/<environment-id>/responses/<response-id>' }}
Update an existing response in a survey.
<Row>
<Col>
### Mandatory Body Fields
<Properties>
<Property name="finished" type="boolean">
Marks whether the response is complete or not.
</Property>
<Property name="data" type="string">
The data of the response as JSON object (key: questionId, value: answer).
</Property>
</Properties>
### Parameters Explained
| field name | required | default | description |
| ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| data | yes | - | The response data object (answers to the survey). In this object the key is the questionId, the value the answer of the user to this question. |
| finished | yes | false | Mark a response as complete to be able to filter accordingly. |
</Col>
<Col sticky>
<CodeGroup title="Request" tag="PUT" label="/api/v1/client/<environment-id>/responses/<response-id>">
```bash {{ title: 'cURL' }}
curl --location --request PUT 'https://app.formbricks.com/api/v1/client/<environment-id>/responses/<response-id>' \
--data-raw '{
"finished":false,
"data": {
"clfqjny0v0003yzgscnog1j9i": 10,
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
}
}'
```
```json {{ title: 'Example Request Body' }}
{
"finished":false,
"data": {
"clfqjny0v0003yzgscnog1j9i": 10,
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
}
}
```
</CodeGroup>
<CodeGroup title="Response">
```json {{ title: '200 Success' }}
{
"data": {}
}
```
```json {{ title: '400 Bad Request' }}
{
"code": "bad_request",
"message": "data was not provided.",
"details": {
"data": "This field is required."
}
}
```
```json {{ title: '404 Not Found' }}
{
"code": "not_found",
"message": "Response not found"
}
```
</CodeGroup>
</Col>
</Row>

View File

@@ -1,297 +0,0 @@
import { Fence } from "@/components/shared/Fence";
import {generateManagementApiMetadata} from "@/lib/utils"
export const metadata = generateManagementApiMetadata("Action Class",["Fetch","Create","Delete"])
#### Management API
# Action Classes API
This set of API can be used to
- [List Actions](#get-all-action-classes)
- [Get Action](#get-action-class-by-id)
- [Create Actions](#create-action-class)
- [Delete Actions](#delete-action-class)
<Note>You will need an API Key to interact with these APIs.</Note>
---
## Get all Action Classes {{ tag: 'GET', label: '/api/v1/management/action-classes' }}
<Row>
<Col>
Get all the existing action classes in your environment.
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/action-classes">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/action-classes' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": [
{
"id": "cln8k0t47000gz87nw4ibwv35",
"createdAt": "2023-10-02T07:13:19.207Z",
"updatedAt": "2023-10-02T07:13:19.207Z",
"name": "New Session",
"description": "Gets fired when a new session is created",
"type": "automatic",
"noCodeConfig": null,
"environmentId": "cln8k0t47000fz87njmmu2bck"
},
{
"id": "cln8k0t55000uz87noerwdooj",
"createdAt": "2023-10-02T07:13:19.241Z",
"updatedAt": "2023-10-02T07:13:19.241Z",
"name": "Invited Team Member",
"description": "Person invited a team member",
"type": "noCode",
"noCodeConfig": {
"type": "innerHtml",
"innerHtml": {
"value": "Add Team Member"
}
},
"environmentId": "cln8k0t47000fz87njmmu2bck"
},
]
}
```
```json {{ title: '401 Unauthorized' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Get Action Class by ID {{ tag: 'GET', label: '/api/v1/management/action-classes/<action-class-id>' }}
<Row>
<Col>
Fetch an action class by its ID.
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/action-classes/<action-class-id>">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/action-classes/<action-class-id>' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "cln8k0t55000uz87noerwdooj",
"createdAt": "2023-10-02T07:13:19.241Z",
"updatedAt": "2023-10-02T07:13:19.241Z",
"name": "Invited Team Member",
"description": "Person invited a team member",
"type": "noCode",
"noCodeConfig": {
"type": "innerHtml",
"innerHtml": {
"value": "Add Team Member"
}
},
"environmentId": "cln8k0t47000fz87njmmu2bck"
}
}
```
```json {{ title: '401 Unauthorized' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Create Action Class {{ tag: 'POST', label: '/api/v1/management/action-classes/' }}
<Row>
<Col>
Create an action class.
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
### Body
<CodeGroup title="Request Body">
```json {{ title: 'cURL' }}
{
"environmentId": "cln8k0t47000fz87njmmu2bck",
"name": "My Action from API",
"type": "code"
}
```
</CodeGroup>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/api/v1/management/action-classes/">
```bash {{ title: 'cURL' }}
curl -X POST https://app.formbricks.com/api/v1/management/action-classes/ \
--header 'Content-Type: application/json' \
--header 'x-api-key: <your-api-key>' \
-d '{"environmentId": "cln8k0t47000fz87njmmu2bck", "name": "My Action from API", "type": "code"}'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "cln9w1cno0008z8zu79nk5w0c",
"createdAt": "2023-10-03T05:37:26.100Z",
"updatedAt": "2023-10-03T05:37:26.100Z",
"name": "My Action from API",
"description": null,
"type": "code",
"noCodeConfig": null,
"environmentId": "cln8k0t47000fz87njmmu2bck"
}
}
```
```json {{ title: '401 Unauthorized' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Delete Action Class {{ tag: 'DELETE', label: '/api/v1/management/action-classes/<action-class-id>' }}
<Row>
<Col>
Delete an action class by its ID.
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="DELETE" label="/api/v1/management/action-classes/<action-class-id>">
```bash {{ title: 'cURL' }}
curl -X DELETE https://app.formbricks.com/api/v1/management/action-classes/<action-class-id> \
--header 'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "cln9w1cno0008z8zu79nk5w0c",
"createdAt": "2023-10-03T05:37:26.100Z",
"updatedAt": "2023-10-03T05:37:26.100Z",
"name": "My Action from API",
"description": null,
"type": "code",
"noCodeConfig": null,
"environmentId": "cln8k0t47000fz87njmmu2bck"
}
}
```
```json {{ title: '401 Unauthorized' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---

View File

@@ -1,102 +0,0 @@
import { MdxImage } from "@/components/shared/MdxImage";
import AddApiKey from "./add-api-key.webp";
import ApiKeySecret from "./api-key-secret.webp";
export const metadata = {
title: "Formbricks API Key: Setup and Testing",
description:
"This guide provides step-by-step instructions to generate, store, and delete API keys, ensuring safe and authenticated access to your Formbricks account.",
};
#### API
# API Key Setup
## Auth: Personal API key
The API requests are authorized with a personal API key. This API key gives you the same rights as if you were logged in at formbricks.com - **don't share it around!**
### How to generate an API key
1. Go to your settings on [app.formbricks.com](https://app.formbricks.com).
2. Go to page “API keys”
<MdxImage src={AddApiKey} alt="Add API Key" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
3. Create a key for the development or production environment.
4. Copy the key immediately. You wont be able to see it again.
<MdxImage
src={ApiKeySecret}
alt="API Key Secret"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
<Note>
### Store API key safely Anyone who has your API key has full control over your account. For security
reasons, you cannot view the API key again.
</Note>
### Test your API Key
Hit the below request to verify that you are authenticated with your API Key and the server is responding.
## Get My Profile {{ tag: 'GET', label: '/api/v1/me' }}
<Row>
<Col>
Get the product details and environment type of your account.
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/me">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/me' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"id": "cll2m30r70004mx0huqkitgqv",
"createdAt": "2023-08-08T18:04:59.922Z",
"updatedAt": "2023-08-08T18:04:59.922Z",
"type": "production",
"product": {
"id": "cll2m30r60003mx0hnemjfckr",
"name": "My Product"
},
"widgetSetupCompleted": false
}
```
```json {{ title: '401 Not Authenticated' }}
Not authenticated
```
</CodeGroup>
</Col>
</Row>
---
### Delete a personal API key
1. Go to settings on [app.formbricks.com](https://app.formbricks.com/).
2. Go to page “API keys”.
3. Find the key you wish to revoke and select “Delete”.
4. Your API key will stop working immediately.

View File

@@ -1,289 +0,0 @@
import { Fence } from "@/components/shared/Fence";
import {generateManagementApiMetadata} from "@/lib/utils"
export const metadata = generateManagementApiMetadata("Attribute Class",["Fetch","Create","Delete"])
#### Management API
# Attribute Classes API
This set of API can be used to
- [List Attributes](#get-all-attribute-classes)
- [Get Attributes](#get-attribute-class-by-id)
- [Create Attributes](#create-attribute-class)
- [Delete Attributes](#delete-attribute-class)
<Note>You will need an API Key to interact with these APIs.</Note>
---
## Get all Attribute Classes {{ tag: 'GET', label: '/api/v1/management/attribute-classes' }}
<Row>
<Col>
Get all the existing attribute classes in your environment.
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/attribute-classes">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/attribute-classes' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": [
{
"id": "cln8k0t47000kz87n3lh23zf0",
"createdAt": "2023-10-02T07:13:19.207Z",
"updatedAt": "2023-10-02T07:13:19.207Z",
"name": "email",
"description": "The email of the person",
"archived": false,
"type": "automatic",
"environmentId": "cln8k0t47000fz87njmmu2bck"
},
{
"id": "cln8k0t55000xz87nrtwbo7sf",
"createdAt": "2023-10-02T07:13:19.241Z",
"updatedAt": "2023-10-02T07:13:19.241Z",
"name": "Name",
"description": "Full Name of the Person",
"archived": false,
"type": "code",
"environmentId": "cln8k0t47000fz87njmmu2bck"
},
]
}
```
```json {{ title: '401 Unauthorized' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Get Attribute Class by ID {{ tag: 'GET', label: '/api/v1/management/attribute-classes/<attribute-class-id>' }}
<Row>
<Col>
Fetch an Attribute class by its ID.
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/attribute-classes/<attribute-class-id>">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/attribute-classes/<attribute-class-id>' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "cln8k0t47000jz87nfwcey6mh",
"createdAt": "2023-10-02T07:13:19.207Z",
"updatedAt": "2023-10-02T07:13:19.207Z",
"name": "userId",
"description": "The internal ID of the person",
"archived": false,
"type": "automatic",
"environmentId": "cln8k0t47000fz87njmmu2bck"
}
}
```
```json {{ title: '401 Unauthorized' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Create Attribute Class {{ tag: 'POST', label: '/api/v1/management/attribute-classes/' }}
<Row>
<Col>
Create an Attribute class.
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
### Body
<CodeGroup title="Request Body">
```json {{ title: 'cURL' }}
{
"environmentId": "clmlmwdqq0003196ufewo6ibg",
"name": "My Attribute from API",
"type": "code",
"description": "My description"
}
```
</CodeGroup>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/api/v1/management/attribute-classes/">
```bash {{ title: 'cURL' }}
curl -X POST https://app.formbricks.com/api/v1/management/attribute-classes/ \
--header 'Content-Type: application/json' \
--header 'x-api-key: <your-api-key>' \
-d '{"environmentId": "clmlmwdqq0003196ufewo6ibg", "name": "My Attribute from API", "type": "code", "description":"My description"}'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "clna0hd7z0009z8zue2z3a7wy",
"createdAt": "2023-10-03T07:41:51.792Z",
"updatedAt": "2023-10-03T07:41:51.792Z",
"name": "My Attribute from API",
"description": null,
"archived": false,
"type": "code",
"environmentId": "cln8k0t47000fz87njmmu2bck"
}
}
```
```json {{ title: '401 Unauthorized' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Delete Attribute Class {{ tag: 'DELETE', label: '/api/v1/management/attribute-classes/<attribute-class-id>' }}
<Row>
<Col>
Delete an Attribute class by its ID.
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="DELETE" label="/api/v1/management/attribute-classes/<attribute-class-id>">
```bash {{ title: 'cURL' }}
curl -X DELETE https://app.formbricks.com/api/v1/management/attribute-classes/<attribute-class-id> \
--header 'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "clna0hd7z0009z8zue2z3a7wy",
"createdAt": "2023-10-03T07:41:51.792Z",
"updatedAt": "2023-10-03T07:41:51.792Z",
"name": "My Attribute from API",
"description": null,
"archived": false,
"type": "code",
"environmentId": "cln8k0t47000fz87njmmu2bck"
}
}
```
```json {{ title: '401 Unauthorized' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---

View File

@@ -1,78 +0,0 @@
import { Fence } from "@/components/shared/Fence";
export const metadata = {
title: "Formbricks Me API: Fetch your environment details",
description:
"Dive into Formbricks' Me API within the Public Client API suite. Seamlessly fetch your own current environment details.",
};
#### Management API
# Me API
This API can be used to get your own current environment details.
<Note>You will need an API Key to interact with these APIs.</Note>
---
## Get Environment {{ tag: 'GET', label: '/api/v1/management/me' }}
<Row>
<Col>
Get your current environment details.
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/me">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/me' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"id": "cln8k0t47000fz87njmmu2bck",
"createdAt": "2023-10-02T07:13:19.207Z",
"updatedAt": "2023-10-02T07:14:14.162Z",
"type": "production",
"product": {
"id": "cln8k0t47000ez87n57aqywvz",
"name": "Demo Product"
},
"widgetSetupCompleted": true
}
```
```json {{ title: '401 Unauthorized' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---

View File

@@ -1,232 +0,0 @@
import { Fence } from "@/components/shared/Fence";
import {generateManagementApiMetadata} from "@/lib/utils"
export const metadata = generateManagementApiMetadata("People",["Fetch","Delete"])
#### Management API
# People API
This set of API can be used to
- [List People](#list-people)
- [Get Person](#get-person)
- [Delete Person](#delete-person)
<Note>You will need an API Key to interact with these APIs.</Note>
---
## List People {{ tag: 'GET', label: '/api/v1/management/people' }}
<Row>
<Col>
List People
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/people">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/people' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": [
{
"id": "b4wgrzl363dn3zb6yy5gf265",
"attributes": {
"userId": "CYO618",
"email": "sophia@amazon.com",
"Name": "Sophia Johnson",
"Role": "Designer",
"Company": "Amazon",
"Experience": "7 years",
"Usage Frequency": "Yearly",
"Company Size": "1628 employees",
"Product Satisfaction Score": "62",
"Recommendation Likelihood": "9"
},
"environmentId": "cln8k0t47000fz87njmmu2bck",
"createdAt": "2023-10-02T07:13:19.444Z",
"updatedAt": "2023-10-02T07:13:19.444Z"
},
{
"id": "jrb5iyzqvnkg9322ckhde3j4",
"attributes": {
"userId": "CYO511",
"email": "antonio@ibm.com",
"Name": "Antonio García",
"Role": "Designer",
"Company": "IBM",
"Experience": "1 years",
"Usage Frequency": "Weekly",
"Company Size": "4023 employees",
"Product Satisfaction Score": "77",
"Recommendation Likelihood": "4"
},
"environmentId": "cln8k0t47000fz87njmmu2bck",
"createdAt": "2023-10-02T07:13:19.444Z",
"updatedAt": "2023-10-02T07:13:19.444Z"
},
]
}
```
```json {{ title: '400 Bad Request' }}
{
"code": "bad_request",
"message": "Fields are missing or incorrectly formatted",
"details": {
"userId": ""
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Get Person {{ tag: 'GET', label: '/api/v1/management/people/<person-id>' }}
<Row>
<Col>
Get Person by ID
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/people/<person-id>">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/people/<person-id>' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "jrb5iyzqvnkg9322ckhde3j4",
"attributes": {
"userId": "CYO511",
"email": "antonio@ibm.com",
"Name": "Antonio García",
"Role": "Designer",
"Company": "IBM",
"Experience": "1 years",
"Usage Frequency": "Weekly",
"Company Size": "4023 employees",
"Product Satisfaction Score": "77",
"Recommendation Likelihood": "4"
},
"environmentId": "cln8k0t47000fz87njmmu2bck",
"createdAt": "2023-10-02T07:13:19.444Z",
"updatedAt": "2023-10-02T07:13:19.444Z"
}
}
```
```json {{ title: '404 Not Found' }}
{
"code": "not_found",
"message": "Person not found",
"details": {
"resource_id": "clmlmykc2000019vz5o3jglsa",
"resource_type": "Person"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Delete Person {{ tag: 'DELETE', label: '/api/v1/management/people/<person-id>' }}
<Row>
<Col>
Delete Person by ID
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="DELETE" label="/api/v1/management/people/<person-id>">
```bash {{ title: 'cURL' }}
curl -X DELETE https://app.formbricks.com/api/v1/management/people/<person-id> \
--header 'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"success": "Person deleted successfully"
}
}
```
```json {{ title: '404 Not Found' }}
{
"code": "not_found",
"message": "Person not found",
"details": {
"resource_id": "clmlmykc2000019vz5o3jglsa",
"resource_type": "Person"
}
}
```
</CodeGroup>
</Col>
</Row>
---

View File

@@ -1,379 +0,0 @@
import { Fence } from "@/components/shared/Fence";
import { generateManagementApiMetadata } from "@/lib/utils";
export const metadata = generateManagementApiMetadata("Responses", ["Fetch", "Delete"]);
#### Management API
# Responses API
This set of API can be used to
- [List Responses](#list-all-responses)
- [List all Responses by surveyId](#list-all-responses-by-survey-id)
- [Get Response](#get-response-by-id)
- [Delete Response](#delete-a-response)
<Note>You will need an API Key to interact with these APIs.</Note>
---
## List all Responses {{ tag: 'GET', label: '/api/v1/management/responses' }}
<Row>
<Col>
Retrieve all the responses you have received in your environment.
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/responses">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/responses' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data":[
{
"id": "cln8k0tqv00pcz87no4qrw333",
"createdAt": "2023-10-02T07:13:20.023Z",
"updatedAt": "2023-10-02T07:13:20.023Z",
"surveyId": "cln8k0tqu00p7z87nqr4thi3k",
"finished": true,
"data": {
"interview-prompt": "clicked"
},
"meta": {
"userAgent": {
"os": "MacOS",
"browser": "Chrome"
}
},
"personAttributes": null,
"person": {
"id": "e0x4i5tvsp8puxfztyrwykvn",
"attributes": {
"userId": "CYO675",
"email": "ravi@netflix.com",
"Name": "Ravi Kumar",
"Role": "Manager",
"Company": "Netflix",
"Experience": "6 years",
"Usage Frequency": "Monthly",
"Company Size": "4610 employees",
"Product Satisfaction Score": "43",
"Recommendation Likelihood": "4"
},
"environmentId": "cln8k0t47000fz87njmmu2bck",
"createdAt": "2023-10-02T07:13:19.444Z",
"updatedAt": "2023-10-02T07:13:19.444Z"
},
"notes": [],
"tags": []
},
]
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## List all Responses by surveyId {{ tag: 'GET', label: '/api/v1/management/responses?surveyId=<survey-Id>' }}
<Row>
<Col>
Retrieve all the responses received in your survey.
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/responses?surveyId=<survey-Id>">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/responses?surveyId=<survey-Id>' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data":[
{
"id": "cln8k0tqv00pcz87no4qrw333",
"createdAt": "2023-10-02T07:13:20.023Z",
"updatedAt": "2023-10-02T07:13:20.023Z",
"surveyId": "cln8k0tqu00p7z87nqr4thi3k",
"finished": true,
"data": {
"interview-prompt": "clicked"
},
"meta": {
"userAgent": {
"os": "MacOS",
"browser": "Chrome"
}
},
"personAttributes": null,
"person": {
"id": "e0x4i5tvsp8puxfztyrwykvn",
"attributes": {
"userId": "CYO675",
"email": "ravi@netflix.com",
"Name": "Ravi Kumar",
"Role": "Manager",
"Company": "Netflix",
"Experience": "6 years",
"Usage Frequency": "Monthly",
"Company Size": "4610 employees",
"Product Satisfaction Score": "43",
"Recommendation Likelihood": "4"
},
"environmentId": "cln8k0t47000fz87njmmu2bck",
"createdAt": "2023-10-02T07:13:19.444Z",
"updatedAt": "2023-10-02T07:13:19.444Z"
},
"notes": [],
"tags": []
},
]
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Get Response by ID {{ tag: 'GET', label: '/api/v1/management/responses/<response-id>' }}
<Row>
<Col>
Retrieve a response by its ID.
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/responses/<response-id>">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/responses/<response-id>' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data":
{
"id": "cln8k0tqv00pbz87nwo5lr72b",
"createdAt": "2023-10-02T07:13:20.023Z",
"updatedAt": "2023-10-02T07:13:20.023Z",
"surveyId": "cln8k0tqu00p7z87nqr4thi3k",
"finished": true,
"data": {
"interview-prompt": "clicked"
},
"meta": {
"userAgent": {
"os": "Windows",
"browser": "Edge"
}
},
"personAttributes": null,
"person": {
"id": "hsx38f15v50ua8383uadagq5",
"attributes": {
"userId": "CYO278",
"email": "jorge@facebook.com",
"Name": "Jorge Sanchez",
"Role": "Product Manager",
"Company": "Facebook",
"Experience": "10 years",
"Usage Frequency": "Daily",
"Company Size": "1685 employees",
"Product Satisfaction Score": "84",
"Recommendation Likelihood": "6"
},
"environmentId": "cln8k0t47000fz87njmmu2bck",
"createdAt": "2023-10-02T07:13:19.444Z",
"updatedAt": "2023-10-02T07:13:19.444Z"
},
"notes": [],
"tags": []
}
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Delete a response {{ tag: 'DELETE', label: '/api/v1/client/responses/<response-id>' }}
<Row>
<Col>
Delete Response by ID
### Mandatory Headers
<Properties>
<Property name="x-api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="DELETE" label="/api/v1/client/responses/<response-id>">
```bash {{ title: 'cURL' }}
curl -X DELETE https://app.formbricks.com/api/v1/management/responses/<response-id> \
--header 'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{ title: '200 Success' }}
{
"data": {
"id": "cln8k0tqv00pbz87nwo5lr72b",
"createdAt": "2023-10-02T07:13:20.023Z",
"updatedAt": "2023-10-02T07:13:20.023Z",
"surveyId": "cln8k0tqu00p7z87nqr4thi3k",
"finished": true,
"data": {
"interview-prompt": "clicked"
},
"meta": {
"userAgent": {
"os": "Windows",
"browser": "Edge"
}
},
"personAttributes": null,
"person": {
"id": "hsx38f15v50ua8383uadagq5",
"attributes": {
"userId": "CYO278",
"email": "jorge@facebook.com",
"Name": "Jorge Sanchez",
"Role": "Product Manager",
"Company": "Facebook",
"Experience": "10 years",
"Usage Frequency": "Daily",
"Company Size": "1685 employees",
"Product Satisfaction Score": "84",
"Recommendation Likelihood": "6"
},
"environmentId": "cln8k0t47000fz87njmmu2bck",
"createdAt": "2023-10-02T07:13:19.444Z",
"updatedAt": "2023-10-02T07:13:19.444Z"
},
"notes": [],
"tags": []
}
}
```
```json {{ title: '400 Bad Request' }}
{
"code": "bad_request",
"message": "surveyId was not provided.",
"details": {
"surveyId": "This field is required."
}
}
```
</CodeGroup>
</Col>
</Row>
---

View File

@@ -1,789 +0,0 @@
import { Fence } from "@/components/shared/Fence";
import { generateManagementApiMetadata } from "@/lib/utils";
export const metadata = generateManagementApiMetadata("Surveys", ["Fetch", "Create", "Update", "Delete"]);
#### Management API
# Surveys API
This set of API can be used to
- [List All Surveys](#list-all-surveys)
- [Get Survey](#get-survey-by-id)
- [Create Survey](#create-survey)
- [Update Survey](#update-survey-by-id)
- [Delete Survey](#delete-survey-by-id)
<Note>You will need an API Key to interact with these APIs.</Note>
---
## List all surveys {{ tag: 'GET', label: '/api/v1/management/surveys' }}
<Row>
<Col>
Retrieve all the surveys you have for the environment with pagination.
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
### Query Parameters
<Properties>
<Property name="offset" type="number">
The number of surveys to skip before returning the results.
</Property>
<Property name="limit" type="number">
The number of surveys to return.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/surveys">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/surveys?offset=20&limit=10' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": [
{
"id": "cllnfy2780fromy0hy7uoxvtn",
"createdAt": "2023-08-23T07:56:20.516Z",
"updatedAt": "2023-08-23T07:56:26.947Z",
"name": "Product Market Fit (Superhuman)",
"type": "link",
"environmentId": "cll2m30r70004mx0huqkitgqv",
"status": "inProgress",
"attributeFilters": [],
"displayOption": "displayOnce",
"autoClose": null,
"triggers": [],
"redirectUrl": null,
"recontactDays": null,
"questions": [
{
"id": "gml6mgy71efgtq8np3s9je5p",
"type": "cta",
"headline": "You are one of our power users! Do you have 5 minutes?",
"required": false,
"buttonLabel": "Happy to help!",
"logic": [
{
"condition": "skipped",
"destination": "end"
}
],
"html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We would love to understand your user experience better. Sharing your insight helps a lot.</span></p>",
"buttonExternal": false,
"dismissButtonLabel": "No, thanks."
},
{
"id": "kp62fbqe8cfzmvy8qwpr81b2",
"type": "multipleChoiceSingle",
"headline": "How disappointed would you be if you could no longer use My Product?",
"subheader": "Please select one of the following options:",
"required": true,
"choices": [
{
"id": "bdgy1hnwd7uwmfxk1ljqp1n5",
"label": "Not at all disappointed"
},
{
"id": "poabnvgtwenp8rb2v70gj4hj",
"label": "Somewhat disappointed"
},
{
"id": "opfiqyqz8wrqn0i0f7t24d3n",
"label": "Very disappointed"
}
],
"shuffleOption": "none"
},
{
"id": "klvpwd4x08x8quesihvw5l92",
"type": "multipleChoiceSingle",
"headline": "What is your role?",
"subheader": "Please select one of the following options:",
"required": true,
"choices": [
{
"id": "c8nerw6l9gpsxcmqkn10f9hy",
"label": "Founder"
},
{
"id": "ebjqezei6a2axtuq86cleetn",
"label": "Executive"
},
{
"id": "ctiijjblyhlp22snypfamqt1",
"label": "Product Manager"
},
{
"id": "ibalyr0mhemfkkr82vypmg40",
"label": "Product Owner"
},
{
"id": "fipk606aegslbd0e7yhc0xjx",
"label": "Software Engineer"
}
],
"shuffleOption": "none"
},
{
"id": "ryo75306flyg72iaeditbv51",
"type": "openText",
"headline": "What type of people do you think would most benefit from My Product?",
"required": true
},
{
"id": "lkjaxb73ulydzeumhd51sx9g",
"type": "openText",
"headline": "What is the main benefit you receive from My Product?",
"required": true
},
{
"id": "ec7agikkr58j8uonhioinkyk",
"type": "openText",
"headline": "How can we improve My Product for you?",
"subheader": "Please be as specific as possible.",
"required": true
}
],
"thankYouCard": {
"enabled": true,
"headline": "Thank you!",
"subheader": "We appreciate your feedback."
},
"delay": 0,
"autoComplete": null,
"closeOnDate": null
}
]
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Get Survey by ID {{ tag: 'GET', label: '/api/v1/management/surveys/<survey-id>' }}
<Row>
<Col>
Get a specific survey by its ID.
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/management/surveys/<survey-id>">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/management/surveys/<survey-id>' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "cln8k0tjz00n5z87nwq527h3z",
"createdAt": "2023-10-02T07:13:19.775Z",
"updatedAt": "2023-10-02T07:13:19.775Z",
"name": "Churn Survey",
"type": "link",
"environmentId": "cln8k0t47000fz87njmmu2bck",
"status": "inProgress",
"attributeFilters": [],
"displayOption": "displayOnce",
"autoClose": null,
"triggers": [],
"redirectUrl": null,
"recontactDays": null,
"questions": [
{
"id": "churn-reason",
"type": "multipleChoiceSingle",
"headline": "Why did you cancel your subscription?",
"subheader": "We're sorry to see you leave. Help us do better:",
"required": true,
"logic": [
{
"condition": "equals",
"value": "Difficult to use",
"destination": "easier-to-use"
},
{
"condition": "equals",
"value": "It's too expensive",
"destination": "30-off"
},
{
"condition": "equals",
"value": "I am missing features",
"destination": "missing-features"
},
{
"condition": "equals",
"value": "Poor customer service",
"destination": "poor-service"
},
{
"condition": "equals",
"value": "I just didn't need it anymore",
"destination": "end"
}
],
"choices": [
{
"id": "isud2xethsw63dlwl89kr4kj",
"label": "Difficult to use"
},
{
"id": "opuu4ba3dlele3n0gjkuh27c",
"label": "It's too expensive"
},
{
"id": "gnypapo0rhvkt8pwosrphvbl",
"label": "I am missing features"
},
{
"id": "wkgsrsrazd9kfunqhzjezx6t",
"label": "Poor customer service"
},
{
"id": "pykmgyyw74vg0gaeryj6bo4c",
"label": "I just didn't need it anymore"
}
]
},
{
"id": "easier-to-use",
"type": "openText",
"headline": "What would have made {{productName}} easier to use?",
"subheader": "",
"required": true,
"buttonLabel": "Send",
"logic": [
{
"condition": "submitted",
"destination": "end"
}
]
},
{
"id": "30-off",
"type": "cta",
"headline": "Get 30% off for the next year!",
"required": true,
"buttonLabel": "Get 30% off",
"logic": [
{
"condition": "clicked",
"destination": "end"
}
],
"html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We'd love to keep you as a customer. Happy to offer a 30% discount for the next year.</span></p>",
"buttonUrl": "https://formbricks.com",
"buttonExternal": true,
"dismissButtonLabel": "Skip"
},
{
"id": "missing-features",
"type": "openText",
"headline": "What features are you missing?",
"subheader": "",
"required": true,
"logic": [
{
"condition": "submitted",
"destination": "end"
}
]
},
{
"id": "poor-service",
"type": "cta",
"headline": "So sorry to hear 😔 Talk to our CEO directly!",
"required": true,
"buttonLabel": "Send email to CEO",
"logic": [
{
"condition": "clicked",
"destination": "end"
}
],
"html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We aim to provide the best possible customer service. Please email our CEO and she will personally handle your issue.</span></p>",
"buttonUrl": "mailto:ceo@company.com",
"buttonExternal": true,
"dismissButtonLabel": "Skip"
}
],
"thankYouCard": {
"enabled": false
},
"delay": 0,
"autoComplete": null,
"closeOnDate": null,
"surveyClosedMessage": null,
"verifyEmail": null
}
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Create Survey {{ tag: 'POST', label: '/api/v1/management/surveys' }}
<Row>
<Col>
Create a survey
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
### Body
<CodeGroup title="Request Body">
```json {{ title: 'cURL' }}
{
"environmentId": "clmlmwdqq0003196ufewo6ibg",
"type": "link",
"name": "My new Survey"
}
```
</CodeGroup>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/api/v1/management/surveys">
```bash {{ title: 'cURL' }}
curl -X POST \
'https://app.formbricks.com/api/v1/management/surveys' \
--header \
'x-api-key: <your-api-key>'
```
```bash {{ title: 'cURL' }}
curl -X POST https://app.formbricks.com/api/v1/management/surveys/ \
--header 'Content-Type: application/json' \
--header 'x-api-key: <your-api-key>' \
-d '{"environmentId": "cln8k0t47000fz87njmmu2bck", "name": "My Survey from API", "type": "link"}'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "clna6bqnz000az8zubq3e757t",
"createdAt": "2023-10-03T10:25:26.975Z",
"updatedAt": "2023-10-03T10:25:26.975Z",
"name": "My new Survey",
"redirectUrl": null,
"type": "link",
"environmentId": "cln8k0t47000fz87njmmu2bck",
"status": "draft",
"questions": [],
"thankYouCard": {
"enabled": false
},
"displayOption": "displayOnce",
"recontactDays": null,
"autoClose": null,
"delay": 0,
"autoComplete": null,
"closeOnDate": null,
"surveyClosedMessage": null,
"verifyEmail": null
}
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Update Survey by ID {{ tag: 'PUT', label: '/api/v1/management/surveys/<survey-id>' }}
<Row>
<Col>
Update a survey by its ID
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
### Body
<CodeGroup title="Request Body">
```json {{ title: 'cURL' }}
{
"name": "My renamed Survey",
"redirectUrl":"https://formbricks.com",
"type":"web"
}
```
</CodeGroup>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="PUT" label="/api/v1/management/surveys/<survey-id>">
```bash {{ title: 'cURL' }}
curl -X PUT https://app.formbricks.com/api/v1/management/surveys/<survey-id> \
--header 'Content-Type: application/json' \
--header 'x-api-key: <your-api-key>' \
-d '{"name": "My renamed Survey"}'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "cloqzeuu70000z8khcirufo60",
"createdAt": "2023-11-09T09:23:42.367Z",
"updatedAt": "2023-11-09T09:23:42.367Z",
"name": "My renamed Survey",
"redirectUrl": null,
"type": "link",
"environmentId": "clonzr6vc0009z8md7y06hipl",
"status": "inProgress",
"welcomeCard": {
"html": "Thanks for providing your feedback - let's go!",
"enabled": false,
"headline": "Welcome!",
"timeToFinish": false
},
"questions": [
{
"id": "l9rwn5nbk48y44tvnyyjcvca",
"type": "openText",
"headline": "Why did you leave the platform?",
"required": true,
"inputType": "text"
}
],
"thankYouCard": {
"enabled": true,
"headline": "Thank you!",
"subheader": "We appreciate your feedback."
},
"hiddenFields": {
"enabled": true,
"fieldIds": []
},
"displayOption": "displayOnce",
"recontactDays": null,
"autoClose": null,
"delay": 0,
"autoComplete": 50,
"closeOnDate": null,
"surveyClosedMessage": null,
"productOverwrites": null,
"singleUse": {
"enabled": false,
"isEncrypted": true
},
"verifyEmail": null,
"pin": null,
"triggers": [],
"attributeFilters": []
}
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Delete Survey by ID {{ tag: 'DELETE', label: '/api/v1/management/surveys/<survey-id>' }}
<Row>
<Col>
Delete a survey by its ID.
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="DELETE" label="/api/v1/management/surveys/<survey-id>">
```bash {{ title: 'cURL' }}
curl -X DELETE \
'https://app.formbricks.com/api/v1/management/surveys/<survey-id>' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"data": {
"id": "cln8k0tjz00n5z87nwq527h3z",
"createdAt": "2023-10-02T07:13:19.775Z",
"updatedAt": "2023-10-02T07:13:19.775Z",
"name": "Churn Survey",
"type": "link",
"environmentId": "cln8k0t47000fz87njmmu2bck",
"status": "inProgress",
"attributeFilters": [],
"displayOption": "displayOnce",
"autoClose": null,
"triggers": [],
"redirectUrl": null,
"recontactDays": null,
"questions": [
{
"id": "churn-reason",
"type": "multipleChoiceSingle",
"headline": "Why did you cancel your subscription?",
"subheader": "We're sorry to see you leave. Help us do better:",
"required": true,
"logic": [
{
"condition": "equals",
"value": "Difficult to use",
"destination": "easier-to-use"
},
{
"condition": "equals",
"value": "It's too expensive",
"destination": "30-off"
},
{
"condition": "equals",
"value": "I am missing features",
"destination": "missing-features"
},
{
"condition": "equals",
"value": "Poor customer service",
"destination": "poor-service"
},
{
"condition": "equals",
"value": "I just didn't need it anymore",
"destination": "end"
}
],
"choices": [
{
"id": "isud2xethsw63dlwl89kr4kj",
"label": "Difficult to use"
},
{
"id": "opuu4ba3dlele3n0gjkuh27c",
"label": "It's too expensive"
},
{
"id": "gnypapo0rhvkt8pwosrphvbl",
"label": "I am missing features"
},
{
"id": "wkgsrsrazd9kfunqhzjezx6t",
"label": "Poor customer service"
},
{
"id": "pykmgyyw74vg0gaeryj6bo4c",
"label": "I just didn't need it anymore"
}
]
},
{
"id": "easier-to-use",
"type": "openText",
"headline": "What would have made {{productName}} easier to use?",
"subheader": "",
"required": true,
"buttonLabel": "Send",
"logic": [
{
"condition": "submitted",
"destination": "end"
}
]
},
{
"id": "30-off",
"type": "cta",
"headline": "Get 30% off for the next year!",
"required": true,
"buttonLabel": "Get 30% off",
"logic": [
{
"condition": "clicked",
"destination": "end"
}
],
"html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We'd love to keep you as a customer. Happy to offer a 30% discount for the next year.</span></p>",
"buttonUrl": "https://formbricks.com",
"buttonExternal": true,
"dismissButtonLabel": "Skip"
},
{
"id": "missing-features",
"type": "openText",
"headline": "What features are you missing?",
"subheader": "",
"required": true,
"logic": [
{
"condition": "submitted",
"destination": "end"
}
]
},
{
"id": "poor-service",
"type": "cta",
"headline": "So sorry to hear 😔 Talk to our CEO directly!",
"required": true,
"buttonLabel": "Send email to CEO",
"logic": [
{
"condition": "clicked",
"destination": "end"
}
],
"html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We aim to provide the best possible customer service. Please email our CEO and she will personally handle your issue.</span></p>",
"buttonUrl": "mailto:ceo@company.com",
"buttonExternal": true,
"dismissButtonLabel": "Skip"
}
],
"thankYouCard": {
"enabled": false
},
"delay": 0,
"autoComplete": null,
"closeOnDate": null,
"surveyClosedMessage": null,
"verifyEmail": null
}
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---

View File

@@ -1,398 +0,0 @@
import {generateManagementApiMetadata} from "@/lib/utils"
export const metadata = generateManagementApiMetadata("Webhook",["Fetch","Create","Delete"])
#### Management API
# Webhook API
Formbricks' Webhook API offers a powerful interface for interacting with webhooks. Webhooks allow you to receive real-time HTTP notifications of changes to specific objects in the Formbricks environment.
The behavior of the webhooks is determined by their trigger settings. The trigger determines which updates the webhook sends. Current available triggers include "responseCreated", "responseUpdated", and "responseFinished". This allows you to customize your webhooks to only send notifications for the events that are relevant to your application.
Webhooks are tied to a specific Formbricks environment. Once set, a webhook will receive updates from all surveys within this environment. This makes it easy to manage your data flow and ensure that all relevant updates are caught by the webhook.
This set of API can be used to
- [List All Webhooks](#list-webhooks)
- [Get Webhook](#retrieve-webhook-by-id)
- [Create Webhook](#create-webhook)
- [Delete Webhook](#delete-webhook-by-id)
And the detailed Webhook Payload is elaborated [here](#webhook-payload).
These APIs are designed to facilitate seamless integration of Formbricks with third-party systems. By making use of our webhook API, you can automate the process of sending data to these systems whenever significant events occur within your Formbricks environment.
<Note>You will need an API Key to interact with these APIs.</Note>
---
## List Webhooks {{ tag: 'GET', label: '/api/v1/webhooks' }}
<Row>
<Col>
Learn how to retrieve a list of all webhooks via API.
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/webhooks">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/webhooks' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{ title: '200 Success' }}
{
"data": [
{
"id": "cliu1kdza000219zftad4ip6c",
"createdAt": "2023-06-13T08:49:04.198Z",
"updatedAt": "2023-06-13T08:49:04.198Z",
"url": "https://mysystem.com/myendpoint",
"environmentId": "clisypjy4000319t4imm289uo",
"triggers": [
"responseFinished"
]
}
]
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Retrieve Webhook by ID {{ tag: 'GET', label: '/api/v1/webhooks/<webhook-id>' }}
<Row>
<Col>
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/webhooks/<webhook-id>">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/webhooks/<webhook-id>' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{ title: '200 Success' }}
{
"data": {
"id": "cliu167rk000019zfhbo68bar",
"createdAt": "2023-06-13T08:38:02.960Z",
"updatedAt": "2023-06-13T08:38:02.960Z",
"url": "https://mysystem.com/myendpoint",
"environmentId": "clisypjy4000319t4imm289uo",
"triggers": [
"responseFinished"
]
}
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Create Webhook {{ tag: 'POST', label: '/api/v1/webhooks' }}
Add a webhook to your product.
<Row>
<Col>
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
### Request Body Parameters
<Properties>
<Property name="url" type="string" required>
The URL where the webhook will send data to.
</Property>
<Property name="triggers" type="string[]" required>
List of events that will trigger the webhook.
</Property>
<Property name="surveyIds" type="string[]">
List of survey IDs that will trigger the webhook. If not provided, the webhook will be triggered for all surveys.
</Property>
</Properties>
| field name | required | default | description |
| ---------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
| url | yes | - | The endpoint that the webhook will send data to |
| trigger | yes | - | The event that will trigger the webhook ("responseCreated" or "responseUpdated" or "responseFinished") |
| surveyIds | no | - | List of survey IDs that will trigger the webhook. If not provided, the webhook will be triggered for all surveys. |
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/api/v1/webhooks">
```bash {{ title: 'cURL' }}
curl --location --request POST 'https://app.formbricks.com/api/v1/webhooks' \
--header 'x-api-key: <your-api-key>' \
--header 'Content-Type: application/json' \
--data-raw '{
"url": "https://mysystem.com/myendpoint",
"triggers": ["responseFinished"]
}'
```
```json {{ title: 'Example Request Body' }}
{
"url": "https://mysystem.com/myendpoint",
"triggers": ["responseFinished"]
}
```
</CodeGroup>
<CodeGroup title="Response">
```json {{ title: '200 Success' }}
{
"data": {
"id": "cliu1kdza000219zftad4ip6c",
"createdAt": "2023-06-13T08:49:04.198Z",
"updatedAt": "2023-06-13T08:49:04.198Z",
"url": "https://mysystem.com/myendpoint",
"environmentId": "clisypjy4000319t4imm289uo",
"triggers": ["responseFinished"],
"surveyIds": ["clisypjy4000319t4imm289uo"]
}
}
```
```json {{ title: '400 Bad Request' }}
{
"code": "bad_request",
"message": "Missing trigger",
"details": {
"missing_field": "trigger"
}
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Delete Webhook by ID {{ tag: 'DELETE', label: '/api/v1/webhooks/<webhook-id>' }}
<Row>
<Col>
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="DELETE" label="/api/v1/webhooks/<webhook-id>">
```bash {{ title: 'cURL' }}
curl --location --request DELETE 'https://app.formbricks.com/api/v1/webhooks/<webhook-id>' \
--header 'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{ title: '200 Success' }}
{
"data": {
"id": "cliu167rk000019zfhbo68bar",
"createdAt": "2023-06-13T08:38:02.960Z",
"updatedAt": "2023-06-13T08:38:02.960Z",
"url": "https://mysystem.com/myendpoint",
"environmentId": "clisypjy4000319t4imm289uo",
"triggers": ["responseFinished"]
}
}
```
```json {{ title: '401 Not Authenticated' }}
{
"code": "not_authenticated",
"message": "Not authenticated",
"details": {
"x-Api-Key": "Header not provided or API Key invalid"
}
}
```
```json {{ title: '404 Not Found' }}
{
"code": "not_found",
"message": "Webhook not found.",
"details": {
"webhookId": "The requested webhook does not exist."
}
}
```
</CodeGroup>
</Col>
</Row>
---
## Webhook Payload
This documentation helps understand the payload structure that will be received when the webhook is triggered in Formbricks.
<Row>
<Col sticky>
| Variable | Type | Description |
| --------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| webhookId | String | Webhook's Id |
| event | String | The name of the trigger event [responseCreated, responseUpdated, responseFinished] |
| data | Object | Contains the details of the newly created response. |
| data.id | String | Formbricks Response ID. |
| data.createdAt | String | The timestamp when the response was created. |
| data.updatedAt | String | The timestamp when the response was last updated. |
| data.surveyId | String | The identifier of the survey associated with this response. |
| data.finished | Boolean | A boolean value indicating whether the survey response is marked as finished. |
| data.data | Object | An object containing the response data, where keys are question identifiers, and values are the corresponding answers given by the respondent. |
| data.meta | Object | Additional metadata related to the response, such as the user's operating system and browser information. |
| data.personAttributes | Object | An object with attributes related to the respondent, such as their email and a user ID (if available). |
| data.person | Object | Information about the respondent, including their unique id, attributes, and creation/update timestamps. |
| data.notes | Array | An array of notes associated with the response (if any). |
| data.tags | Array | An array of tags assigned to the response (if any). |
</Col>
<Col>
### An example webhook payload
<CodeGroup title="Payload">
```json
{
"webhookId": "cljwxvjos0003qhnvj2jg4k5i",
"event": "responseCreated",
"data": {
"id": "cljwy2m8r0001qhclco1godnu",
"createdAt": "2023-07-10T14:14:17.115Z",
"updatedAt": "2023-07-10T14:14:17.115Z",
"surveyId": "cljsf3d7a000019cv9apt2t27",
"finished": false,
"data": {
"qumbk3fkr6cky8850bvvq5z1": "Executive"
},
"meta": {
"userAgent": {
"os": "Mac OS",
"browser": "Chrome"
}
},
"personAttributes": {
"email": "test@web.com",
"userId": "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING"
},
"person": {
"id": "cljold01t0000qh8ewzigzmjk",
"attributes": {
"email": "test@web.com",
"userId": "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING"
},
"createdAt": "2023-07-04T17:56:17.154Z",
"updatedAt": "2023-07-04T17:56:17.154Z"
},
"notes": [],
"tags": []
}
}
```
</CodeGroup>
</Col>
</Row>
---

View File

@@ -209,13 +209,12 @@ We will rewrite the function `getApiKey` we created in the `service.ts` file to
<CodeGroup title="packages/lib/apiKey/service.ts">
```ts
import { unstable_cache } from "next/cache";
import { cache } from "@formbricks/lib/cache";
import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
import { apiKeyCache } from "./cache";
export const getApiKey = async (apiKeyId: string): Promise<TApiKey> =>
unstable_cache(
export const getApiKey = (apiKeyId: string): Promise<TApiKey> =>
cache(
async () => {
validateInputs([apiKeyId, ZString]);
@@ -242,7 +241,6 @@ export const getApiKey = async (apiKeyId: string): Promise<TApiKey> =>
[`getApiKey-${apiKeyId}`],
{
tags: [apiKeyCache.tag.byId(apiKeyId)],
revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
```
@@ -265,9 +263,7 @@ From the screenshot above we see that `unstable_cache` receives 3 arguments:
1. `fetchData`: In our case this is the exact function of your service without caching (step 3)
2. `keyParts`: As a rule of thumb, the key must consist of the name of the function and the arguments passed into the function, all separated by a dash. In our case it is called `getApiKey-${apiKeyId}` because the function name is `getApiKey` and we receive only one argument called `apiKeyId`
3. `options`: which consists of **tags** and **revalidate**
1. `tags`: This is where the tags you created in step 4a comes in, tags are created solely based on the arguments passed to the function. (please reference existing services in `packages/lib` to see more variations of this when dealing with more than one argument)
2. `revalidate`: We have a global constant for this which you can use called `SERVICES_REVALIDATION_INTERVAL`
3. `options`: which consists of **tags** that controls the revalidation of the cache. This is where the tags you created in step 4a comes in, tags are created solely based on the arguments passed to the function. (please reference existing services in `packages/lib` to see more variations of this when dealing with more than one argument)
<Note>
In create, update and delete requests, you dont need caching however these are the places where the revalidate method is called. For example when the apiKey is deleted we want to call the revalidate method and pass in the id and environmentId, so we invalidate every cached function with `id` and `environmentId` tags.

View File

@@ -76,7 +76,7 @@ Install the Formbricks SDK using one of the package managers ie `npm`,`pnpm`,`ya
<Col>
<CodeGroup title="Install Formbricks JS library">
```shell {{ title: 'npm' }}
npm install --save @formbricks/js
npm install @formbricks/js
```
```shell {{ title: 'pnpm' }}
pnpm add @formbricks/js
@@ -153,7 +153,7 @@ Code snippets for the integration for both conventions are provided to further a
<Col>
<CodeGroup title="Install Formbricks JS library">
```shell {{ title: 'npm' }}
npm install --save @formbricks/js
npm install @formbricks/js
```
```shell {{ title: 'pnpm' }}
pnpm add @formbricks/js
@@ -283,7 +283,7 @@ We will make sure the SDK is only loaded and used on the client side, as it's no
<Col>
<CodeGroup title="Install Formbricks JS library">
```shell {{ title: 'npm' }}
npm install --save @formbricks/js
npm install @formbricks/js
````
```shell {{ title: 'pnpm' }}

View File

@@ -33,7 +33,7 @@ Advanced Targeting allows you to show surveys to the right group of people. You
details to start the freemium plan.
</Note>
1. On the Formbricks dashboard, click on **People & Segments** tab from the top navigation bar.
1. On the Formbricks dashboard, click on **People** tab from the top navigation bar.
2. Switch to the **Segments** tab & click on **Create Segment**.

View File

@@ -0,0 +1,184 @@
import DemoPreview from "@/components/dummyUI/DemoPreview";
import { MdxImage } from "@/components/shared/MdxImage";
export const metadata = {
title: "Formbricks Functions for Frontend Developers: Quickstart Guide",
description:
"An overview of all available options for frontend developers to integrate and display surveys in web applications. Learn the key methods, configuration settings, and best practices.",
};
# Formbricks Functions for Frontend Developers: Quickstart Guide
An overview of all available options for frontend developers to integrate and display surveys in web applications. Learn the key methods, configuration settings, and best practices.
## Formbricks Integration
Integrating Formbricks into your web application is straightforward, but it's important to follow the correct steps to ensure proper setup and functionality. For detailed instructions tailored to your development environment, please refer to our [Framework Guides](/docs/getting-started/framework-guides).
## Check Availability
Before using Formbricks, it's best practice to confirm it's available on the current web page. You can use a simple check to ensure Formbricks is not null:
<Col>
<CodeGroup title="Check Formbricks Availability">
```javascript
if (window.formbricks !== null) {
console.log("Formbricks is available");
} else {
console.error("Formbricks is not available");
}
```
</CodeGroup>
</Col>
If Formbricks is not available, ensure it's properly integrated into your web application according to the installation guide.
## Initializing Formbricks
To start using Formbricks features, you must initialize it with the necessary environment information. This can be done with or without user identification.
For comprehensive guidance on setting up user identification, please consult our [User Identification Guide](/docs/in-app-surveys/user-identification).
### Initialization Without User ID
If you do not need user-specific tracking (e.g. on public facing websites with a lot of traffic), you can initialize Formbricks with just the `environmentId` and `apiHost`:
<Col>
<CodeGroup title="Initialize Without User ID">
```javascript
formbricks.init({
environmentId: "<your-environment-id>",
apiHost: "<your-api-host>",
});
```
</CodeGroup>
</Col>
### Initialization With User ID
If you need user-specific tracking, initialize Formbricks with a `userId` in addition to the `environmentId` and `apiHost`:
<Col>
<CodeGroup title="Initialize With User ID">
```javascript
formbricks.init({
environmentId: "<your-environment-id>",
apiHost: "<your-api-host>",
userId: "<user-id>",
});
```
</CodeGroup>
</Col>
This setup allows you to associate interactions with specific users, enabling detailed tracking and user-specific functionality.
## Enabling Debug Mode
To enable debug mode in Formbricks, add `?formbricksDebug=true` to your URL. This activates detailed debug messages in the browser console, providing deeper insights into Formbricks' operation and potential issues.
For comprehensive guidance on using debug mode, refer to our [Debug Mode Documentation](/docs/getting-started/framework-guides#debugging-formbricks-integration). It covers additional troubleshooting tips and information on analyzing Formbricks' integration.
## Tracking Code Actions
Formbricks allows you to track code-based actions, which is useful for logging events or user interactions in your application.
For detailed information on using code-based actions, please visit our [Code Actions Guide](/docs/in-app-surveys/actions#code-actions).
<Col>
<CodeGroup title="Track Code Action">
```javascript
formbricks.track("Code Action");
```
</CodeGroup>
</Col>
The parameter "Code Action" can be customized to represent various actions, providing flexibility for different tracking scenarios.
## Setting User Attributes
<Note>
Please note that this function requires user identification to be active. Ensure you've initialized Formbricks with a `userId` before attempting to use this function.
</Note>
If user identification is active, you can set custom attributes for the identified user. This can be helpful for segmenting users based on specific characteristics or properties.
To learn how to set custom user attributes, please check out our [User Attributes Guide](/docs/in-app-surveys/attributes#setting-custom-user-attributes).
<Col>
<CodeGroup title="Set User Attribute">
```javascript
formbricks.setAttribute("Plan", "Paid");
```
</CodeGroup>
</Col>
In this example, the "Plan" attribute is set to "Paid", indicating the user's subscription status. You can set multiple attributes to capture additional user information. These attributes can be used to target surveys to specific users. You cannot set `userId` via this function.
## Setting User Email
<Note>
Please note that this function requires user identification to be active. Ensure you've initialized Formbricks with a `userId` before attempting to use this function.
</Note>
To associate an email address with an identified user, you can use the `setEmail` function. This is useful for linking a user's email with their interactions:
<Col>
<CodeGroup title="Set User Email">
```javascript
formbricks.setEmail("test@example.com");
```
</CodeGroup>
</Col>
Setting the email can facilitate user communication and integration with other systems, enabling a more seamless user experience.
## Logout
To log out and deinitialize Formbricks, use the `formbricks.logout()` function. This action clears the current initialization configuration and erases stored frontend information, such as the surveys a user has viewed or completed. It's an important step when a user logs out of your application or when you want to reset Formbricks.
<Col>
<CodeGroup title="Logout User">
```javascript
formbricks.logout();
```
</CodeGroup>
</Col>
<Note>
After calling `formbricks.logout()`, you'll need to reinitialize Formbricks before using any of its features again. Ensure that you properly reinitialize Formbricks to avoid unexpected errors or behavior in your application.
</Note>
## Resetting Formbricks
The `formbricks.reset()` function is a convenient way to clear current Formbricks data, and then reinitialize Formbricks. This action not only removes stored frontend information, such as the surveys a user has viewed or completed, but also reinitializes Formbricks with the settings used during the original initialization.
<Col>
<CodeGroup title="Reset Formbricks">
```javascript
formbricks.reset();
```
</CodeGroup>
</Col>
After calling `formbricks.reset()`, Formbricks is reinitialized, meaning you can continue using its features without additional setup. Be aware that any custom attributes, tracking, or user-specific data will be cleared and restored to the initial state.
## Deprecated Function
Please be aware that the following function is deprecated and should not be used in new code or maintained projects:
- `formbricks.setUserId()`: Instead of using this function, set the `userId` during the initialization of Formbricks. This change ensures a more consistent approach to user identification and reduces the risk of errors due to inconsistent user context.

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,108 @@
import { MdxImage } from "@/components/shared/MdxImage";
import AppSurvey from "./app-survey.webp";
import GlobalWaitTime from "./global-wait-time.webp";
import SurveyRecontact from "./survey-recontact.webp";
import IgnoreWaitTime from "./ignore-wait-time.webp";
export const metadata = {
title: "Recontact Options in Formbricks: When to show a survey again to a user",
description:
"Explore how to configure Recontact options in Formbricks to control the frequency of survey exposure to users, ensuring effective feedback collection without compromising user experience.",
};
#### In-App Surveys
# Recontact Options
Recontact options in Formbricks enable you to manage how often and under what conditions a survey is shown to a user. This feature is crucial for balancing effective feedback collection with a positive user experience by preventing survey fatigue.
## When do Recontact Options come into play?
Recontact options are the last layer of the logic that determines if a survey is shown to the current user. The logic goes as follows:
1. Targeting: Does the current user targeted to fill out this survey? If yes...
2. Trigger: Is the survey triggered? If yes...
3. **Recontact Options:** Should the survey be shown (again) to this user? That's dependent on:
- Did the user see any survey recently (meaning, has Global Waiting Time passed)?
- Did the user see this specific survey already?
- How many times did the user see this specific survey already?
- Has the user already responded to this survey?
As you can see, there are a lot of different cases to cover. Let's have a closer look 👇
## Recontact Options
<Note>By default, a survey is shown to each user only once.</Note>
You can adjust the default behavior by modifying the Recontact Options for each survey in the settings:
1. Open the Survey Editor for the survey you want to see & modify the Recontact Options for.
2. Select the Settings Tab.
3. Ensure your Survey type is set to **App Survey**.
<MdxImage
src={AppSurvey}
alt="Choose Survey Type as App Survey"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
4. Scroll down to the Recontact Options section.
Available Recontact Options include:
- **Show only once**: (default) Displays the survey a single time, regardless of whether it was completed.
- **Until they Submit a Response**: If tareting matches and trigger fires, Formbricks keeps showing the survey until the user submits a response.
- **Keep Showing while Conditions Match**: Always shows the survey while specific conditions are met. Useful for continuous feedback collection, such as in [Docs Feedback Survey](/docs/best-practices/docs-feedback) or the [Feedback Box](/docs/best-practices/feedback-box).
<MdxImage
src={SurveyRecontact}
alt="Choose Recontanct Options for the Survey"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
## Product-wide Global Waiting Time
The Global Waiting Time is a universal blocker to make sure that no user sees too many surveys. This is particularly helpful when several teams of large organisations use Formbricks at the same time.
<Note>
The default Global Waiting Time is set to 7 days.
</Note>
To adjust the Global Waiting Time:
1. Visit Formbricks Settings
2. Go to Product Settings
3. Find the **Recontact Waiting Time** section
4. Modify the interval (in days) as needed.
<MdxImage
src={GlobalWaitTime}
alt="Formbricks Product-Wide Wait Time"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
## Overriding Global Waiting Time for a Specific Survey
For specific surveys, you may need to override the default waiting time. Below is how you can do that:
1. In the Survey Editor, access the Settings Tab.
2. Find the Ignore Waiting Time between Surveys toggle under Recontact Options.
3. Enable this toggle to bypass the global setting.
4. Set a custom recontact period:
- **Always Show Survey**: Displays the survey whenever triggered, ignoring the waiting time.
- **Wait `X` days before showing this survey again**: Sets a specific interval before the survey can be shown again.
<MdxImage
src={IgnoreWaitTime}
alt="Ignore Global Waiting Time for a Specific Survey"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
---
Still struggling or something not working as expected? [Join our Discord!](https://formbricks.com/discord) and we'd be glad to assist you!

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -74,7 +74,7 @@ Before the next step, make sure that you have a Formbricks Survey with at least
</Note>
6. Now click on the "Link New Table" button to link a new Airtable with Formbricks and a modal will open up.
6. Now click on the "Link New Table" button to link an Airtable with Formbricks and a modal will open up.
<MdxImage
src={LinkSurveyWithTable}
@@ -102,7 +102,7 @@ Before the next step, make sure that you have a Formbricks Survey with at least
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Congratulations! You have successfully linked an Airtable with Formbricks. Now whenever a response is submitted for the linked Survey, it will be automatically added to the linked Airtable.
Congratulations! You have successfully linked an Airtable with Formbricks. Now whenever a response is submitted for the linked survey, it will be automatically added to the linked Airtable.
Still struggling or something not working as expected? [Join our Discord!](https://formbricks.com/discord) and we'd be glad to assist you!

View File

@@ -24,10 +24,10 @@ The Google Sheets integration allows you to automatically send responses to a Go
<Note>
This feature is enabled by default in Formbricks Cloud but needs to be self-configured when running a
self-hosted version of Formbricks.
self-hosted version of Formbricks. For self-configuration, see additional setup [below](#setup-in-self-hosted-formbricks).
</Note>
## Formbricks Cloud
## Connect Google Sheets
1. Go to the Integrations tab in your [Formbricks Cloud dashboard](https://app.formbricks.com/) and click on the "Connect" button under Google Sheets integration.
@@ -64,7 +64,7 @@ Before the next step, make sure that you have a Formbricks Survey with at least
</Note>
5. Now click on the "Link New Sheet" button to link a new Google Sheet with Formbricks and a modal will open up.
5. Now click on the "Link New Sheet" button to link a Google Sheet with Formbricks and a modal will open up.
<MdxImage
src={LinkSurveyWithSheet}
@@ -91,57 +91,16 @@ Before the next step, make sure that you have a Formbricks Survey with at least
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Congratulations! You have successfully linked a Google Sheet with Formbricks. Now whenever a response is submitted for the linked Survey, it will be automatically added to the linked Google Sheet.
## Setup in self-hosted Formbricks
Enabling the Google Sheets Integration in a self-hosted environment isn't easy and requires a setup using Google Cloud and changing the environment variables of your Formbricks instance.
<Note>This process is really complicated and we recommend using Formbricks Cloud for this feature.</Note>
We will first create a Google Cloud Project and then enable the Google Sheets API for it. Then we will create an OAuth Client ID and Client Secret for our Formbricks instance and set them as environment variables.
1. Go to the [Google Cloud Console](https://console.cloud.google.com/) and **create a new project**.
2. Now select the project you just created and go to the "**APIs & Services**" section.
3. Click on the "**Enable APIs and Services**" button and search for "**Google Sheets API**" and enable it.
4. Now go to the "**OAuth Consent screen**" section and select the **"External" User Type** if you want any Google User to be able to use the integration or select "Internal" if you want only the users of your Google Workspace to be able to use the integration.
5. Now provide it the details such as
- App name (Will **show up in the OAuth modal** when the user is asked to authenticate with Google)
- User support email (ideally should be **your email** for any support queries by the Users or Google)
- Developer contact information (ideally should be **your email** for any **support queries by Google**)
6. Now click on the "Save and Continue" button and you will be taken to the Scopes step.
7. Click on the "**Add or Remove Scopes**" button and add the scopes `https://www.googleapis.com/auth/userinfo.email`, `https://www.googleapis.com/auth/spreadsheets` & `https://www.googleapis.com/auth/drive` and click on the "Update" button:
8. Now Verify the scopes and click on the "Save and Continue" button.
9. Now go to the **"Test Users" section, skip the step**, and click the "Save and Continue" button.
10. You will now be shown a summary of the OAuth Consent Screen. Verify the details and Click on the "**Back to Dashboard**" button.
11. Now go to the "**Credentials**" section and click on the "**Create Credentials**" button and select "**OAuth Client ID**".
12. Select "**Web Application**" as the Application Type and provide it a name (this name will **not be visible** to your end users).
13. Now add your **public facing URL** in the "**Authorized JavaScript Origins**" section:
- https://`<your-public-facing-url`>
14. Now add the following URL in the "**Authorized redirect URIs**" section and click on the "**Create**" button:
- https://`<your-public-facing-url`>/api/google-sheet/callback
15. You will now be shown the **Client ID** and **Client Secret**. Copy them and set them as the **environment variables** in your Formbricks instance as:
- `GOOGLE_SHEETS_CLIENT_ID` - Client ID
- `GOOGLE_SHEETS_CLIENT_SECRET` - Client Secret
16. Also use the **same Authorized redirect URI** in the `GOOGLE_SHEETS_REDIRECT_URL` environment variable.
17. One last that we need to do is to **enable the Google Drive API** for the project. For that, go to the "**APIs & Services**" section and click on the "**Enable APIs and Services**" button and search for "**Google Drive API**" and enable it.
### By now, your environment variables should include the below ones as well:
- `GOOGLE_SHEETS_CLIENT_ID`
- `GOOGLE_SHEETS_CLIENT_SECRET`
- `GOOGLE_SHEETS_REDIRECT_URL`
Voila! You have successfully enabled the Google Sheets integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Formbricks Cloud](#formbricks-cloud) section to link a Google Sheet with Formbricks.
Congratulations! You have successfully linked a Google Sheet with Formbricks. Now whenever a response is submitted for the linked survey, it will be automatically added to the linked Google Sheet.
## Remove Integration with Google Account
To remove the integration with Google Account,
1. Visit the Integrations tab in your Formbricks Cloud dashboard.
2. Select "Manage Sheets" button in the Google Sheets card.
3. Click on the "Delete Integration" button.
4. It will now ask for a confirmation to remove the integration. Click on the "Delete" button to remove the integration. You can always come back and connect again with the same Google Account.
2. Select **Manage Sheets** button in the Google Sheets card.
3. Click on the **Delete Integration** button.
4. It will now ask for a confirmation to remove the integration. Click on the **Delete** button to remove the integration. You can always come back and connect again with the same Google Account.
<MdxImage
src={DeleteConnection}
@@ -150,7 +109,63 @@ To remove the integration with Google Account,
className="max-w-full rounded-lg sm:max-w-3xl"
/>
## What data do you need?
## Setup in self-hosted Formbricks
Integrating Google Sheets with a self-hosted Formbricks instance requires configuring Google Cloud and updating your environment variables. This guide provides step-by-step instructions to facilitate this setup using Google Cloud Project & OAuth Setup.
<Note>This process is might be complicated and we recommend using Formbricks Cloud for this feature.</Note>
1. Go to the [Google Cloud Console](https://console.cloud.google.com/) and **create a new project**.
2. Enable necessary APIs:
- Now select the project you just created and go to the **APIs & Services** section.
- Click on the **Enable APIs and Services** button and search for **Google Sheets API** & **Google Drive API** and enable it.
3. Configure OAuth Consent Screen:
- Go to **OAuth Consent screen** and select the appropriate User Type (External or Internal). Select **Internal** if you want only the users of your Google Workspace to be able to use the integration.
- Fill the required details:
- App name: Name displayed during OAuth authentication.
- User support email and Developer contact information: Your contact details for support.
- Click on **Save and Continue**.
4. Add required Scopes:
- Click on the **Add or Remove Scopes** button and add the scopes:
- `https://www.googleapis.com/auth/userinfo.email`
- `https://www.googleapis.com/auth/spreadsheets`
- `https://www.googleapis.com/auth/drive`
- Click on the **Update** button. Verify the scopes and click on the **Save and Continue** button.
- Skip the **Test Users** section and click on the **Save and Continue** button.
5. View the OAuth Consent Screen summary and click on the **Back to Dashboard** button.
6. Register OAuth Client:
- Navigate to **Credentials** > **Create Credentials** > **OAuth Client ID**.
- Select **Web Application** and set:
- Name: Name of the OAuth Client ID.
- Authorized JavaScript Origins: `https://<your-public-facing-url>`
- Authorized redirect URIs: `https://<your-public-facing-url>/api/google-sheet/callback`
- Save and note the Client ID and Client Secret.
7. Copy the Client ID and Client Secret and set them as environment variables in your Formbricks instance:
- `GOOGLE_SHEETS_CLIENT_ID`
- `GOOGLE_SHEETS_CLIENT_SECRET`
- `GOOGLE_SHEETS_REDIRECT_URL`
8. Enable Google Drive API:
- Go to the **APIs & Services** section and click on the **Enable APIs and Services** button.
- Search for **Google Drive API** and enable it.
By now, your **environment variables** should include the below ones as well:
- `GOOGLE_SHEETS_CLIENT_ID`
- `GOOGLE_SHEETS_CLIENT_SECRET`
- `GOOGLE_SHEETS_REDIRECT_URL`
Voila! You have successfully enabled the Google Sheets integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Formbricks Cloud](#formbricks-cloud) section to link a Google Sheet with Formbricks.
## What info do you need?
- Your **Email ID** for authentication (We use this to identify you)
- Your **Google Sheets Names and IDs** (We fetch this to list and show you the options of choosing a sheet to integrate with)
@@ -163,8 +178,7 @@ For the above, we ask for:
1. **Google Spreadsheet API**: To write to the spreadsheet you select (that's it, nothing else, we're opensource, see this method in our codebase [here](https://github.com/formbricks/formbricks/blob/main/packages/lib/googleSheet/service.ts#L70))
<Note>
We do not store any other information of yours! We value Privacy more than you and rest assured you're safe
with us!
We store as little personal information as possible.
</Note>
Still struggling or something not working as expected? [Join our Discord!](https://formbricks.com/discord) and we'd be glad to assist you!

View File

@@ -95,7 +95,7 @@ Click "Create a webhook":
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Enter the Formbricks API key. Learn how to get one from the [API Key tutorial](/docs/api/management/api-key-setup).
Enter the Formbricks API key. Learn how to get one from the [API Key tutorial](/docs/additional-features/api#how-to-generate-an-api-key).
<MdxImage
src={EnterApiKey}

View File

@@ -90,7 +90,7 @@ Click on Create New Credentail button to add your host and API Key
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Now you need an API key. Please refer to the [API Key Setup](/docs/api/management/api-key-setup) page to learn how to create one.
Now you need an API key. Please refer to the [API Key Setup](/docs/additional-features/api#how-to-generate-an-api-key) page to learn how to create one.
Once you copied it in the API Key field, hit Save button to test the connection and save the credentials.

View File

@@ -61,7 +61,7 @@ The notion integration allows you to automatically send responses to a Notion da
database in the Notion account you integrated.
</Note>
5. Now click on the "Link New Database" button to link a new Notion database with Formbricks and a modal will open up.
5. Now click on the "Link New Database" button to link a Notion database with Formbricks and a modal will open up.
<MdxImage
src={LinkSurveyWithDatabase}
@@ -88,7 +88,7 @@ The notion integration allows you to automatically send responses to a Notion da
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Congratulations! You have successfully linked a Notion database with Formbricks. Now whenever a response is submitted for the linked Survey, it will be automatically added to the linked Notion database.
Congratulations! You have successfully linked a Notion database with Formbricks. Now whenever a response is submitted for the linked survey, it will be automatically added to the linked Notion database.
## Setup in self-hosted Formbricks

View File

@@ -69,7 +69,7 @@ The slack integration allows you to automatically send responses to a Slack chan
channel in the Slack workspace you integrated.
</Note>
5. Now click on the "Link channel" button to link a new Slack channel with Formbricks and a modal will open up.
5. Now click on the "Link channel" button to link a Slack channel with Formbricks and a modal will open up.
<MdxImage
src={LinkSurveyWithChannel}
@@ -96,7 +96,7 @@ The slack integration allows you to automatically send responses to a Slack chan
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Congratulations! You have successfully linked a Slack channel with Formbricks. Now whenever a response is submitted for the linked Survey, it will be automatically sent to the linked Slack channel.
Congratulations! You have successfully linked a Slack channel with Formbricks. Now whenever a response is submitted for the linked survey, it will be automatically sent to the linked Slack channel.
## Setup in self-hosted Formbricks

View File

@@ -93,7 +93,7 @@ Now, you have to connect Zapier with Formbricks via an API Key:
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Now you need an API key. Please refer to the [API Key Setup](/docs/api/management/api-key-setup) page to learn how to create one.
Now you need an API key. Please refer to the [API Key Setup](/docs/additional-features/api#how-to-generate-an-api-key) page to learn how to create one.
Once you copied it in the newly opened Zapier window, you will be connected:

View File

@@ -12,15 +12,16 @@ export const metadata = {
# Data Prefilling in Link Surveys
Data prefilling via the URL allows you to increase conversion rate by prefilling data you already have in a different system.
Data prefilling via the URL allows you to increase completion rate by prefilling data you already have in a different system. Formbricks allows you to prefill multiple questions in a survey.
## Purpose
URL prefilling of data comes in handy when you:
Data prefilling via URL comes in handy when you:
- Have data for some of the respondents, but not all
- Have data you want the respondent to confirm or update
- Have data in a different system (e.g. your database) and want to add it to the user profile in Formbricks
- Want to embed the first question in an email and increase conversion by prefilling the choice
- Want to embed a survey in an email and increase completion by prefilling the choice selected in the email
## Quick Example
@@ -28,24 +29,24 @@ URL prefilling of data comes in handy when you:
<CodeGroup title="Example URL">
```sh
https://app.formbricks.com/s/clin3dxja02k8l80hpwmx4bjy?question_id=5
https://app.formbricks.com/s/clin3dxja02k8l80hpwmx4bjy?question_id_1=answer_1&question_id_2=answer_2
```
</CodeGroup>
</Col>
## How it works
To prefill the first question of a survey, append `?question_id=answer` at the end of the survey URL. The answer has to match the expected type of the question. For example, if the first question is a rating question, the answer has to be a number. If the first question is a single select question, the answer has to be a string.
To prefill the questions of a survey, add query parameters to the survey URL. The query parameter should be in the format `questionId=answer`. The answer has to match the expected type of the question to pass through the [validation](/docs/link-surveys/data-prefilling#validation). For example, if the first question is a rating question, the answer has to be a number. If the first question is a single select question, the answer has to be a string identical to one of the answer options.
Please make sure the answer is [URL encoded](https://www.urlencoder.org/).
<Note>Please make sure the answer is [URL encoded](https://www.urlencoder.org/).</Note>
<Note>
## Prefill only the first question Currently, you can only prefill the first question of a link survey.
</Note>
## Prefilling multiple values
Formbricks let's you prefill as many values as you want. You can combine multiple values in the URL using `&` so for example `name=Bernadette&age=18`. The order of the query parameters does not matter so you can always move around questions or add new ones without having to worry about the order of the query parameters.
## Where do I find my question Id?
You find the `questionId` in the Advanced Settings at the bottom of each question card in the Survey Editor. As you see, you can update the `questionId` to any string you like. However, once you published your survey, this `questionId` cannot be updated anymore:
You find the `questionId` in the **Advanced Settings** toggle at the bottom of each question card in the Survey Editor. As you see, you can update the `questionId` to any string you like. However, once you published your survey, this `questionId` cannot be updated anymore:
<MdxImage
src={QuestionId}
@@ -60,8 +61,10 @@ Here are a few examples to get you started:
### Rating Question
Translates to 5 stars / points / emojis:
<Col>
<CodeGroup title="Translates to 5 stars / points / emojis">
<CodeGroup title="Rating Question">
```sh
https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?rating_question_id=5
@@ -69,9 +72,13 @@ https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?rating_question_id=5
</CodeGroup>
</Col>
### NPS Question
Translates to an NPS rating of 10:
<Col>
<CodeGroup title="Translates to an NPS rating of 10">
<CodeGroup title="NPS Questions">
```sh
https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?nps_question_id=10
@@ -79,9 +86,13 @@ https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?nps_question_id=10
</CodeGroup>
</Col>
### Single Select Question (Radio)
Chooses the option 'Very disappointed' in the single select question. The string has to be identical to the option in your question:
<Col>
<CodeGroup title="Chooses the option 'Very disappointed' in the single select question. The string has to be identical to the option in your question">
<CodeGroup title="Single-select Question">
```sh
https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?single_select_question_id=Very%20disappointed
@@ -89,9 +100,13 @@ https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?single_select_question_id
</CodeGroup>
</Col>
### Multi Select Question (Checkbox)
Selects three options 'Sun, Palms and Beach' in the multi select question. The strings have to be identical to the options in your question:
<Col>
<CodeGroup title="Selects three options 'Sun, Palms and Beach' in the multi select question. The strings have to be identical to the options in your question">
<CodeGroup title="Multi-select Question">
```sh
https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?multi_select_question_id=Sun%2CPalms%2CBeach
@@ -99,9 +114,13 @@ https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?multi_select_question_id=
</CodeGroup>
</Col>
### Open Text Question
Adds 'I love Formbricks' as the answer to the open text question:
<Col>
<CodeGroup title="Adds 'I love Formbricks' as the answer to the open text question">
<CodeGroup title="Open Text Question">
```sh
https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?openText_question_id=I%20love%20Formbricks
@@ -109,9 +128,13 @@ https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?openText_question_id=I%20
</CodeGroup>
</Col>
### CTA Question
Adds 'clicked' as the answer to the CTA question. Alternatively, you can set it to 'dismissed' to skip the question:
<Col>
<CodeGroup title="Adds 'clicked' as the answer to the CTA question. Alternatively, you can set it to 'dismissed' to skip the question.">
<CodeGroup title="CTA Question">
```txt
https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?cta_question_id=clicked
@@ -119,15 +142,50 @@ https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?cta_question_id=clicked
</CodeGroup>
</Col>
### Consent Question
Adds 'accepted' as the answer to the Consent question. Alternatively, you can set it to 'dismissed' to skip the question.
<Col>
<CodeGroup title="Consent Question">
```txt
https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?consent_question_id=accepted
```
</CodeGroup>
</Col>
### Picture Selection Question
Adds index of the selected image(s) as the answer to the Picture Selection question. The index starts from 1
<Col>
<CodeGroup title="Picture Selection Question.">
```txt
https://app.formbricks.com/s/clin3yxja52k8l80hpwmx4bjy?pictureSelection_question_id=1%2C2%2C3
```
</CodeGroup>
</Col>
<Note>
All other question types, you currently cannot prefill via the URL.
</Note>
## Validation
Make sure that the answer in the URL matches the expected type for the first question.
Make sure that the answer in the URL matches the expected type for the questions.
The URL validation works as follows:
- For Rating or NPS questions, the response is parsed as a number and verified if it's accepted by the schema.
- For CTA type questions, the valid values are "clicked" (main CTA) and "dismissed" (skip CTA).
- For Consent type questions, the valid values are "accepted" (consent given) and "dismissed" (consent not given).
- For Picture Selection type questions, the response is parsed as an array of numbers and verified if it's accepted by the schema.
- All other question types are strings.
### Youre good to go! 🎉
<Note>
If an answer is invalid, the prefilling will be ignored and the question is presented as if not prefilled.
</Note>

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -0,0 +1,146 @@
import { TellaVideo } from "@/components/docs/TellaVideo";
import { MdxImage } from "@/components/shared/MdxImage";
import EmailContentWithSurvey from "./email-content-with-survey.webp";
import EmailContentWithoutSurvey from "./email-content-without-survey.webp";
import JoSignature from "./jo-signature.webp";
import PluginAddSurvey from "./plugin-add-survey.webp";
import PluginSourceTab from "./plugin-source-tab.webp";
export const metadata = {
title: "Embed Surveys in Your Emails",
description: "Embed Formbricks surveys seamlessly into your emails to collect feedback from your users.",
};
#### Link Surveys
# Embed Surveys in Your Email
Embedding Formbricks surveys directly into your emails allows you to collect valuable feedback from your users at every touchpoint. Seamlessly integrate interactive surveys into your email campaigns to gather insights and improve user experience.
## Generate an Embed Code
To embed a Formbricks survey in an email, first, create a survey and publish it. Follow these steps to generate the embed code:
1. **Create and Publish a Survey**: Start by creating a link survey and publish it once ready.
2. **Access the Share Options**: Go to the survey summary page and click the Share button (see below).
3. **Get the Embed Code**: Click on Embed Survey at the bottom of the share modal, navigate to the `Embed in an Email` tab, and click `Copy Code`.
4. **Preview and Test**: Before sending it to your users, click on Send Preview to receive a test email. This helps ensure the survey appears correctly.
<TellaVideo tellaVideoIdentifier="clvex3puw05oi0gl4bp1qgc3s" />
## Embedding the Survey in Emails
Different email clients have different support for HTML and CSS. We recommend testing the email in different email clients to ensure the survey looks good in all of them.
Below are some of the methods and services that we know that allows HTML embedding and how you can use them:
<Note>
Please use the below methods at your own discretion. We do not officially endorse any of the services
mentioned below.
</Note>
### 1. Gmail
Gmail does not support HTML embedding natively. It's a WYSIWYG (What You See Is What You Get) editor. However, you can use a free plugin like [HTML Editor for Gmail by cloudHQ](https://chromewebstore.google.com/detail/free-html-editor-for-gmai/ioinaaeeacahcmbgfmeaaofhfkijpdeb) to embed HTML in your emails.
- Install the plugin from the Chrome Web Store.
- Open Gmail and compose a new email.
- Write your email content after which you want to embed the survey.
<MdxImage
src={EmailContentWithoutSurvey}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- Right next to the Send button you will see a new button called **HTML Editor**. Click on it.
- This will open a new window with the **Design** tab active. Switch to the **Source** tab.
<MdxImage
src={PluginSourceTab}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- Now paste the copied HTML code from Formbricks into this window. On the right, you will see a preview of how the email will look.
<MdxImage
src={PluginAddSurvey}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- Click on the **Close Editor** button to save the changes & close the editor.
<MdxImage
src={EmailContentWithSurvey}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- Voila! You have successfully embedded the survey in your email.
### 2. Sendgrid
Sendgrid supports HTML content in emails directly:
- Compose Your Email: Use Sendgrid's email composition tools to embed the HTML directly into your email body.
- Reference: For detailed steps, refer to Sendgrid's official documentation [here](https://sendgrid.com/en-us/solutions/email-marketing/email-design) or API docs [here](https://sendgrid.com/docs/for-developers/sending-email/api-getting-started/)
### 3. Mailchimp
Available in their Standard plan and above, Mailchimp allows HTML content embedding:
- Use the Code Block: Drag a code block into your email template and paste the HTML code for the survey.
- Reference: Check out Mailchimp's guide on pasting in custom HTML [here](https://mailchimp.com/help/paste-in-html-to-create-an-email/)
### 4. Notemailer
Nodemailer is a Node.js module that allows you to send emails with HTML content.
- If you use Node.js to send emails, just attach the `html` parameter in your email message.
- Reference: Take a look at Nodemailer's official message documentation [here](https://nodemailer.com/message/)
<Note>
Please note that the above methods are not exhaustive and there are many other ways to embed HTML in emails.
</Note>
## Example: Email Footer Survey
Embed a survey link in your email signature to collect feedback subtly yet effectively. Heres how:
<MdxImage
src={JoSignature}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
1. Create a Survey: Adjust an existing survey or create a new one.
2. Scroll down & enable the **Hidden Fields** option.
3. Add a new hidden field with the name **helpful**.
4. Now Publish the survey as a Link Survey & copy the link.
5. Embed in Your Signature: Add this HTML snippet to your email signature in your email client settings.
<Col>
<CodeGroup title="Embed this in your Email">
```html
Was our conversation helpful? <a href="<Link-Survey-URL>?helpful=Yes">Yes 👍</a> | <a href="<Link-Survey-URL>?helpful=No">No 👎</a>
```
</CodeGroup>
</Col>
Replace `YOUR_SURVEY_LINK` with the actual survey link.
PS: If you do not see any signature settings, just use one of the methods we've mentioned above to embed the HTML code in your email.
---
**Cant figure it out?** [Join our Discord!](https://formbricks.com/discord)

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1,81 @@
import { TellaVideo } from "@/components/docs/TellaVideo";
export const metadata = {
title: "Embed Surveys in Your Web Page",
description: "Embed Formbricks surveys seamlessly into your website or web application using an iframe.",
};
#### Embed Surveys
# Embed Surveys in Your Web Page
Embedding Formbricks surveys directly into your web pages allows you to integrate interactive surveys without redirecting users to a separate survey site. This method ensures a seamless integration and maintains the aesthetic continuity of your website or application.
## How to Use it?
<TellaVideo tellaVideoIdentifier="clvavyy2f00000fjr0mple922"/>
1. Create and publish a link survey.
2. Open survey summary page and click on **share** button on the top right.
3. In the survey share modal, click on **Embed survey** button.
4. Navigate to **Embed in a Web Page** tab and click on Copy code
5. Paste the copied iframe code into the HTML of your web page where you want the survey to appear.
### Example of Embedding a Survey
<Col>
<CodeGroup title="Example Embedding Code">
```html
<div style="position: relative; height:100vh; max-height:100vh; overflow:auto;">
<iframe
src="https://app.formbricks.com/s/<your-surveyId>"
frameborder="0"
style="position: absolute; left:0; top:0; width:100%; height:100%; border:0;">
</iframe>
</div>
```
</CodeGroup>
</Col>
## Iframe Events
The iframe fires a **formbricksSurveyCompleted** event when a user finishes a survey within the embedded iframe. This event can be captured through a message listener in your webpage's JavaScript
### How to Use it?
1. Embed the Formbricks survey on your webpage using the iframe method as described above.
2. Add an event listener to your webpages JavaScript that listens for `message` events from the iframe.
3. Check if the received message indicates that the survey is completed by comparing the `event.data` with the value `formbricksSurveyCompleted`.
<Note>
It is important to verify the origin of the message to ensure it comes from the iframe containing your
survey, enhancing the security of your event handling.
</Note>
4. Implement your custom actions within the callback function based on the survey completion.
### Example of Handling Survey Completion Events
<Col>
<CodeGroup title="Example Code for Event Listener">
```javascript
window.addEventListener("message", (event) => {
// Replace 'https://app.formbricks.com' with the actual web app url
if (event.origin === "https://app.formbricks.com" && event.data === "formbricksSurveyCompleted") {
console.log("Survey completed!");
// Implement your custom actions here
}
});
```
</CodeGroup>
</Col>

View File

@@ -26,8 +26,6 @@ Additional to the AGPL licensed Formbricks core, the Formbricks repository conta
| Multi-language surveys | ❌ | ✅ |
| Advanced targeting / Segments | ❌ | ✅ |
| Make code changes and keep private | ❌ | ✅ |
| Whitelabel Formbricks | ❌ | ✅ |
| Sell Formbricks as SaaS to others | ❌ | ✅ |
**Please note:** Sooner than later we will introduce a enterprise license pricing. For a free beta key, fill out this form:

View File

@@ -147,7 +147,7 @@ These variables can be provided at the runtime i.e. in your docker-compose file.
| S3_ACCESS_KEY | Access key for S3. | optional | (resolved by the AWS SDK) |
| S3_SECRET_KEY | Secret key for S3. | optional | (resolved by the AWS SDK) |
| S3_REGION | Region for S3. | optional | (resolved by the AWS SDK) |
| S3_BUCKET_NAME | Bucket name for S3. | optional (required if S3 is enabled) | |
| S3_BUCKET_NAME | S3 bucket name for data storage. Formbricks enables S3 storage when this is set. | optional (required if S3 is enabled) | |
| S3_ENDPOINT | Endpoint for S3. | optional | (resolved by the AWS SDK) |
| PRIVACY_URL | URL for privacy policy. | optional | |
| TERMS_URL | URL for terms of service. | optional | |

View File

@@ -192,12 +192,14 @@ export const navigation: Array<NavGroup> = [
title: "In-App Surveys",
links: [
{ title: "Quickstart", href: "/docs/getting-started/quickstart-in-app-survey" },
{ title: "Developer Quickstart", href: "/docs/in-app-surveys/developer-quickstart" },
{ title: "Framework Guides", href: "/docs/getting-started/framework-guides" },
{ title: "Troubleshooting", href: "/docs/getting-started/troubleshooting" },
{ title: "Identify Users", href: "/docs/in-app-surveys/user-identification" },
{ title: "Actions", href: "/docs/in-app-surveys/actions" },
{ title: "Attributes", href: "/docs/in-app-surveys/attributes" },
{ title: "Advanced Targeting", href: "/docs/in-app-surveys/advanced-targeting" },
{ title: "Recontact Options", href: "/docs/in-app-surveys/recontact" },
],
},
{
@@ -210,11 +212,17 @@ export const navigation: Array<NavGroup> = [
{ title: "Source Tracking", href: "/docs/link-surveys/source-tracking" },
{ title: "Hidden Fields", href: "/docs/link-surveys/hidden-fields" },
{ title: "Start At Question", href: "/docs/link-surveys/start-at-question" },
{ title: "Embed Surveys in Website", href: "/docs/link-surveys/embed-surveys" },
{ title: "Embed Surveys in Email", href: "/docs/link-surveys/embed-in-email" },
],
},
{
title: "Additional Features",
links: [{ title: "Multi Language Surveys", href: "/docs/additional-features/multi-language-surveys" }],
links: [
{ title: "API", href: "/docs/additional-features/api" },
{ title: "Multi-Language Surveys", href: "/docs/additional-features/multi-language-surveys" },
{ title: "Metadata", href: "/docs/additional-features/metadata" },
],
},
{
title: "Best Practices",
@@ -266,29 +274,6 @@ export const navigation: Array<NavGroup> = [
{ title: "FAQ", href: "/docs/faq" },
],
},
{
title: "Client API",
links: [
{ title: "Overview", href: "/docs/api/client/overview" },
{ title: "Actions", href: "/docs/api/client/actions" },
{ title: "Displays", href: "/docs/api/client/displays" },
{ title: "People", href: "/docs/api/client/people" },
{ title: "Responses", href: "/docs/api/client/responses" },
],
},
{
title: "Management API",
links: [
{ title: "API Key Setup", href: "/docs/api/management/api-key-setup" },
{ title: "Action Classes", href: "/docs/api/management/action-classes" },
{ title: "Attribute Classes", href: "/docs/api/management/attribute-classes" },
{ title: "Me", href: "/docs/api/management/me" },
{ title: "People", href: "/docs/api/management/people" },
{ title: "Responses", href: "/docs/api/management/responses" },
{ title: "Surveys", href: "/docs/api/management/surveys" },
{ title: "Webhooks", href: "/docs/api/management/webhooks" },
],
},
];
export function Navigation(props: React.ComponentPropsWithoutRef<"nav">) {

View File

@@ -0,0 +1,18 @@
import React from "react";
export function TellaVideo({ tellaVideoIdentifier }: { tellaVideoIdentifier: string }) {
return (
<div>
<iframe
className="aspect-video"
style={{
width: "100%",
height: "100%",
border: 0,
}}
src={`https://www.tella.tv/video/${tellaVideoIdentifier}/embed?b=0&title=0&a=1&loop=0&autoPlay=true&t=0&muted=1&wt=0`}
allowFullScreen={true}
title="Tella Video Help"></iframe>
</div>
);
}

View File

@@ -28,7 +28,7 @@ const DemoPreview: React.FC<DemoPreviewProps> = ({ template }) => {
<div className="flex items-center justify-center rounded-xl border-2 border-slate-300 bg-slate-200 py-6 transition-transform duration-150 dark:border-slate-500 dark:bg-slate-700">
<div className="flex flex-col items-center justify-around">
<p className="my-3 text-sm text-slate-500 dark:text-slate-300">Preview</p>
<div className="">
<div>
{selectedTemplate && (
<PreviewSurvey
activeQuestionId={activeQuestionId}

View File

@@ -36,7 +36,7 @@ export const GitHubSponsorship: React.FC = () => {
</p>
</div>
<div className="flex items-center justify-end">
{/* <Image src={PHIcon} alt="Product Hunt Logo" width={80} className="" /> */}
{/* <Image src={PHIcon} alt="Product Hunt Logo" width={80} /> */}
</div>
</div>
</Link>

View File

@@ -1,14 +1,6 @@
import CalLogoLight from "@/images/clients/cal-logo-light.svg";
import CrowdLogoLight from "@/images/clients/crowd-logo-light.svg";
import FlixbusLogo from "@/images/clients/flixbus-white.svg";
import GumtreeLogo from "@/images/clients/gumtree.png";
import NILogoDark from "@/images/clients/niLogoDark.svg";
import OpinodoLogo from "@/images/clients/opinodo.png";
import OptimoleLogo from "@/images/clients/optimole-logo.svg";
import ThemeisleLogo from "@/images/clients/themeisle-logo.webp";
import LogoBar from "@/components/salespage/LogoBar";
import { ShieldCheckIcon, StarIcon } from "lucide-react";
import { usePlausible } from "next-plausible";
import Image from "next/image";
import { useRouter } from "next/router";
import { Button } from "@formbricks/ui/Button";
@@ -42,20 +34,9 @@ export const Hero: React.FC = ({}) => {
know what your customers need.
</span>
</p>
<div className="mx-auto mt-5 max-w-xl items-center px-4 sm:flex sm:justify-center md:mt-6 md:space-x-8 md:px-0 lg:max-w-4xl">
<div className="grid grid-cols-2 items-center gap-8 pt-2 md:grid-cols-3 lg:grid-cols-8">
<Image src={FlixbusLogo} alt="Flixbus Flix Flixtrain Logo" className="rounded-md" width={200} />
<Image src={GumtreeLogo} alt="Gumtree Logo" width={200} />
<Image src={CalLogoLight} alt="Cal Logo" width={170} />
<Image src={ThemeisleLogo} alt="ThemeIsle Logo" width={200} />
<Image src={OpinodoLogo} alt="Opinodo.com Logo" width={200} />
<Image src={CrowdLogoLight} alt="Crowd.dev Logo" width={200} />
<Image src={OptimoleLogo} alt="Optimole Logo" width={200} />
<Image src={NILogoDark} alt="Neverinstall Logo" width={200} />
</div>
</div>
<LogoBar hideTeamsClaim />
<div className="hidden pt-14 md:block">
<div className="hidden pt-7 md:block">
<Button
variant="darkCTA"
className="mr-3 px-6"

View File

@@ -19,7 +19,7 @@ export const SurveyTypeSelection: React.FC = () => {
subheading="Follow individual feedback trails or zoom out for the big picture. All in one place."
/>
<div className="flex space-x-8 text-center">
<div className="space-y-6 text-center md:flex md:space-x-8 md:space-y-0">
<OptionCard
size="lg"
title="On your website"
@@ -32,7 +32,7 @@ export const SurveyTypeSelection: React.FC = () => {
<OptionCard
size="lg"
title="In emails"
description="Create on brand surveys, embedded in your emails."
description="Embed branded surveys in your emails."
onSelect={() => {
router.push("/open-source-form-builder");
}}>

View File

@@ -2,48 +2,61 @@ import CalLogoLight from "@/images/clients/cal-logo-light.svg";
import CrowdLogoLight from "@/images/clients/crowd-logo-light.svg";
import FlixbusLogo from "@/images/clients/flixbus-white.svg";
import GumtreeLogo from "@/images/clients/gumtree.png";
import LelyLogo from "@/images/clients/lely-logo.webp";
import NILogoDark from "@/images/clients/niLogoDark.svg";
import OpinodoLogo from "@/images/clients/opinodo.png";
import OptimoleLogo from "@/images/clients/optimole-logo.svg";
import ThemeisleLogo from "@/images/clients/themeisle-logo.webp";
import Image from "next/image";
export default function LogoBar() {
interface LogoBarProps {
hideTeamsClaim?: boolean;
}
export default function LogoBar({ hideTeamsClaim = false }: LogoBarProps) {
return (
<div className="mx-auto max-w-5xl">
<p className="text-center text-lg text-slate-700">
10,000+ teams at the worlds best companies trust Formbricks
</p>
<div className="mt-5 items-center px-4 sm:flex sm:justify-center md:mt-6 md:space-x-8 md:px-0">
<div className="grid grid-cols-2 items-center gap-8 pt-2 md:grid-cols-2 md:gap-10 lg:grid-cols-8">
<Image
src={FlixbusLogo}
alt="Flixbus Flix Flixtrain Logo"
className="rounded-lg pb-1 "
width={200}
/>
<Image
src={GumtreeLogo}
alt="Flixbus Flix Flixtrain Logo"
className="rounded-lg pb-1 "
width={200}
/>
<Image src={CalLogoLight} alt="Cal Logo" className="block dark:hidden" width={170} />
<Image src={ThemeisleLogo} alt="ThemeIsle Logo" className="pb-1" width={200} />
<Image
src={OpinodoLogo}
alt="Crowd.dev Logo"
className="block rounded-lg pb-1 dark:hidden"
width={200}
/>
<Image
src={CrowdLogoLight}
alt="Crowd.dev Logo"
className="block rounded-lg pb-1 dark:hidden"
width={200}
/>
<Image src={OptimoleLogo} alt="Optimole Logo" className="pb-1" width={200} />
<Image src={NILogoDark} alt="Neverinstall Logo" className="block pb-1 dark:hidden" width={200} />
{!hideTeamsClaim && (
<p className="text-center text-lg text-slate-700">
10,000+ teams at the worlds best companies trust Formbricks
</p>
)}
<div className="mt-5 flex justify-center">
<div className="w-full overflow-hidden">
<div className="animate-scroll flex items-center space-x-20">
{/* List of logos, each wrapped in a div with specific width and flex properties */}
{[
ThemeisleLogo,
CalLogoLight,
FlixbusLogo,
GumtreeLogo,
LelyLogo,
OpinodoLogo,
CrowdLogoLight,
OptimoleLogo,
NILogoDark,
].map((src, index) => (
<div key={index} className="flex-none" style={{ width: 150 }}>
<Image src={src} alt="Formbricks Client Logo" width={150} height={75} layout="responsive" />
</div>
))}
{/* Repeat the logos for a seamless loop */}
{[
ThemeisleLogo,
CalLogoLight,
FlixbusLogo,
GumtreeLogo,
LelyLogo,
OpinodoLogo,
CrowdLogoLight,
OptimoleLogo,
NILogoDark,
].map((src, index) => (
<div key={index + 9} className="flex-none" style={{ width: 150 }}>
<Image src={src} alt="Formbricks Client Logo" width={150} height={75} layout="responsive" />
</div>
))}
</div>
</div>
</div>
</div>

View File

@@ -1,7 +1,11 @@
import CCPALogo from "@/images/ccpa.svg";
import GPDRLogo from "@/images/gdpr.svg";
import Image from "next/image";
import Link from "next/link";
import { FaDiscord, FaGithub, FaXTwitter } from "react-icons/fa6";
import { FooterLogo } from "./Logo";
import SourceForgeBadge from "./SourceForgeBadge";
const navigation = {
products: [
@@ -89,6 +93,11 @@ export default function Footer() {
</Link>
))}
</div>
<div className="flex space-x-4">
<SourceForgeBadge />
<Image src={GPDRLogo} alt="GDPR Logo" width={50} />
<Image src={CCPALogo} alt="CCPA Logo" width={50} />
</div>
</div>
<div className="grid grid-cols-2 gap-8 lg:col-span-2 lg:grid-cols-4">
<div>

View File

@@ -7,7 +7,7 @@ export default function HeadingCentered() {
const router = useRouter();
return (
<div className="mx-auto grid grid-cols-1 content-center gap-10 pb-12 pt-24 md:grid-cols-2">
<div className="">
<div>
<p className="text-md text-brand-dark dark:text-brand-light font-semibold uppercase">
What are you waiting for?
</p>

View File

@@ -0,0 +1,34 @@
import React, { useEffect } from "react";
const SourceForgeBadge: React.FC = () => {
useEffect(() => {
const script = document.createElement("script");
script.async = true;
script.src = "https://b.sf-syn.com/badge_js?sf_id=3747607&variant_id=sf";
const firstScript = document.getElementsByTagName("script")[0];
firstScript.parentNode?.insertBefore(script, firstScript);
return () => {
// Clean up the script when the component unmounts
firstScript.parentNode?.removeChild(script);
};
}, []);
return (
<div
data-id="3747607"
data-badge="heart-badge-white"
data-variant-id="sf"
style={{ width: "75px" }}
className="p-0.5">
<a
href="https://sourceforge.net/software/product/Formbricks/"
target="_blank"
rel="noopener noreferrer">
Formbricks Reviews
</a>
</div>
);
};
export default SourceForgeBadge;

View File

@@ -7,7 +7,7 @@ export default function HeadingCentered() {
const router = useRouter();
return (
<div className="mx-auto grid max-w-md grid-cols-1 content-center gap-10 px-4 py-12 sm:max-w-3xl sm:px-6 md:grid-cols-2 md:pb-36 md:pt-24 lg:max-w-6xl lg:px-8">
<div className="">
<div>
<p className="text-md text-brand-dark dark:text-brand-light mb-3 font-semibold uppercase">
What are you waiting for?
</p>

View File

@@ -0,0 +1,11 @@
<svg width="32" height="50" viewBox="0 0 32 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.59947 48.1181C9.09296 48.1181 9.38736 47.8022 9.47458 47.4725L9.17472 47.3736C9.10928 47.5934 8.92393 47.8022 8.59947 47.8022C8.26962 47.8022 7.95884 47.5605 7.95884 47.1044C7.95884 46.6318 8.27784 46.3983 8.59677 46.3983C8.92117 46.3983 9.10112 46.5879 9.15834 46.8241L9.46642 46.7198C9.37921 46.3791 9.0875 46.0879 8.59677 46.0879C8.09519 46.0879 7.62354 46.4698 7.62354 47.1044C7.62354 47.739 8.07881 48.1181 8.59947 48.1181ZM10.0062 47.1016C10.0062 46.6319 10.3279 46.3983 10.6523 46.3983C10.9795 46.3983 11.3012 46.6319 11.3012 47.1016C11.3012 47.5715 10.9795 47.805 10.6523 47.805C10.3279 47.805 10.0062 47.5715 10.0062 47.1016ZM9.67091 47.1016C9.67091 47.7418 10.1453 48.1181 10.6523 48.1181C11.1593 48.1181 11.6365 47.7418 11.6365 47.1016C11.6365 46.4643 11.1593 46.0879 10.6523 46.0879C10.1453 46.0879 9.67091 46.4643 9.67091 47.1016ZM14.1244 48.0769V46.1291H13.68L13.0612 47.6154L12.4341 46.1291H11.9979V48.0769H12.3169V46.6483L12.914 48.0769H13.1974L13.7999 46.6428V48.0769H14.1244ZM14.9367 47.0247V46.4203H15.2775C15.4847 46.4203 15.6101 46.5385 15.6101 46.7253C15.6101 46.9093 15.4847 47.0247 15.2775 47.0247H14.9367ZM15.3266 47.316C15.6973 47.316 15.9427 47.066 15.9427 46.7225C15.9427 46.3819 15.6973 46.1291 15.3266 46.1291H14.6096V48.0769H14.9367V47.316H15.3266ZM17.4735 48.0769V47.7637H16.5874V46.1291H16.2603V48.0769H17.4735ZM18.0944 48.0769V46.1291H17.7619V48.0769H18.0944ZM19.8987 48.0769H20.2558L19.5033 46.1291H19.1244L18.372 48.0769H18.7182L18.8981 47.5879H19.716L19.8987 48.0769ZM19.307 46.4863L19.6015 47.283H19.0126L19.307 46.4863ZM22.1554 48.0769V46.1291H21.8282V47.511L20.9504 46.1291H20.5333V48.0769H20.8604V46.6016L21.8146 48.0769H22.1554ZM24.0293 46.4396V46.1291H22.4454V46.4396H23.0724V48.0769H23.3996V46.4396H24.0293Z" fill="#64748b"/>
<path d="M7.4822 43.2638C9.40139 43.2638 10.2215 41.9451 10.4221 41.0836L9.10479 40.7055C8.98269 41.1539 8.55521 41.8748 7.4822 41.8748C6.55747 41.8748 5.70255 41.1978 5.70255 40.0287C5.70255 38.7187 6.63596 38.121 7.46476 38.121C8.55521 38.121 8.9478 38.8506 9.04374 39.2814L10.3436 38.8682C10.1429 37.9715 9.32289 36.7671 7.46476 36.7671C5.73744 36.7671 4.27185 38.0858 4.27185 40.0287C4.27185 41.9715 5.70254 43.2638 7.4822 43.2638ZM13.8911 43.2638C15.8104 43.2638 16.6304 41.9451 16.831 41.0836L15.5138 40.7055C15.3916 41.1539 14.9641 41.8748 13.8911 41.8748C12.9664 41.8748 12.1115 41.1978 12.1115 40.0287C12.1115 38.7187 13.0449 38.121 13.8737 38.121C14.9641 38.121 15.3567 38.8506 15.4527 39.2814L16.7525 38.8682C16.5519 37.9715 15.7319 36.7671 13.8737 36.7671C12.1464 36.7671 10.6808 38.0858 10.6808 40.0287C10.6808 41.9715 12.1115 43.2638 13.8911 43.2638ZM18.8345 39.6946V38.1033H19.6371C20.1605 38.1033 20.5182 38.4023 20.5182 38.9033C20.5182 39.3868 20.1605 39.6946 19.6371 39.6946H18.8345ZM19.7767 40.8902C21.0329 40.8902 21.8965 40.0726 21.8965 38.8945C21.8965 37.7341 21.0329 36.899 19.7767 36.899H17.4474V43.1319H18.8258V40.8902H19.7767ZM26.1414 43.1319H27.6419L25.3388 36.899H23.7424L21.4132 43.1319H22.8613L23.3062 41.866H25.6965L26.1414 43.1319ZM24.5188 38.4462L25.2603 40.6H23.7599L24.5188 38.4462Z" fill="#64748b"/>
<path d="M14.393 7.2895V0.507324H6.22569V2.47134L5.29443 5.16282L6.22569 6.10842V8.80019L8.08849 10.6914V11.5645L9.73642 14.2559V15.4197L12.4588 18.9114V21.8213H15.3962L19.838 24.3672V26.3315L26.2859 25.3131V20.8757L21.7725 16.0466H12.3824V7.2895H14.393Z" fill="#64748b"/>
<path d="M15.1082 23.3091V22.4849H12.3821V23.3091H15.1082Z" fill="#64748b"/>
<path d="M15.3815 25.5071V24.4082H16.1993V25.5071H15.3815Z" fill="#64748b"/>
<path d="M16.1989 24.4082V23.584H17.0167V24.4082H16.1989Z" fill="#64748b"/>
<path d="M13.7455 9.20666C13.7455 8.90341 13.9895 8.65723 14.2907 8.65723H21.3787C21.68 8.65723 21.924 8.90341 21.924 9.20666V14.1284C21.924 14.432 21.68 14.6779 21.3787 14.6779H14.2907C13.9895 14.6779 13.7455 14.432 13.7455 14.1284V9.20666Z" fill="#64748b"/>
<path d="M17.0931 12.9479L16.017 11.9471C15.896 11.8345 15.896 11.6528 16.017 11.5402C16.1373 11.4284 16.3327 11.4278 16.4538 11.5386C16.4541 11.5391 16.4546 11.5394 16.4551 11.5399L17.3501 12.3699L19.4863 10.3833C19.6063 10.2718 19.8015 10.2713 19.9223 10.382C19.9231 10.3825 19.9239 10.3833 19.9247 10.3842C20.046 10.4977 20.0458 10.68 19.9239 10.7932L17.6072 12.9479C17.4663 13.079 17.237 13.0795 17.0953 12.9495C17.0944 12.949 17.0939 12.9485 17.0931 12.9479Z" fill="#131212"/>
<path d="M19.7595 8.79228V7.27003C19.7595 6.26615 18.9517 5.45215 17.9553 5.45215C16.9589 5.45215 16.1511 6.26615 16.1511 7.27003V8.79228" stroke="#64748b" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,19 @@
<svg width="34" height="50" viewBox="0 0 34 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.1891 49.1803H12.5685L11.7691 47.2431H11.3665L10.567 49.1803H10.9349L11.126 48.694H11.995L12.1891 49.1803ZM11.5606 47.5983L11.8734 48.3907H11.2477L11.5606 47.5983ZM14.1523 49.1803V48.8688H13.2109V47.2431H12.8633V49.1803H14.1523ZM14.8121 49.1803V47.2431H14.4588V49.1803H14.8121ZM17.1461 49.1803V48.1995H16.141V48.4863H16.8188C16.8014 48.653 16.645 48.9208 16.2308 48.9208C15.8774 48.9208 15.553 48.683 15.553 48.2104C15.553 47.7295 15.9006 47.5055 16.2336 47.5055C16.561 47.5055 16.7638 47.6913 16.8332 47.9098L17.1606 47.7923C17.0505 47.4726 16.7319 47.2021 16.2336 47.2021C15.7007 47.2021 15.1997 47.5738 15.1997 48.2104C15.1997 48.8497 15.6746 49.2213 16.2105 49.2213C16.5378 49.2213 16.7492 49.0765 16.839 48.9344L16.8651 49.1803H17.1461ZM19.3023 49.1803V47.2431H18.9547V48.6175L18.022 47.2431H17.5788V49.1803H17.9264V47.7131L18.9402 49.1803H19.3023ZM21.0877 49.1803V48.8743H20.1666V48.3606H21.0008V48.0628H20.1666V47.5491H21.0877V47.2431H19.819V49.1803H21.0877ZM21.8469 48.8798V47.5437H22.2148C22.571 47.5437 22.8636 47.7623 22.8636 48.2158C22.8636 48.6639 22.5681 48.8798 22.2118 48.8798H21.8469ZM22.2234 49.1803C22.7796 49.1803 23.2256 48.8361 23.2256 48.2158C23.2256 47.5929 22.7854 47.2431 22.2263 47.2431H21.4993V49.1803H22.2234Z" fill="#64748b"/>
<path d="M11.1576 44.2621V40.9485H7.81151V42.1201H9.78584C9.70237 42.4698 9.24824 43.1343 8.16377 43.1343C7.09784 43.1343 6.18945 42.4611 6.18945 41.1671C6.18945 39.7856 7.23684 39.2261 8.12664 39.2261C9.22037 39.2261 9.65604 39.9256 9.75804 40.3103L11.1669 39.8469C10.8796 38.9813 10.0082 37.9321 8.12664 37.9321C6.27287 37.9321 4.70642 39.2173 4.70642 41.1671C4.70642 43.1256 6.20799 44.3933 8.03397 44.3933C8.97017 44.3933 9.59117 44.0261 9.87851 43.6326L9.97117 44.2621H11.1576ZM13.5866 42.9594V39.366H14.4394C15.4497 39.366 16.2746 39.9256 16.2746 41.1671C16.2746 42.4086 15.4497 42.9594 14.4394 42.9594H13.5866ZM14.495 44.2621C16.4786 44.2621 17.804 43.0818 17.804 41.1671C17.804 39.2523 16.4786 38.0633 14.5043 38.0633H12.1222V44.2621H14.495ZM20.1248 40.8436V39.2611H20.9775C21.5336 39.2611 21.9137 39.5583 21.9137 40.0567C21.9137 40.5376 21.5336 40.8436 20.9775 40.8436H20.1248ZM21.1258 42.0326C22.4606 42.0326 23.3782 41.2195 23.3782 40.0479C23.3782 38.8938 22.4606 38.0633 21.1258 38.0633H18.651V44.2621H20.1155V42.0326H21.1258ZM27.2181 44.2621H28.8309L27.4962 41.7529C28.3026 41.4818 28.7938 40.8436 28.7938 40.0043C28.7938 38.9026 27.9596 38.0633 26.662 38.0633H24.0574V44.2621H25.5219V41.9539H26.041L27.2181 44.2621ZM25.5219 40.7649V39.2611H26.3839C26.9864 39.2611 27.3108 39.5496 27.3108 40.0129C27.3108 40.4501 26.9864 40.7649 26.3839 40.7649H25.5219Z" fill="#64748b"/>
<path d="M16.8006 1.87061L17.3072 3.38312H18.9472L17.6206 4.31787L18.1272 5.83039L16.8006 4.89506L15.4739 5.83039L15.9808 4.31787L14.6536 3.38312H16.2936L16.8006 1.87061Z" fill="#64748b"/>
<path d="M16.8006 26.7607L17.3072 28.2736H18.9472L17.6206 29.2083L18.1272 30.7206L16.8006 29.7859L15.4739 30.7206L15.9808 29.2083L14.6536 28.2736H16.2936L16.8006 26.7607Z" fill="#64748b"/>
<path d="M23.5467 4.13281L24.053 5.6453H25.6933L24.3664 6.58044L24.8733 8.09257L23.5467 7.15744L22.2195 8.09257L22.7264 6.58044L21.3998 5.6453H23.0401L23.5467 4.13281Z" fill="#64748b"/>
<path d="M29.0669 8.42285L29.5731 9.93523H31.2135L29.8866 10.8702L30.3935 12.3827L29.0669 11.448L27.7399 12.3827L28.2468 10.8702L26.9199 9.93523H28.5597L29.0669 8.42285Z" fill="#64748b"/>
<path d="M29.0669 20.5381L29.5735 22.0512H31.2135L29.8866 22.9859L30.3937 24.498L29.0669 23.5635L27.7399 24.498L28.2468 22.9859L26.9199 22.0512H28.5599L29.0669 20.5381Z" fill="#64748b"/>
<path d="M4.53114 8.42285L5.03772 9.93523H6.67777L5.35101 10.8702L5.85758 12.3827L4.53114 11.448L3.20412 12.3827L3.71092 10.8702L2.38416 9.93523H4.02459L4.53114 8.42285Z" fill="#64748b"/>
<path d="M30.294 14.3154L30.8006 15.8279H32.4406L31.1138 16.7626L31.6206 18.2751L30.294 17.341L28.9671 18.2751L29.4743 16.7626L28.1471 15.8279H29.7868L30.294 14.3154Z" fill="#64748b"/>
<path d="M3.30594 14.3154L3.81249 15.8279H5.45246L4.12549 16.7626L4.63265 18.2751L3.30594 17.341L1.97889 18.2751L2.48578 16.7626L1.15881 15.8279H2.79905L3.30594 14.3154Z" fill="#64748b"/>
<path d="M4.53128 20.5381L5.0378 22.0512H6.67777L5.35118 22.9859L5.85764 24.498L4.53128 23.5635L3.20432 24.498L3.71112 22.9859L2.38416 22.0512H4.02448L4.53128 20.5381Z" fill="#64748b"/>
<path d="M24.7739 25.6294L25.2805 27.1417H26.9206L25.5934 28.077L26.1006 29.5893L24.7739 28.6546L23.4467 29.5893L23.9539 28.077L22.627 27.1417H24.2673L24.7739 25.6294Z" fill="#64748b"/>
<path d="M10.0512 4.13281L10.5576 5.6453H12.198L10.871 6.58044L11.3782 8.09257L10.0512 7.15744L8.7245 8.09257L9.2313 6.58044L7.9043 5.6453H9.5443L10.0512 4.13281Z" fill="#64748b"/>
<path d="M8.82574 25.6294L9.33248 27.1425H10.9727L9.64581 28.0767L10.1526 29.5893L8.82574 28.6551L7.49914 29.5893L8.00588 28.0767L6.67908 27.1425H8.31888L8.82574 25.6294Z" fill="#64748b"/>
<path d="M12.4551 15.3887C12.4551 15.0869 12.7145 14.8423 13.0344 14.8423H20.5654C20.8855 14.8423 21.1447 15.0869 21.1447 15.3887V20.2604C21.1447 20.5623 20.8855 20.8068 20.5654 20.8068H13.0344C12.7145 20.8068 12.4551 20.5623 12.4551 20.2604V15.3887Z" fill="#64748b"/>
<path d="M16.0118 19.1917L14.8686 18.2004C14.7399 18.0887 14.7399 17.9087 14.8686 17.7972C14.9962 17.6865 15.2039 17.6857 15.3325 17.7956C15.333 17.7961 15.3334 17.7964 15.334 17.7969L16.285 18.6193L18.5547 16.6513C18.6822 16.5406 18.8896 16.5401 19.0179 16.6496C19.0188 16.6504 19.0196 16.651 19.0205 16.6518C19.1494 16.7644 19.1491 16.9453 19.0196 17.0573L16.5581 19.1917C16.4084 19.3215 16.1648 19.3223 16.0142 19.1934C16.0133 19.1928 16.0127 19.1923 16.0118 19.1917Z" fill="#64748b"/>
<path d="M18.8449 14.9775V13.4766C18.8449 12.478 17.9867 11.6685 16.928 11.6685C15.8693 11.6685 15.0111 12.478 15.0111 13.4766V14.9775" stroke="#64748b" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -2,7 +2,7 @@ import { slugifyWithCounter } from '@sindresorhus/slugify'
import * as acorn from 'acorn'
import { toString } from 'mdast-util-to-string'
import { mdxAnnotations } from 'mdx-annotations'
import shiki from 'shiki'
import { getHighlighter, renderToHtml } from 'shiki'
import { visit } from 'unist-util-visit'
function rehypeParseCodeBlocks() {
@@ -23,7 +23,7 @@ let highlighter
function rehypeShiki() {
return async (tree) => {
highlighter =
highlighter ?? (await shiki.getHighlighter({ theme: 'css-variables' }))
highlighter ?? (await getHighlighter({ theme: 'css-variables' }))
visit(tree, 'element', (node) => {
if (node.tagName === 'pre' && node.children[0]?.tagName === 'code') {
@@ -38,7 +38,7 @@ function rehypeShiki() {
node.properties.language,
)
textNode.value = shiki.renderToHtml(tokens, {
textNode.value = renderToHtml(tokens, {
elements: {
pre: ({ children }) => children,
code: ({ children }) => children,

View File

@@ -125,11 +125,6 @@ const nextConfig = {
destination: "/docs/actions/code",
permanent: true,
},
{
source: "/docs/quickstart",
destination: "/docs/quickstart-in-app-survey",
permanent: true,
},
{
source: "/pmf",
destination: "/",
@@ -210,20 +205,13 @@ const nextConfig = {
destination: "/blog",
permanent: true,
},
{
source: '/docs/api/:slug*',
destination: '/docs/additional-features/api',
permanent: false,
}
];
},
async rewrites() {
return {
fallback: [
// These rewrites are checked after both pages/public files
// and dynamic routes are checked
{
source: "/:path*",
destination: `https://app.formbricks.com/s/:path*`,
},
],
};
},
};
export default withPlausibleProxy({ customDomain: "https://plausible.formbricks.com" })(

View File

@@ -13,30 +13,30 @@
"browserslist": "defaults, not ie <= 11",
"dependencies": {
"@algolia/autocomplete-core": "^1.17.0",
"@calcom/embed-react": "^1.3.2",
"@calcom/embed-react": "^1.4.0",
"@docsearch/css": "3",
"@docsearch/react": "^3.6.0",
"@formbricks/lib": "workspace:*",
"@formbricks/types": "workspace:*",
"@formbricks/ui": "workspace:*",
"@headlessui/react": "^1.7.18",
"@headlessui/react": "^1.7.19",
"@headlessui/tailwindcss": "^0.2.0",
"@mapbox/rehype-prism": "^0.9.0",
"@mdx-js/loader": "^3.0.1",
"@mdx-js/react": "^3.0.1",
"@next/mdx": "14.1.3",
"@next/mdx": "14.2.1",
"@paralleldrive/cuid2": "^2.2.2",
"@sindresorhus/slugify": "^2.2.1",
"@tailwindcss/typography": "^0.5.10",
"@tailwindcss/typography": "^0.5.12",
"acorn": "^8.11.3",
"autoprefixer": "^10.4.18",
"autoprefixer": "^10.4.19",
"clsx": "^2.1.0",
"fast-glob": "^3.3.2",
"flexsearch": "^0.7.43",
"framer-motion": "11.0.13",
"framer-motion": "11.1.1",
"lottie-web": "^5.12.2",
"lucide": "^0.350.0",
"lucide-react": "^0.356.0",
"lucide": "^0.368.0",
"lucide-react": "^0.368.0",
"mdast-util-to-string": "^4.0.0",
"mdx-annotations": "^0.1.4",
"next": "14.1.3",
@@ -50,17 +50,17 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-highlight-words": "^0.20.0",
"react-icons": "^5.0.1",
"react-icons": "^5.1.0",
"react-markdown": "^9.0.1",
"react-responsive-embed": "^2.1.0",
"remark": "^15.0.1",
"remark-gfm": "^4.0.0",
"remark-mdx": "^3.0.0",
"remark-mdx": "^3.0.1",
"schema-dts": "^1.1.2",
"sharp": "^0.33.1",
"sharp": "^0.33.3",
"shiki": "^0.14.7",
"simple-functional-loader": "^1.2.1",
"tailwindcss": "^3.4.1",
"tailwindcss": "^3.4.3",
"unist-util-filter": "^5.0.1",
"unist-util-visit": "^5.0.0",
"zustand": "^4.5.2"

View File

@@ -1,252 +0,0 @@
import AuthorBox from "@/components/shared/AuthorBox";
import LayoutMdx from "@/components/shared/LayoutMdx";
import Image from "next/image";
import Formbricks from "./formbricks-best-open-source-hotjar-alternative.webp";
import FullStory from "./fullstory-comprehensive-analytics-tool.webp";
import Smartlook from "./g2-crowd-award-winner-Smartlook.webp";
import Header from "./header-best-hotjar-alternatives-2024-incl-open-source-solutions.webp";
import LuckyOrange from "./lucky-orange-best-analytics-tool-2024.webp";
import MouseFlow from "./mouseflow-best-hotjar-alternatives-2024.webp";
export const meta = {
title: "Best HotJar Alternatives 2024 incl. Open Source",
description:
"Looking for HotJar alternatives? We curated a list of the best HotJar alternatives going into 2024 for you.",
date: "2023-12-29",
publishedTime: "2023-12-29T12:00:00",
authors: ["Johannes Dancker"],
section: "Feedback Apps",
tags: ["Feedback Apps", "Formbricks", "Smartlook", "Lucky Orange", "Fullstory", "Mouseflow"],
ogImage: "/blog/hotjar.jpg"
};
<Image src={Header} alt="Get the best HotJar features with these 5 tools." className="w-full rounded-lg" />
<AuthorBox
name="Johannes"
title="Co-Founder and CEO"
date="December 29th, 2023"
duration="10"
author={"Johannes"}
/>
HotJar is a popular product experience insights platform that provides you with valuable data and insights into how users interact with your websites. It offers features such as heatmaps and recordings, surveys, and funnels to help you get these insights.
But while its a staple in user behavior analytics, this article introduces a wide range of alternatives just waiting to be discovered. These options are just for you, whether you're a budget-conscious blogger or an enterprise giant.
As we discuss these options, the next section will guide you through the essential criteria to consider when comparing them to HotJar. These criteria will empower you to pinpoint the perfect fit for your specific requirements.
## How we compare HotJar alternatives 👇
We'll categorize the criteria into three main factors to improve your choice.
1. **Feature depth**
- **Surveys & Forms**: Can you gather users voices through polls and surveys to understand your audience better?
- **Heatmaps & Recordings**: Do you want basic click maps or detailed session replays with visitor insights?
- **Integrations**: Does it work well with your existing third-party analytics tools?
2. **Pricing**:
- **Freemium Plans**
- **Premium Plans**
3. **Privacy**: Is it fully GDPR, CCPA, or HIPAA-compliant?
4. **Extensibility**: How extensible and customizable are each of the tools?
Now, we will explore these options based on the factors mentioned above.
## 5 Free HotJar Alternatives in 2024
Let's have a look at the best HotJar alternatives in 2024, including open source options - all of which start free!
### Formbricks - The Open Source HotJar Ask Alternative
<Image
src={Formbricks}
alt="Formbricks is a free and open source survey software for in-app micro surveys. Ask any user segment at any point in the user journey."
className="w-full rounded-lg"
/>
[Formbricks](https://formbricks.com/) is an open source micro-survey solution designed to gather specific user feedback at the perfect moment in the journey. It allows you to create and deploy **targeted surveys within your app or on public websites** without disrupting the user experience.
It's super good at one thing: making your forms and survey experiences awesome. It shows you why people abandon your forms, which questions cause churn, and how to fix them to get more people to finish. No heatmaps or fancy recordings, just laser focus on surveys.
Formbricks compares to HotJar based on the aforementioned factors:
**Feature depth**:
- **Surveys & Forms**: Formbricks specializes in in-product micro-surveys for SaaS and digital products. With Formbricks, you're better equipped to understand user behavior, improve your product, and make data-driven decisions. You can seamlessly integrate surveys into web, mobile, and desktop applications. If forms and surveys are your primary concern, this is the best tool for you.
- **Heatmaps & Recordings**: Formbricks focuses on forms and surveys. No fancy website heatmaps here for now, but you get detailed insights into individual form fields and how users interact with them. If youre looking for open source heatmaps, [OpenReplay](https://openreplay.com/) might be worth checking out.
- **Integrations:** HotJar plays well with lots of other tools, while Formbricks is still young in this aspect. But it works with the most popular ones, like Zapier, Make.com, Airtable, Notion, Slack, etc. The Formbricks team and [open source community](/community) are working on adding more all the time.
**Pricing**: Both tools have free plans, but HotJar's paid plans can get expensive. Formbricks is generally cheaper, especially if you only care about targeted surveys. Formbricks has a very generous free plan to get started easily. Paid plans begin at $30 per month for link surveys and $0.15 per submission for web and in-app surveys, **after your survey submission exceeds 250 submissions.** If you self-host Formbricks, [its completely free.](/pricing)
**Privacy:** Formbricks Cloud is hosted in Germany and has full GDPR as well as CCPA compliance. Since Formbricks is easily self-hostable, keeping full control over your data is smooth.
**Extensibility:** Unlike HotJar, Formbricks is an open source solution. It provides APIs that allow you to build anything on top, below, and around it as per your customization needs - your imagination is the limit.
Lets see how Formbricks compares side-by-side with HotJar.
| Factors | Formbricks | HotJar |
| ---------------------- | ---------- | ------ |
| Surveys & Forms | 🟢 | 🟢 |
| Heatmaps & Recordings | 🔴 | 🟢 |
| Integrations | 🟡🟢 | 🟢 |
| Pricing | 🟢 | 🟡🟢 |
| Privacy and compliance | 🟢 | 🟡 |
| Extensibility | 🟢 | 🟡 |
### Smartlook - G2 Crowd Award Winner
<Image
src={Smartlook}
alt="Smartlook is a comprehensive product analytics and visual user insights tool designed to help businesses gain deep insights into user behavior on their websites or mobile applications."
className="w-full rounded-lg"
/>
Smartlook, which was recently acquired by Cisco, is a comprehensive product analytics and visual user insights tool designed to help businesses gain deep insights into user behavior on their websites or mobile applications. It offers a range of features that enable organizations to understand, analyze, and optimize the user experience.
Smartlook has also received numerous awards and recognition, including the G2 Crowd Awards for **Top 100 Software Products** and **Best Products for Marketers**, as well as being named on Deloittes Technology Fast 50 in Central Europe.
Below is an overview of how Smartlook compares with HotJar.
**Features**:
- **Surveys**: Both platforms include survey features, but Smartlook does not offer standalone surveys, unlike HotJar. Instead, you can create surveys through its integration with Survicate (for a deeper look into Survicate, go [here](https://formbricks.com/blog/best-feedback-app-and-how-to-use-them)).
- **Heatmaps & Recordings**: They both offer heatmap and recording features. Although Smartlook provides a more comprehensive insight into recordings by combining them with funnel analysis, this will help you pinpoint the exact recordings you need.
- **Integrations:** Both platforms work well with many external tools. However, if you're a big enterprise seeking a broader selection of tools, HotJar is the better choice.
**Pricing**: Compared to HotJar, Smartlook is relatively more expensive. Its pro plan provides only 30 heatmaps a month and three months of storage. HotJars equivalent business plan offers unlimited heatmaps with 12 months of data storage.
**Privacy and Compliance:** Smartlook stores all data on EU servers. If you collect personal data with Smartlook, GDPR applies. Smartlook is also fully CCPA-compliant.
**Extensibility:** Smartlook, like HotJar, offers practical methods for programmatically accessing information on different resources. The API empowers you to analyze visitor data more comprehensively and delve deeper into the values captured by Smartlook. However, it may not offer the precise level of control and flexibility needed for intricate integrations or custom workflows.
| Factors | Smartlook | HotJar |
| ---------------------- | --------- | ------ |
| Surveys & Forms | 🟡🟢 | 🟢 |
| Heatmaps & Recordings | 🟢 | 🟢 |
| Integrations | 🟢 | 🟢 |
| Pricing | 🔴 | 🟢 |
| Privacy and compliance | 🟢 | 🟢 |
| Extensibility | 🟡 | 🟡 |
### Lucky Orange
<Image
src={LuckyOrange}
alt="Lucky Orange is a tool for web analytics and conversion optimization. It helps businesses understand how users behave on their websites."
className="w-full rounded-lg"
/>
Lucky Orange is a tool for web analytics and conversion optimization. It helps businesses understand how users behave on their websites. Its features include **surveys**, **session recordings**, **live view,** and **conversion funnels**. These features move beyond vanity metrics, aiming to uncover the reasons behind visitors' actions on your website.
**Feature depth**:
- **Surveys:** Like HotJar, Lucky Orange offers survey features, but in a more limited fashion. You can choose from four survey types that suit your needs. They include **multiple-choice**, **like-or-dislike**, **rating**, and **open-ended** surveys. You can also customize how your survey is triggered based on your users location on your website and their devices, or if you want a delay before your survey is triggered.
- **Heatmaps & Recordings:** Both Lucky Orange and HotJar offer session recordings; however, while this feature is on par with HotJars features like filtering, some users still report that the [session viewer crashes when watching a desktop session on the mobile screen](https://www.g2.com/products/lucky-orange/reviews/lucky-orange-review-7862805).
- **Integrations**: Lucky Orange offers a smaller but growing selection of integrations compared to HotJar, focusing on essentials like Google Analytics, CMS platforms, and marketing automation tools.
**Pricing**: Lucky Orange offers pricing plans suitable for businesses of different sizes, including a 7-day free trial; as of the time of writing this article, they begin at $32 per month. Each of these plans is based on sessions but only has 60-day data storage, unlike Hojar, which provides data storage for 365 days.
**Privacy & Compliance:** Lucky Orange tools, like HotJar, are fully CCPA and GDPR-compliant. This means that it does not store sensitive information, ensuring a secure and trustworthy environment for user data.
**Extensibility:** Lucky Orange currently works with fewer outside tools than HotJar. This might be a drawback for large companies. However, they're planning to add support for a public API in the future. This means you'll be able to build on top of it.
| Factors | Lucky Orange | HotJar |
| ---------------------- | ------------ | ------ |
| Surveys & Forms | 🟢 | 🟢 |
| Heatmaps & Recordings | 🟡🟢 | 🟢 |
| Integrations | 🟡 | 🟢 |
| Pricing | 🟡 | 🟢 |
| Privacy and compliance | 🟢 | 🟢 |
| Extensibility | 🟡 | 🟢 |
### FullStory
<Image
src={FullStory}
alt="FullStory is a comprehensive user experience analytics platform that enables businesses to gain detailed insights into user interactions with their websites and applications."
className="w-full rounded-lg"
/>
FullStory is a comprehensive user experience analytics platform that enables businesses to gain detailed insights into user interactions with their websites and applications. Through features such as session recordings, dynamic heatmaps, and advanced analytics, FullStory provides a nuanced understanding of user behavior.
Lets see how FullStory compares to HotJar in terms of the factors we mentioned earlier:
**Features:**
- **Surveys:** Both FullStory and HotJar offer survey features, with FullStory utilizing integration with third-party tools like Survicate and SurveyMonkey for versatility and in-depth feedback.
FullStory wins here if you are looking for a versatile tool to integrate with other existing third-party survey tools. However, if you want an all-in-one solution, HotJar is your go-to solution.
- **Heatmaps & Recordings:** FullStory's interactive heatmaps and detailed visuals help you better understand how users interact with your website, improving the analysis of page activities. This feature is similar to what HotJar offers.
However, a notable difference is that in FullStory, you can't save a session to watch later. So, if you find a recording interesting and want to see it again, you'll need to search for it manually when you want to revisit it.
- **Integrations:** Like HotJar, FullStory integrates seamlessly with various third-party tools, enhancing its versatility and allowing users to integrate it into their existing tech stack.
**Pricing:** FullStory does not have a free plan, and the price for paid plans is available upon request from the sales team. Although their pricing page states that you get a 14-day free trial for their business plan.
**Privacy & Compliance:** You are in full control of what data FullStory captures and saves. FullStory is not just GDPR and CCPA-compliant but also holds a SOC 2 Type II attestation and a SOC 3 report.
**Extensibility:** FullStory also provides several APIs, like HotJar, including a Webhooks API that enables developers to build on top of its functionality and integrate it into their workflows. However, they might not provide the level of control and flexibility required for more complex integrations or custom workflows.
Heres how FullStory and HotJar compare side by side:
| Factors | FullStory | HotJar |
| ---------------------- | --------- | ------ |
| Surveys & Forms | 🟢 | 🟢 |
| Heatmaps & Recordings | 🟢 | 🟢 |
| Integrations | 🟢 | 🟢 |
| Pricing | 🟡 | 🟢 |
| Privacy and compliance | 🟢 | 🟢 |
| Extensibility | 🟡 | 🟡 |
### Mouseflow
<Image
src={MouseFlow}
alt="Mouseflow is a web analytics tool designed to provide insights into user behavior on websites."
className="w-full rounded-lg"
/>
Mouseflow is a web analytics tool designed to provide insights into user behavior on websites. It offers features such as session recordings, heatmaps, surveys, and funnel analysis to help businesses optimize user experiences and conversions.
**Feature depth**
- **Surveys**: Mouseflow provides you with a funnel-like analysis for in-depth form analytics, which is not available on HotJar. With Mouseflow, you can replay sessions from visitors who dropped out or succeeded in completing the form. It also helps you analyze how users interact with each of your form fields.
- **Heatmaps & Recordings:** Mouseflow, like Hojar, provides heatmaps and session recordings to visualize user interactions and behaviors, aiding in the analysis of website engagement.
However, HotJar samples the data you collect daily. That is, you are allowed to review just a small fraction of the whole set of data you receive daily. For example, if you have 3000 recordings per month, you are allowed to record just 100 daily sessions on standard plans.
- **Integrations:** Mouseflow, like HotJar, integrates with about 58 third-party tools, including other analytics, eCommerce, CMS, and marketing platforms in your stack.
**Pricing**: Mouseflow's pricing is tiered based on usage and additional features. It offers a range of plans to accommodate businesses of different sizes.
Its free plan comes with 500 recordings per month, unlimited page views, and a month of storage, all for one website. Paid plans begin at $31/month, however, if you are an enterprise, you can contact their sales team to create a customized plan.
**Privacy & Compliance:** Mouseflow is committed to data protection. Its compliant with GDPR, CCPA, CPRA, and VCDPA.
**Extensibility:** Like HotJar, Mouseflow's API and Webhooks enable developers to build custom integrations, connecting them to virtually any platform or tool imaginable. However, they might not provide the level of control and flexibility required for more complex integrations or custom workflows.
| Factors | Mouseflow | HotJar |
| ---------------------- | --------- | ------ |
| Surveys & Forms | 🟢 | 🟡🟢 |
| Heatmaps & Recordings | 🟢 | 🟡🟢 |
| Integrations | 🟢 | 🟢 |
| Pricing | 🟢 | 🟢 |
| Privacy and compliance | 🟢 | 🟢 |
| Extensibility | 🟡 | 🟡 |
## So, which option is the better fit for you?
If you're seeking a comprehensive solution encompassing heatmaps, recordings, surveys, and a strong focus on privacy, MouseFlow emerges as a prime choice.
On the other hand, if your primary emphasis is on highly targeted surveys, [Formbricks](http://www.formbricks.com/) stands out as the optimal solution.
What's even more noteworthy is that it is the sole open-source solution for website surveys available. This translates to not just being completely free to use if you self-host, but also offering the freedom for modification due to its extensibility and the liberty to seamlessly integrate with your preferred tools.
export default ({ children }) => <LayoutMdx meta={meta}>{children}</LayoutMdx>;

View File

@@ -0,0 +1,345 @@
import AuthorBox from "@/components/shared/AuthorBox";
import LayoutMdx from "@/components/shared/LayoutMdx";
import Image from "next/image";
import Formbricks from "./formbricks-best-open-source-hotjar-alternative.webp";
import FullStory from "./fullstory-comprehensive-analytics-tool.webp";
import Smartlook from "./g2-crowd-award-winner-Smartlook.webp";
import Header from "./header-best-hotjar-alternatives-2024-incl-open-source-solutions.webp";
import LuckyOrange from "./lucky-orange-best-analytics-tool-2024.webp";
import MouseFlow from "./mouseflow-best-hotjar-alternatives-2024.webp";
import SurveyMonkey from "./surveyMonkey-the-worlds-most-popular-free-online-survey-tool.webp";
export const meta = {
title: "Best Hotjar Alternatives 2024",
description:
"Discover 2024's best Hotjar alternatives with advanced website surveys and user behavior tools. Elevate your website insights and user experience today!",
date: "2023-04-22",
publishedTime: "2024-04-22T12:00:00",
authors: ["Johannes"],
section: "Feedback Apps",
tags: ["Feedback Apps", "Formbricks", "SurveyMonkey", "Smartlook", "Lucky Orange", "Fullstory", "Mouseflow"],
ogImage: "/blog/hotjar.jpg"
};
<Image src={Header} alt="Get the best HotJar features with these 5 tools." className="w-full rounded-lg" />
<AuthorBox name="Johannes" title="Co-Founder" date="December 29th, 2023" duration="4" author={"Johannes"} />
Hotjar is a popular product experience insights platform that provides valuable data and insights into how users interact with your websites. It offers features such as heatmaps and recordings, surveys, and funnels to help you get these insights.
But while its a staple in user behavior analytics, this article introduces 6 of the best Hotjar alternatives just waiting to be discovered. Whether you're a budget-conscious blogger or an enterprise giant, there is an option in this list perfect for your needs 🤓
To have a framework to compare the different options, the following section will guide you through the essential criteria to consider when comparing them to Hotjar. These criteria will empower you to pinpoint the perfect fit for your requirements.
## How We Compare & Group Hotjar Alternatives
There are many reasons why users seek alternatives to Hotjar. To make choosingt the best one for you easy, we'll categorize the criteria into three main factors:
1. **Feature depth**
- **Website Surveys & Forms**: Does the tool help you gather users voices through polls and surveys to understand your audience better?
- **Heatmaps & Recordings**: Do you want a tool for click maps and session replays with visitor insights?
- **Integrations**: Does the tool work well with your current tech stack?
2. **Privacy**: Is the tool fully GDPR, CCPA, or HIPAA compliant? What about data ownership?
3. **Extensibility**: Do they provide API services for extensibility and customization?
4. **Pricing: Freemium and Premium Plans**
Moving forward, well group these Hotjar alternatives into two different categories: first, for **website** **survey tools**, and second, for **behavioral analysis tools**.
### Two Hotjar Ask Alternatives For Website Surveys
1. Formbricks
2. SurveyMonkey
### Four Hotjar Alternatives For User Behavior Analysis
1. Smartlook
2. Lucky Orange
3. FullStory
4. MouseFlow
Enough setting up, let's dive right in! 🤿
## Hotjar Ask Alternatives For Targeted Website Surveys
<Image
src={Formbricks}
alt="Formbricks is a free and open source survey software for in-app micro surveys. Ask any user segment at any point in the user journey."
className="w-full rounded-lg"
/>
### Formbricks - The Open Source Hotjar Alternative
[Formbricks](http://formbricks.com/) is open-source survey software designed to gather specific feedback at the perfect moment in the user or customer journey. Formbricks allows you to create and deploy targeted surveys within your app, website, or links without disrupting your user experience.
Formbricks is super good at one thing: making your surveys and survey experiences awesome. We show you why people abandon your surveys, which questions cause churn, and how to fix them to get more people to finish. No heatmaps or fancy recordings, just laser focus on surveys.
### Formbricks vs Hotjar
**TL;DR**: Lets see how Formbricks compares side-by-side to Hotjar.
| Factors | Formbricks | Hotjar |
| --- | --- | --- |
| Surveys & Forms | 🟢 | 🟡🟢 |
| Heatmaps & Recordings | 🔴 | 🟢 |
| Integrations | 🟡🟢 | 🟡🟢 |
| Pricing | 🟢 | 🟡🟢 |
| Privacy and Compliance | 🟢 | 🟡 |
| Extensibility | 🟢 | 🟡 |
Now, well go into the details.
**Feature depth**
- **Surveys & Forms**: Formbricks offers a diverse range of survey templates, including options like [Product-Market fit](https://formbricks.com/docs/best-practices/pmf-survey), [Improving Newsletter Content](https://formbricks.com/docs/best-practices/improve-email-content), and NPS surveys. These surveys can be seamlessly to your website using the Formbricks SDK.
To learn more about setting up the Formbricks widget, visit our guide on [How to set up the Formbricks widget](https://formbricks.com/docs/getting-started/quickstart-in-app-survey).
Furthermore, Formbricks provides a comprehensive analytics dashboard that assists in optimizing survey conversion rates. This dashboard helps gather user data, analyze drop-offs, and track the number of users who viewed your surveys. The level of analytics provided by Formbricks is comparable to Hotjar's offerings.
- **Heatmaps & Recordings**: Formbricks focuses on surveys. No fancy website heatmaps here for now, but you get detailed insights into individual form fields and how users interact with them. If youre looking for open source heatmaps, OpenReplay might be worth checking out.
- **Integrations:** Formbricks integrates with popular tools like Zapier, Make.com, Airtable, Notion, and Slack, and these integrations are all available **on its Free Plan**. The Formbricks team and open-source community are continuously adding more integrations.
Hotjar, on the other hand, offers integrations with many tools for their surveys, but these are only available on their Business Plan. The Basic plan offers just one integration (HubSpot).
**Privacy:** Formbricks takes data privacy very seriously. Hence, we take on considerable additional effort to collect as little data as necessary and handle it safely and securely.
Formbricks is easily self-hostable and if you do so you have full control over the data you collect. This removes a huge chunk of privacy compliance and security reviews because the data never leaves your servers. Our privacy policy does not apply here, since no data is ever processed by Formbricks (the company).
We also offer Formbricks as a managed service in the Cloud. Formbricks Cloud is hosted by a German entity (GmbH) in Germany and comes with full GDPR and CCPA compliance. Learn more about how we handle private data on our Cloud in the [Privacy Policy](https://formbricks.com/privacy-policy). We also provide a [guide on how to create a GDPR compliant](https://formbricks.com/gdpr-guide) survey as well as [GDPR FAQs](https://formbricks.com/gdpr).
**Extensibility:** Formbricks stands out for its open-source nature and extensive API access, **available on all plans**. This unique feature allows users to customize and enhance their experience without limitations. In contrast, Hotjar's API access is restricted to its Scale plan, which comes at a higher price point of **$128/month** with as little as 500 sessions / day.
**Pricing**: Both tools have free plans, but Formbricks gives you more value on a free plan than Hotjar. Ultimately, Formbricks offers a lot more value for your money, especially if youre mostly interested in running surveys.
If you decide to [self-host](https://formbricks.com/docs/self-hosting/deployment) Formbricks on your servers, the community edition **is completely free including Branding Removal.** If you require the Enterprise Edition because you need Team Roles, Advanced Targeting or Multi-language Surveys, [please reach out.](mailto:hola@formbricks.com)
### SurveyMonkey
<Image
src={SurveyMonkey}
alt="SurveyMonkey is the world's most popular online survey tool. It is one the top alternatives to Hotjar."
className="w-full rounded-lg"
/>
SurveyMonkey prides itself on being the global leader in online surveys and forms, and rightfully so, as it has been around for over 20 years. It is an online survey software that helps you create and run professional online surveys.
According to their website, SurveyMonkey provides answers to more than 20 million questions every day, helping organizations of all sizes build products people love, create winning marketing strategies, delight their customers, and cultivate an engaged and happy workforce.
### SurveyMonkey vs Hotjar
**TL:DR**: How SurveyMonkey compares side-by-side to Hotjar.
| Factors | SurveyMonkey | Hotjar |
| --- | --- | --- |
| Surveys & Forms | 🟡🟢 | 🟡🟢 |
| Heatmaps & Recordings | 🔴 | 🟢 |
| Integrations | 🟡🟢 | 🟡🟢 |
| Privacy and Compliance | 🟢 | 🟢 |
| Extensibility | 🟡🟢 | 🟡🟢 |
| Pricing | 🟢 | 🟡 |
Now, lets dive into the details.
**Feature depth:**
- **Surveys & Forms:** SurveyMonkey provides over 150 survey templates cutting across different categories ranging from customer feedback, human resources, and events, among many others. However, most of its survey templates and features, like adding a custom logo, logic skips, and analysis features, are only available on paid plans.
Another feature that gives SurveyMonkey an edge over competitors is their recently rolled out Build with AI feature; if you dont know where or how to start building your survey, all you have to do is enter a prompt into the text area stating what you need a survey for.
- **Heatmaps & Recordings:** SurveyMonkey does not offer heatmaps or recording features, unlike Hotjar. However, if you need feedback on an image, they provide a click map feature, which is available on paid plans.
- **Integrations:** SurveyMonkey integrates with popular apps like Office 365, Google Drive, and Slack, but these integrations are only available on the **Team plans**.
**Privacy:** Like Hotjar, SurveyMonkey complies with GDPR and CCPA regulations, although its HIPAA-compliant features are only available on its enterprise plans.
**Extensibility:** SurveyMonkey provides an API to integrate survey data into your mobile and web applications. But its only **available on its Enterprise Plan**.
**Pricing:** SurveyMonkeys paid plans begin at $25/month whereas paid plans for Hotjar surveys begin at **$47.2/month**. However, dont forget that SurveyMonkey is a full-fledged survey software, so youll get more value for your money if you are concerned about only surveys.
## 4 Hotjar Alternatives For User Behavior Analysis
### Smartlook - G2 Crowd Award Winner
<Image
src={Smartlook}
alt="Smartlook is a comprehensive product analytics and visual user insights tool designed to help businesses gain deep insights into user behavior on their websites or mobile applications."
className="w-full rounded-lg"
/>
[Smartlook](https://smartlook.com/), which was recently acquired by [Cisco](https://cisco.com/), is a comprehensive product analytics and visual user insights tool designed to help businesses gain deep insights into user behavior on their websites or mobile applications. Like Hotjar, it offers a range of features, including heatmaps, surveys, and session recordings, that enable organizations to understand, analyze, and optimize the user experience.
It has received numerous awards and recognition, including the G2 Crowd Awards for **Top 100 Software Products** and **Best Products for Marketers**, as well as being named on Deloittes Technology Fast 50 in Central Europe.
### Smartlook vs Hotjar
**TL;DR**: How Smartlook compares side-by-side to Hotjar.
| Factors | Smartlook | Hotjar |
| --- | --- | --- |
| Surveys & Forms | 🟡🟢 | 🟢 |
| Heatmaps & Recordings | 🟢 | 🟢 |
| Integrations | 🟢 | 🟢 |
| Privacy and Compliance | 🟢 | 🟢 |
| Extensibility | 🟡🟢 | 🟡 |
| Pricing | 🔴 | 🟢 |
Next, well into the details.
**Feature depth**:
- **Surveys**: Smartlook also offers survey features in addition to user behavior analysis tools. However, it does not offer standalone surveys, unlike Hotjar. Instead, you can create surveys through its integration with Survicate.
For a deeper look into Survicate, check out our article on best feedback apps.
- **Heatmaps & Recordings**: Similar to Hotjar, Smartlook provides comprehensive heatmap and recording features. Your recordings are displayed on a dashboard with versatile filtering capabilities and customizable user information. You can also save recordings to a vault session in case the amount of time designated for them to remain in your account expires due to your purchase plan.
Smartlook provides three types of heatmap overlays for heatmaps: click and move, and scroll overlays to help you see how your users use your website.
- **Integrations:** Both platforms work well with many external tools. However, if you're a big enterprise seeking a broader selection of tools, Hotjar is the better choice, but it's worth noting that with Hotjar, only Hubspot and Microsoft Teams integrations are available on free plans.
**Privacy and Compliance**: Smartlook is privacy compliant just like Hotjar. Smartlook stores all data on EU servers. If you collect personal data with Smartlook, GDPR applies. Smartlook is also fully CCPA compliant.
**Extensibility:** Smartlook, like Hotjar, provides a REST API you can build on top of, and its available across all plans; however, there are rate limits across the plans. Its free plan accepts only twenty (20) requests per hour; its paid plan accepts one hundred (100) requests per hour, and its REST API add-on accepts one thousand (1,000) requests per hour.
On the contrary, Hotjars API integration for heatmaps and recordings is only available on its scale plan at **$170.4/month**.
**Pricing**: Compared to Hotjar, Smartlook is relatively more expensive. Its pro plan provides only 30 heatmaps a month and three months of storage. Hotjars equivalent business plan offers unlimited heatmaps with 12 months of data storage
### Lucky Orange
<Image
src={LuckyOrange}
alt="Lucky Orange is a tool for web analytics and conversion optimization. It helps businesses understand how users behave on their websites."
className="w-full rounded-lg"
/>
Lucky Orange is a tool for web analytics and conversion optimization. It helps businesses understand how users behave on their websites. Its features include surveys, session recordings, live viewing, and conversion funnels. These features move beyond vanity metrics, aiming to uncover the reasons behind visitors' actions on your website.
### LuckyOrange vs Hotjar
**TL:DR**: Lets see how they compare side-by-side.
| Factors | Lucky Orange | Hotjar |
| --- | --- | --- |
| Surveys & Forms | 🟢 | 🟢 |
| Heatmaps & Recordings | 🟡🟢 | 🟢 |
| Integrations | 🟡 | 🟢 |
| Privacy and Compliance | 🟢 | 🟢 |
| Extensibility | 🟡 | 🟢 |
| Pricing | 🟡 | 🟢 |
Next, well take a look at the details.
**Feature depth**:
- **Surveys:** Like Hotjar, Lucky Orange offers survey features. You can choose from four survey types that suit your needs. They include Multiple Choice, Like or Dislike, rating, and open-ended surveys.
You can also customize how your survey is triggered based on your users location on your website and their devices, or if you want a delay before your survey is triggered. There are also advanced settings with which you can customize your survey.
- **Heatmaps & Recordings:** Both Lucky Orange and Hotjar offer session recordings; however, while this feature is on par with Hotjars features like filtering, some users still report that the [session viewer crashes when watching a desktop session on the mobile screen](https://www.g2.com/products/lucky-orange/reviews/lucky-orange-review-7862805).
- **Integrations**: Lucky Orange offers a smaller but growing selection of integrations compared to Hotjar, focusing on essentials like Google Analytics, CMS platforms, and marketing automation tools.
**Privacy & Compliance**: Lucky Orange tools, like Hotjar, are fully CCPA and GDPR-compliant. This means that it does not store sensitive information, ensuring a secure and trustworthy environment for user data.
**Extensibility:** Lucky Orange currently works with fewer third-party tools than Hotjar. This might be a drawback for large companies. However, they're planning to add support for a public API in the future. This means you'll be able to build on top of it.
**Pricing**: Lucky Orange offers pricing plans suitable for businesses of different sizes, including a 7-day free trial; as of the time of writing this article, they begin at $32 per month. Each of these plans is based on sessions but only has 60-day data storage, unlike Hojar, which provides data storage for 365 days.
### FullStory
<Image
src={FullStory}
alt="FullStory is a comprehensive user experience analytics platform that enables businesses to gain detailed insights into user interactions with their websites and applications."
className="w-full rounded-lg"
/>
FullStory is a comprehensive user experience analytics platform that enables businesses to gain detailed insights into user interactions with their websites and applications. Through features such as session recordings, dynamic heatmaps, and advanced analytics, FullStory provides a nuanced understanding of user behavior.
### FullStory vs Hotjar
**TL;DR**: FullStory vs Hotjar side by side.
| Factors | FullStory | Hotjar |
| --- | --- | --- |
| Surveys & Forms | 🟢 | 🟢 |
| Heatmaps & Recordings | 🟢 | 🟢 |
| Integrations | 🟢 | 🟢 |
| Pricing | 🟡 | 🟢 |
| Privacy and Compliance | 🟢 | 🟢 |
| Extensibility | 🟡 | 🟡 |
**Features depth**:
- **Surveys:** Both FullStory and Hotjar offer survey features, with FullStory utilizing integration with third-party tools like Survicate and SurveyMonkey for versatility and in-depth feedback.
FullStory wins here if you are looking for a versatile tool to integrate with other existing third-party survey tools. However, if you want an all-in-one solution, Hotjar is your go-to solution.>
- **Heatmaps & Recordings:** FullStory's interactive heatmaps and detailed visuals help you better understand how users interact with your website, improving the analysis of page activities. This feature is similar to what Hotjar offers.
However, a notable difference is that in FullStory, you can't save a session to watch later. So, if you find a recording interesting and want to see it again, you'll need to search for it manually when you want to revisit it.
- **Integrations:** Like Hotjar, FullStory integrates seamlessly with various third-party tools, enhancing its versatility and allowing users to integrate it into their existing tech stack.
**Privacy & Compliance:** You are in full control of what data FullStory captures and saves. FullStory is not just GDPR and CCPA-compliant but also holds a SOC 2 Type II attestation and a SOC 3 report.
**Extensibility:** FullStory also provides several APIs, like Hotjar, including a Webhooks API that enables developers to build on top of its functionality and integrate it into their workflows. However, its worth noting that this is available on paid plans.
**Pricing:** FullStory does not have a free plan, and the price for paid plans is available upon request from the sales team. Although their pricing page states that you get a 14-day free trial for their business plan.
### Mouseflow
<Image
src={MouseFlow}
alt="Mouseflow is a web analytics tool designed to provide insights into user behavior on websites."
className="w-full rounded-lg"
/>
Mouseflow is a web analytics tool designed to provide insights into user behavior on websites. It offers features such as session recordings, heatmaps, surveys, and funnel analysis to help businesses optimize user experiences and conversions.
### MouseFlow vs Hotjar
**TL;DR**: MouseFlow side-by-side with Hotjar.
| Factors | Mouseflow | Hotjar |
| --- | --- | --- |
| Surveys & Forms | 🟢 | 🟡🟢 |
| Heatmaps & Recordings | 🟢 | 🟡🟢 |
| Integrations | 🟢 | 🟢 |
| Pricing | 🟢 | 🟢 |
| Privacy and Compliance | 🟢 | 🟢 |
| Extensibility | 🟡 | 🟡 |
Feature depth
- **Surveys**: Mouseflow provides you with a funnel-like analysis for in-depth form analytics, which is not available on Hotjar. With Mouseflow, you can replay sessions from visitors who dropped out or succeeded in completing the form. It also helps you analyze how users interact with each of your form fields.
- **Heatmaps & Recordings:** Mouseflow, like Hojar, provides heatmaps and session recordings to visualize user interactions and behaviors, aiding in the analysis of website engagement.
However, Hotjar samples the data you collect daily. That is, you are allowed to review just a small fraction of the whole set of data you receive daily. For example, if you have 3000 recordings per month, you are allowed to record just 100 daily sessions on standard plans.
- **Integrations:** Mouseflow, like Hotjar, integrates with about 58 third-party tools, including other analytics, eCommerce, CMS, and marketing platforms in your stack.
**Privacy & Compliance:** Mouseflow is committed to data protection. Its compliant with GDPR, CCPA, CPRA, and VCDPA.
**Extensibility**: Like Hotjar, Mouseflow's open REST API and Webhooks enable developers to build custom integrations, connecting them to virtually any platform or tool imaginable. However, the API is only available on its Growth plan, starting at $109/month.
**Pricing:** Mouseflow's pricing is tiered based on usage and additional features. It offers a range of plans to accommodate businesses of different sizes.
Its free plan comes with 500 recordings per month, unlimited page views, and a month of storage, all for one website. Paid plans begin at $31/month, however, if you are an enterprise, you can contact their sales team to create a customized plan.
## So, which option is the better fit for you?
If you're seeking a comprehensive solution encompassing heatmaps, recordings, surveys, and a strong focus on privacy, MouseFlow emerges as a prime choice.
On the other hand, if your primary emphasis is on forms and surveys, [Formbricks](http://www.formbricks.com/) stands out as the optimal Hotjar alternative. What's even more noteworthy is that it is the sole open-source solution for website surveys available. This translates to not just being completely free to use if you self-host, but also offering the freedom for modification due to its extensibility and the liberty to seamlessly integrate with your preferred tools.
export default ({ children }) => <LayoutMdx meta={meta}>{children}</LayoutMdx>;

View File

@@ -13,7 +13,7 @@ export default function Layout({ title, description, children }: LayoutProps) {
<div className="mx-auto bg-gradient-to-br from-slate-800 via-slate-900 to-slate-900">
<MetaInformation title={title} description={description} />
<HeaderTribe />
<main className="">{children}</main>
<main>{children}</main>
<Footer />
</div>
);

View File

@@ -562,15 +562,15 @@ export default function FormTribeHackathon() {
<div className="max-w-8xl mt-8 grid grid-cols-3 gap-4 px-56">
<div className="px-8">
<p className="h-0 text-lg font-bold text-slate-300">+ Sticker Set</p>
<Image src={ArrowSticker} alt="rookie batch" className="" />
<Image src={ArrowSticker} alt="rookie batch" />
</div>
<div className="px-8">
<p className="h-0 text-lg font-bold text-slate-300">+ Hoodie</p>
<Image src={HoodieSticker} alt="rookie batch" className="" />
<Image src={HoodieSticker} alt="rookie batch" />
</div>
<div className="px-8">
<p className="h-0 text-lg font-bold text-slate-300">+ Handmade Gift</p>
<Image src={ArrowGift} alt="rookie batch" className="" />
<Image src={ArrowGift} alt="rookie batch" />
</div>
</div>
</div>
@@ -754,7 +754,7 @@ export default function FormTribeHackathon() {
</div>
{FAQ.map((question) => (
<div key={question.question} className="">
<div key={question.question}>
<div>
<h3 className="mt-6 text-lg font-bold text-slate-700">{question.question} </h3>
<p className="text-slate-600">{question.answer}</p>

View File

@@ -415,7 +415,7 @@ export default function LinkSurveyPage() {
headline="Try THE open source form builder 💪"
subheadline="Convinced that Formbricks is a good open source Typeform alternative? Try it now!"
/>
<div className="">
<div>
<HeadingCentered
heading="All form builder features"
teaser="Build open source forms like never before"
@@ -440,7 +440,7 @@ export default function LinkSurveyPage() {
imgAlt="Peer Richelsen, Co-Founder and CEO of Cal.com"
textSize="large"
/>
<div className="">
<div>
<HeadingCentered heading="All question types included" teaser="A complete open source form builder" />
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{allQuestionTypes.map((feature) => {

View File

@@ -78,6 +78,14 @@ We only share your information with our Service providers who help us operate ou
| Sentry | Error Logs | Error Tracking | 🇺🇸 | DPA signed | [GDPR Info](https://sentry.io/legal/dpa/) |
| Customer.io | Email Address, User Interaction Data | Marketing and Communication | 🇪🇺 | DPA signed | [GDPR Info](https://customer.io/legal/privacy-policy/) |
## **Native Integrations**
Formbricks comes with a number of native integrations. These integrations let you connect your Formbricks project with external services like Google, Slack, Zapier, etc.
In case you decide to setup an integration, you acknowledge and agree to the following:
**Google Sheets Integration:** Formbricks use and transfer to any other app of information received from Google APIs will adhere to [Google API Services User Data Policy](https://developers.google.com/terms/api-services-user-data-policy#additional_requirements_for_specific_api_scopes), including the Limited Use requirements.
## **Data retention**
If you are a Formbricks Researcher we do not delete the data in your account. You can delete data in your Formbricks account. You are responsible for the time period for which you store the data.

View File

@@ -266,7 +266,7 @@ export default function WebsiteSurveyPage() {
headline="All clear? Run your first website survey 👉"
subheadline="Targeted website surveys, all privacy-first. Run professional research without compromising data privacy."
/>
<div className="">
<div>
<HeadingCentered
heading={
<span>

View File

@@ -38,6 +38,15 @@ export default {
},
typography: typographyStyles,
extend: {
keyframes: {
scroll: {
"0%": { transform: "translateX(0%)" },
"100%": { transform: "translateX(-1990px)" },
},
},
animation: {
scroll: "scroll 60s linear infinite",
},
boxShadow: {
glow: "0 0 4px rgb(0 0 0 / 0.1)",
},

View File

@@ -17,19 +17,19 @@
},
"devDependencies": {
"@formbricks/tsconfig": "workspace:*",
"@storybook/addon-essentials": "^8.0.6",
"@storybook/addon-interactions": "^8.0.6",
"@storybook/addon-links": "^8.0.6",
"@storybook/addon-onboarding": "^8.0.6",
"@storybook/blocks": "^8.0.6",
"@storybook/react": "^8.0.6",
"@storybook/react-vite": "^8.0.6",
"@storybook/addon-essentials": "^8.0.9",
"@storybook/addon-interactions": "^8.0.9",
"@storybook/addon-links": "^8.0.9",
"@storybook/addon-onboarding": "^8.0.9",
"@storybook/blocks": "^8.0.9",
"@storybook/react": "^8.0.9",
"@storybook/react-vite": "^8.0.9",
"@storybook/testing-library": "^0.2.2",
"@typescript-eslint/eslint-plugin": "^7.5.0",
"@typescript-eslint/parser": "^7.5.0",
"@typescript-eslint/eslint-plugin": "^7.7.1",
"@typescript-eslint/parser": "^7.7.1",
"@vitejs/plugin-react": "^4.2.1",
"esbuild": "^0.20.2",
"tsup": "^8.0.2",
"vite": "^5.2.8"
"vite": "^5.2.10"
}
}

View File

@@ -4,7 +4,7 @@ import { formbricksEnabled } from "@/app/lib/formbricks";
import { usePathname, useSearchParams } from "next/navigation";
import { useEffect } from "react";
import formbricks from "@formbricks/js";
import formbricks from "@formbricks/js/app";
import { env } from "@formbricks/lib/env";
type UsageAttributesUpdaterProps = {

View File

@@ -1,24 +0,0 @@
import ActionClassesTable from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/components/ActionClassesTable";
import ActionClassDataRow from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/components/ActionRowData";
import ActionTableHeading from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/actions/components/ActionTableHeading";
import { Metadata } from "next";
import { getActionClasses } from "@formbricks/lib/actionClass/service";
export const metadata: Metadata = {
title: "Actions",
};
export default async function ActionClassesComponent({ params }) {
let actionClasses = await getActionClasses(params.environmentId);
return (
<>
<ActionClassesTable environmentId={params.environmentId} actionClasses={actionClasses}>
<ActionTableHeading />
{actionClasses.map((actionClass) => (
<ActionClassDataRow key={actionClass.id} actionClass={actionClass} />
))}
</ActionClassesTable>
</>
);
}

View File

@@ -1,26 +0,0 @@
import SecondNavbar from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/attributes/components/SecondNavbar";
import { MousePointerClickIcon, TagIcon } from "lucide-react";
interface ActionsAttributesTabsProps {
activeId: string;
environmentId: string;
}
export default function ActionsAttributesTabs({ activeId, environmentId }: ActionsAttributesTabsProps) {
const tabs = [
{
id: "actions",
label: "Actions",
icon: <MousePointerClickIcon className="h-5 w-5" />,
href: `/environments/${environmentId}/actions`,
},
{
id: "attributes",
label: "Attributes",
icon: <TagIcon className="h-5 w-5" />,
href: `/environments/${environmentId}/attributes`,
},
];
return <SecondNavbar tabs={tabs} activeId={activeId} environmentId={environmentId} />;
}

View File

@@ -1,12 +0,0 @@
import ActionsAttributesTabs from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/attributes/components/ActionsAttributesTabs";
import { ContentWrapper } from "@formbricks/ui/ContentWrapper";
export default function ActionsAndAttributesLayout({ params, children }) {
return (
<>
<ActionsAttributesTabs activeId="attributes" environmentId={params.environmentId} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@@ -1,6 +1,5 @@
"use client";
import { getSegmentsByAttributeClassAction } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/attributes/actions";
import { TagIcon } from "lucide-react";
import { useEffect, useState } from "react";
@@ -11,6 +10,8 @@ import { ErrorComponent } from "@formbricks/ui/ErrorComponent";
import { Label } from "@formbricks/ui/Label";
import LoadingSpinner from "@formbricks/ui/LoadingSpinner";
import { getSegmentsByAttributeClassAction } from "../actions";
interface EventActivityTabProps {
attributeClass: TAttributeClass;
}

View File

@@ -1,16 +1,17 @@
"use client";
import { AttributeDetailModal } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/attributes/components/AttributeDetailModal";
import { AttributeClassDataRow } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/attributes/components/AttributeRowData";
import { AttributeTableHeading } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/attributes/components/AttributeTableHeading";
import { HowToAddAttributesButton } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/attributes/components/HowToAddAttributesButton";
import { UploadAttributesModal } from "@/app/(app)/environments/[environmentId]/(actionsAndAttributes)/attributes/components/UploadAttributesModal";
import { useState } from "react";
import { useMemo } from "react";
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import { Switch } from "@formbricks/ui/Switch";
import { AttributeDetailModal } from "./AttributeDetailModal";
import { AttributeClassDataRow } from "./AttributeRowData";
import { AttributeTableHeading } from "./AttributeTableHeading";
import { HowToAddAttributesButton } from "./HowToAddAttributesButton";
import { UploadAttributesModal } from "./UploadAttributesModal";
interface AttributeClassesTableProps {
attributeClasses: TAttributeClass[];
}

View File

@@ -1,7 +1,7 @@
import { TagIcon } from "lucide-react";
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import ModalWithTabs from "@formbricks/ui/ModalWithTabs";
import { ModalWithTabs } from "@formbricks/ui/ModalWithTabs";
import AttributeActivityTab from "./AttributeActivityTab";
import AttributeSettingsTab from "./AttributeSettingsTab";

Some files were not shown because too many files have changed in this diff Show More