Compare commits
96 Commits
feat-redir
...
delete-ava
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f4ca53a1b | ||
|
|
81a4da6199 | ||
|
|
b8efc442e3 | ||
|
|
e00bdf2f79 | ||
|
|
cea5716c48 | ||
|
|
fc150f8860 | ||
|
|
7fdf8a63c8 | ||
|
|
374f17df63 | ||
|
|
d27da8927e | ||
|
|
785afd4bda | ||
|
|
e28c226308 | ||
|
|
4170e20e21 | ||
|
|
af548aa624 | ||
|
|
13d68bbac0 | ||
|
|
fabea3c813 | ||
|
|
db80e7f7cb | ||
|
|
1ebddbd1de | ||
|
|
6c6061a123 | ||
|
|
0bf38aed9f | ||
|
|
8aedbde36a | ||
|
|
17279cb3fe | ||
|
|
1b4823421f | ||
|
|
deef604325 | ||
|
|
22e44b47e6 | ||
|
|
08052b13cf | ||
|
|
5e7fe96ef6 | ||
|
|
83ff98cd3a | ||
|
|
eb54230445 | ||
|
|
59d57c50eb | ||
|
|
f358254e3c | ||
|
|
3ab8092a82 | ||
|
|
3b08b718ff | ||
|
|
a473719eee | ||
|
|
cd40e655fb | ||
|
|
5d468b4420 | ||
|
|
96806c613f | ||
|
|
6f2a4b2b03 | ||
|
|
d33efa0274 | ||
|
|
9b35ebc114 | ||
|
|
dba62157bf | ||
|
|
556184f442 | ||
|
|
c33532f952 | ||
|
|
8f61ceb4ea | ||
|
|
e19dcdc0c4 | ||
|
|
65f977786d | ||
|
|
95c13fd9a9 | ||
|
|
f8adf28df8 | ||
|
|
9d468379f2 | ||
|
|
8071e82390 | ||
|
|
3ce775ec05 | ||
|
|
1223a30127 | ||
|
|
f3906cab55 | ||
|
|
d33304e3ad | ||
|
|
ebed950392 | ||
|
|
4e6ab1c2bb | ||
|
|
543d85eb28 | ||
|
|
afe01a61ae | ||
|
|
b4c86835ed | ||
|
|
ab80bc1bf2 | ||
|
|
5e5a9fac00 | ||
|
|
09b6805886 | ||
|
|
33822350fd | ||
|
|
8c7b5891a2 | ||
|
|
864b3a34e9 | ||
|
|
a382a18d44 | ||
|
|
70e77247f6 | ||
|
|
915fe00434 | ||
|
|
2e64b0d54f | ||
|
|
ed4b885935 | ||
|
|
5bf5825f30 | ||
|
|
9888d128a2 | ||
|
|
a143e9d1a3 | ||
|
|
4878e8e43a | ||
|
|
b989272bce | ||
|
|
df927555e0 | ||
|
|
5e94d0b4af | ||
|
|
c73d4e82b5 | ||
|
|
a269da4e1c | ||
|
|
b49ca8087a | ||
|
|
7649095c03 | ||
|
|
a8223d2f3c | ||
|
|
53aef9ce0b | ||
|
|
bcceab4858 | ||
|
|
ac4064503a | ||
|
|
d9b115db37 | ||
|
|
a61f294eea | ||
|
|
7b4db30efd | ||
|
|
c8aece8003 | ||
|
|
ad8d473a2d | ||
|
|
55db14e758 | ||
|
|
bbfdba7615 | ||
|
|
681c559c79 | ||
|
|
4e39f45446 | ||
|
|
62c514acf2 | ||
|
|
48638e8ca2 | ||
|
|
cb44b575c2 |
@@ -22,7 +22,7 @@
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "cp .env.example .env && sed -i '/^ENCRYPTION_KEY=/c\\ENCRYPTION_KEY='$(openssl rand -hex 32) .env && sed -i '/^NEXTAUTH_SECRET=/c\\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env && pnpm install && pnpm db:migrate:dev",
|
||||
"postAttachCommand": "pnpm dev --filter=web... --filter=demo...",
|
||||
"postAttachCommand": "pnpm dev --filter=@formbricks/web... --filter=@formbricks/demo...",
|
||||
|
||||
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "node"
|
||||
|
||||
@@ -35,3 +35,5 @@ yarn-error.log*
|
||||
.vscode
|
||||
.github
|
||||
**/.turbo
|
||||
|
||||
.env
|
||||
|
||||
18
.env.example
@@ -28,13 +28,17 @@ DATABASE_URL='postgresql://postgres:postgres@localhost:5432/formbricks?schema=pu
|
||||
###############
|
||||
|
||||
# @see: https://next-auth.js.org/configuration/options#nextauth_secret
|
||||
# You can use: `openssl rand -hex 32` to generate one
|
||||
# You can use: `openssl rand -hex 32` to generate a secure one
|
||||
NEXTAUTH_SECRET=RANDOM_STRING
|
||||
|
||||
# Set this to your public-facing URL, e.g., https://example.com
|
||||
# You do not need the NEXTAUTH_URL environment variable in Vercel.
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
|
||||
# Cron Secret
|
||||
# You can use: `openssl rand -hex 32` to generate a secure one
|
||||
CRON_SECRET=
|
||||
|
||||
################
|
||||
# MAIL SETUP #
|
||||
################
|
||||
@@ -83,6 +87,7 @@ EMAIL_VERIFICATION_DISABLED=1
|
||||
PASSWORD_RESET_DISABLED=1
|
||||
|
||||
# Signup. Disable the ability for new users to create an account.
|
||||
# Note: This variable is only available to the SaaS setup of Formbricks Cloud. Signup is disable by default for self-hosting.
|
||||
# SIGNUP_DISABLED=1
|
||||
|
||||
# Email login. Disable the ability for users to login with email.
|
||||
@@ -120,9 +125,6 @@ AZUREAD_TENANT_ID=
|
||||
# OIDC_DISPLAY_NAME=
|
||||
# OIDC_SIGNING_ALGORITHM=
|
||||
|
||||
# Cron Secret
|
||||
CRON_SECRET=
|
||||
|
||||
# Configure this when you want to ship JS & CSS files from a complete URL instead of the current domain
|
||||
# ASSET_PREFIX_URL=
|
||||
|
||||
@@ -160,9 +162,6 @@ ENTERPRISE_LICENSE_KEY=
|
||||
# DEFAULT_ORGANIZATION_ID=
|
||||
# DEFAULT_ORGANIZATION_ROLE=admin
|
||||
|
||||
# set to 1 to skip onboarding for new users
|
||||
# ONBOARDING_DISABLED=1
|
||||
|
||||
# Send new users to customer.io
|
||||
# CUSTOMER_IO_API_KEY=
|
||||
# CUSTOMER_IO_SITE_ID=
|
||||
@@ -177,7 +176,10 @@ ENTERPRISE_LICENSE_KEY=
|
||||
UNSPLASH_ACCESS_KEY=
|
||||
|
||||
# The below is used for Next Caching (uses In-Memory from Next Cache if not provided)
|
||||
# REDIS_URL:
|
||||
# REDIS_URL=redis://localhost:6379
|
||||
|
||||
# The below is used for Rate Limiting (uses In-Memory LRU Cache if not provided) (You can use a service like Webdis for this)
|
||||
# REDIS_HTTP_URL:
|
||||
|
||||
# Disable custom cache handler if necessary (e.g. if deployed on Vercel)
|
||||
# CUSTOM_CACHE_DISABLED=1
|
||||
|
||||
2
.eslintignore
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules/
|
||||
packages/config-eslint/
|
||||
10
.eslintrc.js
@@ -1,10 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
// This tells ESLint to load the config from the package `eslint-config-formbricks`
|
||||
extends: ["formbricks"],
|
||||
settings: {
|
||||
next: {
|
||||
rootDir: ["apps/*/"],
|
||||
},
|
||||
},
|
||||
};
|
||||
16
.github/actions/cache-build-web/action.yml
vendored
@@ -49,20 +49,16 @@ runs:
|
||||
run: cp .env.example .env
|
||||
shell: bash
|
||||
|
||||
- name: Add E2E Testing Mode
|
||||
- name: Fill ENCRYPTION_KE, ENTERPRISE_LICENSE_KEY and E2E_TESTING in .env
|
||||
run: |
|
||||
echo "E2E_TESTING=${{ inputs.e2e_testing_mode }}" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Generate Random ENCRYPTION_KEY
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
|
||||
echo "ENTERPRISE_LICENSE_KEY=$SECRET" >> $GITHUB_ENV
|
||||
RANDOM_KEY=$(openssl rand -hex 32)
|
||||
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${RANDOM_KEY}/" .env
|
||||
sed -i "s/ENTERPRISE_LICENSE_KEY=.*/ENTERPRISE_LICENSE_KEY=${RANDOM_KEY}/" .env
|
||||
echo "E2E_TESTING=${{ inputs.e2e_testing_mode }}" >> .env
|
||||
shell: bash
|
||||
|
||||
- run: |
|
||||
pnpm build --filter=web...
|
||||
pnpm build --filter=@formbricks/web...
|
||||
|
||||
if: steps.cache-build.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
|
||||
2
.github/workflows/build-web.yml
vendored
@@ -31,4 +31,4 @@ jobs:
|
||||
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Formbricks-web
|
||||
run: pnpm build --filter=web...
|
||||
run: pnpm build --filter=@formbricks/web...
|
||||
|
||||
24
.github/workflows/cron-reportUsageToStripe.yml
vendored
@@ -1,24 +0,0 @@
|
||||
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 * * *"
|
||||
jobs:
|
||||
cron-reportUsageToStripe:
|
||||
env:
|
||||
APP_URL: ${{ secrets.APP_URL }}
|
||||
CRON_SECRET: ${{ secrets.CRON_SECRET }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: cURL request
|
||||
if: ${{ env.APP_URL && env.CRON_SECRET }}
|
||||
run: |
|
||||
curl ${{ env.APP_URL }}/api/cron/report-usage \
|
||||
-X POST \
|
||||
-H 'x-api-key: ${{ env.CRON_SECRET }}' \
|
||||
-H 'Cache-Control: no-cache' \
|
||||
--fail
|
||||
6
.github/workflows/cron-weeklySummary.yml
vendored
@@ -4,9 +4,9 @@ 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:
|
||||
|
||||
60
.github/workflows/e2e.yml
vendored
@@ -7,6 +7,20 @@ jobs:
|
||||
name: Run E2E Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:latest
|
||||
env:
|
||||
POSTGRES_DB: postgres
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd="pg_isready -U testuser"
|
||||
--health-interval=10s
|
||||
--health-timeout=5s
|
||||
--health-retries=5
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
@@ -16,44 +30,46 @@ jobs:
|
||||
with:
|
||||
e2e_testing_mode: "1"
|
||||
|
||||
- name: Check if pnpm is installed
|
||||
id: pnpm-check
|
||||
run: |
|
||||
if pnpm --version; then
|
||||
echo "pnpm is installed."
|
||||
echo "PNPM_INSTALLED=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "pnpm is not installed."
|
||||
echo "PNPM_INSTALLED=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Install pnpm
|
||||
if: env.PNPM_INSTALLED == 'false'
|
||||
uses: pnpm/action-setup@v2
|
||||
|
||||
- name: Install dependencies
|
||||
if: env.PNPM_INSTALLED == 'false'
|
||||
run: pnpm install
|
||||
|
||||
- name: Start PostgreSQL
|
||||
- name: Apply Prisma Migrations
|
||||
run: |
|
||||
cd packages/database && pnpm db:up &
|
||||
for attempt in {1..20}; do
|
||||
if nc -zv localhost 5432; then
|
||||
echo "Ready"
|
||||
break
|
||||
fi
|
||||
echo "Waiting..."
|
||||
sleep 5
|
||||
done
|
||||
pnpm db:migrate:dev
|
||||
- name: Serve packages for lazy loading
|
||||
run: |
|
||||
cd packages/surveys && pnpm serve &
|
||||
pnpm prisma migrate deploy
|
||||
|
||||
- name: Run App
|
||||
run: |
|
||||
NODE_ENV=test pnpm start --filter=web &
|
||||
for attempt in {1..20}; do
|
||||
NODE_ENV=test pnpm start --filter=@formbricks/web &
|
||||
sleep 10 # Optional: gives some buffer for the app to start
|
||||
for attempt in {1..10}; do
|
||||
if [ $(curl -o /dev/null -s -w "%{http_code}" http://localhost:3000/health) -eq 200 ]; then
|
||||
echo "Ready"
|
||||
echo "Application is ready."
|
||||
break
|
||||
fi
|
||||
echo "Waiting..."
|
||||
if [ $attempt -eq 10 ]; then
|
||||
echo "Application failed to start in time."
|
||||
exit 1
|
||||
fi
|
||||
echo "Still waiting for the application to be ready..."
|
||||
sleep 10
|
||||
done
|
||||
|
||||
- name: Test Serve endpoints
|
||||
run: |
|
||||
curl -s http://localhost:3003
|
||||
|
||||
- name: Cache Playwright
|
||||
uses: actions/cache@v3
|
||||
id: playwright-cache
|
||||
|
||||
7
.github/workflows/kamal-deploy.yml
vendored
@@ -5,9 +5,9 @@ concurrency:
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
#push:
|
||||
# branches:
|
||||
# - main
|
||||
|
||||
jobs:
|
||||
Deploy:
|
||||
@@ -57,7 +57,6 @@ jobs:
|
||||
AIRTABLE_CLIENT_ID: ${{ secrets.AIRTABLE_CLIENT_ID }}
|
||||
ENTERPRISE_LICENSE_KEY: ${{ secrets.ENTERPRISE_LICENSE_KEY }}
|
||||
DEFAULT_ORGANIZATION_ID: ${{ vars.DEFAULT_ORGANIZATION_ID }}
|
||||
ONBOARDING_DISABLED: ${{ vars.ONBOARDING_DISABLED }}
|
||||
CUSTOMER_IO_API_KEY: ${{ secrets.CUSTOMER_IO_API_KEY }}
|
||||
CUSTOMER_IO_SITE_ID: ${{ secrets.CUSTOMER_IO_SITE_ID }}
|
||||
NEXT_PUBLIC_POSTHOG_API_KEY: ${{ vars.NEXT_PUBLIC_POSTHOG_API_KEY }}
|
||||
|
||||
1
.github/workflows/kamal-setup.yml
vendored
@@ -54,7 +54,6 @@ jobs:
|
||||
AIRTABLE_CLIENT_ID: ${{ secrets.AIRTABLE_CLIENT_ID }}
|
||||
ENTERPRISE_LICENSE_KEY: ${{ secrets.ENTERPRISE_LICENSE_KEY }}
|
||||
DEFAULT_ORGANIZATION_ID: ${{ vars.DEFAULT_ORGANIZATION_ID }}
|
||||
ONBOARDING_DISABLED: ${{ vars.ONBOARDING_DISABLED }}
|
||||
CUSTOMER_IO_API_KEY: ${{ secrets.CUSTOMER_IO_API_KEY }}
|
||||
CUSTOMER_IO_SITE_ID: ${{ secrets.CUSTOMER_IO_SITE_ID }}
|
||||
NEXT_PUBLIC_POSTHOG_API_KEY: ${{ vars.NEXT_PUBLIC_POSTHOG_API_KEY }}
|
||||
|
||||
6
.github/workflows/lint.yml
vendored
@@ -25,10 +25,10 @@ jobs:
|
||||
- name: create .env
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Generate Random ENCRYPTION_KEY
|
||||
- name: Generate Random ENCRYPTION_KEY and fill in .env
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
|
||||
ENCRYPTION_KEY=$(openssl rand -hex 32)
|
||||
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${ENCRYPTION_KEY}/" .env
|
||||
|
||||
- name: Lint
|
||||
run: pnpm lint
|
||||
|
||||
7
.github/workflows/release-changesets.yml
vendored
@@ -1,9 +1,10 @@
|
||||
name: Release Changesets
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
#push:
|
||||
# branches:
|
||||
# - main
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
|
||||
91
.github/workflows/release-docker-github-experimental.yml
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
name: Docker Release to Github Experimental
|
||||
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: ghcr.io
|
||||
# github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}-experimental
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/formbricks?schema=public"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
# This is used to complete the identity challenge
|
||||
# with sigstore/fulcio when running outside of PRs.
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Depot CLI
|
||||
uses: depot/setup-action@v1
|
||||
|
||||
# Install the cosign tool except on PR
|
||||
# https://github.com/sigstore/cosign-installer
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@v3.5.0
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3 # v3.0.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Extract metadata (tags, labels) for Docker
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5 # v5.0.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
# Build and push Docker image with Buildx (don't push on PR)
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: depot/build-push-action@v1
|
||||
with:
|
||||
project: tw0fqmsx3c
|
||||
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
|
||||
context: .
|
||||
file: ./apps/web/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
# Sign the resulting Docker image digest except on PRs.
|
||||
# This will only write to the public Rekor transparency log when the Docker
|
||||
# repository is public to avoid leaking data. If you would like to publish
|
||||
# transparency data even for private images, pass --force to cosign below.
|
||||
# https://github.com/sigstore/cosign
|
||||
- name: Sign the published Docker image
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
env:
|
||||
# https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
|
||||
TAGS: ${{ steps.meta.outputs.tags }}
|
||||
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||
# This step uses the identity token to provision an ephemeral certificate
|
||||
# against the sigstore community Fulcio instance.
|
||||
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
|
||||
6
.github/workflows/test.yml
vendored
@@ -25,10 +25,10 @@ jobs:
|
||||
- name: create .env
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Generate Random ENCRYPTION_KEY
|
||||
- name: Generate Random ENCRYPTION_KEY and fill in .env
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
|
||||
ENCRYPTION_KEY=$(openssl rand -hex 32)
|
||||
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${ENCRYPTION_KEY}/" .env
|
||||
|
||||
- name: Test
|
||||
run: pnpm test
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const baseConfig = require("./packages/prettier-config/prettier-preset");
|
||||
const baseConfig = require("./packages/config-prettier/prettier-preset");
|
||||
|
||||
module.exports = {
|
||||
...baseConfig,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["formbricks"],
|
||||
extends: ["@formbricks/eslint-config/legacy-next.js"],
|
||||
};
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
ShieldCheckIcon,
|
||||
UsersIcon,
|
||||
} from "lucide-react";
|
||||
|
||||
import { classNames } from "../lib/utils";
|
||||
|
||||
const navigation = [
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
"dependencies": {
|
||||
"@formbricks/js": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"lucide-react": "^0.379.0",
|
||||
"next": "14.2.3",
|
||||
"lucide-react": "^0.395.0",
|
||||
"next": "14.2.4",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-config-formbricks": "workspace:*",
|
||||
"@formbricks/tsconfig": "workspace:*"
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"@formbricks/config-typescript": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { AppProps } from "next/app";
|
||||
import Head from "next/head";
|
||||
|
||||
import "../styles/globals.css";
|
||||
|
||||
const App = ({ Component, pageProps }: AppProps) => {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import formbricks from "@formbricks/js/app";
|
||||
|
||||
import { SurveySwitch } from "../../components/SurveySwitch";
|
||||
import fbsetup from "../../public/fb-setup.png";
|
||||
|
||||
@@ -59,7 +57,7 @@ const AppPage = ({}) => {
|
||||
router.events.off("routeChangeComplete", handleRouteChange);
|
||||
};
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="h-screen bg-white px-12 py-6 dark:bg-slate-800">
|
||||
@@ -142,7 +140,7 @@ const AppPage = ({}) => {
|
||||
|
||||
<div className="p-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">
|
||||
<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">
|
||||
No-Code Action
|
||||
</button>
|
||||
</div>
|
||||
@@ -171,7 +169,7 @@ const AppPage = ({}) => {
|
||||
onClick={() => {
|
||||
formbricks.setAttribute("Plan", "Free");
|
||||
}}
|
||||
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">
|
||||
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">
|
||||
Set Plan to 'Free'
|
||||
</button>
|
||||
</div>
|
||||
@@ -194,7 +192,7 @@ const AppPage = ({}) => {
|
||||
onClick={() => {
|
||||
formbricks.setAttribute("Plan", "Paid");
|
||||
}}
|
||||
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">
|
||||
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">
|
||||
Set Plan to 'Paid'
|
||||
</button>
|
||||
</div>
|
||||
@@ -217,7 +215,7 @@ const AppPage = ({}) => {
|
||||
onClick={() => {
|
||||
formbricks.setEmail("test@web.com");
|
||||
}}
|
||||
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">
|
||||
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">
|
||||
Set Email
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
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";
|
||||
|
||||
@@ -36,7 +34,7 @@ const AppPage = ({}) => {
|
||||
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const defaultAttributes = {
|
||||
language: "de",
|
||||
language: "en",
|
||||
};
|
||||
|
||||
formbricks.init({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "@formbricks/tsconfig/nextjs.json",
|
||||
"extends": "@formbricks/config-typescript/nextjs.json",
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["formbricks"],
|
||||
extends: ["@formbricks/eslint-config/legacy-next.js"],
|
||||
};
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 53 KiB |
@@ -57,12 +57,35 @@ To add a No-Code Action:
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Here are three types of No-Code actions you can set up:
|
||||
Here are four types of No-Code actions you can set up:
|
||||
|
||||
### **1. Page URL Action**
|
||||
### **1. Click Action**
|
||||
|
||||
Click Action is triggered when a user clicks on a specific element within your application. You can define the element's inner text or CSS selector to trigger the survey.
|
||||
|
||||
- **Inner Text**: Checks if the innerText of a clicked HTML element, like a button label, matches a specific text. This action allows you to display a survey based on text interactions within your application.
|
||||
|
||||
- **CSS Selector**: Verifies if a clicked HTML element matches a provided CSS selector, such as a class, ID, or any other CSS selector used in your website. It enables survey triggers based on element interactions.
|
||||
|
||||
### **2. Page view Action**
|
||||
|
||||
This action is triggered when a user visits a page within your application.
|
||||
|
||||
### **3. Exit Intent Action**
|
||||
|
||||
This action is triggered when a user is about to leave your application. It helps capture user feedback before they exit, providing valuable insights into user experiences and potential improvements.
|
||||
|
||||
### **4. 50% Scroll Action**
|
||||
|
||||
This action is triggered when a user scrolls through 50% of a page within your application. It helps capture user feedback at a specific point in their journey, enabling you to gather insights based on user interactions.
|
||||
|
||||
This action is triggered when a user visits a specific page within your application. You can define the URL match conditions as follows:
|
||||
|
||||
<Note>
|
||||
You can combine the url filters with any of the no-code actions to trigger the survey based on the URL match conditions.
|
||||
|
||||
### **URL Match Conditions**
|
||||
|
||||
- **exactMatch**: Triggers the action when the URL exactly matches the specified string.
|
||||
- **contains**: Activates when the URL contains the specified substring.
|
||||
- **startsWith**: Fires when the URL starts with the specified string.
|
||||
@@ -70,15 +93,7 @@ This action is triggered when a user visits a specific page within your applicat
|
||||
- **notMatch**: Triggers when the URL does not match the specified condition.
|
||||
- **notContains**: Activates when the URL does not contain the specified substring.
|
||||
|
||||
### **2. innerText Action**
|
||||
|
||||
Checks if the innerText of a clicked HTML element, like a button label, matches a specific text. This action allows you to display a survey based on text interactions within your application.
|
||||
|
||||
### **3. CSS Selector Action**
|
||||
|
||||
This action verifies if a clicked HTML element matches a provided CSS selector, such as a class, ID, or any other CSS selector used in your website. It enables survey triggers based on element interactions.
|
||||
|
||||
<Note>You can have an action use combination of the 3 types as you wish</Note>
|
||||
</Note>
|
||||
|
||||
## **Setting Up Code Actions**
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 34 KiB |
@@ -22,9 +22,7 @@ export const metadata = {
|
||||
App surveys have 6-10x better conversion rates than emailed out surveys. This tutorial explains how to run an app survey in your web app in 10 to 15 minutes. Let’s go!
|
||||
|
||||
<Note>
|
||||
App Surveys are ideal for websites that **have a user authentication** system. If you are looking to run
|
||||
surveys on your public facing website, head over to the [Website Surveys Quickstart
|
||||
Guide](/website-surveys/quickstart).
|
||||
App Surveys are ideal for websites that **have a user authentication** system. If you are looking to run surveys on your public facing website, head over to the [Website Surveys Quickstart Guide](/website-surveys/quickstart).
|
||||
</Note>
|
||||
|
||||
1. **Create a free Formbricks Cloud account**: While you can [self-host](/self-hosting/deployment) Formbricks, but the quickest and easiest way to get started is with the free Cloud plan. Just [sign up here](https://app.formbricks.com/auth/signup) and you'll be guided to our onboarding like below:
|
||||
|
||||
@@ -41,9 +41,7 @@ To run the Churn Survey in your app you want to proceed as follows:
|
||||
4. Prevent that churn!
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(takes 15mins max.)](/app-surveys/quickstart)
|
||||
## Formbricks Widget running? We assume that you have already installed the Formbricks Widget in your web app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide (takes 15mins max.)](/app-surveys/quickstart)
|
||||
</Note>
|
||||
|
||||
### 1. Create new Churn Survey
|
||||
@@ -80,9 +78,9 @@ In this case, you don’t really need to pre-segment your audience. You likely w
|
||||
|
||||
### 4. Set up a trigger
|
||||
|
||||
To create the trigger for your Churn Survey, you have two options to choose from:
|
||||
To create the trigger for your Churn Survey, you have three options to choose from:
|
||||
|
||||
1. **Trigger by innerText:** You likely have a “Cancel Subscription” button in your app. You can setup a user Action with the according `innerText` to trigger the survey, like so:
|
||||
1. **Trigger by Inner Text:** You likely have a “Cancel Subscription” button in your app. You can setup a user Action with the according `Inner Text` to trigger the survey, like so:
|
||||
|
||||
<MdxImage
|
||||
src={TriggerInnerText}
|
||||
@@ -100,7 +98,7 @@ To create the trigger for your Churn Survey, you have two options to choose from
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. **Trigger by pageURL:** Lastly, you could also display your survey on a subpage “/subscription-cancelled” where you forward users once they cancelled the trial subscription. You can then create a user Action with the type `pageURL` with the following settings:
|
||||
1. **Trigger by page view filters:** Lastly, you could also display your survey on a subpage “/subscription-cancelled” where you forward users once they cancelled the trial subscription. You can then create a user Action with the type `Page View` and add select `Limit to specific pages` to add url filters, with the following settings:
|
||||
|
||||
<MdxImage
|
||||
src={TriggerPageUrl}
|
||||
@@ -111,7 +109,7 @@ To create the trigger for your Churn Survey, you have two options to choose from
|
||||
|
||||
Whenever a user visits this page, matches the filter conditions above and the recontact options (below) the survey will be displayed ✅
|
||||
|
||||
Here is our complete [Actions manual](/actions/why) covering [Code](/actions/code) and [No-Code](/actions/no-code) Actions.
|
||||
Here is our complete [Actions manual](/app-surveys/actions/) covering [No-Code](/app-surveys/actions#setting-up-no-code-actions) and [Code](/app-surveys/actions#setting-up-code-actions) Actions.
|
||||
|
||||
<Note>
|
||||
## Pre-churn flow coming soon We’re currently building full-screen survey pop-ups. You’ll be able to prevent
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 59 KiB |
@@ -38,9 +38,10 @@ To run the Feature Chaser survey in your app you want to proceed as follows:
|
||||
2. Setup a user action to display survey at the right point in time
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web wapp. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(takes 15mins max.)](/app-surveys/quickstart)
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web
|
||||
wapp. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start
|
||||
Guide (takes 15mins max.)](/app-surveys/quickstart)
|
||||
</Note>
|
||||
|
||||
### 1. Create new Feature Chaser
|
||||
@@ -73,11 +74,11 @@ Save, and move over to where the magic happens: The “Audience” tab.
|
||||
|
||||
Before setting the right trigger, you need to identify a user action in your app which signals, that they have just used the feature you want to understand better. In most cases, it is clicking a specific button in your product.
|
||||
|
||||
You can create [Code Actions](/actions/code) and [No Code Actions](/actions/no-code) to follow users through your app. In this example, we will create a No Code Action.
|
||||
You can create [Code Actions](/app-surveys/actions#setting-up-code-actions) and [No Code Actions](/app-surveys/actions#setting-up-no-code-actions) to follow users through your app. In this example, we will create a No Code Action.
|
||||
|
||||
There are two ways to track a button:
|
||||
|
||||
1. **Trigger by innerText:** You might have a button with a unique text at the end of your feature e.g. "Export Report". You can setup a user Action with the according `innerText` to trigger the survey, like so:
|
||||
1. **Trigger by Inner Text:** You might have a button with a unique text at the end of your feature e.g. "Export Report". You can setup a user Action with the according `Inner Text` to trigger the survey, like so:
|
||||
|
||||
<MdxImage
|
||||
src={ActionText}
|
||||
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 57 KiB |
@@ -65,19 +65,18 @@ Change the questions and answer options according to your preference:
|
||||
|
||||
### 3. Create user action to trigger Feedback Box:
|
||||
|
||||
Go to the “Audience” tab, find the “When to send” card and choose “Add Action”. We will now use our super cool No-Code User Action Tracker:
|
||||
Go to the “Audience” tab, find the “When to send” card and choose “Add Action”. We will now use our super cool User Action Tracker:
|
||||
|
||||
<MdxImage src={AddAction} alt="Add action" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
We have two options to track the Feedback Button in your application: innerText and CSS-Selector:
|
||||
|
||||
1. **innerText:** This means that whenever a user clicks any HTML item in your app which has an `innerText` of `Feedback` the Feedback Box will be displayed.
|
||||
2. **CSS-Selector:** This means that when an element with a specific CSS-Selector like `#feedback-button` is clicked, your Feedback Box is triggered.
|
||||
1. **Inner Text:** This means that whenever a user clicks any HTML item in your app which has an `Inner Text` of `Feedback` the Feedback Box will be displayed.
|
||||
|
||||
<div className="grid max-w-full grid-cols-2 space-x-2 sm:max-w-3xl">
|
||||
<MdxImage src={ActionText} alt="Add HTML action" quality="100" className="rounded-lg" />
|
||||
<MdxImage src={ActionCSS} alt="Add CSS action" quality="100" className="rounded-lg" />
|
||||
</div>
|
||||
<MdxImage src={ActionText} alt="Add HTML action" quality="100" className="rounded-lg" />
|
||||
|
||||
2. **CSS Selector:** This means that when an element with a specific CSS-Selector like `#feedback-button` is clicked, your Feedback Box is triggered.
|
||||
<MdxImage src={ActionCSS} alt="Add CSS action" quality="100" className="rounded-lg" />
|
||||
|
||||
### 4. Select action in the “When to ask” card
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 64 KiB |
@@ -38,9 +38,8 @@ To display the Trial Conversion Survey in your app you want to proceed as follow
|
||||
3. Print that 💸
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(takes 15mins max.)](/app-surveys/quickstart)
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide (takes 15mins max.)](/app-surveys/quickstart)
|
||||
</Note>
|
||||
|
||||
### 1. Create new Trial Conversion Survey
|
||||
@@ -84,7 +83,7 @@ Pre-segmentation isn't relevant for this survey because you likely want to solve
|
||||
|
||||
How you trigger your survey depends on your product. There are two options:
|
||||
|
||||
1. **Trigger by pageURL:** Let’s say you have a page under “/trial-cancelled” where you forward users once they cancelled the trial subscription. You can then create an user Action with the type `pageURL` with the following settings:
|
||||
1. **Trigger by Page view:** Let’s say you have a page under “/trial-cancelled” where you forward users once they cancelled the trial subscription. You can then create an user Action with the type `Page View` and add select `Limit to specific pages` to add url filters, with the following settings:
|
||||
|
||||
<MdxImage
|
||||
src={ActionPageurl}
|
||||
@@ -95,7 +94,7 @@ How you trigger your survey depends on your product. There are two options:
|
||||
|
||||
Whenever a user visits this page, the survey will be displayed ✅
|
||||
|
||||
2. **Trigger by Button Click:** In a different case, you have a “Cancel Trial button in your app. You can setup a user Action with the according `innerText` like so:
|
||||
2. **Trigger by Button Click:** In a different case, you have a “Cancel Trial" button in your app. You can setup a user Action with the according `Inner Text` like so:
|
||||
|
||||
<MdxImage
|
||||
src={ActionText}
|
||||
@@ -104,7 +103,7 @@ Whenever a user visits this page, the survey will be displayed ✅
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Please have a look at our complete [Actions manual](/actions/why) if you have questions.
|
||||
Please have a look at our complete [Actions manual](/app-surveys/actions/) if you have questions.
|
||||
|
||||
### 5. Select Action in the “When to ask” card
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 34 KiB |
@@ -43,9 +43,8 @@ To display an Interview Prompt in your app you want to proceed as follows:
|
||||
3. That’s it! 🎉
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(15mins).](/app-surveys/quickstart)
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide (15mins).](/app-surveys/quickstart)
|
||||
</Note>
|
||||
|
||||
### 1. Create new Interview Prompt
|
||||
@@ -86,9 +85,7 @@ Save, and move over to the “Audience” tab.
|
||||
### 3. Pre-segment your audience (coming soon)
|
||||
|
||||
<Note>
|
||||
## Filter by attribute coming soon.
|
||||
We're working on pre-segmenting users by attributes. We will update this
|
||||
manual in the next few days.
|
||||
## Filter by attribute coming soon. We're working on pre-segmenting users by attributes. We will update this manual in the next few days.
|
||||
</Note>
|
||||
|
||||
Once you clicked over to the “Audience” tab you can change the settings. In the **Who To Send** card, select “Filter audience by attribute”. This allows you to only show the prompt to a specific segment of your user base.
|
||||
@@ -99,13 +96,13 @@ Great, now only the “Power User” segment will see our Interview Prompt. But
|
||||
|
||||
### 4. Set up a trigger for the Interview Prompt:
|
||||
|
||||
To create the trigger to show your Interview Prompt, go to the “Audience” tab, find the “When to send” card and choose “Add Action”. We will now use our super cool No-Code User Action Tracker:
|
||||
To create the trigger to show your Interview Prompt, go to the “Audience” tab, find the “When to send” card and choose “Add Action”. We will now use our super cool User Action Tracker:
|
||||
|
||||
<MdxImage src={AddAction} alt="Add action" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
Generally, we have two types of user actions: Page views and clicks. The Interview Prompt, you’ll likely want to display it on a page visit since you already filter who sees the prompt by attributes.
|
||||
|
||||
1. **pageURL:** Whenever a user visits a page the survey will be displayed, as long as the other conditions match. Other conditions are pre-segmentation, if this user has seen a survey in the past 2 weeks, etc.
|
||||
1. **Page view:** Whenever a user visits a page the survey will be displayed, as long as the other conditions match. Other conditions are pre-segmentation, if this user has seen a survey in the past 2 weeks, etc.
|
||||
|
||||
<MdxImage
|
||||
src={ActionPageurl}
|
||||
@@ -114,7 +111,7 @@ Generally, we have two types of user actions: Page views and clicks. The Intervi
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. **innerText & CSS-Selector:** When a user clicks an element (like a button) with a specific text content or CSS selector, the prompt will be displayed as long as the other conditions also match.
|
||||
2. **Click(Inner Text & CSS Selector):** When a user clicks an element (like a button) with a specific text content or CSS selector, the prompt will be displayed as long as the other conditions also match.
|
||||
|
||||
<div className="grid max-w-full grid-cols-2 space-x-2 sm:max-w-3xl">
|
||||
<MdxImage src={ActionCSS} alt="Add CSS action" quality="100" className="rounded-lg" />
|
||||
@@ -146,8 +143,7 @@ Scroll down to “Recontact Options”. Here you have to choose the correct sett
|
||||
<MdxImage src={Publish} alt="Publish survey" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running?
|
||||
You need to have the Formbricks Widget installed to display the Feedback Box in your app. Please follow [this tutorial (Step 4 onwards)](/app-surveys/quickstart) to install the widget.
|
||||
## Formbricks Widget running? You need to have the Formbricks Widget installed to display the Feedback Box in your app. Please follow [this tutorial (Step 4 onwards)](/app-surveys/quickstart) to install the widget.
|
||||
</Note>
|
||||
|
||||
###
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 55 KiB |
@@ -37,9 +37,8 @@ To display the Product-Market Fit survey in your app you want to proceed as foll
|
||||
3. Setup the user action to display survey at good point in time
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(15mins).](/app-surveys/quickstart)
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide (15mins).](/app-surveys/quickstart)
|
||||
</Note>
|
||||
|
||||
### 1. Create new PMF survey
|
||||
@@ -91,7 +90,7 @@ This way you make sure that you separate potentially misleading opinions from va
|
||||
|
||||
### 4. Set up a trigger for the Product-Market Fit survey:
|
||||
|
||||
You need a trigger to display the survey but in this case, the filtering does all the work. It’s up to you to decide to display the survey after the user viewed a specific subpage (pageURL) or after clicking an element. Have a look at the [Actions manual](/actions/why) if you are not sure how to set them up:
|
||||
You need a trigger to display the survey but in this case, the filtering does all the work. It’s up to you to decide to display the survey after the user viewed a specific subpage (pageURL) or after clicking an element. Have a look at the [Actions manual](/app-surveys/actions/) if you are not sure how to set them up:
|
||||
|
||||
<Col>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 56 KiB |
@@ -16,7 +16,7 @@ export const metadata = {
|
||||
|
||||
### Overview
|
||||
|
||||
The Formbricks JS SDK is a 2-in-1 SDK for seamlessly integrating both App Surveys and Website Surveys into your projects. In this section, we'll explore how to leverage the SDK specifically for **app** surveys. It’s available on npm [here](https://www.npmjs.com/package/@formbricks/js/).
|
||||
The Formbricks JS SDK is a 2-in-1 SDK for seamlessly integrating both App Surveys and Website Surveys into your projects. In this section, we'll explore how to leverage the SDK specifically for **app** surveys. It’s available on npm [here](https://www.npmjs.com/package/@formbricks/js/).
|
||||
|
||||
### Install
|
||||
|
||||
@@ -26,9 +26,11 @@ The Formbricks JS SDK is a 2-in-1 SDK for seamlessly integrating both App Survey
|
||||
```js {{ title: 'npm' }}
|
||||
npm install @formbricks/js
|
||||
```
|
||||
|
||||
```js {{ title: 'yarn' }}
|
||||
yarn add @formbricks/js
|
||||
```
|
||||
|
||||
```js {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/js
|
||||
```
|
||||
@@ -51,9 +53,10 @@ import formbricks from "@formbricks/js/app";
|
||||
formbricks.init({
|
||||
environmentId: "<your-environment-id>", // required
|
||||
apiHost: "<your-api-host>", // required
|
||||
userId: "<user-id>" // required
|
||||
userId: "<user-id>", // required
|
||||
});
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
@@ -67,15 +70,16 @@ Formbricks JS is a client SDK meant to be run client-side in their browser so ma
|
||||
|
||||
```js
|
||||
if (window !== undefined) {
|
||||
formbricks.init({
|
||||
environmentId: "<your-environment-id>",
|
||||
apiHost: "<your-api-host>",
|
||||
userId: "<user-id>"
|
||||
});
|
||||
formbricks.init({
|
||||
environmentId: "<your-environment-id>",
|
||||
apiHost: "<your-api-host>",
|
||||
userId: "<user-id>",
|
||||
});
|
||||
} else {
|
||||
console.error("Window object not accessible to init Formbricks");
|
||||
console.error("Window object not accessible to init Formbricks");
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
@@ -91,6 +95,7 @@ You can set custom attributes for the identified user. This can be helpful for s
|
||||
```js
|
||||
formbricks.setAttribute("Plan", "Paid");
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
@@ -104,10 +109,10 @@ Track user actions to trigger surveys based on user interactions, such as button
|
||||
```js
|
||||
formbricks.track("Clicked on Claim");
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
|
||||
### 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.
|
||||
@@ -118,6 +123,7 @@ To log out and deinitialize Formbricks, use the formbricks.logout() function. Th
|
||||
```js
|
||||
formbricks.logout();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
@@ -133,6 +139,7 @@ Reset the current instance and fetch the latest surveys and state again:
|
||||
```js
|
||||
formbricks.reset();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
@@ -140,7 +147,11 @@ formbricks.reset();
|
||||
|
||||
Listen for page changes and dynamically show surveys configured via no-code actions in the Formbricks app:
|
||||
|
||||
<Note> This is only needed when your framework has a custom routing system and you want to trigger surveys on route changes. For example: NextJs</Note>
|
||||
<Note>
|
||||
{" "}
|
||||
This is only needed when your framework has a custom routing system and you want to trigger surveys on route
|
||||
changes. For example: NextJs
|
||||
</Note>
|
||||
|
||||
<Col>
|
||||
<CodeGroup>
|
||||
@@ -148,6 +159,7 @@ Listen for page changes and dynamically show surveys configured via no-code acti
|
||||
```js
|
||||
formbricks.registerRouteChange();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
@@ -167,7 +179,7 @@ In case you don’t see your survey right away, here's what you can do. Go throu
|
||||
|
||||
### Formbricks Cloud and your app are not connected properly.
|
||||
|
||||
Go back to [app.formbricks.com](http://app.formbricks.com) or your self-hosted instance's URL and go to the Setup Checklist in the Settings. If the status is still indicated as “Not connected” your app hasn't yet pinged the Formbricks Cloud:
|
||||
Go back to [app.formbricks.com](http://app.formbricks.com) or your self-hosted instance's URL and go to the App connection in the Configuration. If the status is still indicated as “Not connected” your app hasn't yet pinged the Formbricks Cloud:
|
||||
|
||||
<MdxImage
|
||||
src={I1}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@formbricks/ui/Accordion";
|
||||
|
||||
import { FaqJsonLdComponent } from "./FAQPageJsonLd";
|
||||
|
||||
const FAQ_DATA = [
|
||||
|
||||
@@ -29,8 +29,8 @@ We are so happy that you are interested in contributing to Formbricks 🤗 There
|
||||
- **Issues**: Spotted a bug? Has deployment gone wrong? Do you have user feedback? [Raise an issue](https://github.com/formbricks/formbricks/issues/new/choose) for the fastest response.
|
||||
- **Feature requests**: Raise an issue for these and tag it as an Enhancement. We love every idea. Please give us as much context on the why as possible.
|
||||
- **Creating a PR**: Please fork the repository, make your changes and create a new pull request if you want to make an update.
|
||||
- **E2E Tests**: Understand how we write E2E tests and make sure to write whenever you ship a feature [here](https://www.notion.so/Formbricks-End-to-End-Tests-06dc830d71604deaa8da24714540f7ab?pvs=21).
|
||||
- **Introducing a new Question Type?**: Adding a new question type to our surveys? Follow this guide to make sure you’re on the right track [here](https://www.notion.so/Guidelines-for-Implementing-a-New-Question-Type-9ac0d1c362714addb24b9abeb326d1c1?pvs=21).
|
||||
- **E2E Tests**: Understand how we write E2E tests and make sure to write whenever you ship a feature [here](https://formbricks.notion.site/Formbricks-End-to-End-Tests-06dc830d71604deaa8da24714540f7ab?pvs=4).
|
||||
- **Introducing a new Question Type?**: Adding a new question type to our surveys? Follow this guide to make sure you’re on the right track [here](https://formbricks.notion.site/Guidelines-for-Implementing-a-New-Question-Type-9ac0d1c362714addb24b9abeb326d1c1?pvs=4).
|
||||
- **How we Code at Formbricks**: View this Notion document and understand the coding practises we follow so that you can adhere to them for uniformity.
|
||||
- **How to create a service**: Services are our Database abstraction layer where we connect Prisma (our DB ORM) with logical methods that are reusable across the server. View this document to understand when & how to write them.
|
||||
- **Roadmap**: Our roadmap is open on GitHub tickets and some customer and community tickets on GitHub.
|
||||
@@ -43,7 +43,6 @@ To be able to keep working on Formbricks over the coming years, we need to colle
|
||||
|
||||
Once you open a PR, you will get a message from the CLA bot to fill out the form. Please note that we can only get your contribution merged when we have a CLA signed by you.
|
||||
|
||||
|
||||
## Setup Dev Environment
|
||||
|
||||
We currently officially support the below methods to set up your development environment for Formbricks.
|
||||
@@ -57,7 +56,7 @@ We currently officially support the below methods to set up your development env
|
||||
|
||||
This will open a fully configured workspace in your browser with all the necessary dependencies already installed. Click the button below to open this project in Gitpod. For a detailed guide, visit the **Gitpod Setup Guide** section below.
|
||||
|
||||
[](https://gitpod.io/#https://Github.com/formbricks/formbricks)
|
||||
[](https://gitpod.io/#https://github.com/formbricks/formbricks)
|
||||
|
||||
### Github Codespaces
|
||||
|
||||
@@ -125,8 +124,9 @@ After clicking the one-click setup button, Gitpod will open a new tab or window.
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
- This is the Gitpod Authentication Page. It appears when you click the "Open in GitPod" button and Gitpod needs
|
||||
to authenticate your access to the workspace. Click on 'Continue With Github' to authorize your GitPod session.
|
||||
- This is the Gitpod Authentication Page. It appears when you click the "Open in GitPod" button and Gitpod
|
||||
needs to authenticate your access to the workspace. Click on 'Continue With Github' to authorize your GitPod
|
||||
session.
|
||||
|
||||
### 3. Creating a New Workspace
|
||||
|
||||
@@ -136,11 +136,12 @@ to authenticate your access to the workspace. Click on 'Continue With Github' to
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
- After authentication, Gitpod asks to create a new workspace for you. This page displays the configurations of
|
||||
your workspace. - You can use either choose either VS Code Browser or VS Code Desktop editor with the 'Standard
|
||||
Class' for your workspace class. - If you opt for the VS Code Desktop, follow the following steps 1. Gitpod will
|
||||
prompt you to grant access to the VSCode app. Once approved, install the GitPod extension from the VSCode Marketplace
|
||||
and follow the prompts to authorize the integration. 2. Change the `WEBAPP_URL` and the `NEXTAUTH_URL` to `https://localhost:3000`
|
||||
- After authentication, Gitpod asks to create a new workspace for you. This page displays the configurations
|
||||
of your workspace. - You can use either choose either VS Code Browser or VS Code Desktop editor with the
|
||||
'Standard Class' for your workspace class. - If you opt for the VS Code Desktop, follow the following steps 1.
|
||||
Gitpod will prompt you to grant access to the VSCode app. Once approved, install the GitPod extension from the
|
||||
VSCode Marketplace and follow the prompts to authorize the integration. 2. Change the `WEBAPP_URL` and the
|
||||
`NEXTAUTH_URL` to `https://localhost:3000`
|
||||
|
||||
### 4. Gitpod preparing the created Workspace
|
||||
|
||||
@@ -161,8 +162,8 @@ page while Gitpod sets up your development environment.
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
- Once the workspace is fully prepared, voila, it enters the running state. You can start working on your project
|
||||
in this environment.
|
||||
- Once the workspace is fully prepared, voila, it enters the running state. You can start working on your
|
||||
project in this environment.
|
||||
|
||||
### Ports and Services
|
||||
|
||||
@@ -425,7 +426,7 @@ This usually happens when the Formbricks Widget wasn't correctly or completely b
|
||||
<CodeGroup title="Build js library first and then run again">
|
||||
|
||||
```bash
|
||||
pnpm build --filter=js
|
||||
pnpm build --filter=@formbricks/js
|
||||
|
||||
// Run the app again
|
||||
pnpm dev
|
||||
@@ -441,15 +442,15 @@ Since we're working with a monorepo structure, the repository can get quite big.
|
||||
<CodeGroup title="Only run the required project">
|
||||
|
||||
```bash {{ title: 'Formbricks Web-App' }}
|
||||
pnpm dev --filter=web...
|
||||
pnpm dev --filter=@formbricks/web...
|
||||
```
|
||||
|
||||
```bash {{ title: 'Formbricks Landing Page' }}
|
||||
pnpm dev --filter=formbricks-com...
|
||||
```bash {{ title: 'Formbricks Docs' }}
|
||||
pnpm dev --filter=@formbricks/docs...
|
||||
```
|
||||
|
||||
```bash {{ title: 'Formbricks Demo App' }}
|
||||
pnpm dev --filter=demo...
|
||||
pnpm dev --filter=@formbricks/demo...
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -468,4 +469,3 @@ However, in our experience it's better to run `pnpm dev` than having two termina
|
||||
This happens when you're using the Demo App and delete the Person within the Formbricks app which the widget is currently connected with. We're fixing it, but you can also just logout your test person and reload the page to get rid of it.
|
||||
|
||||
<MdxImage src={Logout} alt="Logout Person" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ export const metadata = {
|
||||
The slack integration allows you to automatically send responses to a Slack channel of your choice.
|
||||
|
||||
<Note>
|
||||
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow the guides [here](/self-hosting/integrations) to configure integrations on your self-hosted instance.
|
||||
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow
|
||||
the guides [here](/self-hosting/integrations) to configure integrations on your self-hosted instance.
|
||||
</Note>
|
||||
|
||||
## Formbricks Cloud
|
||||
|
||||
@@ -15,15 +15,7 @@ export const metadata = {
|
||||
|
||||
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>
|
||||
View our [API Documentation](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh) in more than 30 frameworks and languages.
|
||||
|
||||
## Public Client API
|
||||
|
||||
@@ -67,8 +59,8 @@ The API requests are authorized with a personal API key. This API key gives you
|
||||
/>
|
||||
|
||||
<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.
|
||||
### 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
|
||||
@@ -123,7 +115,8 @@ Hit the below request to verify that you are authenticated with your API Key and
|
||||
"id": "cll2m30r60003mx0hnemjfckr",
|
||||
"name": "My Product"
|
||||
},
|
||||
"widgetSetupCompleted": false
|
||||
"appSetupCompleted": false,
|
||||
"websiteSetupCompleted": false,
|
||||
}
|
||||
```
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
|
||||
|
After Width: | Height: | Size: 59 KiB |
@@ -1,4 +1,5 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import I1 from "./images/1-set-up-website-micro-survey-popup.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks Website Survey SDK",
|
||||
@@ -142,4 +143,25 @@ This activates detailed debug messages in the browser console, providing deeper
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
In case you don’t see your survey right away, here's what you can do. Go through these to find the error fast:
|
||||
|
||||
### Formbricks Cloud and your website are not connected properly.
|
||||
|
||||
Go back to [app.formbricks.com](http://app.formbricks.com) or your self-hosted instance's URL and go to the Website connection in the Configuration. If the status is still indicated as “Not connected” your app hasn't yet pinged the Formbricks Cloud:
|
||||
|
||||
<MdxImage
|
||||
src={I1}
|
||||
alt="setup checklist ui of survey popup for website surveys"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
**How to fix it:**
|
||||
|
||||
1. Check if your website loads the Formbricks widget correctly.
|
||||
2. Make sure you have `debug` mode enabled in your integration and you should see the Formbricks debug logs in your browser console while being in your app (right click in the browser, `Inspect`, switch to the console tab). If you don’t see them, double check your integration.
|
||||
|
||||
---
|
||||
|
||||
If you have any questions or need help, feel free to reach out to us on our **[Discord](https://formbricks.com/discord)**
|
||||
|
||||
BIN
apps/docs/app/global/access-roles/images/team-settings-menu.webp
Normal file
|
After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
@@ -1,139 +0,0 @@
|
||||
import { MdxImage } from "@/components/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 won’t 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>
|
||||
|
||||
Can’t figure it out? Join our [Discord](https://discord.com/invite/3YFcABF2Ts) and we'd be glad to assist you!
|
||||
|
||||
---
|
||||
BIN
apps/docs/app/global/hidden-fields/filled-hidden-fields.webp
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
apps/docs/app/global/hidden-fields/hidden-field-responses.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
apps/docs/app/global/hidden-fields/hidden-fields.webp
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
apps/docs/app/global/hidden-fields/input-hidden-fields.webp
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
79
apps/docs/app/global/hidden-fields/page.mdx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import FilledHiddenFields from "./filled-hidden-fields.webp";
|
||||
import HiddenFieldResponses from "./hidden-field-responses.webp";
|
||||
import HiddenFields from "./hidden-fields.webp";
|
||||
import InputHiddenFields from "./input-hidden-fields.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Hidden Fields",
|
||||
description: "Add hidden fields to your surveys to capture additional data without requiring user inputs!",
|
||||
};
|
||||
|
||||
# Hidden Fields
|
||||
|
||||
Hidden fields are a powerful feature in Formbricks that allows you to add data to a submission without asking the user to type it in. This feature is especially useful when you already have information about a user that you want to use in the analysis of the survey results (e.g. `payment plan` or `email`)
|
||||
|
||||
<Note>Hidden fields are now available in the Formbricks in-app and website surveys as well</Note>
|
||||
|
||||
## How to Add Hidden Fields
|
||||
|
||||
### Enable them in the Survey Builder
|
||||
|
||||
1. Edit the survey you want to add hidden fields to & switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Hidden Fields**. Make sure to enable it by toggling the switch.
|
||||
|
||||
<MdxImage
|
||||
src={HiddenFields}
|
||||
alt="Enable Hidden Fields"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Now click on it to add a new hidden field ID. You can add as many hidden fields as you want.
|
||||
|
||||
<MdxImage
|
||||
src={InputHiddenFields}
|
||||
alt="Add Hidden Fields"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
<MdxImage
|
||||
src={FilledHiddenFields}
|
||||
alt="Filled Hidden Fields"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Set Hidden Field
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Example Screen from which the User filled it">
|
||||
|
||||
```sh
|
||||
formbricks.track("my event", {
|
||||
hiddenFields: {
|
||||
screen: "landing_page",
|
||||
job: "Founder"
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
## View Hidden Fields in Responses
|
||||
|
||||
These hidden fields will now be visible in the responses tab just like other fields in the Summary as well as the Response Cards, and you can use them to filter and analyze your responses.
|
||||
|
||||
<MdxImage
|
||||
src={HiddenFieldResponses}
|
||||
alt="Hidden Field Responses"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Use Cases
|
||||
|
||||
- **User Metadata**: You can add hidden fields to capture user metadata such as user ID, email, or any other user-specific information.
|
||||
- **Survey Metadata**: You can add hidden fields to capture other metadata, e.g. the screen from which the survey was filled, or any other app specific information.
|
||||
@@ -49,7 +49,7 @@ How to deliver a specific language depends on the survey type (app or link surve
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Click on the **Edit Languages** button, to add a new language to your survey
|
||||
2. Click on the **Edit languages** button, to add a new language to your survey
|
||||
|
||||
<MdxImage
|
||||
src={SurveyLanguageSettings}
|
||||
@@ -58,7 +58,7 @@ How to deliver a specific language depends on the survey type (app or link surve
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. Select the preferred language from the dropdown and assign an identifier Alias. Click the **Add Language** button to add the language to your product.
|
||||
3. Select the preferred language from the dropdown and assign an identifier Alias. Click the **Add language** button to add the language to your product.
|
||||
|
||||
<MdxImage
|
||||
src={AddLanguages}
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -43,7 +43,7 @@ Set up this feature to control how many users see your survey, using a simple sl
|
||||
4. **Adjust User Visibility Percentage**:
|
||||
|
||||
- Find the **`Show Survey to % of Users`** toggle. Enable it.
|
||||
- Use the slider to select the desired percentage (from 1% to 100%) of users to whom the survey will be shown.
|
||||
- Enter the desired percentage (from 0.01% to 100%) of users to whom the survey will be shown.
|
||||
|
||||
{" "}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 57 KiB |
@@ -4,7 +4,6 @@ import FilledHiddenFields from "./filled-hidden-fields.webp";
|
||||
import HiddenFieldResponses from "./hidden-field-responses.webp";
|
||||
import HiddenFields from "./hidden-fields.webp";
|
||||
import InputHiddenFields from "./input-hidden-fields.webp";
|
||||
import SettingsPage from "./settings.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Hidden Fields",
|
||||
@@ -21,16 +20,7 @@ Hidden fields are a powerful feature in Formbricks that allows you to add data t
|
||||
|
||||
### Enable them in the Survey Builder
|
||||
|
||||
1. Edit the survey you want to add hidden fields to & open it's settings, make sure it's selected as a **Link Survey**.
|
||||
|
||||
<MdxImage
|
||||
src={SettingsPage}
|
||||
alt="Select the Survey Type as Link Survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Hidden Fields**. Make sure to enable it by toggling the switch.
|
||||
1. Edit the survey you want to add hidden fields to & switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Hidden Fields**. Make sure to enable it by toggling the switch.
|
||||
|
||||
<MdxImage
|
||||
src={HiddenFields}
|
||||
@@ -39,7 +29,7 @@ Hidden fields are a powerful feature in Formbricks that allows you to add data t
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. Now click on it to add a new hidden field ID. You can add as many hidden fields as you want.
|
||||
2. Now click on it to add a new hidden field ID. You can add as many hidden fields as you want.
|
||||
|
||||
<MdxImage
|
||||
src={InputHiddenFields}
|
||||
|
||||
|
Before Width: | Height: | Size: 39 KiB |
@@ -3,7 +3,7 @@ import { MdxImage } from "@/components/MdxImage";
|
||||
import PeopleView from "./people-view.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Effective Identify Users in Formbricks Link Surveys",
|
||||
title: "Effectively identify users in Formbricks link surveys",
|
||||
description:
|
||||
"Discover how to seamlessly connect responses from Formbricks link surveys to existing users in your database. Learn the intricacies of the userId URL parameter to enhance user tracking, profiling, and segmentation, ensuring more personalized interactions and data-driven decisions.",
|
||||
};
|
||||
|
||||
@@ -28,7 +28,6 @@ These variables are present inside your machine’s docker-compose file. Restart
|
||||
| PRIVACY_URL | URL for privacy policy. | optional | |
|
||||
| TERMS_URL | URL for terms of service. | optional | |
|
||||
| IMPRINT_URL | URL for imprint. | optional | |
|
||||
| SIGNUP_DISABLED | Disables the ability for new users to create an account if set to 1. | optional | |
|
||||
| EMAIL_AUTH_DISABLED | Disables the ability for users to signup or login via email and password if set to 1. | optional | |
|
||||
| PASSWORD_RESET_DISABLED | Disables password reset functionality if set to 1. | optional | |
|
||||
| EMAIL_VERIFICATION_DISABLED | Disables email verification if set to 1. | optional | |
|
||||
@@ -53,13 +52,13 @@ These variables are present inside your machine’s docker-compose file. Restart
|
||||
| DEFAULT_BRAND_COLOR | Default brand color for your app (Can be overwritten from the UI as well). | optional | #64748b |
|
||||
| DEFAULT_ORGANIZATION_ID | Automatically assign new users to a specific organization when joining | optional | |
|
||||
| DEFAULT_ORGANIZATION_ROLE | Role of the user in the default organization. | optional | admin |
|
||||
| ONBOARDING_DISABLED | Disables onboarding for new users if set to 1 | optional | |
|
||||
| OIDC_DISPLAY_NAME | Display name for Custom OpenID Connect Provider | optional | |
|
||||
| OIDC_CLIENT_ID | Client ID for Custom OpenID Connect Provider | optional (required if OIDC auth is enabled) | |
|
||||
| OIDC_CLIENT_SECRET | Secret for Custom OpenID Connect Provider | optional (required if OIDC auth is enabled) | |
|
||||
| OIDC_ISSUER | Issuer URL for Custom OpenID Connect Provider (should have .well-known configured at this) | optional (required if OIDC auth is enabled) | |
|
||||
| OIDC_SIGNING_ALGORITHM | Signing Algorithm for Custom OpenID Connect Provider | optional | RS256 |
|
||||
| OPENTELEMETRY_LISTENER_URL | URL for OpenTelemetry listener inside Formbricks. | optional | |
|
||||
| CUSTOM_CACHE_DISABLED | Disables custom cache handler if set to 1 (required for deployment on Vercel) | optional | |
|
||||
| `<add more>` | | | |
|
||||
| | | | |
|
||||
|
||||
@@ -176,10 +175,12 @@ An example configuration for a FusionAuth OpenID Connect in Formbricks would loo
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Formbricks Env for FusionAuth OIDC">
|
||||
```yml {{ title: ".env" }}
|
||||
OIDC_CLIENT_ID=59cada54-56d4-4aa8-a5e7-5823bbe0e5b7 OIDC_CLIENT_SECRET=4f4dwP0ZoOAqMW8fM9290A7uIS3E8Xg29xe1umhlB_s
|
||||
OIDC_ISSUER=http://localhost:9011 OIDC_DISPLAY_NAME=FusionAuth OIDC_SIGNING_ALGORITHM=HS256
|
||||
```
|
||||
```yml {{ title: ".env" }}
|
||||
OIDC_CLIENT_ID=59cada54-56d4-4aa8-a5e7-5823bbe0e5b7
|
||||
OIDC_CLIENT_SECRET=4f4dwP0ZoOAqMW8fM9290A7uIS3E8Xg29xe1umhlB_s
|
||||
OIDC_ISSUER=http://localhost:9011
|
||||
OIDC_DISPLAY_NAME=FusionAuth OIDC_SIGNING_ALGORITHM=HS256
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
|
||||
@@ -8,6 +8,207 @@ export const metadata = {
|
||||
|
||||
# Migration Guide
|
||||
|
||||
## v2.2
|
||||
|
||||
Formbricks v2.2 introduces XM research presets into your products with a brand new product onboarding. Our objective is to make user research “obviously easy”, industry by industry. And we're starting with Software-as-a-Service and E-Commerce.
|
||||
|
||||
### Steps to Migrate
|
||||
|
||||
This guide is for users who are self-hosting Formbricks using our one-click setup. If you are using a different setup, you might adjust the commands accordingly.
|
||||
|
||||
To run all these steps, please navigate to the `formbricks` folder where your `docker-compose.yml` file is located.
|
||||
|
||||
1. **Backup your Database**: This is a crucial step. Please make sure to backup your database before proceeding with the upgrade. You can use the following command to backup your database:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Backup Postgres">
|
||||
|
||||
```bash
|
||||
docker exec formbricks-postgres-1 pg_dump -Fc -U postgres -d formbricks > formbricks_pre_v2.2_$(date +%Y%m%d_%H%M%S).dump
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
<Note>
|
||||
If you run into “No such container”, use `docker ps` to find your container name, e.g.
|
||||
`formbricks_postgres_1`.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
If you prefer storing the backup as an `*.sql` file remove the `-Fc` (custom format) option. In case of a
|
||||
restore scenario you will need to use `psql` then with an empty `formbricks` database.
|
||||
</Note>
|
||||
|
||||
2. Pull the latest version of Formbricks:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker compose pull
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
3. Stop the running Formbricks instance & remove the related containers:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
4. Restarting the containers with the latest version of Formbricks:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Restart the containers">
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
5. Now let's migrate the data to the latest schema:
|
||||
|
||||
<Note>To find your Docker Network name for your Postgres Database, find it using `docker network ls`</Note>
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Migrate the data">
|
||||
|
||||
```bash
|
||||
docker pull ghcr.io/formbricks/data-migrations:latest && \
|
||||
docker run --rm \
|
||||
--network=formbricks_default \
|
||||
-e DATABASE_URL="postgresql://postgres:postgres@postgres:5432/formbricks?schema=public" \
|
||||
-e UPGRADE_TO_VERSION="v2.2" \
|
||||
ghcr.io/formbricks/data-migrations:latest
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
The above command will migrate your data to the latest schema. This is a crucial step to migrate your existing data to the new structure. Only if the script runs successful, changes are made to the database. The script can safely run multiple times.
|
||||
|
||||
6. That's it! Once the migration is complete, you can **now access your Formbricks instance** at the same URL as before.
|
||||
|
||||
### Changes in Environment Variables
|
||||
|
||||
- `ONBOARDING_DISABLED` is now deprecated since we replaced the user onboarding with a product onboarding that only runs when creating a new product.
|
||||
|
||||
## v2.1
|
||||
|
||||
Formbricks v2.1 introduces more options for creating No-Code Actions and lays the foundation for easier self-hosting of Formbricks starting with an Onboarding for fresh instances.
|
||||
|
||||
<Note>
|
||||
To improve the user experience in self-hosting instances and to simplify setup, we are moving to a single
|
||||
organization approach for self-hosting instances with this release. This will allow self-hosters to
|
||||
centrally manage their instance and more easily restrict access to the instance. We will soon introduce a
|
||||
new permissions system that will allow more granular access to projects and other resources within an
|
||||
organization. If you have created multiple organizations in the past, you will still be able to switch
|
||||
between them in the UI, but don't have an option to create new organizations.
|
||||
</Note>
|
||||
|
||||
### Steps to Migrate
|
||||
|
||||
This guide is for users who are self-hosting Formbricks using our one-click setup. If you are using a different setup, you might adjust the commands accordingly.
|
||||
|
||||
To run all these steps, please navigate to the `formbricks` folder where your `docker-compose.yml` file is located.
|
||||
|
||||
1. **Backup your Database**: This is a crucial step. Please make sure to backup your database before proceeding with the upgrade. You can use the following command to backup your database:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Backup Postgres">
|
||||
|
||||
```bash
|
||||
docker exec formbricks-postgres-1 pg_dump -Fc -U postgres -d formbricks > formbricks_pre_v2.1_$(date +%Y%m%d_%H%M%S).dump
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
<Note>
|
||||
If you run into “No such container”, use `docker ps` to find your container name, e.g.
|
||||
`formbricks_postgres_1`.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
If you prefer storing the backup as an `*.sql` file remove the `-Fc` (custom format) option. In case of a
|
||||
restore scenario you will need to use `psql` then with an empty `formbricks` database.
|
||||
</Note>
|
||||
|
||||
2. Pull the latest version of Formbricks:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker compose pull
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
3. Stop the running Formbricks instance & remove the related containers:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
4. Restarting the containers with the latest version of Formbricks:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Restart the containers">
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
5. Now let's migrate the data to the latest schema:
|
||||
|
||||
<Note>To find your Docker Network name for your Postgres Database, find it using `docker network ls`</Note>
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Migrate the data">
|
||||
|
||||
```bash
|
||||
docker pull ghcr.io/formbricks/data-migrations:latest && \
|
||||
docker run --rm \
|
||||
--network=formbricks_default \
|
||||
-e DATABASE_URL="postgresql://postgres:postgres@postgres:5432/formbricks?schema=public" \
|
||||
-e UPGRADE_TO_VERSION="v2.1" \
|
||||
ghcr.io/formbricks/data-migrations:latest
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
The above command will migrate your data to the latest schema. This is a crucial step to migrate your existing data to the new structure. Only if the script runs successful, changes are made to the database. The script can safely run multiple times.
|
||||
|
||||
6. That's it! Once the migration is complete, you can **now access your Formbricks instance** at the same URL as before.
|
||||
|
||||
### Changes in Environment Variables
|
||||
|
||||
- `SIGNUP_DISABLED` is now deprecated since self-hosting instaces have signup disabled by default and new users can only be invited by the organization owner or admin.
|
||||
- `DEFAULT_TEAM_ID` got renamed to `DEFAULT_ORGANIZATION_ID`
|
||||
- `DEFAULT_TEAM_ROLE` got renamed to `DEFAULT_ORGANIZATION_ROLE`
|
||||
|
||||
## v2.0
|
||||
|
||||
Formbricks v2.0 comes with huge features such as Multi-Language Surveys and Advanced Styling for Surveys. We have also shipped various optimisations, bug fixes & smaller fixes on the way to make your experience more seamless. This guide will help you migrate your existing Formbricks instance to v2.0 without any hassles or build errors.
|
||||
@@ -63,7 +264,7 @@ docker exec formbricks-postgres-1 pg_dump -Fc -U postgres -d formbricks > formbr
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker-compose pull
|
||||
docker compose pull
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -75,7 +276,7 @@ docker-compose pull
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker-compose down
|
||||
docker compose down
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -87,7 +288,7 @@ docker-compose down
|
||||
<CodeGroup title="Restart the containers">
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -219,7 +420,7 @@ docker exec formbricks-quickstart-postgres-1 pg_dump -Fc -U postgres -d formbric
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker-compose down
|
||||
docker compose down
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -231,7 +432,7 @@ docker-compose down
|
||||
<CodeGroup title="Restart the containers">
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
@@ -26,6 +26,7 @@ Before you proceed, make sure you have the following:
|
||||
|
||||
- A **Linux Ubuntu** Virtual Machine deployed with SSH access.
|
||||
- An **A record** set up to connect a custom domain to your instance. Formbricks will **automatically create an SSL certificate** for your domain using Let's Encrypt.
|
||||
- **Port 80 and 443** open in your VM's Security Group to allow Traefik to create the SSL certificate.
|
||||
|
||||
## Start
|
||||
|
||||
@@ -91,7 +92,7 @@ File '/etc/apt/keyrings/docker.gpg' exists. Overwrite? (y/N)
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
3. **Domain Name**: Enter the domain name that Traefik will use to create the SSL certificate and forward requests to Formbricks.
|
||||
3. **Domain Name**: Enter the domain name that Traefik will use to create the SSL certificate and forward requests to Formbricks. Please make sure that port 80 and 443 are open in your VM's Security Group to allow Traefik to create the SSL certificate.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Domain Name for SSL certificate Prompt">
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 53 KiB |
@@ -57,26 +57,44 @@ Formbricks provides an intuitive No-Code interface for configuring actions, enab
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
/>
|
||||
Here are three types of No-Code actions you can set up:
|
||||
|
||||
### **1. Page URL Action**
|
||||
Here are four types of No-Code actions you can set up:
|
||||
|
||||
Triggers a survey when a specific URL page condition is met. Setup options include:
|
||||
### **1. Click Action**
|
||||
|
||||
- **exactMatch**: Triggers the survey when the URL exactly matches the specified string.
|
||||
- **contains**: Triggers the survey when the URL contains a specified substring.
|
||||
- **startsWith**: Triggers the survey when the URL starts with a specified string.
|
||||
- **endsWith**: Triggers the survey when the URL ends with a specified string.
|
||||
- **notMatch**: Triggers the survey when the URL does not match a specified condition.
|
||||
- **notContains**: Triggers the survey when the URL does not contain a specified substring.
|
||||
Click Action is triggered when a user clicks on a specific element within your application. You can define the element's inner text or CSS selector to trigger the survey.
|
||||
|
||||
### **2. innerText Action**
|
||||
- **Inner Text**: Checks if the innerText of a clicked HTML element, like a button label, matches a specific text. This action allows you to display a survey based on text interactions within your application.
|
||||
|
||||
Activated when the innerText of a clicked HTML element, such as a button or link, matches specified text. This is useful for triggering surveys related to specific content interactions.
|
||||
- **CSS Selector**: Verifies if a clicked HTML element matches a provided CSS selector, such as a class, ID, or any other CSS selector used in your website. It enables survey triggers based on element interactions.
|
||||
|
||||
### **3. CSS Selector Action**
|
||||
### **2. Page view Action**
|
||||
|
||||
Triggers a survey when a clicked HTML element matches a specified CSS selector, such as a class, ID, or other CSS selector. This allows for precise control over survey triggers based on site structure and design.
|
||||
This action is triggered when a user visits a page within your application.
|
||||
|
||||
### **3. Exit Intent Action**
|
||||
|
||||
This action is triggered when a user is about to leave your application. It helps capture user feedback before they exit, providing valuable insights into user experiences and potential improvements.
|
||||
|
||||
### **4. 50% Scroll Action**
|
||||
|
||||
This action is triggered when a user scrolls through 50% of a page within your application. It helps capture user feedback at a specific point in their journey, enabling you to gather insights based on user interactions.
|
||||
|
||||
This action is triggered when a user visits a specific page within your application. You can define the URL match conditions as follows:
|
||||
|
||||
<Note>
|
||||
You can combine the url filters with any of the no-code actions to trigger the survey based on the URL match conditions.
|
||||
|
||||
### **URL Match Conditions**
|
||||
|
||||
- **exactMatch**: Triggers the action when the URL exactly matches the specified string.
|
||||
- **contains**: Activates when the URL contains the specified substring.
|
||||
- **startsWith**: Fires when the URL starts with the specified string.
|
||||
- **endsWith**: Executes when the URL ends with the specified string.
|
||||
- **notMatch**: Triggers when the URL does not match the specified condition.
|
||||
- **notContains**: Activates when the URL does not contain the specified substring.
|
||||
|
||||
</Note>
|
||||
|
||||
## **Setting Up Code Actions**
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 34 KiB |
@@ -22,9 +22,7 @@ export const metadata = {
|
||||
Website Surveys make it easy for your public website visitors to give you feedback. They are a great way to get feedback from your users, without interrupting their workflow. This quickstart guide will show you how to create your first website survey in under 5 minutes.
|
||||
|
||||
<Note>
|
||||
Website Surveys are ideal for **public facing websites**. If you are looking to run surveys in your app
|
||||
where you have user identification & want advanced user targeting, head over to the [App Surveys Quickstart
|
||||
Guide](/app-surveys/quickstart).
|
||||
Website Surveys are ideal for **public facing websites**. If you are looking to run surveys in your app where you have user identification & want advanced user targeting, head over to the [App Surveys Quickstart Guide](/app-surveys/quickstart).
|
||||
</Note>
|
||||
|
||||
1. **Create a free Formbricks Cloud account**: While you can [self-host](/self-hosting/deployment) Formbricks, but the quickest and easiest way to get started is with the free Cloud plan. Just [sign up here](https://app.formbricks.com/auth/signup) and you'll be guided to our onboarding like below:
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { navigation } from "@/lib/navigation";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
import { Button } from "./Button";
|
||||
import { DiscordIcon } from "./icons/DiscordIcon";
|
||||
import { GithubIcon } from "./icons/GithubIcon";
|
||||
@@ -116,7 +115,7 @@ const SmallPrint = () => {
|
||||
|
||||
export const Footer = () => {
|
||||
return (
|
||||
<footer className="mx-auto w-full max-w-2xl space-y-10 pb-16 lg:max-w-5xl">
|
||||
<footer className="my-10 flex-auto pb-16">
|
||||
<PageNavigation />
|
||||
<SmallPrint />
|
||||
</footer>
|
||||
|
||||
@@ -6,7 +6,6 @@ import clsx from "clsx";
|
||||
import { motion, useScroll, useTransform } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
import { forwardRef } from "react";
|
||||
|
||||
import { Button } from "./Button";
|
||||
import { MobileNavigation, useIsInsideMobileNavigation, useMobileNavigationStore } from "./MobileNavigation";
|
||||
import { ThemeToggle } from "./ThemeToggle";
|
||||
|
||||
@@ -44,7 +44,7 @@ const Anchor = ({ id, inView, children }: { id: string; inView: boolean; childre
|
||||
);
|
||||
};
|
||||
|
||||
export const Heading = <Level extends 2 | 3>({
|
||||
export const Heading = <Level extends 2 | 3 | 4>({
|
||||
children,
|
||||
tag,
|
||||
label,
|
||||
@@ -59,11 +59,11 @@ export const Heading = <Level extends 2 | 3>({
|
||||
anchor?: boolean;
|
||||
}) => {
|
||||
level = level ?? (2 as Level);
|
||||
let Component = `h${level}` as "h2" | "h3";
|
||||
let ref = useRef<HTMLHeadingElement>(null);
|
||||
let registerHeading = useSectionStore((s) => s.registerHeading);
|
||||
const Component: "h2" | "h3" | "h4" = `h${level}`;
|
||||
const ref = useRef<HTMLHeadingElement>(null);
|
||||
const registerHeading = useSectionStore((s) => s.registerHeading);
|
||||
|
||||
let inView = useInView(ref, {
|
||||
const inView = useInView(ref, {
|
||||
margin: `${remToPx(-3.5)}px 0px 0px 0px`,
|
||||
amount: "all",
|
||||
});
|
||||
@@ -71,8 +71,12 @@ export const Heading = <Level extends 2 | 3>({
|
||||
useEffect(() => {
|
||||
if (level === 2) {
|
||||
registerHeading({ id: props.id, ref, offsetRem: tag || label ? 8 : 6 });
|
||||
} else if (level === 3) {
|
||||
registerHeading({ id: props.id, ref, offsetRem: tag || label ? 7 : 5 });
|
||||
} else if (level === 4) {
|
||||
registerHeading({ id: props.id, ref, offsetRem: tag || label ? 6 : 4 });
|
||||
}
|
||||
});
|
||||
}, [label, level, props.id, registerHeading, tag]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
import { Logo } from "@/components/Logo";
|
||||
import { Navigation } from "@/components/Navigation";
|
||||
import { SideNavigation } from "@/components/SideNavigation";
|
||||
import { motion } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
import { Footer } from "./Footer";
|
||||
import { Header } from "./Header";
|
||||
import { type Section, SectionProvider } from "./SectionProvider";
|
||||
@@ -17,7 +17,7 @@ export const Layout = ({
|
||||
children: React.ReactNode;
|
||||
allSections: Record<string, Array<Section>>;
|
||||
}) => {
|
||||
let pathname = usePathname();
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<SectionProvider sections={allSections[pathname || ""] ?? []}>
|
||||
@@ -35,9 +35,12 @@ export const Layout = ({
|
||||
<Navigation className="hidden lg:mt-10 lg:block" isMobile={false} />
|
||||
</div>
|
||||
</motion.header>
|
||||
<div className="relative flex h-full flex-col px-4 pt-14 sm:px-6 lg:px-8">
|
||||
<main className="flex-auto">{children}</main>
|
||||
<Footer />
|
||||
<div className="flex h-screen flex-col">
|
||||
<div className="flex flex-col px-4 pt-14 sm:px-6 lg:w-[calc(100%-20rem)] lg:px-8">
|
||||
<main className="overflow-y-auto overflow-x-hidden">{children}</main>
|
||||
<Footer />
|
||||
</div>
|
||||
<SideNavigation pathname={pathname} />
|
||||
</div>
|
||||
</div>
|
||||
</SectionProvider>
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import Image, { ImageProps } from "next/image";
|
||||
import React from "react";
|
||||
|
||||
export const MdxImage = (props: ImageProps) => {
|
||||
return <Image {...props} alt={props.alt} />;
|
||||
return (
|
||||
<Image
|
||||
{...props}
|
||||
alt={props.alt}
|
||||
sizes="100vw"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,6 @@ import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import { Button } from "./Button";
|
||||
import { useIsInsideMobileNavigation } from "./MobileNavigation";
|
||||
import { useSectionStore } from "./SectionProvider";
|
||||
|
||||
82
apps/docs/components/SideNavigation.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { useTableContentObserver } from "@/hooks/useTableContentObserver";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
type Heading = {
|
||||
id: string;
|
||||
text: string | null;
|
||||
level: number;
|
||||
};
|
||||
|
||||
export const SideNavigation = ({ pathname }) => {
|
||||
const [headings, setHeadings] = useState<Heading[]>([]);
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||
|
||||
useTableContentObserver(setSelectedId, pathname);
|
||||
|
||||
useEffect(() => {
|
||||
const getHeadings = () => {
|
||||
// Select all heading elements (h2, h3, h4) with an 'id' attribute
|
||||
const headingElements = document.querySelectorAll("h2[id], h3[id], h4[id]");
|
||||
// Convert the NodeList of heading elements into an array and map them to an array of 'Heading' objects
|
||||
const headings: Heading[] = Array.from(headingElements).map((heading) => ({
|
||||
id: heading.id,
|
||||
text: heading.textContent,
|
||||
level: parseInt(heading.tagName.slice(1)),
|
||||
}));
|
||||
|
||||
// Check if there are any h2 headings in the list
|
||||
const hasH2 = headings.some((heading) => heading.level === 2);
|
||||
|
||||
// Update the 'headings' state with the retrieved headings, but only if there are h2 headings
|
||||
setHeadings(hasH2 ? headings : []);
|
||||
};
|
||||
|
||||
getHeadings();
|
||||
}, [pathname]);
|
||||
|
||||
const renderHeading = (items: Heading[], currentLevel: number) => (
|
||||
<ul className="ml-1 mt-4">
|
||||
{items.map((heading, index) => {
|
||||
if (heading.level === currentLevel) {
|
||||
let nextIndex = index + 1;
|
||||
while (nextIndex < items.length && items[nextIndex].level > currentLevel) {
|
||||
nextIndex++;
|
||||
}
|
||||
|
||||
return (
|
||||
<li
|
||||
key={heading.text}
|
||||
className={`mb-4 ml-4 text-slate-900 dark:text-white ml-${heading.level === 2 ? 0 : heading.level === 3 ? 4 : 6}`}>
|
||||
<Link
|
||||
href={`#${heading.id}`}
|
||||
onClick={() => setSelectedId(heading.id)}
|
||||
className={`${
|
||||
heading.id === selectedId
|
||||
? "text-brand font-medium text-opacity-35"
|
||||
: "font-normal text-slate-600 hover:text-slate-950 dark:text-white dark:hover:text-slate-50"
|
||||
}`}>
|
||||
{heading.text}
|
||||
</Link>
|
||||
{nextIndex > index + 1 && renderHeading(items.slice(index + 1, nextIndex), currentLevel + 1)}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
|
||||
if (headings.length) {
|
||||
return (
|
||||
<aside className="fixed right-0 top-0 hidden h-[calc(100%-2.5rem)] w-80 overflow-hidden overflow-y-auto pr-8 pt-16 text-sm [scrollbar-width:none] lg:mt-10 lg:block">
|
||||
<div className="border-l border-slate-200 dark:border-slate-700">
|
||||
<h3 className="ml-5 mt-1 text-xs font-semibold uppercase text-slate-400">on this page</h3>
|
||||
{renderHeading(headings, 2)}
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -19,10 +19,19 @@ export const wrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const h2 = (props: Omit<React.ComponentPropsWithoutRef<typeof Heading>, "level">) => {
|
||||
return <Heading level={2} {...props} />;
|
||||
const createHeadingComponent = (level: 2 | 3 | 4) => {
|
||||
const Component = (props: Omit<React.ComponentPropsWithoutRef<typeof Heading>, "level">) => {
|
||||
return <Heading level={level} {...props} />;
|
||||
};
|
||||
|
||||
Component.displayName = `H${level}`;
|
||||
return Component;
|
||||
};
|
||||
|
||||
export const h2 = createHeadingComponent(2);
|
||||
export const h3 = createHeadingComponent(3);
|
||||
export const h4 = createHeadingComponent(4);
|
||||
|
||||
const InfoIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
return (
|
||||
<svg viewBox="0 0 16 16" aria-hidden="true" {...props}>
|
||||
|
||||
71
apps/docs/hooks/useTableContentObserver.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
interface HeadingElement extends IntersectionObserverEntry {
|
||||
target: HTMLHeadingElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom hook that sets up an IntersectionObserver to track the visibility of headings on the page.
|
||||
*
|
||||
* @param {Function} setActiveId - A function to set the active heading ID.
|
||||
* @param {string} pathname - The current pathname, used as a dependency for the useEffect hook.
|
||||
* @returns {void}
|
||||
*
|
||||
* This hook performs the following tasks:
|
||||
* 1. Creates a map of heading elements, where the key is the heading's ID and the value is the heading element.
|
||||
* 2. Finds the visible headings (i.e., headings that are currently intersecting with the viewport).
|
||||
* 3. If there is only one visible heading, sets it as the active heading using the `setActiveId` function.
|
||||
* 4. If there are multiple visible headings, sets the active heading to the one that is highest on the page (i.e., the one with the lowest index in the `headingElements` array).
|
||||
* 5. Cleans up the IntersectionObserver and the `headingElementsRef` when the component is unmounted.
|
||||
*/
|
||||
export const useTableContentObserver = (setActiveId: (id: string) => void, pathname: string) => {
|
||||
const headingElementsRef = useRef<Record<string, HeadingElement>>({});
|
||||
|
||||
useEffect(() => {
|
||||
const callback = (headings: HeadingElement[]) => {
|
||||
// Create a map of heading elements, where the key is the heading's ID and the value is the heading element
|
||||
headingElementsRef.current = headings.reduce(
|
||||
(map, headingElement) => {
|
||||
return { ...map, [headingElement.target.id]: headingElement };
|
||||
},
|
||||
{} as Record<string, HeadingElement>
|
||||
);
|
||||
|
||||
// Find the visible headings (i.e., headings that are currently intersecting with the viewport)
|
||||
const visibleHeadings: HeadingElement[] = [];
|
||||
Object.keys(headingElementsRef.current).forEach((key) => {
|
||||
const headingElement = headingElementsRef.current[key];
|
||||
if (headingElement.isIntersecting) visibleHeadings.push(headingElement);
|
||||
});
|
||||
|
||||
// Define a function to get the index of a heading element in the headingElements array
|
||||
const getIndexFromId = (id: string) => headingElements.findIndex((heading) => heading.id === id);
|
||||
|
||||
// If there is only one visible heading, set it as the active heading
|
||||
if (visibleHeadings.length === 1) {
|
||||
setActiveId(visibleHeadings[0].target.id);
|
||||
}
|
||||
// If there are multiple visible headings, set the active heading to the one that is highest on the page
|
||||
else if (visibleHeadings.length > 1) {
|
||||
const sortedVisibleHeadings = visibleHeadings.sort((a, b) => {
|
||||
const aIndex = getIndexFromId(a.target.id);
|
||||
const bIndex = getIndexFromId(b.target.id);
|
||||
return aIndex - bIndex;
|
||||
});
|
||||
setActiveId(sortedVisibleHeadings[0].target.id);
|
||||
}
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver(callback, {
|
||||
rootMargin: "-40px 0px -40% 0px",
|
||||
});
|
||||
|
||||
const headingElements = Array.from(document.querySelectorAll("h2[id], h3[id], h4[id]"));
|
||||
headingElements.forEach((element) => observer.observe(element));
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
headingElementsRef.current = {};
|
||||
};
|
||||
}, [setActiveId, pathname]);
|
||||
};
|
||||
@@ -35,6 +35,7 @@ export const navigation: Array<NavGroup> = [
|
||||
{ title: "Advanced Targeting", href: "/app-surveys/advanced-targeting" },
|
||||
{ title: "Show Survey to % of users", href: "/global/show-survey-to-percent-of-users" }, // app and website
|
||||
{ title: "Recontact Options", href: "/app-surveys/recontact" },
|
||||
{ title: "Hidden Fields", href: "/global/hidden-fields" }, // global
|
||||
{ title: "Multi Language Surveys", href: "/global/multi-language-surveys" }, // global
|
||||
{ title: "User Metadata", href: "/global/metadata" }, // global
|
||||
{ title: "Custom Styling", href: "/global/overwrite-styling" }, // global
|
||||
@@ -57,6 +58,7 @@ export const navigation: Array<NavGroup> = [
|
||||
{ title: "Actions & Targeting", href: "/website-surveys/actions-and-targeting" },
|
||||
{ title: "Show Survey to % of users", href: "/global/show-survey-to-percent-of-users" }, // app and website
|
||||
{ title: "Recontact Options", href: "/app-surveys/recontact" },
|
||||
{ title: "Hidden Fields", href: "/global/hidden-fields" }, // global
|
||||
{ title: "Multi Language Surveys", href: "/global/multi-language-surveys" }, // global
|
||||
{ title: "User Metadata", href: "/global/metadata" }, // global
|
||||
{ title: "Custom Styling", href: "/global/overwrite-styling" }, // global
|
||||
|
||||
@@ -46,9 +46,9 @@ const rehypeShiki = () => {
|
||||
|
||||
const rehypeSlugify = () => {
|
||||
return (tree) => {
|
||||
let slugify = slugifyWithCounter();
|
||||
const slugify = slugifyWithCounter();
|
||||
visit(tree, "element", (node) => {
|
||||
if (node.tagName === "h2" && !node.properties.id) {
|
||||
if (["h2", "h3", "h4"].includes(node.tagName) && !node.properties.id) {
|
||||
node.properties.id = slugify(toString(node));
|
||||
}
|
||||
});
|
||||
@@ -83,15 +83,15 @@ const rehypeAddMDXExports = (getExports) => {
|
||||
};
|
||||
|
||||
const getSections = (node) => {
|
||||
let sections = [];
|
||||
const sections = [];
|
||||
|
||||
for (let child of node.children ?? []) {
|
||||
if (child.type === "element" && child.tagName === "h2") {
|
||||
for (const child of node.children ?? []) {
|
||||
if (child.type === "element" && ["h2", "h3", "h4"].includes(child.tagName)) {
|
||||
sections.push(`{
|
||||
title: ${JSON.stringify(toString(child))},
|
||||
id: ${JSON.stringify(child.properties.id)},
|
||||
...${child.properties.annotation}
|
||||
}`);
|
||||
title: ${JSON.stringify(toString(child))},
|
||||
id: ${JSON.stringify(child.properties.id)},
|
||||
...${child.properties.annotation}
|
||||
}`);
|
||||
} else if (child.children) {
|
||||
sections.push(...getSections(child));
|
||||
}
|
||||
|
||||
@@ -12,34 +12,34 @@
|
||||
},
|
||||
"browserslist": "defaults, not ie <= 11",
|
||||
"dependencies": {
|
||||
"@algolia/autocomplete-core": "^1.17.0",
|
||||
"@calcom/embed-react": "^1.4.0",
|
||||
"@algolia/autocomplete-core": "^1.17.2",
|
||||
"@calcom/embed-react": "^1.5.0",
|
||||
"@docsearch/css": "3",
|
||||
"@docsearch/react": "^3.6.0",
|
||||
"@formbricks/lib": "workspace:*",
|
||||
"@formbricks/types": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"@headlessui/react": "^2.0.3",
|
||||
"@headlessui/tailwindcss": "^0.2.0",
|
||||
"@headlessui/react": "^2.0.4",
|
||||
"@headlessui/tailwindcss": "^0.2.1",
|
||||
"@mapbox/rehype-prism": "^0.9.0",
|
||||
"@mdx-js/loader": "^3.0.1",
|
||||
"@mdx-js/react": "^3.0.1",
|
||||
"@next/mdx": "14.2.3",
|
||||
"@next/mdx": "14.2.4",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"acorn": "^8.11.3",
|
||||
"acorn": "^8.12.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"clsx": "^2.1.1",
|
||||
"fast-glob": "^3.3.2",
|
||||
"flexsearch": "^0.7.43",
|
||||
"framer-motion": "11.1.9",
|
||||
"framer-motion": "11.2.11",
|
||||
"lottie-web": "^5.12.2",
|
||||
"lucide": "^0.378.0",
|
||||
"lucide-react": "^0.378.0",
|
||||
"lucide": "^0.395.0",
|
||||
"lucide-react": "^0.395.0",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"mdx-annotations": "^0.1.4",
|
||||
"next": "14.2.3",
|
||||
"next": "14.2.4",
|
||||
"next-plausible": "^3.12.0",
|
||||
"next-seo": "^6.5.0",
|
||||
"next-sitemap": "^4.2.3",
|
||||
@@ -59,15 +59,15 @@
|
||||
"sharp": "^0.33.4",
|
||||
"shiki": "^0.14.7",
|
||||
"simple-functional-loader": "^1.2.1",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"unist-util-filter": "^5.0.1",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"zustand": "^4.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/tsconfig": "workspace:*",
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/react-highlight-words": "^0.16.7",
|
||||
"eslint-config-formbricks": "workspace:*"
|
||||
"@types/react-highlight-words": "^0.20.0",
|
||||
"@formbricks/eslint-config": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import forms from "@tailwindcss/forms";
|
||||
import typographyPlugin from "@tailwindcss/typography";
|
||||
import { type Config } from "tailwindcss";
|
||||
import defaultTheme from "tailwindcss/defaultTheme";
|
||||
|
||||
import typographyStyles from "./typography";
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "@formbricks/tsconfig/nextjs.json",
|
||||
"extends": "@formbricks/config-typescript/nextjs.json",
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "../../packages/types/*.d.ts"],
|
||||
"exclude": ["../../.env", "node_modules"],
|
||||
"compilerOptions": {
|
||||
|
||||
6
apps/formbricks-com/next-env.d.ts
vendored
@@ -1,6 +0,0 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
/// <reference types="next/navigation-types/compat/navigation" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
@@ -1,118 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
|
||||
<url><loc>https://formbricks.com</loc><lastmod>2024-04-08T07:33:12.606Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog</loc><lastmod>2024-04-08T07:33:12.613Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/author/johannes</loc><lastmod>2024-04-08T07:33:12.613Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/author/shubham</loc><lastmod>2024-04-08T07:33:12.613Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/author/sudhanshu</loc><lastmod>2024-04-08T07:33:12.613Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/best-feedback-app-and-how-to-use-them</loc><lastmod>2024-04-08T07:33:12.613Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/best-hotjar-alternatives-2024-incl-open-source</loc><lastmod>2024-04-08T07:33:12.613Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/best-open-source-survey-software-2023</loc><lastmod>2024-04-08T07:33:12.613Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/best-website-feedback-tools-2024</loc><lastmod>2024-04-08T07:33:12.613Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/experience-management-open-source</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/first-end-to-endcommunity-feature</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/github-accelerator-experience</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/granular-targeting-in-app-surveys</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/how-smart-writers-use-formbricks-open-source-tool-to-measure-the-quality-of-their-newsletter-content</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/inaugural-batch-github-accelerator</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/join-the-formtribe</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/open-source-forms-will-save-the-world</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/open-source-qualtrics-beats-typeform</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/remove-branding-for-free</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/snoopforms-becomes-formbricks</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/terraform-ecs-aws-self-hosting</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/the-perfect-waitlist-survey</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/understanding-formbricks-self-hosting</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/blog/why-open-source-no-code-is-the-future-of-enterprise-gov-software</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/careers</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/community</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/community/ContributorGrid</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/community/HallOfFame</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/community/HeaderTribe</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/community/LayoutTribe</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/community/LevelCard</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/community/LevelGrid</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/community/Roadmap</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/concierge</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs-feedback</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/feature-chaser</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/feedback-box</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/gdpr</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/gdpr-guide</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/imprint</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/improve-trial-conversion</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/in-app-survey</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/interview-prompt</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/learn-from-churn</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/measure-product-market-fit</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/onboarding-segmentation</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/open-source-form-builder</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/oss-friends</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/pricing</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/privacy-policy</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/terms</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/vs-formspree</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/vs-google-forms</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/vs-ohmyform</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/website-survey</loc><lastmod>2024-04-08T07:33:12.614Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/client/responses</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/management/action-classes</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/management/attribute-classes</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/management/me</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/management/people</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/client/overview</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/management/responses</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/management/webhooks</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/client/displays</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/best-practices/cancel-subscription</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/client/people</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/best-practices/feedback-box</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/best-practices/feature-chaser</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/best-practices/docs-feedback</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/best-practices/improve-trial-cr</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/management/api-key-setup</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/best-practices/improve-email-content</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/best-practices/pmf-survey</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/best-practices/interview-prompt</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/contributing/demo</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/contributing/how-we-code</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/contributing/introduction</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/contributing/creating-a-service</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/contributing/setup</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/additional-features/multi-language-surveys</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/contributing/troubleshooting</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/getting-started/quickstart-in-app-survey</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/faq</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/in-app-surveys/actions</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/client/actions</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/getting-started/framework-guides</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/in-app-surveys/advanced-targeting</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/in-app-surveys/user-identification</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/getting-started/troubleshooting</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/in-app-surveys/attributes</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/api/management/surveys</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/integrations/make</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/integrations/airtable</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/integrations/notion</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/integrations/zapier</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/link-surveys/data-prefilling</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/integrations/wordpress</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/introduction/what-is-formbricks</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/introduction/how-it-works</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/introduction/why-is-it-better</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/link-surveys/single-use-links</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/link-surveys/hidden-fields</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/link-surveys/quickstart</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/link-surveys/source-tracking</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/self-hosting/docker</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/self-hosting/deployment</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/link-surveys/start-at-question</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/link-surveys/user-identification</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/self-hosting/enterprise</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/self-hosting/external-auth-providers</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/self-hosting/migration-guide</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/self-hosting/production</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/self-hosting/license</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/integrations/n8n</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
<url><loc>https://formbricks.com/docs/integrations/google-sheets</loc><lastmod>2024-04-08T07:33:12.615Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
|
||||
</urlset>
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<sitemap><loc>https://formbricks.com/sitemap-0.xml</loc></sitemap>
|
||||
</sitemapindex>
|
||||