Compare commits

..

15 Commits

Author SHA1 Message Date
review-agent-prime[bot]
10743b953e Edit packages/database/migrations/20240229062232_adds_styling_column_to_product_model/migration.sql 2024-03-04 16:40:25 +00:00
pandeymangg
7a1af85141 fix: product settings 2024-03-04 22:07:13 +05:30
pandeymangg
2586a3ba3a feat: surveys package styling changes 2024-03-04 15:39:24 +05:30
pandeymangg
77408bf0b0 Merge branch 'main' of https://github.com/formbricks/formbricks into feat/form-styling 2024-03-04 13:19:00 +05:30
pandeymangg
d5b183155b feat: product settings page styling UI and service 2024-03-04 13:18:39 +05:30
pandeymangg
d7fc7995bc wip 2024-02-29 18:37:11 +05:30
pandeymangg
a9d8239a25 UI 2024-02-29 14:07:10 +05:30
pandeymangg
71bdb5095a fix: schema 2024-02-29 11:51:45 +05:30
pandeymangg
b84e322eee Merge branch 'main' into feat/form-styling 2024-02-29 11:49:41 +05:30
pandeymangg
08ccb954f3 fix: styling object 2024-02-28 14:43:10 +05:30
pandeymangg
38c6cb01df fix: styling object 2024-02-28 14:42:38 +05:30
pandeymangg
2c13121487 fix: data migration and product types 2024-02-28 12:04:06 +05:30
pandeymangg
73f1d09dc8 Merge branch 'main' into feat/form-styling 2024-02-28 11:24:42 +05:30
pandeymangg
1f884a408c feat: styling zod schema and data migration 2024-02-28 11:24:27 +05:30
pandeymangg
ed2253dcfc feat: styling zod schema and data migration 2024-02-28 11:23:58 +05:30
1840 changed files with 51051 additions and 50820 deletions

View File

@@ -12,8 +12,8 @@
// Configure properties specific to VS Code.
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["dbaeumer.vscode-eslint"]
}
"extensions": ["dbaeumer.vscode-eslint"],
},
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
@@ -25,5 +25,5 @@
"postAttachCommand": "pnpm dev --filter=web... --filter=demo...",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node"
"remoteUser": "node",
}

View File

@@ -56,14 +56,11 @@ SMTP_PASSWORD=smtpPassword
# Uncomment the variables you would like to use and customize the values.
# Custom local storage path for file uploads
#UPLOADS_DIR=
##############
# S3 STORAGE #
##############
# S3 Storage is required for the file upload in serverless environments like Vercel
# S3 Storage is required for the file uplaod in serverless environments like Vercel
S3_ACCESS_KEY=
S3_SECRET_KEY=
S3_REGION=
@@ -147,10 +144,6 @@ GOOGLE_SHEETS_REDIRECT_URL=
# Oauth credentials for Airtable integration
AIRTABLE_CLIENT_ID=
# Oauth credentials for Slack integration
SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=
# Enterprise License Key
ENTERPRISE_LICENSE_KEY=
@@ -169,15 +162,3 @@ ENTERPRISE_LICENSE_KEY=
# Ignore Rate Limiting across the Formbricks app
# RATE_LIMITING_DISABLED=1
# OpenTelemetry URL for tracing
# OPENTELEMETRY_LISTENER_URL=http://localhost:4318/v1/traces
# Unsplash API Key
UNSPLASH_ACCESS_KEY=
# The below is used for Next Caching (uses In-Memory from Next Cache if not provided)
# REDIS_URL:
# 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:

View File

@@ -32,7 +32,6 @@ Fixes # (issue)
- [ ] Removed all `console.logs`
- [ ] Merged the latest changes from main onto my branch with `git pull origin main`
- [ ] My changes don't cause any responsiveness issues
- [ ] First PR at Formbricks? [Please sign the CLA!](https://cla-assistant.io/formbricks/formbricks) Without it we wont be able to merge it 🙏
### Appreciated

View File

@@ -1,21 +1,11 @@
name: Build & Cache Web App
on:
workflow_dispatch:
inputs:
e2e_testing_mode:
description: "Set E2E Testing Mode"
required: false
default: "0"
runs:
using: "composite"
steps:
- name: Checkout repo
uses: actions/checkout@v3
- uses: ./.github/actions/dangerous-git-checkout
- name: Cache Build
uses: actions/cache@v3
id: cache-build
@@ -23,12 +13,13 @@ runs:
cache-name: prod-build
key-1: ${{ hashFiles('pnpm-lock.yaml') }}
key-2: ${{ hashFiles('apps/**/**.[jt]s', 'apps/**/**.[jt]sx', 'packages/**/**.[jt]s', 'packages/**/**.[jt]sx', '!**/node_modules') }}
key-3: ${{ github.event.pull_request.number || github.ref }}
with:
path: |
${{ github.workspace }}/apps/web/.next
**/.turbo/**
**/dist/**
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ env.key-3 }}
- name: Setup Node.js 20.x
uses: actions/setup-node@v3
@@ -49,16 +40,10 @@ runs:
run: cp .env.example .env
shell: bash
- name: Add E2E Testing Mode
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
shell: bash
- run: |

View File

@@ -1,12 +1,11 @@
name: Cron - Survey status update
name: Cron - closeOnDate
on:
workflow_dispatch:
# "Scheduled workflows run on the latest commit on the default or base branch."
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
# schedule:
# Runs “At 00:00.” (see https://crontab.guru)
# - cron: "0 0 * * *"
schedule:
# Runs “At 00:00.” (see https://crontab.guru)
- cron: "0 0 * * *"
jobs:
cron-weeklySummary:
env:
@@ -17,7 +16,7 @@ jobs:
- name: cURL request
if: ${{ env.APP_URL && env.CRON_SECRET }}
run: |
curl ${{ env.APP_URL }}/api/cron/survey-status \
curl ${{ env.APP_URL }}/api/cron/close_surveys \
-X POST \
-H 'content-type: application/json' \
-H 'x-api-key: ${{ env.CRON_SECRET }}' \

View File

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

View File

@@ -1,12 +1,11 @@
name: Cron - Weekly summary
name: Cron - weeklySummary
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:
@@ -17,7 +16,7 @@ jobs:
- name: cURL request
if: ${{ env.APP_URL && env.CRON_SECRET }}
run: |
curl ${{ env.APP_URL }}/api/cron/weekly-summary \
curl ${{ env.APP_URL }}/api/cron/weekly_summary \
-X POST \
-H 'content-type: application/json' \
-H 'x-api-key: ${{ env.CRON_SECRET }}' \

View File

@@ -13,8 +13,6 @@ jobs:
- name: Build & Cache Web Binaries
uses: ./.github/actions/cache-build-web
with:
e2e_testing_mode: "1"
- name: Install pnpm
uses: pnpm/action-setup@v2

129
.github/workflows/ecs-deployment.yml vendored Normal file
View File

@@ -0,0 +1,129 @@
name: ECS
# 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:
push:
branches: [main]
workflow_dispatch: # Add manual trigger support
env:
REGISTRY: ghcr.io
IMAGE_NAME: formbricks/formbricks-experimental
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/formbricks?schema=public"
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write # Only necessary for sigstore/fulcio outside PRs
steps:
- name: Generate Secrets
run: |
echo "NEXTAUTH_SECRET=$(openssl rand -hex 32)" >> $GITHUB_ENV
echo "ENCRYPTION_KEY=$(openssl rand -hex 32)" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Depot CLI
uses: depot/setup-action@v1
# https://github.com/sigstore/cosign-installer
- name: Install cosign
uses: sigstore/cosign-installer@6e04d228eb30da1757ee4e1dd75a0ec73a653e06 #v3.1.1
with:
cosign-release: "v2.1.1"
# https://github.com/docker/login-action
- name: Log into registry
uses: docker/login-action@v3
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 }}
tags: |
type=sha,format=long
# Build and push Docker image with Buildx
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: build-and-push
uses: depot/build-push-action@v1
env:
NEXT_PUBLIC_SENTRY_DSN: ${{ secrets.NEXT_PUBLIC_SENTRY_DSN }}
with:
project: tw0fqmsx3c
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
context: .
file: ./apps/web/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
NEXTAUTH_SECRET=${{ env.NEXTAUTH_SECRET }}
DATABASE_URL=${{ env.DATABASE_URL }}
ENCRYPTION_KEY=${{ env.ENCRYPTION_KEY }}
NEXT_PUBLIC_SENTRY_DSN=${{ env.NEXT_PUBLIC_SENTRY_DSN }}
- name: Sign the images with GitHub OIDC Token
env:
DIGEST: ${{ steps.build-and-push.outputs.digest }}
TAGS: ${{ steps.meta.outputs.tags }}
run: |
images=""
for tag in ${TAGS}; do
images+="${tag}@${DIGEST} "
done
cosign sign --yes ${images}
outputs:
image_tag_sha: ${{ steps.meta.outputs.tags }}
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Download task definition
run: |
aws ecs describe-task-definition --task-definition prod-webapp-ecs-service --query taskDefinition > task-definition.json
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: task-definition.json
container-name: prod-webapp-container
image: ${{ needs.build.outputs.image_tag_sha }}
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: prod-webapp-ecs-service
cluster: prod-core-infra-ecs-cluster
wait-for-service-stability: true

View File

@@ -1,131 +0,0 @@
name: Kamal Deploy
concurrency:
group: deploy-to-kamal
cancel-in-progress: false
on:
workflow_dispatch:
push:
branches:
- main
jobs:
Deploy:
runs-on: ubuntu-latest
environment: production
env:
DOCKER_BUILDKIT: 1
IS_FORMBRICKS_CLOUD: ${{ vars.IS_FORMBRICKS_CLOUD }}
WEBAPP_URL: ${{ vars.WEBAPP_URL }}
MIGRATE_DATABASE_URL: ${{ secrets.MIGRATE_DATABASE_URL }}
NEXTAUTH_URL: ${{ vars.NEXTAUTH_URL }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }}
SHORT_URL_BASE: ${{ vars.SHORT_URL_BASE }}
MAIL_FROM: ${{ secrets.MAIL_FROM }}
SMTP_HOST: ${{ secrets.SMTP_HOST }}
SMTP_PORT: ${{ secrets.SMTP_PORT }}
SMTP_USER: ${{ secrets.SMTP_USER }}
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
PRIVACY_URL: ${{ vars.PRIVACY_URL }}
TERMS_URL: ${{ vars.TERMS_URL }}
IMPRINT_URL: ${{ vars.IMPRINT_URL }}
GITHUB_ID: ${{ secrets.FB_GITHUB_ID }}
GITHUB_SECRET: ${{ secrets.FB_GITHUB_SECRET }}
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
AZUREAD_CLIENT_ID: ${{ secrets.AZUREAD_CLIENT_ID }}
AZUREAD_CLIENT_SECRET: ${{ secrets.AZUREAD_CLIENT_SECRET }}
AZUREAD_TENANT_ID: ${{ secrets.AZUREAD_TENANT_ID }}
OIDC_CLIENT_ID: ${{ secrets.OIDC_CLIENT_ID }}
OIDC_CLIENT_SECRET: ${{ secrets.OIDC_CLIENT_SECRET }}
OIDC_ISSUER: ${{ secrets.OIDC_ISSUER }}
OIDC_DISPLAY_NAME: ${{ secrets.OIDC_DISPLAY_NAME }}
OIDC_SIGNING_ALGORITHM: ${{ secrets.OIDC_SIGNING_ALGORITHM }}
CRON_SECRET: ${{ secrets.CRON_SECRET }}
ASSET_PREFIX_URL: ${{ vars.ASSET_PREFIX_URL }}
NOTION_OAUTH_CLIENT_ID: ${{ secrets.NOTION_OAUTH_CLIENT_ID }}
NOTION_OAUTH_CLIENT_SECRET: ${{ secrets.NOTION_OAUTH_CLIENT_SECRET }}
SLACK_CLIENT_ID: ${{ secrets.SLACK_CLIENT_ID }}
SLACK_CLIENT_SECRET: ${{ secrets.SLACK_CLIENT_SECRET }}
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
STRIPE_WEBHOOK_SECRET: ${{ secrets.STRIPE_WEBHOOK_SECRET }}
GOOGLE_SHEETS_CLIENT_ID: ${{ secrets.GOOGLE_SHEETS_CLIENT_ID }}
GOOGLE_SHEETS_CLIENT_SECRET: ${{ secrets.GOOGLE_SHEETS_CLIENT_SECRET }}
GOOGLE_SHEETS_REDIRECT_URL: ${{ secrets.GOOGLE_SHEETS_REDIRECT_URL }}
AIRTABLE_CLIENT_ID: ${{ secrets.AIRTABLE_CLIENT_ID }}
ENTERPRISE_LICENSE_KEY: ${{ secrets.ENTERPRISE_LICENSE_KEY }}
DEFAULT_TEAM_ID: ${{ vars.DEFAULT_TEAM_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 }}
NEXT_PUBLIC_POSTHOG_API_HOST: ${{ vars.NEXT_PUBLIC_POSTHOG_API_HOST }}
NEXT_PUBLIC_FORMBRICKS_API_HOST: ${{ vars.NEXT_PUBLIC_FORMBRICKS_API_HOST }}
NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID }}
NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID }}
NEXT_PUBLIC_SENTRY_DSN: ${{ vars.NEXT_PUBLIC_SENTRY_DSN }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
NODE_ENV: production
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
CLOUDFLARE_DNS_API_TOKEN: ${{ secrets.CLOUDFLARE_DNS_API_TOKEN }}
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
S3_REGION: ${{ vars.S3_REGION }}
S3_BUCKET_NAME: ${{ vars.S3_BUCKET_NAME }}
OPENTELEMETRY_LISTENER_URL: ${{ vars.OPENTELEMETRY_LISTENER_URL }}
RATE_LIMITING_DISABLED: ${{ vars.RATE_LIMITING_DISABLED }}
KAMAL_REGISTRY_PASSWORD: ${{ secrets.KAMAL_REGISTRY_PASSWORD }}
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
DB_NAME: ${{ secrets.DB_NAME }}
REDIS_URL: ${{ secrets.REDIS_URL }}
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3.0
bundler-cache: true
- name: Install dependencies
run: |
gem install kamal
- uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
- name: Create builder
run: docker buildx create --use --name formbricks-gh-actions-builder
if: steps.buildx.outputs.should_create_builder == 'true'
- name: Push env variables to Kamal
run: |
kamal() { command kamal "$@" -c kamal/deploy.yml; }
kamal env push
- name: Run deploy command
run: |
kamal() { command kamal "$@" -c kamal/deploy.yml; }
set +e
DEPLOY_OUTPUT=$(kamal deploy 2>&1)
DEPLOY_EXIT_CODE=$?
echo "$DEPLOY_OUTPUT"
if [[ "$DEPLOY_OUTPUT" == *"container not unhealthy (healthy)"* ]]; then
echo "Deployment reported healthy container. Considering as success."
kamal lock release
exit 0
else
exit $DEPLOY_EXIT_CODE
fi
shell: bash

View File

@@ -1,128 +0,0 @@
name: Kamal Setup
concurrency:
group: setup-kamal
cancel-in-progress: false
on:
workflow_dispatch: # Only to be triggered when accessories are updated
jobs:
Setup:
runs-on: ubuntu-latest
environment: production
env:
DOCKER_BUILDKIT: 1
IS_FORMBRICKS_CLOUD: ${{ vars.IS_FORMBRICKS_CLOUD }}
WEBAPP_URL: ${{ vars.WEBAPP_URL }}
NEXTAUTH_URL: ${{ vars.NEXTAUTH_URL }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
MIGRATE_DATABASE_URL: ${{ secrets.MIGRATE_DATABASE_URL }}
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }}
SHORT_URL_BASE: ${{ vars.SHORT_URL_BASE }}
MAIL_FROM: ${{ secrets.MAIL_FROM }}
SMTP_HOST: ${{ secrets.SMTP_HOST }}
SMTP_PORT: ${{ secrets.SMTP_PORT }}
SMTP_USER: ${{ secrets.SMTP_USER }}
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
PRIVACY_URL: ${{ vars.PRIVACY_URL }}
TERMS_URL: ${{ vars.TERMS_URL }}
IMPRINT_URL: ${{ vars.IMPRINT_URL }}
GITHUB_ID: ${{ secrets.FB_GITHUB_ID }}
GITHUB_SECRET: ${{ secrets.FB_GITHUB_SECRET }}
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
AZUREAD_CLIENT_ID: ${{ secrets.AZUREAD_CLIENT_ID }}
AZUREAD_CLIENT_SECRET: ${{ secrets.AZUREAD_CLIENT_SECRET }}
AZUREAD_TENANT_ID: ${{ secrets.AZUREAD_TENANT_ID }}
OIDC_CLIENT_ID: ${{ secrets.OIDC_CLIENT_ID }}
OIDC_CLIENT_SECRET: ${{ secrets.OIDC_CLIENT_SECRET }}
OIDC_ISSUER: ${{ secrets.OIDC_ISSUER }}
OIDC_DISPLAY_NAME: ${{ secrets.OIDC_DISPLAY_NAME }}
OIDC_SIGNING_ALGORITHM: ${{ secrets.OIDC_SIGNING_ALGORITHM }}
CRON_SECRET: ${{ secrets.CRON_SECRET }}
ASSET_PREFIX_URL: ${{ vars.ASSET_PREFIX_URL }}
NOTION_OAUTH_CLIENT_ID: ${{ secrets.NOTION_OAUTH_CLIENT_ID }}
NOTION_OAUTH_CLIENT_SECRET: ${{ secrets.NOTION_OAUTH_CLIENT_SECRET }}
SLACK_CLIENT_ID: ${{ secrets.SLACK_CLIENT_ID }}
SLACK_CLIENT_SECRET: ${{ secrets.SLACK_CLIENT_SECRET }}
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
STRIPE_WEBHOOK_SECRET: ${{ secrets.STRIPE_WEBHOOK_SECRET }}
GOOGLE_SHEETS_CLIENT_ID: ${{ secrets.GOOGLE_SHEETS_CLIENT_ID }}
GOOGLE_SHEETS_CLIENT_SECRET: ${{ secrets.GOOGLE_SHEETS_CLIENT_SECRET }}
GOOGLE_SHEETS_REDIRECT_URL: ${{ secrets.GOOGLE_SHEETS_REDIRECT_URL }}
AIRTABLE_CLIENT_ID: ${{ secrets.AIRTABLE_CLIENT_ID }}
ENTERPRISE_LICENSE_KEY: ${{ secrets.ENTERPRISE_LICENSE_KEY }}
DEFAULT_TEAM_ID: ${{ vars.DEFAULT_TEAM_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 }}
NEXT_PUBLIC_POSTHOG_API_HOST: ${{ vars.NEXT_PUBLIC_POSTHOG_API_HOST }}
NEXT_PUBLIC_FORMBRICKS_API_HOST: ${{ vars.NEXT_PUBLIC_FORMBRICKS_API_HOST }}
NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID }}
NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID }}
NEXT_PUBLIC_SENTRY_DSN: ${{ vars.NEXT_PUBLIC_SENTRY_DSN }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
NODE_ENV: production
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
CLOUDFLARE_DNS_API_TOKEN: ${{ secrets.CLOUDFLARE_DNS_API_TOKEN }}
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
S3_REGION: ${{ vars.S3_REGION }}
S3_BUCKET_NAME: ${{ vars.S3_BUCKET_NAME }}
OPENTELEMETRY_LISTENER_URL: ${{ vars.OPENTELEMETRY_LISTENER_URL }}
RATE_LIMITING_DISABLED: ${{ vars.RATE_LIMITING_DISABLED }}
KAMAL_REGISTRY_PASSWORD: ${{ secrets.KAMAL_REGISTRY_PASSWORD }}
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
DB_NAME: ${{ secrets.DB_NAME }}
REDIS_URL: ${{ secrets.REDIS_URL }}
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3.0
bundler-cache: true
- name: Install dependencies
run: |
gem install kamal
- uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
- name: Create builder
run: docker buildx create --use --name formbricks-gh-actions-builder
if: steps.buildx.outputs.should_create_builder == 'true'
- name: Push env variables to Kamal
run: |
kamal() { command kamal "$@" -c kamal/deploy.yml; }
kamal env push
- name: Run setup command
run: |
kamal() { command kamal "$@" -c kamal/deploy.yml; }
set +e
DEPLOY_OUTPUT=$(kamal setup 2>&1)
DEPLOY_EXIT_CODE=$?
echo "$DEPLOY_OUTPUT"
if [[ "$DEPLOY_OUTPUT" == *"container not unhealthy (healthy)"* ]]; then
echo "Deployment reported healthy container. Considering as success."
kamal lock release
exit 0
else
exit $DEPLOY_EXIT_CODE
fi
shell: bash

View File

@@ -1,7 +1,7 @@
name: PR Update
on:
pull_request:
pull_request_target:
branches:
- main
merge_group:
@@ -30,7 +30,7 @@ jobs:
- "!(**.md|.github/CODEOWNERS)"
test:
name: Run Unit Tests
name: Run Tests
needs: [changes]
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/test.yml
@@ -58,7 +58,6 @@ jobs:
secrets: inherit
required:
name: PR Check Summary
needs: [lint, test, build, e2e-test]
if: always()
runs-on: ubuntu-latest

View File

@@ -31,6 +31,16 @@ jobs:
id-token: write
steps:
- name: Generate Random NEXTAUTH_SECRET
run: |
SECRET=$(openssl rand -hex 32)
echo "NEXTAUTH_SECRET=$SECRET" >> $GITHUB_ENV
- name: Generate Random ENCRYPTION_KEY
run: |
SECRET=$(openssl rand -hex 32)
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v3
@@ -79,6 +89,10 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
NEXTAUTH_SECRET=${{ env.NEXTAUTH_SECRET }}
DATABASE_URL=${{ env.DATABASE_URL }}
ENCRYPTION_KEY=${{ env.ENCRYPTION_KEY }}
# Sign the resulting Docker image digest except on PRs.
# This will only write to the public Rekor transparency log when the Docker

View File

@@ -14,6 +14,16 @@ jobs:
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/formbricks?schema=public"
steps:
- name: Generate Random NEXTAUTH_SECRET
run: |
SECRET=$(openssl rand -hex 32)
echo "NEXTAUTH_SECRET=$SECRET" >> $GITHUB_ENV
- name: Generate Random ENCRYPTION_KEY
run: |
SECRET=$(openssl rand -hex 32)
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
- name: Checkout Repo
uses: actions/checkout@v2
@@ -42,3 +52,7 @@ jobs:
tags: |
${{ secrets.DOCKER_USERNAME }}/formbricks:${{ env.RELEASE_TAG }}
${{ secrets.DOCKER_USERNAME }}/formbricks:latest
build-args: |
NEXTAUTH_SECRET=${{ env.NEXTAUTH_SECRET }}
DATABASE_URL=${{ env.DATABASE_URL }}
ENCRYPTION_KEY=${{ env.ENCRYPTION_KEY }}

View File

@@ -3,7 +3,7 @@ on:
workflow_call:
jobs:
build:
name: Unit Tests
name: Tests
runs-on: ubuntu-latest
timeout-minutes: 15

4
.gitignore vendored
View File

@@ -54,7 +54,3 @@ Zone.Identifier
# uploads
packages/lib/uploads
# Vite Timestamps
vite.config.*.timestamp-*

View File

@@ -1,14 +0,0 @@
#!/bin/sh
# A sample post-deploy hook
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)
# KAMAL_RUNTIME
echo "$KAMAL_PERFORMER deployed $KAMAL_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds"

View File

@@ -1,3 +0,0 @@
#!/bin/sh
echo "Rebooted Traefik on $KAMAL_HOSTS"

View File

@@ -1,51 +0,0 @@
#!/bin/sh
# A sample pre-build hook
#
# Checks:
# 1. We have a clean checkout
# 2. A remote is configured
# 3. The branch has been pushed to the remote
# 4. The version we are deploying matches the remote
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)
if [ -n "$(git status --porcelain)" ]; then
echo "Git checkout is not clean, aborting..." >&2
git status --porcelain >&2
exit 1
fi
first_remote=$(git remote)
if [ -z "$first_remote" ]; then
echo "No git remote set, aborting..." >&2
exit 1
fi
current_branch=$(git branch --show-current)
if [ -z "$current_branch" ]; then
echo "Not on a git branch, aborting..." >&2
exit 1
fi
remote_head=$(git ls-remote $first_remote --tags $current_branch | cut -f1)
if [ -z "$remote_head" ]; then
echo "Branch not pushed to remote, aborting..." >&2
exit 1
fi
if [ "$KAMAL_VERSION" != "$remote_head" ]; then
echo "Version ($KAMAL_VERSION) does not match remote HEAD ($remote_head), aborting..." >&2
exit 1
fi
exit 0

View File

@@ -1,47 +0,0 @@
#!/usr/bin/env ruby
# A sample pre-connect check
#
# Warms DNS before connecting to hosts in parallel
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)
# KAMAL_RUNTIME
hosts = ENV["KAMAL_HOSTS"].split(",")
results = nil
max = 3
elapsed = Benchmark.realtime do
results = hosts.map do |host|
Thread.new do
tries = 1
begin
Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)
rescue SocketError
if tries < max
puts "Retrying DNS warmup: #{host}"
tries += 1
sleep rand
retry
else
puts "DNS warmup failed: #{host}"
host
end
end
tries
end
end.map(&:value)
end
retries = results.sum - hosts.size
nopes = results.count { |r| r == max }
puts "Prewarmed %d DNS lookups in %.2f sec: %d retries, %d failures" % [ hosts.size, elapsed, retries, nopes ]

View File

@@ -1,109 +0,0 @@
#!/usr/bin/env ruby
# A sample pre-deploy hook
#
# Checks the Github status of the build, waiting for a pending build to complete for up to 720 seconds.
#
# Fails unless the combined status is "success"
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_COMMAND
# KAMAL_SUBCOMMAND
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)
# Only check the build status for production deployments
if ENV["KAMAL_COMMAND"] == "rollback" || ENV["KAMAL_DESTINATION"] != "production"
exit 0
end
require "bundler/inline"
# true = install gems so this is fast on repeat invocations
gemfile(true, quiet: true) do
source "https://rubygems.org"
gem "octokit"
gem "faraday-retry"
end
MAX_ATTEMPTS = 72
ATTEMPTS_GAP = 10
def exit_with_error(message)
$stderr.puts message
exit 1
end
class GithubStatusChecks
attr_reader :remote_url, :git_sha, :github_client, :combined_status
def initialize
@remote_url = `git config --get remote.origin.url`.strip.delete_prefix("https://github.com/")
@git_sha = `git rev-parse HEAD`.strip
@github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
refresh!
end
def refresh!
@combined_status = github_client.combined_status(remote_url, git_sha)
end
def state
combined_status[:state]
end
def first_status_url
first_status = combined_status[:statuses].find { |status| status[:state] == state }
first_status && first_status[:target_url]
end
def complete_count
combined_status[:statuses].count { |status| status[:state] != "pending"}
end
def total_count
combined_status[:statuses].count
end
def current_status
if total_count > 0
"Completed #{complete_count}/#{total_count} checks, see #{first_status_url} ..."
else
"Build not started..."
end
end
end
$stdout.sync = true
puts "Checking build status..."
attempts = 0
checks = GithubStatusChecks.new
begin
loop do
case checks.state
when "success"
puts "Checks passed, see #{checks.first_status_url}"
exit 0
when "failure"
exit_with_error "Checks failed, see #{checks.first_status_url}"
when "pending"
attempts += 1
end
exit_with_error "Checks are still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds" if attempts == MAX_ATTEMPTS
puts checks.current_status
sleep(ATTEMPTS_GAP)
checks.refresh!
end
rescue Octokit::NotFound
exit_with_error "Build status could not be found"
end

View File

@@ -1,3 +0,0 @@
#!/bin/sh
echo "Rebooting Traefik on $KAMAL_HOSTS..."

View File

@@ -138,12 +138,6 @@ You can deploy Formbricks on [Railway](https://railway.app) using the button bel
[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/PPDzCd)
##### RepoCloud
Or you can also deploy Formbricks on [RepoCloud](https://repocloud.io) using the button below.
[![Deploy on RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploy.png)](https://repocloud.io/details/?app_id=254)
<a id="development"></a>
## 👨‍💻 Development

View File

@@ -1,28 +1,27 @@
import { classNames } from "@/lib/utils";
import {
ClockIcon,
CogIcon,
CreditCardIcon,
FileBarChartIcon,
HelpCircleIcon,
DocumentChartBarIcon,
HomeIcon,
QuestionMarkCircleIcon,
ScaleIcon,
ShieldCheckIcon,
UsersIcon,
} from "lucide-react";
import { classNames } from "../lib/utils";
UserGroupIcon,
} from "@heroicons/react/24/outline";
const navigation = [
{ name: "Home", href: "#", icon: HomeIcon, current: true },
{ name: "History", href: "#", icon: ClockIcon, current: false },
{ name: "Balances", href: "#", icon: ScaleIcon, current: false },
{ name: "Cards", href: "#", icon: CreditCardIcon, current: false },
{ name: "Recipients", href: "#", icon: UsersIcon, current: false },
{ name: "Reports", href: "#", icon: FileBarChartIcon, current: false },
{ name: "Recipients", href: "#", icon: UserGroupIcon, current: false },
{ name: "Reports", href: "#", icon: DocumentChartBarIcon, current: false },
];
const secondaryNavigation = [
{ name: "Settings", href: "#", icon: CogIcon },
{ name: "Help", href: "#", icon: HelpCircleIcon },
{ name: "Help", href: "#", icon: QuestionMarkCircleIcon },
{ name: "Privacy", href: "#", icon: ShieldCheckIcon },
];

View File

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

View File

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

View File

@@ -12,14 +12,12 @@
},
"dependencies": {
"@formbricks/js": "workspace:*",
"@formbricks/ui": "workspace:*",
"lucide-react": "^0.378.0",
"next": "14.2.3",
"react": "18.3.1",
"react-dom": "18.3.1"
"@heroicons/react": "^2.1.1",
"next": "14.1.1",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"eslint-config-formbricks": "workspace:*",
"@formbricks/tsconfig": "workspace:*"
"eslint-config-formbricks": "workspace:*"
}
}

View File

@@ -2,9 +2,8 @@ import Image from "next/image";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import formbricks from "@formbricks/js/app";
import formbricks from "@formbricks/js";
import { SurveySwitch } from "../../components/SurveySwitch";
import fbsetup from "../../public/fb-setup.png";
declare const window: any;
@@ -22,28 +21,17 @@ export default function AppPage({}) {
}, [darkMode]);
useEffect(() => {
// enable Formbricks debug mode by adding formbricksDebug=true GET parameter
const addFormbricksDebugParam = () => {
const urlParams = new URLSearchParams(window.location.search);
if (!urlParams.has("formbricksDebug")) {
urlParams.set("formbricksDebug", "true");
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
window.history.replaceState({}, "", newUrl);
}
};
addFormbricksDebugParam();
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
const userId = "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING";
const userInitAttributes = { language: "de", "Init Attribute 1": "eight", "Init Attribute 2": "two" };
const isUserId = window.location.href.includes("userId=true");
const attributes = isUserId ? { "Init Attribute 1": "eight", "Init Attribute 2": "two" } : undefined;
const userId = isUserId ? "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING" : undefined;
formbricks.init({
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
userId,
attributes: userInitAttributes,
attributes,
});
window.formbricks = formbricks;
}
// Connect next.js router to Formbricks
@@ -60,19 +48,15 @@ export default function AppPage({}) {
return (
<div className="h-screen bg-white px-12 py-6 dark:bg-slate-800">
<div className="flex flex-col justify-between md:flex-row">
<div className="flex items-center gap-2">
<SurveySwitch value="app" formbricks={formbricks} />
<div>
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
Formbricks In-product Survey Demo App
</h1>
<p className="text-slate-700 dark:text-slate-300">
This app helps you test your app surveys. You can create and test user actions, create and
update user attributes, etc.
</p>
</div>
<div>
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
Formbricks In-product Survey Demo App
</h1>
<p className="text-slate-700 dark:text-slate-300">
This app helps you test your in-app surveys. You can create and test user actions, create and
update user attributes, etc.
</p>
</div>
<button
className="mt-2 rounded-lg bg-slate-200 px-6 py-1 dark:bg-slate-700 dark:text-slate-100"
onClick={() => setDarkMode(!darkMode)}>
@@ -85,7 +69,7 @@ export default function AppPage({}) {
<div className="rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-900">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">1. Setup .env</h3>
<p className="text-slate-700 dark:text-slate-300">
Copy the environment ID of your Formbricks app to the env variable in /apps/demo/.env
Copy the environment ID of your Formbricks app to the env variable in demo/.env
</p>
<Image src={fbsetup} alt="fb setup" className="mt-4 rounded" priority />
@@ -96,7 +80,7 @@ export default function AppPage({}) {
{process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID}
</strong>
<span className="relative ml-2 flex h-3 w-3">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-500 opacity-75"></span>
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75"></span>
<span className="relative inline-flex h-3 w-3 rounded-full bg-green-500"></span>
</span>
</div>
@@ -115,7 +99,7 @@ export default function AppPage({}) {
</div>
<div className="md:grid md:grid-cols-3">
<div className="col-span-3 self-start rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-800">
<div className="col-span-3 rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-800">
<h3 className="text-lg font-semibold dark:text-white">
Reset person / pull data from Formbricks app
</h3>
@@ -136,6 +120,26 @@ export default function AppPage({}) {
</p>
</div>
<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"
onClick={() => {
formbricks.track("Code Action");
}}>
Code Action
</button>
</div>
<div>
<p className="text-xs text-slate-700 dark:text-slate-300">
This button sends a{" "}
<a href="https://formbricks.com/docs/actions/code" className="underline" target="_blank">
Code Action
</a>{" "}
to the Formbricks API called &apos;Code Action&apos;. You will find it in the Actions Tab.
</p>
</div>
</div>
<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">
@@ -230,6 +234,41 @@ export default function AppPage({}) {
</p>
</div>
</div>
<div className="p-6">
{router.query.userId === "true" ? (
<div>
<button
onClick={() => {
window.location.href = "/app";
}}
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
Deactivate User Identification
</button>
</div>
) : (
<div>
<button
onClick={() => {
window.location.href = "/app?userId=true";
}}
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
Activate User Identification
</button>
</div>
)}
<div>
<p className="text-xs text-slate-700 dark:text-slate-300">
This button activates/deactivates{" "}
<a
href="https://formbricks.com/docs/attributes/identify-users"
target="_blank"
className="underline dark:text-blue-500">
user identification
</a>{" "}
with the userId &apos;THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING&apos;
</p>
</div>
</div>
</div>
</div>
</div>

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -1,123 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import I1 from "./images/I1.png";
import I2 from "./images/I2.png";
export const metadata = {
title: "Using Actions in Formbricks | Fine-tuning User Moments",
description:
"Dive deep into how actions in Formbricks help products and teams to engage users at precise moments in their journey. Discover the power of actions, from coding to no-code setups, to refine user targeting and generate richer, more detailed user insights.",
};
#### App Surveys
# Actions & Targeting
Understanding user thoughts and feelings at critical moments in their journey is pivotal. To achieve this, Formbricks uses user-centric actions that trigger surveys at precisely the right time. Actions are essentially notifications sent from your application to Formbricks when predefined user activities occur, making it possible to gather insights during key interactions.
<Note>
Ensure that youve **initialized Formbricks with a userId** to fully utilize this feature along with other
app survey capabilities.
</Note>
## **How Do Actions Work?**
Actions in Formbricks App Surveys are deeply integrated with user activities within your app. When a user performs a specified action, the Formbricks widget detects this activity and can present a survey to that specific user if the trigger conditions match of that survey, while also recording the event. This capability ensures that surveys are not only triggered at the right time but are also tailored to the users recent interactions within the app. You can set up these actions either programmatically in your code or through a user-friendly No-Code interface within the Formbricks dashboard.
## **Why Are Actions Useful?**
Actions are invaluable for enhancing survey relevance and effectiveness:
- **Personalized Engagement**: Surveys triggered by user actions ensure content is highly relevant and engaging, matching each users current context.
- **User Attributes**: By tying surveys to specific user attributes, such as activity levels or feature usage, you can customize the survey experience to reflect individual user profiles.
- **User Segments**: Analyze action data to create detailed user segments, targeting specific groups with surveys that are pertinent to their behaviors or interactions within the app.
- **User Targeting**: Precise targeting based on user actions and attributes ensures that surveys are shown only to users who meet certain criteria, enhancing the relevance and effectiveness of each survey.
<Note>
You now have the option to create survey-specific action classes directly within the survey editor. These
actions are exclusive to the individual survey and won't appear in the global action list, helping to keep
it uncluttered. For actions that are needed across multiple surveys, we recommend creating them from the
Actions tab.
</Note>
## **Setting Up No-Code Actions**
Formbricks offers an intuitive No-Code interface that allows you to configure actions without needing to write any code.
To add a No-Code Action:
1. Visit the Formbricks Dashboard & switch to the Actions tab:
<MdxImage
src={I1}
alt="setup checklist ui of survey popup for app surveys"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
2. Now click on “Add Action”
<MdxImage
src={I2}
alt="setup checklist ui of survey popup for app surveys"
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**
This action is triggered when a user visits a specific page within your application. You can define the URL match conditions as follows:
- **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.
### **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>
## **Setting Up Code Actions**
For more granular control, you can implement actions directly in your codebase:
1. **Configure the Action**: First, add the action via the Formbricks web interface to make it available for survey configuration.
After that you can fire an action using `formbricks.track()`
2. **Track an Action**: Use formbricks.track() to send an action event to Formbricks.
<Col>
<CodeGroup title="Track an action">
```javascript
formbricks.track("Action Name");
```
</CodeGroup>
</Col>
Here is an example of how to fire an action when a user clicks a button:
<Col>
<CodeGroup title="Track Button Click">
```javascript
const handleClick = () => {
formbricks.track("Button Clicked");
};
return <button onClick={handleClick}>Click Me</button>;
```
</CodeGroup>
</Col>
This documentation frames actions around user interactions, emphasizing the connection between the user's activities and the survey experience. By leveraging user-centric actions, you can create highly targeted and timely surveys that resonate with users and yield valuable insights.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,94 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import { ResponsiveVideo } from "@/components/ResponsiveVideo";
import GermansGpt from "./germans-gpt.webp";
import Hni from "./hni.webp";
import PowerUsers from "./power-users.webp";
import RideHailing from "./ride-hailing.webp";
import UpsellMiro from "./upsell-miro.webp";
export const metadata = {
title: "Advanced Targeting in Surveys | Formbricks",
description:
"Advanced Targeting allows you to show surveys to just the right group of people. You can target surveys based on user attributes, user events, metadata , literally anything! This helps you get more relevant feedback and make data-driven decisions. All of this without writing a single line of code.",
};
#### App Surveys
# Advanced Targeting
Advanced Targeting allows you to show surveys to the right group of people. You can target surveys based on user attributes, user events, and more instead of spraying and praying. This helps you get more relevant feedback and make data-driven decisions. All of this without writing a single line of code.
<ResponsiveVideo title="Formbricks Multi-language Surveys"
src="https://www.youtube-nocookie.com/embed/0BQp6N4cXzU?si=KeBM7G7Ch1xtrsOm&amp;controls=0" />
## How to setup Advanced Targeting
<Note>
Advanced Targeting is available on the Pro plan! Don't worry, you just need to enter your credit card
details to start the freemium plan.
</Note>
1. On the Formbricks dashboard, click on **People** tab from the top navigation bar.
2. Switch to the **Segments** tab & click on **Create Segment**.
3. Give your segment a title & a description to help you remember what this segment is about.
4. Now click on the **Add Filter** button to add a filter. You can filter based on actions, user attributes, other segments, devices, and more.
5. To group a set of filters together, click on the Three Dots icon on the right side of the filter and click on **Create Group**.
6. Try playing around with different filters & conditions that we have provided to see how the segment size changes.
7. Once you are happy with the segment, click on **Save Segment**.
8. Now, when you create a survey, you can select this segment to target your survey to.
## Examples:
1. Let's say you want to upsell to: Miro, Loom, Figma, Slack and Asana.
<MdxImage
src={UpsellMiro}
alt="Upselling Opportunity"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
2. Post-experience surveying for a ride hailing app where users who have taken more than 1 ride are shown a survey.
<MdxImage
src={RideHailing}
alt="Ride Hailing Targeting"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
3. Target High Value users who have $100k+ in their bank account, own 20+ stocks, and have are an active user.
<MdxImage
src={Hni}
alt="Target Active High Net Worth Individuals"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
4. Target Germans on mobile phones who have regenerated chatGPT answers frequently in the last quarter and did so today.
<MdxImage
src={GermansGpt}
alt="Target Germans on Mobile Phones who have regenerated chatGPT answers frequently in the last quarter and did so today"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
5. Sneak Peak: How we at Formbricks automate inviting power users to chat with us
<MdxImage
src={PowerUsers}
alt="Automate inviting power users to chat with us at Formbricks"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -1,60 +0,0 @@
import { Button } from "@/components/Button";
import logoHtml from "@/images/frameworks/html5.svg";
import logoNextjs from "@/images/frameworks/nextjs.svg";
import logoReactJs from "@/images/frameworks/reactjs.svg";
import logoVueJs from "@/images/frameworks/vuejs.svg";
import Image from "next/image";
const libraries = [
{
href: "#html",
name: "HTML",
description: "All you need to do is add 3 lines of code to your HTML script and thats it, you're done!",
logo: logoHtml,
},
{
href: "#react-js",
name: "React.js",
description: "Load the our Js library with your environment ID and you're ready to go!",
logo: logoReactJs,
},
{
href: "#next-js",
name: "Next.js",
description:
"Natively add us to your NextJs project with support for both App as well as Pages project structure!",
logo: logoNextjs,
},
{
href: "#vue-js",
name: "Vue.js",
description: "Simply add us to your router change and sit back!",
logo: logoVueJs,
},
];
export function Libraries() {
return (
<div className="my-16 xl:max-w-none">
<div className="not-prose mt-4 grid grid-cols-1 gap-x-6 gap-y-10 border-slate-900/5 sm:grid-cols-2 xl:max-w-none xl:grid-cols-3 dark:border-white/5">
{libraries.map((library) => (
<a
key={library.name}
href={library.href}
className="flex flex-row-reverse gap-6 rounded-2xl p-6 transition-all duration-100 ease-in-out hover:cursor-pointer hover:bg-slate-100/50 dark:hover:bg-slate-800/50">
<div className="flex-auto">
<h3 className="text-sm font-semibold text-slate-900 dark:text-white">{library.name}</h3>
<p className="mt-1 text-sm text-slate-600 dark:text-slate-400">{library.description}</p>
<p className="mt-4">
<Button href={library.href} variant="text" arrow="right">
Read more
</Button>
</p>
</div>
<Image src={library.logo} alt="" className="h-12 w-12" unoptimized />
</a>
))}
</div>
</div>
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

View File

@@ -1,115 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import I1 from "./images/I1.png";
import I2 from "./images/I2.png";
import I3 from "./images/I3.png";
import I4 from "./images/I4.png";
import I5 from "./images/I5.png";
import I6 from "./images/I6.png";
import I7 from "./images/I7.png";
import I8 from "./images/I8.png";
export const metadata = {
title: "Formbricks Quickstart Guide: App Surveys Made Easier & Faster",
description:
"Formbricks is the easiest way to create and manage app surveys. This quickstart guide will show you how to create your first app survey in under 5 minutes.",
};
#### App Surveys
# Quickstart
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. Lets 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).
</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:
<Note>
Website & App Surveys have the same integration process. The difference will come when we setup our survey.
</Note>
<MdxImage
src={I1}
alt="Choose website survey from survey type"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. **Connect your App/Website**: Once you get through a couple of onboarding steps, youll be asked to connect your app or website. This is where youll find the code snippet for both HTML as well as the npm package which you need to embed in your app:
<MdxImage
src={I2}
alt="Code snippet for connecting app with Formbricks"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Paste the code snippet in your app and reload the page. You should now see the Formbricks widget in the lower right corner of your app! The integration is now complete.
<MdxImage
src={I3}
alt="App connected with Formbricks"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Onboarding is complete! Now lets create our first survey as you should see templates to choose from after clicking on **Next**:
<MdxImage
src={I4}
alt="Choose a survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
3. **Create your first survey**: To be able to see a survey in your app, you need to create one. Well choose one of the templates and head over to the survey settings:
Pick the Survey Type as **App Survey**.
<MdxImage
src={I5}
alt="Survey settings for app survey"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
4. **Set Trigger for the Survey**: Scroll down to Survey Trigger and inside **When**, choose **New Session**. This will cause this survey to appear when the Formbricks Widget tracks a new user session:
<MdxImage
src={I6}
alt="Survey trigger settings for app survey"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
5. **Set Recontact Options for debugging**: In Recontact Options we choose the following settings, so that we can play around with the survey more easily. By default, each survey will be shown only once to each user to prevent survey fatigue:
<Note>
Please change this setting later on after testing your survey to prevent survey fatigue for your users.
</Note>
<MdxImage
src={I7}
alt="Recontact options for app survey"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
6. **Publish your survey**: Now hit **Publish** and youll be forwarded to the Summary Page. This is where youll find the responses to this survey.
<MdxImage
src={I8}
alt="Survey published successfully"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
---
- We offer framework guides for various frontend tech, head over to the the [App Survey Framework Guides](/app-survey/framework-guides) to get started with your app survey.
- Head over to our App Survey SDK documentation to get started with the [App Survey JS SDK](/developer-docs/app-survey-sdk).
Still struggling or something not working as expected? [Join our Discord!](https://formbricks.com/discord) and we'd be glad to assist you!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -1,269 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
export const metadata = {
title: "Formbricks API SDK",
description:
"An overview of all available methods & how to integrate Formbricks API for backend developers in web applications. Learn the key methods, configuration settings, and best practices.",
};
#### Developer Docs
# SDK: Formbricks API
### Overview
The Formbricks Client API Wrapper is a lightweight package designed to simplify the integration of Formbricks API endpoints into your JavaScript (JS) or TypeScript (TS) projects. With this wrapper, you can easily interact with Formbricks API endpoints without the need for complex setup or manual HTTP requests.
### Install
<Col>
<CodeGroup title="npm">
```js {{ title: 'npm' }}
npm install @formbricks/api
```
```js {{ title: 'yarn' }}
yarn add @formbricks/api
```
```js {{ title: 'pnpm' }}
pnpm add @formbricks/api
```
</CodeGroup>
</Col>
## Methods
### Initialize Formbricks
Initialize the Formbricks API Client for backend developers to interact with Formbricks API endpoints:
<Col>
<CodeGroup title="Initialize Formbricks API">
```javascript
import { FormbricksAPI } from "@formbricks/api";
const api = new FormbricksAPI({
apiHost: `https://app.formbricks.com`, // If you have self-hosted Formbricks, change this to your self hosted instance's URL
environmentId: "<environment-id>", // Replace this with your Formbricks environment ID
});
```
</CodeGroup>
</Col>
The API client is now ready to be used across your project. It can be used to interact with the following models:
## Displays
- Create Display
<Col>
<CodeGroup title="Crate Display">
```javascript {{ title: 'Create Display Method Call'}}
await api.client.display.create({
surveyId: "<your-survey-id>", // required
userId: "<your-user-id>", // optional
responseId: "<your-response-id>", // optional
});
```
```javascript {{ title: 'Create Display Method Return Type' }}
Promise<{ id: string }, NetworkError | Error>
```
</CodeGroup>
</Col>
- Update Display
<Col>
<CodeGroup title="Update Display">
```javascript {{ title: 'Update Display Method Call'}}
await api.client.display.update(
displayId: "<your-display-id>",
{
userId: "<your-user-id>", // optional
responseId: "<your-response-id>", // optional
},
);
```
```javascript {{ title: 'Update Display Method Return Type' }}
Promise<{ }, NetworkError | Error]>
```
</CodeGroup>
</Col>
## Responses
- Create Response
<Col>
<CodeGroup title="Create Response">
```javascript {{ title: 'Create Response Method Call'}}
await api.client.response.create({
surveyId: "<your-survey-id>", // required
finished: boolean, // required
data: {
// required
questionId: "<answer-to-this-question-in-string>",
anotherQuestionId: 123, // answer to this question in number
yetAnotherQuestionId: ["option1", "option2"], // answer to this question in array,
},
userId: "<your-user-id>",
singleUseId: "<your-single-use-id>",
ttc: {
questionId: 123,
},
meta: {
source: "<your-source>",
url: "<your-url>",
userAgent: {
browser: "<your-browser>",
device: "<your-device>",
os: "<your-os>",
},
country: "<your-country>",
},
});
```
```javascript {{ title: 'Create Response Method Return Type' }}
Promise<{ id: string }, NetworkError | Error>
```
</CodeGroup>
</Col>
- Update Response
<Col>
<CodeGroup title="Update Response">
```javascript {{ title: 'Update Response Method Call'}}
await api.client.response.update({
responseId: "<your-response-id>", // required
finished: boolean, // required
data: {
// required
questionId: "<answer-to-this-question-in-string>",
anotherQuestionId: 123, // answer to this question in number
yetAnotherQuestionId: ["option1", "option2"], // answer to this question in array,
},
ttc: {
// required
questionId: 123,
},
});
```
```javascript {{ title: 'Update Response Method Return Type' }}
Promise<{ }, NetworkError | Error]>
```
</CodeGroup>
</Col>
## Action
- Create Action:
<Note> An environment cannot have 2 actions with the same name. </Note>
<Col>
<CodeGroup title="Create Action">
```javascript {{ title: 'Create Action Method Call'}}
await api.client.action.create({
name: "<your-action-name>", // required
userId: "<your-user-id>", // required
});
```
```javascript {{ title: 'Create Action Method Return Type' }}
Promise<{ }, NetworkError | Error]>
```
</CodeGroup>
</Col>
## Attribute
- Update Attribute
<Col>
<CodeGroup title="Update Attribute">
```javascript {{ title: 'Update Attribute Method Call'}}
await api.client.attribute.update({
userId: "<your-user-id>", // required
attributes: {
key1: "value1",
key2: "value2",
}, // required
});
```
```javascript {{ title: 'Update Attribute Method Return Type' }}
Promise<{ changed: boolean, message: string }, NetworkError | Error>
```
</CodeGroup>
</Col>
## People
- Create Person
<Col>
<CodeGroup title="Create Person">
```javascript {{ title: 'Create Person Method Call'}}
await api.client.people.create({
userId: "<your-user-id>", // required
});
```
```javascript {{ title: 'Create Person Method Return Type' }}
Promise<{ }, NetworkError | Error]>
```
</CodeGroup>
</Col>
## Storage
- Upload File:
<Col>
<CodeGroup title="Upload File">
```javascript {{ title: 'Upload Method Call'}}
await api.client.storage.uploadFile(
file: File, // required (of interface File of the browser's File API)
{
allowedFileTypes: ["file-type-allowed", "for-example", "image/jpeg"],
surveyId: "<your-survey-id>",
}
);
```
```javascript {{ title: 'Upload Method Return Type' }}
Promise<fileUrl>
```
</CodeGroup>
</Col>
---
If you have any questions or need help, feel free to reach out to us on our **[Discord](https://formbricks.com/discord)**

View File

@@ -1,245 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import I1 from "./images/1-set-up-in-app-micro-survey-popup.webp";
import I2 from "./images/2-micro-survey-pop-up-in-app.webp";
import I3 from "./images/3-survey-logs-in-app-survey-popup.webp";
export const metadata = {
title: "Formbricks App Survey SDK",
description:
"An overview of all available methods & how to integrate Formbricks App Surveys for frontend developers in web applications. Learn the key methods, configuration settings, and best practices.",
};
#### Developer Docs
# SDK: App Survey
### 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. Its available on npm [here](https://www.npmjs.com/package/@formbricks/js/).
### Install
<Col>
<CodeGroup title="npm">
```js {{ title: 'npm' }}
npm install @formbricks/js
```
```js {{ title: 'yarn' }}
yarn add @formbricks/js
```
```js {{ title: 'pnpm' }}
pnpm add @formbricks/js
```
</CodeGroup>
</Col>
## Methods
### Initialize Formbricks
Initialize the Formbricks JS Client for app surveys where you pass the userId (creates a user if not existing in Formbricks) to attribute & target the user based on their actions.
<Col>
<CodeGroup title="Initialize Formbricks">
```javascript
import formbricks from "@formbricks/js/app";
formbricks.init({
environmentId: "<your-environment-id>", // required
apiHost: "<your-api-host>", // required
userId: "<user-id>" // required
});
```
</CodeGroup>
</Col>
The moment you initialise Formbricks, your user will start seeing surveys that get triggered on simpler actions such as on New Session, Page Exit, & other custom actions!
<Note>
Formbricks JS is a client SDK meant to be run client-side in their browser so make sure the window object is accessible. Below is an example of how you can set it!
<Col>
<CodeGroup>
```js
if (window !== undefined) {
formbricks.init({
environmentId: "<your-environment-id>",
apiHost: "<your-api-host>",
userId: "<user-id>"
});
} else {
console.error("Window object not accessible to init Formbricks");
}
```
</CodeGroup>
</Col>
</Note>
### Set Attribute
You can set custom attributes for the identified user. This can be helpful for segmenting users based on specific characteristics or properties. To learn how to set custom user attributes, please check out our [User Attributes Guide](/app-surveys/user-identification).
<Col>
<CodeGroup>
```js
formbricks.setAttribute("Plan", "Paid");
```
</CodeGroup>
</Col>
### Track Action
Track user actions to trigger surveys based on user interactions, such as button clicks or scrolling:
<Col>
<CodeGroup>
```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.
<Col>
<CodeGroup>
```js
formbricks.logout();
```
</CodeGroup>
</Col>
After calling formbricks.logout(), you'll need to reinitialize Formbricks before using any of its features again. Ensure that you properly reinitialize Formbricks to avoid unexpected errors or behavior in your application.
### Reset
Reset the current instance and fetch the latest surveys and state again:
<Col>
<CodeGroup>
```js
formbricks.reset();
```
</CodeGroup>
</Col>
### Register Route Change:
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>
<Col>
<CodeGroup>
```js
formbricks.registerRouteChange();
```
</CodeGroup>
</Col>
## Debug Mode
To enable debug mode in Formbricks, add `?formbricksDebug=true` to your apps URL.
For example, if youve integrated Formbricks JS to your app hosted at `https://example.com`, then change the URL to `https://example.com?formbricksDebug=true` and refresh the page, now view the console logs to see the debug mode live in action.
This activates detailed debug messages in the browser console, providing deeper insights into Formbricks' operation and potential issues.
---
## Troubleshooting
In case you dont see your survey right away, here's what you can do. Go through these to find the error fast:
### 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:
<MdxImage
src={I1}
alt="setup checklist ui of survey popup for app surveys"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
**How to fix it:**
1. Check if your app 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 dont see them, double check your integration.
---
### Survey not loaded
If your app is connected with Formbricks Cloud, the survey might have not been loaded properly. Check the debug logs and search for the list of surveys loaded. It should look like so:
<MdxImage
src={I3}
alt="survey logs for app survey pop up micro"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
**How to fix it:**
The widget only loads surveys which are **public** and **in progress**. Go to Formbricks Cloud and to the Survey Summary page. Check if your survey is live:
<MdxImage
src={I2}
alt="ui of survey popup for app micro surveys"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
---
### Survey not triggered
If the survey is loaded by the widget it might not have been triggered properly.
**How to fix:**
1. Open your local app in an incognito tab or window. The New Session event is only fired if a user was inactive for 60 minutes or was logged out of Formbricks via formrbicks.logout().
2. Check the debug logs for “Event New Session” tracked”. If you see it in the logs and the survey still did not get displayed, [please let us know.](mailto:support@formbricks.com)
---
### Survey not displayed in HTML page
If the survey is loaded by the widget in the HTML page, try the below steps:
**How to fix:**
1. Make sure you have added the [script](/app-surveys/framework-guides#html) in the head of the HTML page.
2. Verify that you have set the \<environment-id\> and \<host\> as per your Formbricks instance.
3. Verify that you have the latest version of the JS Package.
4. Check the debug logs to see if you still see any errors.
---
### Cannot read undefined of .init()
If you see this error in the console, it means that the Formbricks JS package is not loaded properly.
**How to fix:**
1. Update to the latest version of the JS Package.
2. Verify this wherever you call initialise the Formbricks instance in your code.
3. It should now start working.
---
If you are still facing issues, please [Open an Issue on GitHub](https://github.com/formbricks/formbricks/issues) or [join our Discord](https://formbricks.com/discord)! Were more than happy to help you get started 😊

View File

@@ -1,125 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import ConnectWithGoogle from "./connect-with-google.webp";
import DeleteConnection from "./delete-connection.webp";
import GoogleConnected from "./google-connected.webp";
import IntegrationTab from "./integrations-tab.webp";
import LinkSurveyWithSheet from "./link-survey-with-sheet.webp";
import LinkWithQuestions from "./link-with-questions.webp";
import ListLinkedSurveys from "./list-linked-surveys.webp";
export const metadata = {
title: "Google Sheets",
description:
"The Google Sheets integration allows you to automatically send responses to a Google Sheet of your choice.",
};
#### Integrations
# Google Sheets
The Google Sheets integration allows you to automatically send responses to a Google Sheet of your choice.
<Note>
This feature is enabled by default in Formbricks Cloud but needs to be self-configured when running a
self-hosted version of Formbricks. For self-configuration, see additional setup
[below](#setup-in-self-hosted-formbricks).
</Note>
## Connect Google Sheets
1. Go to the Integrations tab in your [Formbricks Cloud dashboard](https://app.formbricks.com/) and click on the "Connect" button under Google Sheets integration.
<MdxImage
src={IntegrationTab}
alt="Formbricks Integrations Tab"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
2. Now click on the "Connect with Google" button to authenticate yourself with Google.
<MdxImage
src={ConnectWithGoogle}
alt="Connect Formbricks with your Google"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
3. You will now be taken to the Google OAuth page where you can select the Google account you want to use for the integration.
4. Once you have selected the account and completed the authentication process, you will be taken back to Formbricks Cloud and see the connected status as below:
<MdxImage
src={GoogleConnected}
alt="Formbricks is now connected with Google"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
<Note>
Before the next step, make sure that you have a Formbricks Survey with at least one question and a Google Sheet in the Google account you integrated.
</Note>
5. Now click on the "Link New Sheet" button to link a Google Sheet with Formbricks and a modal will open up.
<MdxImage
src={LinkSurveyWithSheet}
alt="Link Formbricks with a Google Sheet"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
6. Select the Google Sheet you want to link with Formbricks and the Survey. On doing so, you will be asked with what questions' responses you want to feed in the Google Sheet. Select the questions and click on the "Link Sheet" button.
<MdxImage
src={LinkWithQuestions}
alt="Select question to link with Google Sheet"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
7. On submitting, the modal will close and you will see the linked Google Sheet in the list of linked Google Sheets.
<MdxImage
src={ListLinkedSurveys}
alt="List of linked Google Sheets"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Congratulations! You have successfully linked a Google Sheet with Formbricks. Now whenever a response is submitted for the linked survey, it will be automatically added to the linked Google Sheet.
## Remove Integration with Google Account
To remove the integration with Google Account,
1. Visit the Integrations tab in your Formbricks Cloud dashboard.
2. Select **Manage Sheets** button in the Google Sheets card.
3. Click on the **Delete Integration** button.
4. It will now ask for a confirmation to remove the integration. Click on the **Delete** button to remove the integration. You can always come back and connect again with the same Google Account.
<MdxImage
src={DeleteConnection}
alt="Delete Google Integration with Formbricks"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
## What info do you need?
- Your **Email ID** for authentication (We use this to identify you)
- Your **Google Sheets Names and IDs** (We fetch this to list and show you the options of choosing a sheet to integrate with)
- Write access to **selected Google Sheet** (The google sheet you choose to integrate it with, we write survey responses to it)
For the above, we ask for:
1. **User Email**: To identify you (that's it, nothing else, we're opensource, see this in our codebase [here](https://github.com/formbricks/formbricks/blob/main/apps/web/app/api/google-sheet/callback/route.ts#L47C17-L47C25))
1. **Google Drive API**: To list all your google sheets (that's it, nothing else, we're opensource, see this method in our codebase [here](https://github.com/formbricks/formbricks/blob/main/packages/lib/googleSheet/service.ts#L13))
1. **Google Spreadsheet API**: To write to the spreadsheet you select (that's it, nothing else, we're opensource, see this method in our codebase [here](https://github.com/formbricks/formbricks/blob/main/packages/lib/googleSheet/service.ts#L70))
<Note>We store as little personal information as possible.</Note>
Still struggling or something not working as expected? [Join our Discord!](https://formbricks.com/discord) and we'd be glad to assist you!

View File

@@ -1,27 +0,0 @@
export const metadata = {
title: "Configuring Formbricks with third party applications",
description: "Configure third-party integrations with a Formbricks instance.",
};
#### Developer Docs
# Overview
At Formbricks, we understand the importance of integrating with third-party applications. We have step-by-step guides to configure our third-party integrations with a your Formbricks instance. We currently support the below integrations, click on them to see their individual guides:
<Note>
If you are on a self-hosted instance, you will need to configure these integrations manually. Please follow the guides [here](/self-hosting/integrations) to configure them.
</Note>
- [Airtable](/developer-docs/integrations/airtable): Automatically send responses to an Airtable of your choice.
- [Google Sheets](/developer-docs/integrations/google-sheets): Automatically send responses to a Google Sheet of your choice.
- [Make](/developer-docs/integrations/make): Leverage Make's powerful automation capabilities to automate your workflows.
- [n8n](/developer-docs/integrations/n8n): Automate workflows with n8n's no-code automation tool.
- [Notion](/developer-docs/integrations/notion): Automatically send responses to a Notion database of your choice.
- [Slack](/developer-docs/integrations/slack): Automatically send responses to a Slack channel of your choice on response events.
- [Wordpress](/developer-docs/integrations/wordpress): Automatically integrate your Formbricks surveys with your Wordpress website.
- [Zapier](/developer-docs/integrations/zapier): Connect Formbricks with 2000+ apps on Zapier.
---
If you have any questions or need help with any of the integrations or even want a new integration, please reach out to us on [Discord](https://formbricks.com/discord).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

View File

@@ -1,168 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import ConnectWithSlack from "./images/connect-with-slack.png";
import DeleteConnection from "./images/delete-connection.png";
import IntegrationsTab from "./images/integrations-tab.png";
import LinkSurveyWithChannel from "./images/link-survey-with-channel.png";
import LinkWithQuestions from "./images/link-with-questions.png";
import ListLinkedSurveys from "./images/list-linked-surveys.png";
import SlackAuth from "./images/slack-auth.png";
import SlackConnected from "./images/slack-connected.png";
export const metadata = {
title: "Slack",
description:
"The slack integration allows you to automatically send responses to a Slack channel of your choice.",
};
#### Integrations
# Slack
The slack integration allows you to automatically send responses to a Slack channel of your choice.
<Note>
This feature is enabled by default in Formbricks Cloud but needs to be self-configured when running a
self-hosted version of Formbricks.
</Note>
## Formbricks Cloud
1. Go to the Integrations tab in your [Formbricks Cloud dashboard](https://app.formbricks.com/) and click on the "Connect" button under Slack integration.
<MdxImage
src={IntegrationsTab}
alt="Formbricks Integrations Tab"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
2. Now click on the "Connect with Slack" button to authenticate yourself with Slack.
<MdxImage
src={ConnectWithSlack}
alt="Connect Formbricks with your Slack Workspace"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
3. You will now be taken to the Slack OAuth page where you can select the Slack channel you want to link with Formbricks and click on the "Allow" button.
<MdxImage
src={SlackAuth}
alt="Slack OAuth Page"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
4. Once you have selected the account and completed the authentication process, you will be taken back to Formbricks Cloud and see the connected status as below:
<MdxImage
src={SlackConnected}
alt="Formbricks is now connected with Slack"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
<Note>
Before the next step, make sure that you have a Formbricks Survey with at least one question and a Slack
channel in the Slack workspace you integrated.
</Note>
5. Now click on the "Link channel" button to link a Slack channel with Formbricks and a modal will open up.
<MdxImage
src={LinkSurveyWithChannel}
alt="Link Formbricks with a Slack Channel"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
6. Select the channel you want to link with Formbricks and the Survey. On doing so, you will be asked to select the questions' responses you want to feed in the Slack channel. Select the questions and click on the "Link Channel" button.
<MdxImage
src={LinkWithQuestions}
alt="Select question to link with Slack Channel"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
7. On submitting, the modal will close and you will see the linked Slack channel in the list of linked Slack channels.
<MdxImage
src={ListLinkedSurveys}
alt="List of linked Slack Channels"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Congratulations! You have successfully linked a Slack channel with Formbricks. Now whenever a response is submitted for the linked survey, it will be automatically sent to the linked Slack channel.
## Setup in self-hosted Formbricks
Enabling the Slack Integration in a self-hosted environment requires a setup using slack workspace account and changing the environment variables of your Formbricks instance.
<Note>
If you are running Formbricks locally:
You need to use `https` instead of `http` for the redirect URI.
- You can update the `go` script in your `apps/web/package.json` to include the `--experimental-https` flag. The
command will look like: <br />
```bash
"go": next dev --experimental-https -p 3000
```
- You also need to update the .env file in the `apps/web` directory to include the `NEXTAUTH_URL` and `WEBAPP_URL` as `https://localhost:3000` instead of `http://localhost:3000`.
- You also need to run the terminal in admin mode to run the `go` script(to acquire the SSL certificate). You can do this by running the terminal as an administrator or using the `sudo` command in Unix-based systems.
</Note>
1. Create a Slack workspace if you don't have one already.
2. Go to the [Your apps](https://api.slack.com/apps) page and **Create New App**.
3. Click on **From Scratch** and provide the **App Name** and select your workspace in **Pick a workspace to develop your app in:** dropdown. Click on **Create App**.
4. Go to the **OAuth & Permissions** tab on the sidebar and add the following **Bot Token Scopes**:
- `channels:read`
- `chat:write`
- `chat:write.public`
- `chat:write.customize`
5. Add the **Redirect URLs** under **OAuth & Permissions** tab. You can add the following URLs:
- If you are running formbricks locally, you can enter `https://localhost:3000/api/v1/integrations/slack/callback`.
- Or, you can enter `https://<your-public-facing-url>/api/v1/integrations/slack/callback`
6. Now, click on **Install to Workspace** and **Allow** the permissions.
7. Go to the **Basic Information** tab on the sidebar and copy the **Client ID** and **Client Secret**. Copy them and set them as the environment variables in your Formbricks instance as:
- `SLACK_CLIENT_ID` - OAuth Client ID
- `SLACK_CLIENT_SECRET` - OAuth Client Secret
8. Now, you need to enable the public distribution of your app. Go to the **Basic Information** tab and click on the **Manage distribution** button and click on the "Distribute App".
9. Scroll down to the **Share your app with other workspaces** section, complete the checklist and click on the **Activate public distribution** button.
### By now, your environment variables should include the below ones:
- `SLACK_CLIENT_ID`
- `SLACK_CLIENT_SECRET`
Voila! You have successfully enabled the Slack integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Formbricks Cloud](#formbricks-cloud) section to link a Slack workspace with Formbricks.
## Remove Integration with Slack Workspace
To remove the integration with Slack Workspace,
1. Visit the Integrations tab in your Formbricks Cloud dashboard.
2. Select "Manage" button in the Slack card.
3. Click on the "Delete Integration" button.
4. It will now ask for a confirmation to remove the integration. Click on the "Delete" button to remove the integration. You can always come back and connect again with the same Slack Workspace.
<MdxImage
src={DeleteConnection}
alt="Delete Slack Integration with Formbricks"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Still struggling or something not working as expected? [Join our Discord!](https://formbricks.com/discord) and we'd be glad to assist you!

View File

@@ -1,37 +0,0 @@
export const metadata = {
title: "Formbricks Developer Documentation Overview",
description:
"Welcome to the Developer Docs section, your comprehensive resource for integrating and utilizing Formbricks SDKs & APIs, as well as contributing to our open source codebase. Dive into the documentation to discover how to deploy surveys on your website and effectively engage with your audience.",
};
#### Developer Docs
# Overview
Welcome to the Developer Docs section, your comprehensive resource for integrating and utilizing Formbricks SDKs &APIs, as well as contributing to our open source codebase. Here's what you can expect to find in this section:
### [SDK: App Survey](/developer-docs/app-survey-sdk)
The Formbricks JS SDK tailored for App Surveys is designed for applications where users are logged in, allowing for targeted and identified interactions within Formbricks. This SDK is particularly useful for advanced user tracking, enabling deeper insights into user behavior. Learn how to seamlessly integrate Formbricks into your applications and harness valuable insights from your logged-in users.
### [SDK: Website Survey](/developer-docs/website-survey-sdk)
The Formbricks JS SDK for Website Surveys is ideal for public-facing websites without user authentication. It's recommended for pages with high traffic and no authentication walls, facilitating quick and efficient survey collection. Dive into the documentation to discover how to deploy surveys on your website and effectively engage with your audience.
### [SDK: Formbricks API](/developer-docs/api-sdk)
Get acquainted with the Formbricks API JS SDK, empowering you to interact with Formbricks programmatically. Learn how to access Formbricks functionalities and automate tasks to streamline your workflow.
### [REST API](/developer-docs/rest-api)
Explore the Formbricks REST API documentation with Postman, providing detailed insights into available endpoints, request methods, and response formats. Integrate Formbricks seamlessly into your applications using RESTful principles.
### [Webhooks](/developer-docs/webhooks)
Learn about Formbricks Webhooks and how to set up event-driven notifications in your applications using our UI as well as API. Stay updated with real-time data and trigger actions based on specific response events within your Formbricks environment.
### [Contributing to Formbricks](/developer-docs/contributing)
Interested in contributing to the Formbricks ecosystem? This page provides guidance on how to run Formbricks locally, report issues, contribute through code, and collaborate with the Formbricks community to enhance the platform for everyone.
If you have any questions or need assistance, feel free to reach out to us on [Discord](https://formbricks.com/discord). Happy coding!

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

View File

@@ -1,64 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import StepFive from "./images/StepFive.png";
import StepFour from "./images/StepFour.png";
import StepOne from "./images/StepOne.png";
import StepThree from "./images/StepThree.png";
import StepTwo from "./images/StepTwo.png";
export const metadata = {
title: "Formbricks Webhooks Overview",
description:
"Formbricks provides a powerful Webhooks system to notify your application about response related events that happen in your Formbricks surveys. Learn how to set up Webhooks, the available events, and how to handle them in your application.",
};
#### Developer Docs
# Webhooks
Formbricks' Webhook API offers a powerful interface for interacting with webhooks. Webhooks allow you to receive real-time HTTP notifications of changes to specific objects in the Formbricks environment.
These APIs are designed to facilitate seamless integration of Formbricks with third-party systems. By making use of our webhook API, you can automate the process of sending data to these systems whenever significant events occur within your Formbricks environment.
### Leveraging Webhooks
The behavior of the webhooks is determined by their trigger settings. The trigger determines which updates the webhook sends. Current available triggers include:
- "responseCreated"
- "responseUpdated",
- "responseFinished".
### Creating Webhooks
There are 2 ways for you to create webhooks with Formbricks ie either via our App UI or through API.
**UI:**
1. Login to the Formbricks App & switch to the Integrations Tab
<MdxImage src={StepOne} alt="Step One" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
2. Click on **Manage Webhooks** & then **Add Webhook** button:
<MdxImage src={StepTwo} alt="Step Two" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
3. Add your webhook listener endpoint & test it to make sure it can receive the test endpoint otherwise you will not be able to save it.
<MdxImage src={StepThree} alt="Step Three" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
4. Now add the triggers you want to listen to and the surveys!
<MdxImage src={StepThree} alt="Step Four" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
Thats it! Your webhooks will not start receiving data as soon as it arrives!
<MdxImage
src={StepFive}
alt="Step Five"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
- API: Use our documented methods on Creation, List, & Deletion endpoints of the Webhook API mentioned in the [Postman Documenter](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#62e6ec65-021b-42a4-ac93-d1434b393c6c)
---

View File

@@ -1,145 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
export const metadata = {
title: "Formbricks Website Survey SDK",
description:
"An overview of all available methods & how to integrate Formbricks Website Surveys for frontend developers in public-facing web applications. Learn the key methods, configuration settings, and best practices.",
};
#### Developer Docs
# SDK: Website Survey
### 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 website surveys.
### Install
<Col>
<CodeGroup title="npm">
```js {{ title: 'npm' }}
npm install @formbricks/js
```
```js {{ title: 'yarn' }}
yarn add @formbricks/js
```
```js {{ title: 'pnpm' }}
pnpm add @formbricks/js
```
</CodeGroup>
</Col>
## Methods
### Initialize Formbricks
Initialize the Formbricks JS Client specifically for website surveys, ideal for public-facing websites:
<Note>you cannot set any other attribute other than language (optional) in website surveys.</Note>
<Col>
<CodeGroup title="Initialize Formbricks">
```javascript
import formbricks from "@formbricks/js/website";
formbricks.init({
environmentId: "<your-environment-id>", // required
apiHost: "<your-api-host>", // required
attributes: {
// optional
language: "de", // optional
},
});
```
</CodeGroup>
</Col>
The moment you initialise Formbricks, your users will start seeing surveys that get triggered on simpler actions such as on New Session, Page Exit, & other custom actions!
<Note>
Formbricks JS is a client SDK meant to be run client-side in their browser so make sure the window object is accessible. Below is an example of how you can set it!
<Col>
<CodeGroup>
```js
if (window !== undefined) {
formbricks.init({
environmentId: "<your-environment-id>",
apiHost: "<your-api-host>",
});
} else {
console.error("Window object not accessible to init Formbricks");
}
```
</CodeGroup>
</Col>
</Note>
### Track Action
Track session actions to trigger surveys based on their interactions on your website, such as button clicks or scrolling:
<Col>
<CodeGroup>
```js
formbricks.track("Clicked on Claim");
```
</CodeGroup>
</Col>
### Reset
Reset the current instance and fetch the latest surveys and state again:
<Col>
<CodeGroup>
```js
formbricks.reset();
```
</CodeGroup>
</Col>
### Register Route Change:
Listen for page changes and dynamically show surveys configured via no-code actions in the Formbricks website:
<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>
```js
formbricks.registerRouteChange();
```
</CodeGroup>
</Col>
## Debug Mode
To enable debug mode in Formbricks, add `?formbricksDebug=true` to your apps URL.
For example, if youve integrated Formbricks JS to your app hosted at `https://example.com`, then change the URL to `https://example.com?formbricksDebug=true` and refresh the page, now view the console logs to see the debug mode live in action.
This activates detailed debug messages in the browser console, providing deeper insights into Formbricks' operation and potential issues.
---
If you have any questions or need help, feel free to reach out to us on our **[Discord](https://formbricks.com/discord)**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -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 wont be able to see it again.
<MdxImage
src={ApiKeySecret}
alt="API Key Secret"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
<Note>
### Store API key safely! Anyone who has your API key has full control over your account. For security
reasons, you cannot view the API key again.
</Note>
### Test your API Key
Hit the below request to verify that you are authenticated with your API Key and the server is responding.
## Get My Profile {{ tag: 'GET', label: '/api/v1/me' }}
<Row>
<Col>
Get the product details and environment type of your account.
### Mandatory Headers
<Properties>
<Property name="x-Api-Key" type="string">
Your Formbricks API key.
</Property>
</Properties>
### Delete a personal API key
1. Go to settings on [app.formbricks.com](https://app.formbricks.com/).
2. Go to page “API keys”.
3. Find the key you wish to revoke and select “Delete”.
4. Your API key will stop working immediately.
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/me">
```bash {{ title: 'cURL' }}
curl --location \
'https://app.formbricks.com/api/v1/me' \
--header \
'x-api-key: <your-api-key>'
```
</CodeGroup>
<CodeGroup title="Response">
```json {{title:'200 Success'}}
{
"id": "cll2m30r70004mx0huqkitgqv",
"createdAt": "2023-08-08T18:04:59.922Z",
"updatedAt": "2023-08-08T18:04:59.922Z",
"type": "production",
"product": {
"id": "cll2m30r60003mx0hnemjfckr",
"name": "My Product"
},
"widgetSetupCompleted": false
}
```
```json {{ title: '401 Not Authenticated' }}
Not authenticated
```
</CodeGroup>
</Col>
</Row>
Cant figure it out? Join our [Discord](https://discord.com/invite/3YFcABF2Ts) and we'd be glad to assist you!
---

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1,136 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import StepEight from "./images/StepEight.png";
import StepFive from "./images/StepFive.png";
import StepFour from "./images/StepFour.png";
import StepOne from "./images/StepOne.png";
import StepSeven from "./images/StepSeven.png";
import StepSix from "./images/StepSix.png";
import StepThree from "./images/StepThree.png";
import StepTwo from "./images/StepTwo.png";
export const metadata = {
title: "Conditional Logic in Formbricks Surveys",
description:
"Enhance your surveys with Conditional Logic to create a dynamic and responsive survey experience. Guide respondents through different paths based on their answers, ensuring each survey is tailored to the users responses. This feature is applicable for all kinds of surveys!",
};
# Conditional Logic
With Formbricks, enhance your surveys with Conditional Logic to create a dynamic and responsive survey experience. This feature allows you to guide respondents through different paths based on their answers, ensuring each survey is tailored to the users responses. This feature is applicable for all kinds of surveys!
### Setting Up Conditional Logic
Conditional Logic can be applied to any question within your survey to direct the flow based on specific responses.
1. **Create or Edit a Question**: Start by adding a new question or editing an existing one within your survey.
<MdxImage
src={StepOne}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. **Access Advanced Settings**: Click on **Advanced Settings** beneath the question setup area to access additional configuration options.
<MdxImage
src={StepTwo}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
3. **Configure Logic Jumps**: Choose **Logic Jumps** to set up conditions that dictate the survey's progression based on responses.
<MdxImage
src={StepThree}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
### Configuring Logic Conditions
Enhance survey interactivity by setting up triggers based on respondent answers. You can specify different paths for each type of response:
**General Conditions (Available in All Question Types):**
- **Answer Submitted/Skipped**: Initiate different survey paths based on whether a question is answered or skipped.
<MdxImage
src={StepFour}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
**Choice-Based Conditions:**
<MdxImage
src={StepFive}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **One of Multiple Choice Values**: Activate if the answer is among selected options. (Single select and Multi select)
- **Equals: Exactly the Selected Values**: Initiate a jump if the response matches exactly the selected values provided in the options. (Single select and Multi select)
- **Includes All Selected Values**: Activate if all selected values match those chosen by the survey creator. (Multi select only)
**Numeric Conditions (Rating & NPS Questions Only)**
<MdxImage
src={StepSix}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Value Comparisons**: Initiate jumps based on numerical criteria—equals, does not equal, less than, less than or equal to, greater than, or greater than equal to.
**Matrix-Specific Conditions**
<MdxImage
src={StepSeven}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Submission Completeness**: Initiate based on whether the response is completely or partially submitted.
### **Specifying Survey Paths**
After setting conditions, you specify the paths to take when those conditions are met:
- **Jump to a Specific Question**: Direct the respondent to a particular question elsewhere in the survey.
- **Jump to Survey End**: Conclude the survey early based on the respondent's answers.
<MdxImage
src={StepEight}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
### **Multiple Logic Jumps**
You can add multiple Logic Jumps to a single question. These jumps work in an **OR** fashion, meaning any of the conditions can initiate the specified survey path. The logic jumps are evaluated in the **order they are created**, and the first true condition will take precedence.
---
### **Example Scenario**
Suppose youre conducting a survey about technology usage:
1. **Question (Single Select)**: What devices do you use daily?
2. **Answers**: Smartphone, Laptop, Tablet, None
**Logic Jump Setup**:
- If the respondent selects **None**, jump to the end of the survey.
- If the respondent selects **Smartphone**, jump to a question specific to smartphone usage.
This setup allows for a tailored survey experience that adapts to the respondent's input, making your data collection more targeted and efficient.
Thats it! Now go and configure your surveys to bring down your survey fatigue to 0% and ask respondents through customized paths. Enhance their relevance and engagement with your survey, leading to higher quality responses and better data.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -1,68 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import StepOne from "./images/StepOne.png";
import StepTwo from "./images/StepTwo.png";
import StepThree from "./images/StepThree.png";
export const metadata = {
title: "Custom Start & End Conditions for Surveys",
description:
"Optimize your survey management with custom Start & End Conditions in Formbricks. This feature allows you to control exactly when your survey is available for responses and when it should close, making it ideal for time-sensitive or number-of-response-limited surveys.",
};
# Custom Start & End Conditions
Optimize your survey management with custom Start & End Conditions in Formbricks. This feature allows you to control exactly when your survey is available for responses and when it should close, making it ideal for time-sensitive or number-of-response-limited surveys.
Configure your surveys to open and close based on specific criteria. Heres how to set up these conditions:
### **Opening a Survey**
**1. Schedule a Start Date:**
- **How to Set**: Open the Survey Editor, switch to the Settings tab. Scroll down to Response Options, Toggle the “Release Survey on Date”.
<MdxImage
src={StepOne}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Details**: Choose the date and time when the survey should become available to respondents. All times follow UTC timezone.
- **Use Case**: This is useful for launching surveys in alignment with events, product releases, or specific marketing campaigns.
### **Closing a Survey**
**1. Limit by Number of Responses:**
- **How to Set**: Open the Survey Editor, switch to the Settings tab. Scroll down to Response Options, Toggle the “Close survey on response limit”.
{" "}
<MdxImage
src={StepTwo}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Details**: Set a specific number of responses after which the survey automatically closes.
- **Use Case**: Perfect for limited offers, exclusive surveys, or when you need a precise sample size for statistical significance.
**2. Schedule an End Date:**
- **How to Set**: Open the Survey Editor, switch to the Settings tab. Scroll down to Response Options, Toggle the “Close survey on date”.
<MdxImage
src={StepThree}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Details**: Define a specific date and time for the survey to close. This also follows UTC timezone. - **Use
Case**: Essential for surveys linked to time-bound events or studies where data collection needs to end at a specific
point.
### **Summary**
Setting up Custom Start & End Conditions in Formbricks allows you to control the availability and duration of your surveys with precision. Whether you are conducting academic research, market analysis, or gathering event feedback, these settings help ensure that your data collection aligns perfectly with your objectives.
---

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

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