Compare commits

..

4 Commits

Author SHA1 Message Date
Matti Nannt
da86d95398 Merge branch 'main' into fix/radix-ref 2024-06-20 10:02:13 +02:00
Matti Nannt
00d49b91b2 Merge branch 'main' into fix/radix-ref 2024-06-20 08:14:06 +02:00
pandeymangg
3276ce7844 fix: refactor 2024-06-20 10:54:47 +05:30
pandeymangg
93ce9580a0 fix: radix ui upgrade 2024-06-20 10:47:59 +05:30
1359 changed files with 35412 additions and 55719 deletions

View File

@@ -7,5 +7,5 @@
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["@formbricks/demo", "@formbricks/web"]
"ignore": ["@formbricks/formbricks-com", "@formbricks/demo", "@formbricks/web"]
}

View File

@@ -21,7 +21,7 @@
"forwardPorts": [3000, 5432, 8025],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "cp .env.example .env && sed -i '/^ENCRYPTION_KEY=/c\\ENCRYPTION_KEY='$(openssl rand -hex 32) .env && sed -i '/^NEXTAUTH_SECRET=/c\\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env && sed -i '/^CRON_SECRET=/c\\CRON_SECRET='$(openssl rand -hex 32) .env && pnpm install && pnpm db:migrate:dev",
"postCreateCommand": "cp .env.example .env && sed -i '/^ENCRYPTION_KEY=/c\\ENCRYPTION_KEY='$(openssl rand -hex 32) .env && sed -i '/^NEXTAUTH_SECRET=/c\\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env && pnpm install && pnpm db:migrate:dev",
"postAttachCommand": "pnpm dev --filter=@formbricks/web... --filter=@formbricks/demo...",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.

View File

@@ -8,8 +8,8 @@
WEBAPP_URL=http://localhost:3000
# Required for next-auth. Should be the same as WEBAPP_URL
NEXTAUTH_URL=http://localhost:3000
# Set this if you want to have a shorter link for surveys
SHORT_URL_BASE=
# Encryption keys
# Please set both for now, we will change this in the future
@@ -17,20 +17,28 @@ NEXTAUTH_URL=http://localhost:3000
# You can use: `openssl rand -hex 32` to generate one
ENCRYPTION_KEY=
# @see: https://next-auth.js.org/configuration/options#nextauth_secret
# You can use: `openssl rand -hex 32` to generate a secure one
NEXTAUTH_SECRET=
# API Secret for running cron jobs. (mandatory)
# You can use: `openssl rand -hex 32` to generate a secure one
CRON_SECRET=
##############
# DATABASE #
##############
DATABASE_URL='postgresql://postgres:postgres@localhost:5432/formbricks?schema=public'
###############
# NEXT AUTH #
###############
# @see: https://next-auth.js.org/configuration/options#nextauth_secret
# You can use: `openssl rand -hex 32` to generate a secure one
NEXTAUTH_SECRET=RANDOM_STRING
# Set this to your public-facing URL, e.g., https://example.com
# You do not need the NEXTAUTH_URL environment variable in Vercel.
NEXTAUTH_URL=http://localhost:3000
# Cron Secret
# You can use: `openssl rand -hex 32` to generate a secure one
CRON_SECRET=
################
# MAIL SETUP #
################
@@ -46,9 +54,6 @@ SMTP_SECURE_ENABLED=0
SMTP_USER=smtpUser
SMTP_PASSWORD=smtpPassword
# If set to 0, the server will accept connections without requiring authorization from the list of supplied CAs (default is 1).
# SMTP_REJECT_UNAUTHORIZED_TLS=0
########################################################################
# ------------------------------ OPTIONAL -----------------------------#
########################################################################
@@ -70,8 +75,6 @@ S3_BUCKET_NAME=
# Configure a third party S3 compatible storage service endpoint like StorJ leave empty if you use Amazon S3
# e.g., https://gateway.storjshare.io
S3_ENDPOINT_URL=
# Force path style for S3 compatible storage (0 for disabled, 1 for enabled)
S3_FORCE_PATH_STYLE=0
#####################
# Disable Features #
@@ -173,10 +176,7 @@ ENTERPRISE_LICENSE_KEY=
UNSPLASH_ACCESS_KEY=
# The below is used for Next Caching (uses In-Memory from Next Cache if not provided)
# REDIS_URL=redis://localhost:6379
# 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:
# Disable custom cache handler if necessary (e.g. if deployed on Vercel)
# CUSTOM_CACHE_DISABLED=1

View File

@@ -1,33 +0,0 @@
name: oss.gg hack submission 🕹️
description: "Submit your contribution for the for the oss.gg hackathon"
title: "[🕹️]"
labels: 🕹️ oss.gg, player submission, hacktoberfest
assignees: []
body:
- type: textarea
id: contribution-name
attributes:
label: What side quest or challenge are you solving?
description: Add the name of the side quest or challenge.
validations:
required: true
- type: textarea
id: points
attributes:
label: Points
description: How many points are assigned to this contribution?
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: What's the task your performed?
validations:
- type: textarea
id: proof
attributes:
label: Provide proof that you've completed the task
description: Screenshots, loom recordings, links to the content you shared or interacted with.
validations:
required: true

View File

@@ -30,10 +30,6 @@ runs:
**/dist/**
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}
- name: Set Cache Hit Status
run: echo "cache-hit=${{ steps.cache-build.outputs.cache-hit }}" >> "$GITHUB_OUTPUT"
shell: bash
- name: Setup Node.js 20.x
uses: actions/setup-node@v3
with:
@@ -41,7 +37,7 @@ runs:
if: steps.cache-build.outputs.cache-hit != 'true'
- name: Install pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v2
if: steps.cache-build.outputs.cache-hit != 'true'
- name: Install dependencies
@@ -53,12 +49,10 @@ runs:
run: cp .env.example .env
shell: bash
- name: Fill ENCRYPTION_KEY, ENTERPRISE_LICENSE_KEY and E2E_TESTING in .env
- name: Fill ENCRYPTION_KE, ENTERPRISE_LICENSE_KEY and E2E_TESTING in .env
run: |
RANDOM_KEY=$(openssl rand -hex 32)
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${RANDOM_KEY}/" .env
sed -i "s/CRON_SECRET=.*/CRON_SECRET=${RANDOM_KEY}/" .env
sed -i "s/NEXTAUTH_SECRET=.*/NEXTAUTH_SECRET=${RANDOM_KEY}/" .env
sed -i "s/ENTERPRISE_LICENSE_KEY=.*/ENTERPRISE_LICENSE_KEY=${RANDOM_KEY}/" .env
echo "E2E_TESTING=${{ inputs.e2e_testing_mode }}" >> .env
shell: bash

View File

@@ -1,28 +0,0 @@
name: Build Docs
on:
workflow_call:
jobs:
build:
name: Build Docs
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/dangerous-git-checkout
- name: Setup Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 20.x
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install --config.platform=linux --config.architecture=x64
shell: bash
- run: |
pnpm build --filter=@formbricks/docs...
shell: bash

View File

@@ -1,4 +1,4 @@
name: Build Web
name: Build web
on:
workflow_call:
jobs:
@@ -11,8 +11,24 @@ jobs:
- uses: actions/checkout@v3
- uses: ./.github/actions/dangerous-git-checkout
- name: Build & Cache Web Binaries
uses: ./.github/actions/cache-build-web
id: cache-build-web
- name: Setup Node.js 20.x
uses: actions/setup-node@v3
with:
e2e_testing_mode: "0"
node-version: 20.x
- name: Install pnpm
uses: pnpm/action-setup@v2
- name: Install dependencies
run: pnpm install --config.platform=linux --config.architecture=x64
- name: create .env
run: cp .env.example .env
- name: Generate Random ENCRYPTION_KEY
run: |
SECRET=$(openssl rand -hex 32)
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
- name: Build Formbricks-web
run: pnpm build --filter=@formbricks/web...

View File

@@ -1,30 +0,0 @@
name: "Chromatic"
on:
push:
branches:
- main
workflow_dispatch:
jobs:
chromatic:
name: Run Chromatic
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install --config.platform=linux --config.architecture=x64
- name: Run Chromatic
uses: chromaui/action@latest
with:
# ⚠️ Make sure to configure a `CHROMATIC_PROJECT_TOKEN` repository secret
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
workingDir: apps/storybook

View File

@@ -2,83 +2,67 @@ name: E2E Tests
on:
workflow_call:
workflow_dispatch:
env:
TELEMETRY_DISABLED: 1
jobs:
build:
name: Run E2E Tests
runs-on: ubuntu-latest
timeout-minutes: 60
services:
postgres:
image: postgres:latest
env:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd="pg_isready -U testuser"
--health-interval=10s
--health-timeout=5s
--health-retries=5
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/dangerous-git-checkout
- name: Setup Node.js 20.x
uses: actions/setup-node@v3
- name: Build & Cache Web Binaries
uses: ./.github/actions/cache-build-web
with:
node-version: 20.x
e2e_testing_mode: "1"
- name: Install pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v2
- name: Install dependencies
run: pnpm install --config.platform=linux --config.architecture=x64
shell: bash
run: pnpm install
- name: create .env
run: cp .env.example .env
shell: bash
- name: Fill ENCRYPTION_KEY, ENTERPRISE_LICENSE_KEY and E2E_TESTING in .env
- name: Start PostgreSQL
run: |
RANDOM_KEY=$(openssl rand -hex 32)
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${RANDOM_KEY}/" .env
sed -i "s/CRON_SECRET=.*/CRON_SECRET=${RANDOM_KEY}/" .env
sed -i "s/NEXTAUTH_SECRET=.*/NEXTAUTH_SECRET=${RANDOM_KEY}/" .env
sed -i "s/ENTERPRISE_LICENSE_KEY=.*/ENTERPRISE_LICENSE_KEY=${RANDOM_KEY}/" .env
echo "E2E_TESTING=1" >> .env
shell: bash
- name: Build App
cd packages/database && pnpm db:up &
for attempt in {1..20}; do
if nc -zv localhost 5432; then
echo "Ready"
break
fi
echo "Waiting..."
sleep 5
done
pnpm db:migrate:dev
- name: Serve packages for lazy loading
run: |
pnpm build --filter=@formbricks/web...
- name: Apply Prisma Migrations
run: |
pnpm prisma migrate deploy
cd packages/surveys && pnpm serve &
- name: Run App
run: |
NODE_ENV=test pnpm start --filter=@formbricks/web &
sleep 10 # Optional: gives some buffer for the app to start
for attempt in {1..10}; do
for attempt in {1..20}; do
if [ $(curl -o /dev/null -s -w "%{http_code}" http://localhost:3000/health) -eq 200 ]; then
echo "Application is ready."
echo "Ready"
break
fi
if [ $attempt -eq 10 ]; then
echo "Application failed to start in time."
exit 1
fi
echo "Still waiting for the application to be ready..."
echo "Waiting..."
sleep 10
done
- name: Test Serve endpoints
run: |
curl -s http://localhost:3003
- name: Cache Playwright
uses: actions/cache@v3
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install Playwright
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm exec playwright install --with-deps
- name: Run E2E Tests

130
.github/workflows/kamal-deploy.yml vendored Normal file
View File

@@ -0,0 +1,130 @@
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_ORGANIZATION_ID: ${{ vars.DEFAULT_ORGANIZATION_ID }}
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

127
.github/workflows/kamal-setup.yml vendored Normal file
View File

@@ -0,0 +1,127 @@
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_ORGANIZATION_ID: ${{ vars.DEFAULT_ORGANIZATION_ID }}
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

@@ -11,13 +11,13 @@ jobs:
- uses: actions/checkout@v3
- uses: ./.github/actions/dangerous-git-checkout
- name: Setup Node.js 20.x
- name: Setup Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: 20.x
node-version: 18.x
- name: Install pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v2
- name: Install dependencies
run: pnpm install --config.platform=linux --config.architecture=x64
@@ -25,12 +25,10 @@ jobs:
- name: create .env
run: cp .env.example .env
- name: Generate Random ENCRYPTION_KEY, CRON_SECRET & NEXTAUTH_SECRET and fill in .env
- name: Generate Random ENCRYPTION_KEY and fill in .env
run: |
RANDOM_KEY=$(openssl rand -hex 32)
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${RANDOM_KEY}/" .env
sed -i "s/CRON_SECRET=.*/CRON_SECRET=${RANDOM_KEY}/" .env
sed -i "s/NEXTAUTH_SECRET=.*/NEXTAUTH_SECRET=${RANDOM_KEY}/" .env
ENCRYPTION_KEY=$(openssl rand -hex 32)
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${ENCRYPTION_KEY}/" .env
- name: Lint
run: pnpm lint

View File

@@ -50,13 +50,6 @@ jobs:
uses: ./.github/workflows/build-web.yml
secrets: inherit
docs:
name: Build Docs
needs: [changes]
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/build-docs.yml
secrets: inherit
e2e-test:
name: Run E2E Tests
needs: [changes]
@@ -66,7 +59,7 @@ jobs:
required:
name: PR Check Summary
needs: [lint, test, build, e2e-test, docs]
needs: [lint, test, build, e2e-test]
if: always()
runs-on: ubuntu-latest
steps:

View File

@@ -1,5 +1,10 @@
name: Docker for Data Migrations
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
on:
workflow_dispatch:
push:
@@ -7,6 +12,7 @@ on:
- "v*"
env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
IMAGE_NAME: formbricks/data-migrations
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/formbricks?schema=public"
@@ -17,6 +23,8 @@ jobs:
permissions:
contents: read
packages: write
# This is used to complete the identity challenge
# with sigstore/fulcio when running outside of PRs.
id-token: write
steps:
@@ -42,7 +50,6 @@ jobs:
tags: |
type=ref,event=tag
type=raw,value=${{ github.ref_name }}
type=raw,value=latest
- name: Build and push Docker image
uses: docker/build-push-action@v3
@@ -59,4 +66,3 @@ jobs:
if: ${{ github.event_name != 'pull_request' }}
run: |
cosign sign --yes ghcr.io/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
cosign sign --yes ghcr.io/${{ env.IMAGE_NAME }}:latest

View File

@@ -20,20 +20,6 @@ jobs:
id: lint_pr_title
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: |
fix
feat
chore
docs
style
refactor
perf
test
build
ci
revert
ossgg
- uses: marocchino/sticky-pull-request-comment@v2
# When the previous steps fails, the workflow would stop. By adding this

View File

@@ -17,7 +17,7 @@ jobs:
node-version: 20.x
- name: Install pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v2
- name: Install dependencies
run: pnpm install --config.platform=linux --config.architecture=x64
@@ -25,12 +25,10 @@ jobs:
- name: create .env
run: cp .env.example .env
- name: Generate Random ENCRYPTION_KEY, CRON_SECRET & NEXTAUTH_SECRET and fill in .env
- name: Generate Random ENCRYPTION_KEY and fill in .env
run: |
RANDOM_KEY=$(openssl rand -hex 32)
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${RANDOM_KEY}/" .env
sed -i "s/CRON_SECRET=.*/CRON_SECRET=${RANDOM_KEY}/" .env
sed -i "s/NEXTAUTH_SECRET=.*/NEXTAUTH_SECRET=${RANDOM_KEY}/" .env
ENCRYPTION_KEY=$(openssl rand -hex 32)
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${ENCRYPTION_KEY}/" .env
- name: Test
run: pnpm test

4
.gitignore vendored
View File

@@ -56,7 +56,5 @@ Zone.Identifier
packages/lib/uploads
# Vite Timestamps
*vite.config.*.timestamp-*
vite.config.*.timestamp-*
# js compiled assets
apps/web/public/js

View File

@@ -10,6 +10,9 @@ tasks:
gp sync-await init &&
turbo --filter "@formbricks/demo" go
- name: website
command: gp sync-await init && turbo --filter "@formbricks/formbricks-com" dev
- name: Init Formbricks
init: |
cp .env.example .env &&
@@ -30,6 +33,7 @@ tasks:
gp sync-await init &&
cp .env.example .env &&
sed -i -r "s#^(WEBAPP_URL=).*#\1 $(gp url 3000)#" .env &&
sed -i -r "s#^(NEXTAUTH_URL=).*#\1 $(gp url 3000)#" .env &&
RANDOM_ENCRYPTION_KEY=$(openssl rand -hex 32)
sed -i 's/^ENCRYPTION_KEY=.*/ENCRYPTION_KEY='"$RANDOM_ENCRYPTION_KEY"'/' .env
turbo --filter "@formbricks/web" go

View File

@@ -1 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm lint-staged

14
.kamal/hooks/post-deploy.sample Executable file
View File

@@ -0,0 +1,14 @@
#!/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

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

51
.kamal/hooks/pre-build.sample Executable file
View File

@@ -0,0 +1,51 @@
#!/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

47
.kamal/hooks/pre-connect.sample Executable file
View File

@@ -0,0 +1,47 @@
#!/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 ]

109
.kamal/hooks/pre-deploy.sample Executable file
View File

@@ -0,0 +1,109 @@
#!/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

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

3
.npmrc
View File

@@ -5,5 +5,4 @@ shared-workspace-shrinkwrap = true
access = public
enable-pre-post-scripts = true
legacy-peer-deps=true
node-linker=hoisted
save-exact=true
node-linker=hoisted

View File

@@ -16,9 +16,9 @@ Are you brimming with brilliant ideas? For new features that can elevate Formbri
Ready to dive into the code and make a real impact? Here's your path:
1. **Read our Best Practices**: [It takes 5 minutes](https://formbricks.com/docs/developer-docs/contributing/get-started) but will help you save hours 🤓
1. **Read our Best Practices**: [It takes 5 minutes](https://formbricks.com/docs/contributing/how-we-code) but will help you save hours 🤓
1. **Fork the Repository:** Fork our repository or use [Gitpod](https://formbricks.com/docs/developer-docs/contributing/gitpod) or use [Codespaces](https://formbricks.com/docs/developer-docs/contributing/codespaces)
1. **Fork the Repository:** Fork our repository or use [Gitpod](https://formbricks.com/docs/contributing/gitpod)
1. **Tweak and Transform:** Work your coding magic and apply your changes.

View File

@@ -1,9 +1,9 @@
Copyright (c) 2024 Formbricks GmbH
Copyright (c) 2023 Formbricks GmbH
Portions of this software are licensed as follows:
- All content that resides under the "packages/ee/" & "apps/web/app/(ee)" directories of this repository, if these directories exist, is licensed under the license defined in "packages/ee/LICENSE".
- All content that resides under the "packages/js/", "packages/react-native/" and "packages/api/" directories of this repository, if that directories exist, is licensed under the "MIT" license as defined in the "LICENSE" files of these packages.
- All content that resides under the "packages/ee/" directory of this repository, if that directory exists, is licensed under the license defined in "packages/ee/LICENSE".
- All content that resides under the "packages/js/", "packages/errors/" and "packages/api/" directories of this repository, if that directories exist, is licensed under the "MIT" license as defined in the "LICENSE" files of these packages.
- All third party components incorporated into the Formbricks Software are licensed under the original license provided by the owner of the applicable component.
- Content outside of the above mentioned directories or restrictions above is available under the "AGPLv3" license as defined below.

View File

@@ -1,7 +1,5 @@
<div id="top"></div>
<p align="center">Help us grow and star us on Github! ⭐️</p>
<p align="center">
<a href="https://formbricks.com">
@@ -146,12 +144,6 @@ Or you can also deploy Formbricks on [RepoCloud](https://repocloud.io) using the
[![Deploy on RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploy.png)](https://repocloud.io/details/?app_id=254)
##### Zeabur
Or you can also deploy Formbricks on [Zeabur](https://zeabur.com) using the button below.
[![Deploy to Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/templates/G4TUJL)
<a id="development"></a>
## 👨‍💻 Development
@@ -168,7 +160,7 @@ Here is what you need to be able to run Formbricks:
### Local Setup
To get started locally, we've got a [guide to help you](https://formbricks.com/docs/developer-docs/contributing/get-started#local-machine-setup).
To get started locally, we've got a [guide to help you](https://formbricks.com/docs/contributing/setup).
### Gitpod Setup
@@ -192,7 +184,7 @@ Here are a few options:
- Upvote issues with 👍 reaction so we know what the demand for a particular issue is to prioritize it within the roadmap.
Please check out [our contribution guide](https://formbricks.com/docs/developer-docs/contributing/get-started) and our [list of open issues](https://github.com/formbricks/formbricks/issues) for more information.
Please check out [our contribution guide](https://formbricks.com/docs/contributing/introduction) and our [list of open issues](https://github.com/formbricks/formbricks/issues) for more information.
## All Thanks To Our Contributors

View File

@@ -1,2 +0,0 @@
EXPO_PUBLIC_API_HOST=http://192.168.178.20:3000
EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID=clzr04nkd000bcdl110j0ijyq

View File

@@ -1,7 +0,0 @@
module.exports = {
extends: ["@formbricks/eslint-config/react.js"],
parserOptions: {
project: "tsconfig.json",
tsconfigRootDir: __dirname,
},
};

View File

@@ -1,35 +0,0 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
# dependencies
node_modules/
# Expo
.expo/
dist/
web-build/
# Native
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
# Metro
.metro-health-check*
# debug
npm-debug.*
yarn-debug.*
yarn-error.*
# macOS
.DS_Store
*.pem
# local env files
.env*.local
# typescript
*.tsbuildinfo

View File

@@ -1,34 +0,0 @@
{
"expo": {
"name": "react-native-demo",
"slug": "react-native-demo",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"jsEngine": "hermes",
"assetBundlePatterns": ["**/*"],
"ios": {
"supportsTablet": true,
"infoPlist": {
"NSCameraUsageDescription": "Take pictures for certain activities.",
"NSPhotoLibraryUsageDescription": "Select pictures for certain activities.",
"NSMicrophoneUsageDescription": "Need microphone access for recording videos."
}
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -1,6 +0,0 @@
module.exports = function babel(api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
};
};

View File

@@ -1,7 +0,0 @@
import { registerRootComponent } from "expo";
import { LogBox } from "react-native";
import App from "./src/app";
registerRootComponent(App);
LogBox.ignoreAllLogs();

View File

@@ -1,21 +0,0 @@
// Learn more https://docs.expo.io/guides/customizing-metro
const path = require("node:path");
const { getDefaultConfig } = require("expo/metro-config");
// Find the workspace root, this can be replaced with `find-yarn-workspace-root`
const workspaceRoot = path.resolve(__dirname, "../..");
const projectRoot = __dirname;
const config = getDefaultConfig(projectRoot);
// 1. Watch all files within the monorepo
config.watchFolders = [workspaceRoot];
// 2. Let Metro know where to resolve packages, and in what order
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, "node_modules"),
path.resolve(workspaceRoot, "node_modules"),
];
// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths`
config.resolver.disableHierarchicalLookup = true;
module.exports = config;

View File

@@ -1,28 +0,0 @@
{
"name": "@formbricks/demo-react-native",
"version": "1.0.0",
"main": "./index.js",
"scripts": {
"dev": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject",
"clean": "rimraf .turbo node_modules .expo"
},
"dependencies": {
"@formbricks/js": "workspace:*",
"@formbricks/react-native": "workspace:*",
"expo": "51.0.26",
"expo-status-bar": "1.12.1",
"react": "18.3.1",
"react-native": "0.74.4",
"react-native-webview": "13.8.6"
},
"devDependencies": {
"@babel/core": "7.25.2",
"@types/react": "18.3.11",
"typescript": "5.3.3"
},
"private": true
}

View File

@@ -1,52 +0,0 @@
import { StatusBar } from "expo-status-bar";
import { Button, LogBox, StyleSheet, Text, View } from "react-native";
import Formbricks, { track } from "@formbricks/react-native";
LogBox.ignoreAllLogs();
export default function App(): JSX.Element {
if (!process.env.EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID) {
throw new Error("EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID is required");
}
if (!process.env.EXPO_PUBLIC_API_HOST) {
throw new Error("EXPO_PUBLIC_API_HOST is required");
}
const config = {
environmentId: process.env.EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
apiHost: process.env.EXPO_PUBLIC_API_HOST,
userId: "random-user-id",
attributes: {
language: "en",
testAttr: "attr-test",
},
};
return (
<View style={styles.container}>
<Text>Formbricks React Native SDK Demo</Text>
<Button
title="Trigger Code Action"
onPress={() => {
track("code").catch((error: unknown) => {
// eslint-disable-next-line no-console -- logging is allowed in demo apps
console.error("Error tracking event:", error);
});
}}
/>
<StatusBar style="auto" />
<Formbricks initConfig={config} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});

View File

@@ -1,6 +0,0 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true
}
}

View File

@@ -0,0 +1,22 @@
interface SurveySwitchProps {
value: "website" | "app";
formbricks: any;
}
export const SurveySwitch = ({ value, formbricks }: SurveySwitchProps) => {
return (
<select
value={value}
onChange={(v) => {
formbricks.logout();
window.location.href = `/${v.target.value}`;
}}>
<option value="website" className="h-10 px-4 hover:bg-slate-100">
Website Surveys
</option>
<option value="app" className="hover:bg-slate-10 h-10 px-4">
App Surveys
</option>
</select>
);
};

View File

@@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -1,5 +1,15 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
async redirects() {
return [
{
source: "/",
destination: "/app",
permanent: false,
},
];
},
images: {
remotePatterns: [
{

View File

@@ -5,7 +5,7 @@
"scripts": {
"clean": "rimraf .turbo node_modules .next",
"dev": "next dev -p 3002 --turbo",
"go": "next dev -p 3002 --turbo",
"go": "next dev -p 3002",
"build": "next build",
"start": "next start",
"lint": "next lint"
@@ -13,8 +13,8 @@
"dependencies": {
"@formbricks/js": "workspace:*",
"@formbricks/ui": "workspace:*",
"lucide-react": "0.452.0",
"next": "14.2.15",
"lucide-react": "^0.395.0",
"next": "14.2.4",
"react": "18.3.1",
"react-dom": "18.3.1"
},

View File

@@ -1,6 +1,6 @@
import type { AppProps } from "next/app";
import Head from "next/head";
import "@formbricks/ui/globals.css";
import "../styles/globals.css";
const App = ({ Component, pageProps }: AppProps) => {
return (

View File

@@ -1,8 +1,9 @@
import Image from "next/image";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import formbricks from "@formbricks/js";
import fbsetup from "../public/fb-setup.png";
import formbricks from "@formbricks/js/app";
import { SurveySwitch } from "../../components/SurveySwitch";
import fbsetup from "../../public/fb-setup.png";
declare const window: any;
@@ -59,9 +60,10 @@ const AppPage = ({}) => {
}, []);
return (
<div className="min-h-screen bg-white px-12 py-6 dark:bg-slate-800">
<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 flex-col items-center gap-2 sm: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
@@ -115,7 +117,7 @@ const 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-900">
<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>
@@ -138,7 +140,7 @@ const AppPage = ({}) => {
<div className="p-6">
<div>
<button className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
<button className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
No-Code Action
</button>
</div>
@@ -167,7 +169,7 @@ const AppPage = ({}) => {
onClick={() => {
formbricks.setAttribute("Plan", "Free");
}}
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
Set Plan to &apos;Free&apos;
</button>
</div>
@@ -190,7 +192,7 @@ const AppPage = ({}) => {
onClick={() => {
formbricks.setAttribute("Plan", "Paid");
}}
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
Set Plan to &apos;Paid&apos;
</button>
</div>
@@ -213,7 +215,7 @@ const AppPage = ({}) => {
onClick={() => {
formbricks.setEmail("test@web.com");
}}
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
Set Email
</button>
</div>

View File

@@ -0,0 +1,142 @@
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;
const 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: "en",
};
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>
);
};
export default AppPage;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,26 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Example on overriding packages/js colors */
.dark {
--fb-brand-color: red;
--fb-brand-text-color: white;
--fb-border-color: green;
--fb-border-color-highlight: var(--slate-500);
--fb-focus-color: red;
--fb-heading-color: yellow;
--fb-subheading-color: green;
--fb-info-text-color: orange;
--fb-signature-text-color: blue;
--fb-survey-background-color: black;
--fb-accent-background-color: rgb(13, 13, 12);
--fb-accent-background-color-selected: red;
--fb-placeholder-color: white;
--fb-shadow-color: yellow;
--fb-rating-fill: var(--yellow-300);
--fb-rating-hover: var(--yellow-500);
--fb-back-btn-border: currentColor;
--fb-submit-btn-border: transparent;
--fb-rating-selected: black;
}

View File

@@ -4,18 +4,25 @@ import I1 from "./images/I1.webp";
import I2 from "./images/I2.webp";
export const metadata = {
title: "Using Actions in Formbricks",
title: "Using Actions in Formbricks | Fine-tuning User Moments",
description:
"Dive deep into how actions in Formbricks help products and organizations 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.",
};
# Actions
#### App Surveys
Actions are predefined events within your app that prompt Formbricks to display a survey when triggered. These are detected by the Formbricks widget, which then presents the appropriate survey based on your predefined settings.
# 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 for that survey. This capability ensures that surveys are triggered at the right time. You can set up these actions through a user-friendly No-Code interface within the Formbricks dashboard.
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 through a user-friendly No-Code interface within the Formbricks dashboard.
## **Why Are Actions Useful?**
@@ -23,7 +30,8 @@ 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 Targeting**: Precise targeting based on user attributes ensures that surveys are shown only to users who meet certain criteria, enhancing the relevance and effectiveness of each survey.
- **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.
## **Setting Up No-Code Actions**
@@ -119,3 +127,5 @@ 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.

View File

@@ -1,16 +1,34 @@
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 for App Surveys | Formbricks",
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, metadata, and other segments. This helps you get more relevant feedback and make data-driven decisions.",
"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, device type, 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.
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.
# How to setup Advanced Targeting
<ResponsiveVideo title="Formbricks Multi-language Surveys"
src="https://www.youtube-nocookie.com/embed/0BQp6N4cXzU?si=KeBM7G7Ch1xtrsOm&amp;controls=0" />
<Note>Advanced Targeting is only available on the Pro plan!</Note>
## 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.
@@ -18,7 +36,7 @@ Advanced Targeting allows you to show surveys to the right group of people. You
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 user attributes, other segments, devices, and more.
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**.
@@ -27,3 +45,50 @@ Advanced Targeting allows you to show surveys to the right group of people. You
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"
/>

View File

@@ -31,18 +31,12 @@ const libraries = [
description: "Simply add us to your router change and sit back!",
logo: logoVueJs,
},
{
href: "#react-native",
name: "React Native",
description: "Easily integrate our SDK with your React Native app for seamless survey support!",
logo: logoReactJs,
},
];
export const 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 xl:max-w-none xl:grid-cols-2 2xl:grid-cols-3 dark:border-white/5">
<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}

View File

@@ -42,8 +42,8 @@ All you need to do is copy a `<script>` tag to your HTML head, and thats abou
!function(){
var apiHost = "https://app.formbricks.com";
var environmentId = "<your-environment-id>";
var userId = "<your-user-id>"; //optional
var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=apiHost+"/js/formbricks.umd.cjs";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: environmentId, apiHost: apiHost, userId: userId})},500)}();
var userId = "<your-user-id>";
var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=apiHost+"/api/packages/app";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: environmentId, apiHost: apiHost, userId: userId})},500)}();
</script>
<!-- END Formbricks Surveys -->
```
@@ -58,6 +58,9 @@ All you need to do is copy a `<script>` tag to your HTML head, and thats abou
<Property name="api-host" type="string">
URL of the hosted Formbricks instance.
</Property>
<Property name="userId" type="string">
User ID of the user who has active session.
</Property>
</Properties>
Refer to our [Example HTML project](https://github.com/formbricks/examples/tree/main/html) for more help! Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
@@ -66,18 +69,18 @@ Refer to our [Example HTML project](https://github.com/formbricks/examples/tree/
## ReactJS
Install the Formbricks SDK using one of the package managers ie `npm`,`pnpm`,`yarn`. Note that zod is required as a peer dependency must also be installed in your project.
Install the Formbricks SDK using one of the package managers ie `npm`,`pnpm`,`yarn`.
<Col>
<CodeGroup title="Install Formbricks JS library">
```shell {{ title: 'npm' }}
npm install @formbricks/js zod
npm install @formbricks/js
```
```shell {{ title: 'pnpm' }}
pnpm add @formbricks/js zod
pnpm add @formbricks/js
```
```shell {{ title: 'yarn' }}
yarn add @formbricks/js zod
yarn add @formbricks/js
```
</CodeGroup>
@@ -88,13 +91,13 @@ Now, update your App.js/ts file to initialise Formbricks.
```js
// other imports
import formbricks from "@formbricks/js";
import formbricks from "@formbricks/js/app";
if (typeof window !== "undefined") {
formbricks.init({
environmentId: "<environment-id>",
apiHost: "<api-host>",
userId: "<user-id>", //optional
userId: "<user-id>",
});
}
@@ -116,6 +119,9 @@ export default App;
<Property name="api-host" type="string">
URL of the hosted Formbricks instance.
</Property>
<Property name="userId" type="string">
User ID of the user who has active session.
</Property>
</Properties>
Refer to our [Example ReactJs project](https://github.com/formbricks/examples/tree/main/reactjs) for more help! Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
@@ -136,13 +142,13 @@ Code snippets for the integration for both conventions are provided to further a
<Col>
<CodeGroup title="Install Formbricks JS library">
```shell {{ title: 'npm' }}
npm install @formbricks/js zod
npm install @formbricks/js
```
```shell {{ title: 'pnpm' }}
pnpm add @formbricks/js zod
pnpm add @formbricks/js
```
```shell {{ title: 'yarn' }}
yarn add @formbricks/js zod
yarn add @formbricks/js
```
</CodeGroup>
@@ -158,7 +164,8 @@ yarn add @formbricks/js zod
import { usePathname, useSearchParams } from "next/navigation";
import { useEffect } from "react";
import formbricks from "@formbricks/js";
import formbricks from "@formbricks/js/app";
export default function FormbricksProvider() {
const pathname = usePathname();
@@ -168,7 +175,7 @@ export default function FormbricksProvider() {
formbricks.init({
environmentId: "<environment-id>",
apiHost: "<api-host>",
userId: "<user-id>", //optional
userId: "<user-id>",
});
}, []);
@@ -211,13 +218,14 @@ Refer to our [Example NextJS App Directory project](https://github.com/formbrick
// other import
import { useRouter } from "next/router";
import { useEffect } from "react";
import formbricks from "@formbricks/js";
import formbricks from "@formbricks/js/app";
if (typeof window !== "undefined") {
formbricks.init({
environmentId: "<environment-id>",
apiHost: "<api-host>",
userId: "<user-id>", //optional
userId: "<user-id>",
});
}
@@ -250,6 +258,9 @@ Refer to our [Example NextJS Pages Directory project](https://github.com/formbri
<Property name="api-host" type="string">
URL of the hosted Formbricks instance.
</Property>
<Property name="userId" type="string">
User ID of the user who has active session.
</Property>
</Properties>
First we initialize the Formbricks SDK, ensuring that it only runs on the client side.
@@ -283,13 +294,13 @@ yarn add @formbricks/js
<CodeGroup title="src/formbricks.js">
```js
import formbricks from "@formbricks/js";
import formbricks from "@formbricks/js/app";
if (typeof window !== "undefined") {
formbricks.init({
environmentId: "<environment-id>",
apiHost: "<api-host>",
userId: "<user-id>", //optional
userId: "<user-id>",
});
}
@@ -330,67 +341,13 @@ router.afterEach((to, from) => {
<Property name="api-host" type="string">
URL of the hosted Formbricks instance.
</Property>
<Property name="userId" type="string">
User ID of the user who has active session.
</Property>
</Properties>
Refer to our [Example VueJs project](https://github.com/formbricks/examples/tree/main/vuejs) for more help! Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
## React Native
Install the Formbricks React Native SDK using one of the package managers, i.e., npm, pnpm, or yarn.
<Col>
<CodeGroup title="Install Formbricks JS library">
```shell {{ title: 'npm' }}
npm install @formbricks/react-native
```
```shell {{ title: 'pnpm' }}
pnpm add @formbricks/react-native
```
```shell {{ title: 'yarn' }}
yarn add @formbricks/react-native
```
</CodeGroup>
</Col>
Now, update your App.js/App.tsx file to initialize Formbricks:
<Col>
<CodeGroup title="src/App.js">
```js
// other imports
import Formbricks from "@formbricks/react-native";
const config = {
environmentId: "<environment-id>",
apiHost: "<api-host>",
userId: "<user-id>",
};
export default function App() {
return (
<>
{/* Your app content */}
<Formbricks initConfig={config} />
</>
);
}
```
</CodeGroup>
</Col>
### Required customizations to be made
<Properties>
<Property name="environment-id" type="string">
Formbricks Environment ID.
</Property>
<Property name="api-host" type="string">
URL of the hosted Formbricks instance.
</Property>
</Properties>
---
## Validate your setup
Once you have completed the steps above, you can validate your setup by checking the **Setup Checklist** in the Settings. Your widget status indicator should go from this:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -3,7 +3,6 @@ import { MdxImage } from "@/components/MdxImage";
import I1 from "./images/I1.webp";
import I2 from "./images/I2.webp";
import I3 from "./images/I3.webp";
import I3_1 from "./images/I3_1.webp";
import I4 from "./images/I4.webp";
import I5 from "./images/I5.webp";
import I6 from "./images/I6.webp";
@@ -16,41 +15,42 @@ export const metadata = {
"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 surveys. This tutorial explains how to run a survey in both your web app and mobile app (React Native) in just 10 to 15 minutes. Lets go!
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!
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, choose the "Formbricks Surveys" option:
<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 Formbricks Surveys"
alt="Choose website survey from survey type"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. **Choose your Product Channel**: On this step, you have to choose between the various channels that you want your product to be created in, you can create both app and link surveys from all the channels, but for the onboarding, please choose between the app surveys or the public website options, upon doing this, you'll be prompted to connect your app / website to formbricks.
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="Choose between app and website surveys product channels"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
3. **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={I3}
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 a message being displayed that your app or website is now connected with formbricks.
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_1}
src={I3}
alt="App connected with Formbricks"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
@@ -65,7 +65,7 @@ Onboarding is complete! Now lets create our first survey as you should see te
className="max-w-full rounded-lg sm:max-w-3xl"
/>
4. **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:
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**.
@@ -76,7 +76,7 @@ Pick the Survey Type as **App Survey**.
className="max-w-full rounded-lg sm:max-w-3xl"
/>
5. **Set Trigger for the Survey**: Scroll down to Survey Trigger and click on **+ Add action**, choose **New Session**. This will cause this survey to appear when the Formbricks Widget tracks a new user session:
4. **Set Trigger for the Survey**: Scroll down to Survey Trigger and click on **+ Add action**, choose **New Session**. This will cause this survey to appear when the Formbricks Widget tracks a new user session:
<MdxImage
src={I6}
@@ -85,7 +85,7 @@ Pick the Survey Type as **App Survey**.
className="max-w-full rounded-lg sm:max-w-3xl"
/>
6. **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:
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.
@@ -98,7 +98,7 @@ Pick the Survey Type as **App Survey**.
className="max-w-full rounded-lg sm:max-w-3xl"
/>
7. **Publish your survey**: Now hit **Publish** and youll be forwarded to the Summary Page. This is where youll find the responses to this survey.
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}
@@ -109,7 +109,7 @@ Pick the Survey Type as **App Survey**.
---
- We offer framework guides for various frontend tech, head over to the the [App Survey Framework Guides](/app-surveys/framework-guides) to get started with your app survey.
- Head over to our JS SDK documentation to get started with the [JS SDK](/developer-docs/js-sdk).
- 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!

View File

@@ -11,6 +11,8 @@ export const metadata = {
"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.

View File

@@ -4,12 +4,19 @@ export const metadata = {
"Dive into the importance of user identification in surveys. Boost your survey response rates and target the right users with Formbricks.",
};
#### App Surveys
# User Identification
User Identification helps you to not only segment your users but also to see more information about the user who responded to a survey. This helps you to target surveys to specific user segments and see more information about the user who responded to a survey.
### Understanding Identified vs Unidentified Users
<Note>
Formbricks App Surveys can **only be used with identified users**. If you are looking to run surveys on your
public-facing website, head over to the [Website Surveys](/website-surveys/quickstart) section.
</Note>
In Formbricks, understanding the distinction between identified and unidentified users is crucial for effective survey segmentation and targeted feedback collection.
| Feature | Unidentified Users | Identified Users |

View File

@@ -119,7 +119,7 @@ This allows us to capture and analyze partial feedback where the user is not wil
<MdxImage src={DocsNavi} alt="doc navigation" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
Locate that file. We are using the [Tailwind Template “Syntax”](https://tailwindui.com/templates/syntax) for our docs.
Locate that file. We are using the [Tailwind Template “Syntax”](https://tailwindui.com/templates/syntax) for our docs. Here is our [Layout.tsx](https://github.com/formbricks/formbricks/blob/main/apps/formbricks-com/components/docs/Layout.tsx) file.
3. Write the frontend code for the widget. Here is the full component (we break it down right below):
@@ -129,8 +129,10 @@ Locate that file. We are using the [Tailwind Template “Syntax”](https://tail
```tsx
import { useRouter } from "next/router";
import { useState } from "react";
import { Button } from "@formbricks/ui/components/Button";
import { Popover, PopoverContent, PopoverTrigger } from "@formbricks/ui/components/Popover";
import { Button } from "@formbricks/ui/Button";
import { Popover, PopoverContent, PopoverTrigger } from "@formbricks/ui/Popover";
import { handleFeedbackSubmit, updateFeedback } from "../../lib/handleFeedbackSubmit";
export const DocsFeedback = () => {

View File

@@ -37,9 +37,8 @@ To display the Product-Market Fit survey in your app you want to proceed as foll
3. Setup the user action to display survey at good point in time
<Note>
## Formbricks Widget running? We assume that you have already installed the Formbricks Widget in your web
app. Its required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
(15mins).](/app-surveys/quickstart)
## Formbricks Widget running?
We assume that you have already installed the Formbricks Widget in your web app. Its required to display messages and surveys in your app. If not, please follow the [Quick Start Guide (15mins).](/app-surveys/quickstart)
</Note>
### 1. Create new PMF survey
@@ -70,12 +69,25 @@ _Want to change the button color? You can do so in the product settings!_
Save, and move over to where the magic happens: The “Audience” tab.
### 3. Pre-segment your audience
### 3. Pre-segment your audience (coming soon)
<Note>
## Filter by attribute coming soon We're working on pre-segmenting users by attributes. We will update this
manual in the next days.
</Note>
To run this survey properly, you should pre-segment your user base. As touched upon earlier: if you ask every user youll get lots of opinions which are often misleading. You only want to gather feedback from people who invested the time to get to know and use your product:
**Filter by attribute**: You can keep the logic to decide if a user has (or has not) experienced value in your application. This makes most sense if you want to use historic usage data to decide if a user qualifies or not. Create your logic and if it applies, send an attribute to Formbricks by e.g. `formbricks.setAttribute("Loyalty", "Experienced Value");` Here is the full manual on how to [set attributes](/app-surveys/user-identification).
**Filter by actions (coming soon)**: Later, you can also segment users based on events tracked with Formbricks. However, this makes it impossible to use historic usage data (pre Formbricks usage). Here we will have a few options to achieve that:
- Check the time passed since sign-up (e.g. signed up 4 weeks ago)
- User has performed a specific action a certain number of times or (e.g. created 5 reports)
- User has performed a combination of actions (e.g. created a report **and** invited a organization member)
This way you make sure that you separate potentially misleading opinions from valuable insights.
### 4. Set up a trigger for the Product-Market Fit survey:
You need a trigger to display the survey but in this case, the filtering does all the work. Its up to you to decide to display the survey after the user viewed a specific subpage (pageURL) or after clicking an element. Have a look at the [Actions manual](/app-surveys/actions/) if you are not sure how to set them up:

View File

@@ -79,6 +79,28 @@ 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
@@ -151,6 +173,29 @@ 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -5,18 +5,18 @@ 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 JS SDK",
title: "Formbricks App Survey SDK",
description:
"Integrate Formbricks App Surveys into your web apps and websites with the Formbricks JS SDK. Learn how to initialize Formbricks, set attributes, track actions, and troubleshoot common issues.",
"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: Run Surveys Inside Your Web Apps and Websites
# SDK: App Survey
### Overview
The Formbricks JS SDK is a versatile solution for integrating surveys into both web apps and websites. It adapts based on the presence of a `userId`. If a `userId` is provided, the SDK handles authenticated surveys for logged-in users in web apps. If no `userId` is provided, the SDK can still seamlessly run surveys on public-facing websites. The SDK is available on npm [here](https://www.npmjs.com/package/@formbricks/js/).
The Formbricks JS SDK is a 2-in-1 SDK for seamlessly integrating both App Surveys and Website Surveys into your projects. In this section, we'll explore how to leverage the SDK specifically for **app** surveys. Its available on npm [here](https://www.npmjs.com/package/@formbricks/js/).
### Install
@@ -42,7 +42,7 @@ pnpm add @formbricks/js
### Initialize Formbricks
Initialize the Formbricks JS Client for surveys. When used in a web app, pass a `userId` to create and target a specific user. When using it on a website without authentication, simply omit the `userId`.
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">
@@ -53,7 +53,7 @@ import formbricks from "@formbricks/js/app";
formbricks.init({
environmentId: "<your-environment-id>", // required
apiHost: "<your-api-host>", // required
userId: "<user-id>", // optional
userId: "<user-id>", // required
});
```
@@ -73,7 +73,7 @@ if (window !== undefined) {
formbricks.init({
environmentId: "<your-environment-id>",
apiHost: "<your-api-host>",
userId: "<user-id>", //optional
userId: "<user-id>",
});
} else {
console.error("Window object not accessible to init Formbricks");
@@ -87,7 +87,7 @@ if (window !== undefined) {
### Set Attribute
Set custom attributes for the identified user to help segment them based on specific characteristics. This method only works when a `userId` is provided during initialization, allowing for targeted surveys in web apps. To learn how to set custom user attributes, refer to our [User Attributes Guide](/app-surveys/user-identification).
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>

View File

@@ -1,66 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import GithubCodespaceLoading from "./images/loading.webp";
import GithubCodespaceNew from "./images/new.webp";
import GithubCodespacePorts from "./images/ports.webp";
export const metadata = {
title: "Formbricks Open Source Contribution Guide: How to Enhance yourself and Contribute to Formbricks",
description:
"Join the Formbricks community and learn how to effectively contribute. From raising issues and feature requests to creating PRs, discover the best practices and communicate with our responsive team on Discord",
};
#### Contributing
# Github Codespaces Guide
1. After clicking the one-click setup button, you will be redirected to the Github Codespaces page. Review the configuration and click on the 'Create Codespace' button to create a new Codespace.
<MdxImage
src={GithubCodespaceNew}
alt="New Github Codespace"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
2. This will start loading the Codespace. Keep in mind this might take a few minutes to complete depending on your internet connection and the instance availability.
<MdxImage
src={GithubCodespaceLoading}
alt="Loading Github Codespace"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
3. Once the Codespace is loaded, you will be redirected to the VSCode editor. You can start working on your project in this environment.
4. Monitor the logs in the terminal and once you see the following, you are good to go!
<Col>
<CodeGroup title="The WebApp is running">
```bash
@formbricks/web:dev: ▲ Next.js 13.5.6
@formbricks/web:dev: - Local: http://localhost:3000
@formbricks/web:dev: - Environments: .env
@formbricks/web:dev: - Experiments (use at your own risk):
@formbricks/web:dev: · serverActions
@formbricks/web:dev:
@formbricks/web:dev: ✓ Ready in 9.4s
```
</CodeGroup>
</Col>
5. Right next to the Terminal, you will see a **Ports** tab, click on it to see the ports and their respective URLs. Now access the Forwarded Address for port 3000 and you should be able to visit your Formbricks App!
<MdxImage
src={GithubCodespacePorts}
alt="Github Codespace Ports"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Now make the changes you want to and see them live in action!

View File

@@ -1,9 +1,4 @@
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@formbricks/ui/components/Accordion";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@formbricks/ui/Accordion";
import { FaqJsonLdComponent } from "./FAQPageJsonLd";
const FAQ_DATA = [
@@ -43,7 +38,7 @@ const FAQ_DATA = [
Absolutely! We provide an option for users to host Formbricks on their own server, ensuring even more
control over data and compliance. And the best part? Self-hosting is available for free, always. For
documentation on self hosting, click{" "}
<a href="/self-hosting/deployment" className="text-brand-dark dark:text-brand-light">
<a href="/docs/self-hosting/deployment" className="text-brand-dark dark:text-brand-light">
here
</a>
.

View File

@@ -1,170 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
export const metadata = {
title: "Formbricks Open Source Contribution Guide: How to Enhance yourself and Contribute to Formbricks",
description:
"Join the Formbricks community and learn how to effectively contribute. From raising issues and feature requests to creating PRs, discover the best practices and communicate with our responsive team on Discord",
};
#### Contributing
# Get started
We are so happy that you are interested in contributing to Formbricks 🤗 There are many ways to contribute to Formbricks like writing issues, fixing bugs, building new features or updating the docs.
- **Issues**: Spotted a bug? Has deployment gone wrong? Do you have user feedback? [Raise an issue](https://github.com/formbricks/formbricks/issues/new/choose) for the fastest response.
- **Feature requests**: Raise an issue for these and tag it as an Enhancement. We love every idea. Please [open a feature request](https://github.com/formbricks/formbricks/issues/new?assignees=&labels=enhancement&projects=&template=feature_request.yml&title=%5BFEATURE%5D) clearly describing the problem you want to solve.
- **How we Code at Formbricks**: [View this Notion document](https://formbricks.notion.site/How-we-code-at-Formbricks-8bcaa0304a20445db4871831149c0cf5?pvs=4) and understand the coding practises we follow so that you can adhere to them for uniformity.
- **Creating a PR**: Please fork the repository, make your changes and create a new pull request if you want to make an update.
- **E2E Tests**: [Understand how we write E2E tests](https://formbricks.notion.site/Formbricks-End-to-End-Tests-06dc830d71604deaa8da24714540f7ab?pvs=4) and make sure to consider writing a test whenever you ship a feature.
- **New Question Types**:[Follow this guide](https://formbricks.notion.site/Guidelines-for-Implementing-a-New-Question-Type-9ac0d1c362714addb24b9abeb326d1c1?pvs=4) to keep everything in mind when you want to add a new question type.
- **How to create a service**: [Read this document to understand how we use services](https://formbricks.notion.site/How-to-create-a-service-8e0c035704bb40cb9ea5e5beeeeabd67?pvs=4). This is particulalry important when you need to write a new one.
## Talk to us first
We highly recommend connecting with us on [Discord server](https://formbricks.com/discord) before you ship a contribution. This will increase the likelihood of your PR being merged. And it will decrease the likelihood of you wasting your time :)
## Contributor License Agreement (CLA)
To be able to keep working on Formbricks over the coming years, we need to collect a CLA from all relevant contributors.
Once you open a PR, you will get a message from the CLA bot to fill out the form. Please note that we can only get your contribution merged when we have a CLA signed by you.
## Setup Dev Environment
We currently officially support the below methods to set up your development environment for Formbricks:
- [Gitpod](/developer-docs/contributing/gitpod)
- [GitHub Codespaces](/developer-docs/contributing/codespaces)
- [Local Machine Setup](#local-machine-setup)
Both Gitpod and GitHub Codespaces have a **generous free tier** to explore and develop. For junior developers we suggest using either of these, because you can dive into coding within minutes, not hours.
## Local Machine Setup
<Note>
The below only works for **Mac**, **Linux** & **WSL2** on Windows (not on pure Windows)!
This method is recommended **only for advanced users** & we won't be able to provide official support for this.
</Note>
To get the project running locally on your machine you need to have the following development tools installed:
- Node.JS (we recommend v20)
- [pnpm](https://pnpm.io/)
- [Docker](https://www.docker.com/) (to run PostgreSQL / MailHog)
1. Clone the project & move into the directory:
<Col>
<CodeGroup title="Git clone Formbricks monorepo">
```bash
git clone https://github.com/formbricks/formbricks && cd formbricks
```
</CodeGroup>
</Col>
2. Install Node.JS packages via pnpm. Don't have pnpm? Get it [here](https://pnpm.io/installation)
<Col>
<CodeGroup title="Install dependencies via pnpm">
```bash
pnpm install
```
</CodeGroup>
</Col>
3. Create a `.env` file based on `.env.example`. It's already preset to work with the local development setup but you can also change values if needed.
<Col>
<CodeGroup title="Define environment variables">
```bash
cp .env.example .env
```
</CodeGroup>
</Col>
4. Generate & set some secret values mandatory for the `ENCRYPTION_KEY`, `NEXTAUTH_SECRET` and `CRON_SECRET` in the .env file. You can use the following command to generate the random string of required length:
- For Linux
<Col>
<CodeGroup title="For Linux">
```bash
sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env
sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env
sed -i '/^CRON_SECRET=/c\CRON_SECRET='$(openssl rand -hex 32) .env
```
</CodeGroup>
</Col>
- For Mac
<Col>
<CodeGroup title="For Mac">
```bash
sed -i '' '/^ENCRYPTION_KEY=/s|.*|ENCRYPTION_KEY='$(openssl rand -hex 32)'|' .env
sed -i '' '/^NEXTAUTH_SECRET=/s|.*|NEXTAUTH_SECRET='$(openssl rand -hex 32)'|' .env
sed -i '' '/^CRON_SECRET=/s|.*|CRON_SECRET='$(openssl rand -hex 32)'|' .env
```
</CodeGroup>
</Col>
5. Make sure you have [`Docker`](https://docs.docker.com/compose/) & [`docker-compose`](https://docs.docker.com/compose/) installed and running on your machine. Then run the following command to start the Formbricks dev setup:
<Col>
<CodeGroup title="Start Formbricks Dev Setup">
```bash
pnpm go
```
</CodeGroup>
</Col>
This starts the Formbricks main app (plus all its dependencies) as well as the following services using Docker:
- A `postgres` container for hosting your database,
- A `mailhog` container that acts as a mock SMTP server and shows received mails in a web UI (forwarded to your host's `localhost:8025`)
- Demo App at [http://localhost:3002](http://localhost:3002)
- Landing Page at [http://localhost:3001](http://localhost:3001)
<Note>
**WSL2 users**: If you encounter connection issues with Prisma, ensure your WSL2 instance's PostgreSQL
service is stopped before running `pnpm go`. Use the command `sudo systemctl stop postgresql` to stop the
service.
</Note>
**You can now access the Formbricks app on [http://localhost:3000](http://localhost:3000)**. You will be automatically redirected to the login. To use your local installation of formbricks, create a new account.
{" "}
<Note>
A fresh setup does not have a default account. Please create a new account and proceed accordingly.
</Note>
For viewing the emails sent by the system, you can access mailhog at [http://localhost:8025](http://localhost:8025)
### Build
To build all apps and packages and check for build errors, run the following command:
<Col>
<CodeGroup title="Build Formbricks stack">
```bash
pnpm build
```
</CodeGroup>
</Col>

View File

@@ -1,172 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import GitpodAuth from "./images/auth.webp";
import GitpodNewWorkspace from "./images/new-workspace.webp";
import GitpodPorts from "./images/ports.webp";
import GitpodPreparing from "./images/preparing.webp";
import GitpodRunning from "./images/running.webp";
export const metadata = {
title: "Formbricks Open Source Contribution Guide: How to Enhance yourself and Contribute to Formbricks",
description:
"Join the Formbricks community and learn how to effectively contribute. From raising issues and feature requests to creating PRs, discover the best practices and communicate with our responsive team on Discord",
};
#### Contributing
# Gitpod Guide
**Building custom image for the workspace:**
- This includes : Installing `yq` and `turbo` globally before the workspace starts. This is accomplished within the `.gitpod.Dockerfile` along with starting upon a base custom image building on [workspace-full](https://hub.docker.com/r/workspace-full/dockerfile).
**Initialization of Formbricks:**
- During the prebuilds phase, we initialize Formbricks by performing the following tasks:
1. Setting up environment variables.
2. Installing monorepo dependencies.
3. Installing Docker images by extracting them from the `packages/database/docker-compose.yml` file.
4. Building the @formbricks/js component.
- When the workspace starts:
1. Wait for the web and demo apps to launch on Gitpod. This automatically opens the `apps/demo/.env` file. Utilize dynamic localhost URLs (e.g., `localhost:3000` for signup and `localhost:8025` for email confirmation) to configure `NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID`. After creating your account and finding the `ID` in the URL at `localhost:3000`, replace `YOUR_ENVIRONMENT_ID` in the `.env` file located in `app/demo`.
**Web Component Initialization:**
- We initialize the @formbricks/web component during prebuilds. This involves:
1. Installing build dependencies for the `@formbricks/web#go` task from turbo.json in prebuilds to save time.
2. Starting PostgreSQL and Mailhog containers for running migrations in prebuilds.
3. To prevent the "Init" task from running indefinitely due to prebuild rules, a cleanup `docker compose down` step i.e. `db:down` is added to `turbo.json`. This step is designed to halt the execution of containers that are currently running.
- When the workspace starts:
1. Initializing environment variables.
2. Replacing `NEXT_PUBLIC_WEBAPP_URL` to take in Gitpod URL's ports when running on VSCode browser.
3. Starting the `@formbricks/web` dev environment.
**Demo Component Initialization:**
- Similar to the web component, the demo component is also initialized during prebuilds. This includes:
1. Installing build dependencies for the `formbricks/demo#go` task from turbo.json in prebuilds to save time.
2. Caching hits and replaying builds from the `@formbricks/js` component.
- When the workspace starts:
1. Initializing environment variables.
2. Replaces `NEXT_PUBLIC_FORMBRICKS_API_HOST` to take in Gitpod URL's ports when running on VSCode browser.
3. Starting the `@formbricks/demo` dev environment.
**Github Prebuilds Configuration:**
- This configures Github Prebuilds for the master branch, pull requests, and adding comments. This helps automate the prebuild process for the specified branches and actions.
**VSCode Extensions:**
- This includes a list of VSCode extensions that are added to the configuration when using Gitpod. These extensions can enhance the development experience within Gitpod.
### 1. Browser Redirection
After clicking the one-click setup button, Gitpod will open a new tab or window. Please ensure that your browser allows redirection to successfully access the services:
### 2. Authorizing in Gitpod
<MdxImage
src={GitpodAuth}
alt="Gitpod Auth Page"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
- This is the Gitpod Authentication Page. It appears when you click the "Open in GitPod" button and Gitpod
needs to authenticate your access to the workspace. Click on 'Continue With Github' to authorize your GitPod
session.
### 3. Creating a New Workspace
<MdxImage
src={GitpodNewWorkspace}
alt="Gitpod New workspace Page"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
- After authentication, Gitpod asks to create a new workspace for you. This page displays the configurations
of your workspace. - You can use either choose either VS Code Browser or VS Code Desktop editor with the
'Standard Class' for your workspace class. - If you opt for the VS Code Desktop, follow the following steps 1.
Gitpod will prompt you to grant access to the VSCode app. Once approved, install the GitPod extension from the
VSCode Marketplace and follow the prompts to authorize the integration. 2. Change the `WEBAPP_URL` to
`https://localhost:3000`
### 4. Gitpod preparing the created Workspace
<MdxImage
src={GitpodPreparing}
alt="Gitpod Preparing workspace Page"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
- Gitpod is preparing your workspace with all the necessary dependencies and configurations. You will see this
page while Gitpod sets up your development environment.
### 5. Gitpod running the Workspace
<MdxImage
src={GitpodRunning}
alt="Gitpod Running Workspace Page"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
- Once the workspace is fully prepared, voila, it enters the running state. You can start working on your
project in this environment.
### Ports and Services
Here are the ports and corresponding URLs for the services within your Gitpod environment:
- **Port 3000**:
- **Service**: Demo App
- **Description**: This port hosts the demo application of your project. You can access and interact with your application's demo by navigating to this port.
- **Port 3001**:
- **Service**: Formbricks website
- **Description**: This port hosts the [Formbricks](https://formbricks.com) website, which contains documents, pricing, blogs, best practices, and concierge service.
- **Port 3002**:
- **Service**: Formbricks In-product Survey Demo App
- **Description**: This app helps you test your app & website surveys. You can create and test user actions, create and update user attributes, etc.
- **Port 5432**:
- **Service**: PostgreSQL Database Server
- **Description**: The PostgreSQL DB is hosted on this port.
- **Port 1025**:
- **Service**: SMTP server
- **Description**: SMTP Server for sending and receiving email messages. This server is responsible for handling email communication.
- **Port 8025**:
- **Service**: Mailhog
### Accessing port URLs
1. **Direct URL Composition**:
- You can access the dedicated port URL by pre-pending the port number to the workspace URL.
- For example, if you want to access port 3000, you can use the URL format: `3000-yourworkspace.ws-eu45.gitpod.io`.
2. **Using [gp CLI](https://www.gitpod.io/docs/references-cli)**:
- Gitpod provides a convenient command, `gp url`, to quickly retrieve the URL for a specific port.
- Simply use the command followed by the desired port number. For example, to get the URL for port 3000, run: `gp url 3000`.
3. **Listing All Open Port URLs**:
- If you prefer to see a list of all open port URLs at once, you can use the `gp ports list` command.
- Running this command will display a list of ports along with their corresponding URLs.
4. **Viewing All Ports in Panel**:
- Gitpod also offers a user-friendly 'Ports' tab in the Gitpod panel.
- Click on the 'Ports' tab to view a list of all open ports and their respective URLs.
{" "}
<MdxImage
src={GitpodPorts}
alt="Gitpod Ports tab"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
These URLs and port numbers represent various services and endpoints within your Gitpod environment. You can access and interact with these services by the Port URL for the respective service.

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -0,0 +1,469 @@
import { MdxImage } from "@/components/MdxImage";
import GitpodAuth from "./images/gitpod/auth.webp";
import GitpodNewWorkspace from "./images/gitpod/new-workspace.webp";
import GitpodPorts from "./images/gitpod/ports.webp";
import GitpodPreparing from "./images/gitpod/preparing.webp";
import GitpodRunning from "./images/gitpod/running.webp";
import GithubCodespaceLoading from "./images/github-codespaces/loading.webp";
import GithubCodespaceNew from "./images/github-codespaces/new.webp";
import GithubCodespacePorts from "./images/github-codespaces/ports.webp";
import ClearAppData from "./images/troubleshooting/clear-app-data.webp";
import Logout from "./images/troubleshooting/logout.webp";
import UncaughtPromise from "./images/troubleshooting/uncaught-promise.webp";
export const metadata = {
title: "Formbricks Open Source Contribution Guide: How to Enhance yourself and Contribute to Formbricks",
description:
"Join the Formbricks community and learn how to effectively contribute. From raising issues and feature requests to creating PRs, discover the best practices and communicate with our responsive team on Discord",
};
#### Contributing
# Overview
We are so happy that you are interested in contributing to Formbricks 🤗 There are many ways to contribute to Formbricks with writing Issues, fixing bugs, building new features or updating the docs.
- **Issues**: Spotted a bug? Has deployment gone wrong? Do you have user feedback? [Raise an issue](https://github.com/formbricks/formbricks/issues/new/choose) for the fastest response.
- **Feature requests**: Raise an issue for these and tag it as an Enhancement. We love every idea. Please give us as much context on the why as possible.
- **Creating a PR**: Please fork the repository, make your changes and create a new pull request if you want to make an update.
- **E2E Tests**: Understand how we write E2E tests and make sure to write whenever you ship a feature [here](https://www.notion.so/Formbricks-End-to-End-Tests-06dc830d71604deaa8da24714540f7ab?pvs=21).
- **Introducing a new Question Type?**: Adding a new question type to our surveys? Follow this guide to make sure youre on the right track [here](https://www.notion.so/Guidelines-for-Implementing-a-New-Question-Type-9ac0d1c362714addb24b9abeb326d1c1?pvs=21).
- **How we Code at Formbricks**: View this Notion document and understand the coding practises we follow so that you can adhere to them for uniformity.
- **How to create a service**: Services are our Database abstraction layer where we connect Prisma (our DB ORM) with logical methods that are reusable across the server. View this document to understand when & how to write them.
- **Roadmap**: Our roadmap is open on GitHub tickets and some customer and community tickets on GitHub.
If you want to speak to us before doing lots of work, please join our **[Discord server](https://formbricks.com/discord)** and tell us what you would like to work on - we're very responsive and friendly!
## Contributor License Agreement (CLA)
To be able to keep working on Formbricks over the coming years, we need to collect a CLA from all relevant contributors.
Once you open a PR, you will get a message from the CLA bot to fill out the form. Please note that we can only get your contribution merged when we have a CLA signed by you.
## Setup Dev Environment
We currently officially support the below methods to set up your development environment for Formbricks.
<Note>
Both the below cloud IDEs have a **generous free tier** to explore and develop! But make sure to not overuse
the machines as Formbricks will not be responsible for any charges incurred.
</Note>
### GitPod
This will open a fully configured workspace in your browser with all the necessary dependencies already installed. Click the button below to open this project in Gitpod. For a detailed guide, visit the **Gitpod Setup Guide** section below.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://Github.com/formbricks/formbricks)
### Github Codespaces
This will open a Github VSCode Interface on the cloud for you. This setup will have the Formbricks codebase, all the dependencies installed & Formbricks running. Click the button below to configure your instance and open the project in Github Codespaces. For a detailed guide, visit the **Github Codespaces Setup Guide** section below.
[![Open in Github Codespaces](https://img.shields.io/badge/Open%20in-Github%20Codespaces-blue?logo=Github)](https://Github.com/codespaces/new?machine=standardLinux32gb&repo=500289888&ref=main&devcontainer_path=.devcontainer%2Fdevcontainer.json&location=EastUs2)
### Local Machine
This will install the Formbricks codebase and all the dependencies on your local machine. Note that this method is recommended **only for advanced users**. If you're an advanced user, access the steps for **Local Machine Setup here** below.
<Note>
For a smooth experience, we suggest the above cloud IDE methods. Assistance with setup issues on your local
machine may be limited due to varying factors like OS and permissions.
</Note>
## Gitpod Guide
**Building custom image for the workspace:**
- This includes : Installing `yq` and `turbo` globally before the workspace starts. This is accomplished within the `.gitpod.Dockerfile` along with starting upon a base custom image building on [workspace-full](https://hub.docker.com/r/gitpod/workspace-full/dockerfile).
**Initialization of Formbricks:**
- During the prebuilds phase, we initialize Formbricks by performing the following tasks:
1. Setting up environment variables.
2. Installing monorepo dependencies.
3. Installing Docker images by extracting them from the `packages/database/docker-compose.yml` file.
4. Building the @formbricks/js component.
- When the workspace starts:
1. Wait for the web and demo apps to launch on Gitpod. This automatically opens the `apps/demo/.env` file. Utilize dynamic localhost URLs (e.g., `localhost:3000` for signup and `localhost:8025` for email confirmation) to configure `NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID`. After creating your account and finding the `ID` in the URL at `localhost:3000`, replace `YOUR_ENVIRONMENT_ID` in the `.env` file located in `app/demo`.
**Web Component Initialization:**
- We initialize the @formbricks/web component during prebuilds. This involves:
1. Installing build dependencies for the `@formbricks/web#go` task from turbo.json in prebuilds to save time.
2. Starting PostgreSQL and Mailhog containers for running migrations in prebuilds.
3. To prevent the "Init" task from running indefinitely due to prebuild rules, a cleanup `docker compose down` step i.e. `db:down` is added to `turbo.json`. This step is designed to halt the execution of containers that are currently running.
- When the workspace starts:
1. Initializing environment variables.
2. Replacing `NEXT_PUBLIC_WEBAPP_URL` and `NEXTAUTH_URL` to take in Gitpod URL's ports when running on VSCode browser.
3. Starting the `@formbricks/web` dev environment.
**Demo Component Initialization:**
- Similar to the web component, the demo component is also initialized during prebuilds. This includes:
1. Installing build dependencies for the `formbricks/demo#go` task from turbo.json in prebuilds to save time.
2. Caching hits and replaying builds from the `@formbricks/js` component.
- When the workspace starts:
1. Initializing environment variables.
2. Replaces `NEXT_PUBLIC_FORMBRICKS_API_HOST` to take in Gitpod URL's ports when running on VSCode browser.
3. Starting the `@formbricks/demo` dev environment.
**Github Prebuilds Configuration:**
- This configures Github Prebuilds for the master branch, pull requests, and adding comments. This helps automate the prebuild process for the specified branches and actions.
**VSCode Extensions:**
- This includes a list of VSCode extensions that are added to the configuration when using Gitpod. These extensions can enhance the development experience within Gitpod.
### 1. Browser Redirection
After clicking the one-click setup button, Gitpod will open a new tab or window. Please ensure that your browser allows redirection to successfully access the services:
### 2. Authorizing in Gitpod
<MdxImage
src={GitpodAuth}
alt="Gitpod Auth Page"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
- This is the Gitpod Authentication Page. It appears when you click the "Open in GitPod" button and Gitpod needs
to authenticate your access to the workspace. Click on 'Continue With Github' to authorize your GitPod session.
### 3. Creating a New Workspace
<MdxImage
src={GitpodNewWorkspace}
alt="Gitpod New workspace Page"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
- After authentication, Gitpod asks to create a new workspace for you. This page displays the configurations of
your workspace. - You can use either choose either VS Code Browser or VS Code Desktop editor with the 'Standard
Class' for your workspace class. - If you opt for the VS Code Desktop, follow the following steps 1. Gitpod will
prompt you to grant access to the VSCode app. Once approved, install the GitPod extension from the VSCode Marketplace
and follow the prompts to authorize the integration. 2. Change the `WEBAPP_URL` and the `NEXTAUTH_URL` to `https://localhost:3000`
### 4. Gitpod preparing the created Workspace
<MdxImage
src={GitpodPreparing}
alt="Gitpod Preparing workspace Page"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
- Gitpod is preparing your workspace with all the necessary dependencies and configurations. You will see this
page while Gitpod sets up your development environment.
### 5. Gitpod running the Workspace
<MdxImage
src={GitpodRunning}
alt="Gitpod Running Workspace Page"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
- Once the workspace is fully prepared, voila, it enters the running state. You can start working on your project
in this environment.
### Ports and Services
Here are the ports and corresponding URLs for the services within your Gitpod environment:
- **Port 3000**:
- **Service**: Demo App
- **Description**: This port hosts the demo application of your project. You can access and interact with your application's demo by navigating to this port.
- **Port 3001**:
- **Service**: Formbricks website
- **Description**: This port hosts the [Formbricks](https://formbricks.com) website, which contains documents, pricing, blogs, best practices, and concierge service.
- **Port 3002**:
- **Service**: Formbricks In-product Survey Demo App
- **Description**: This app helps you test your app & website surveys. You can create and test user actions, create and update user attributes, etc.
- **Port 5432**:
- **Service**: PostgreSQL Database Server
- **Description**: The PostgreSQL DB is hosted on this port.
- **Port 1025**:
- **Service**: SMTP server
- **Description**: SMTP Server for sending and receiving email messages. This server is responsible for handling email communication.
- **Port 8025**:
- **Service**: Mailhog
### Accessing port URLs
1. **Direct URL Composition**:
- You can access the dedicated port URL by pre-pending the port number to the workspace URL.
- For example, if you want to access port 3000, you can use the URL format: `3000-yourworkspace.ws-eu45.gitpod.io`.
2. **Using [gp CLI](https://www.gitpod.io/docs/references/gitpod-cli)**:
- Gitpod provides a convenient command, `gp url`, to quickly retrieve the URL for a specific port.
- Simply use the command followed by the desired port number. For example, to get the URL for port 3000, run: `gp url 3000`.
3. **Listing All Open Port URLs**:
- If you prefer to see a list of all open port URLs at once, you can use the `gp ports list` command.
- Running this command will display a list of ports along with their corresponding URLs.
4. **Viewing All Ports in Panel**:
- Gitpod also offers a user-friendly 'Ports' tab in the Gitpod panel.
- Click on the 'Ports' tab to view a list of all open ports and their respective URLs.
{" "}
<MdxImage
src={GitpodPorts}
alt="Gitpod Ports tab"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
These URLs and port numbers represent various services and endpoints within your Gitpod environment. You can access and interact with these services by the Port URL for the respective service.
---
## Github Codespaces Guide
1. After clicking the one-click setup button, you will be redirected to the Github Codespaces page. Review the configuration and click on the 'Create Codespace' button to create a new Codespace.
<MdxImage
src={GithubCodespaceNew}
alt="New Github Codespace"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
2. This will start loading the Codespace. Keep in mind this might take a few minutes to complete depending on your internet connection and the instance availability.
<MdxImage
src={GithubCodespaceLoading}
alt="Loading Github Codespace"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
3. Once the Codespace is loaded, you will be redirected to the VSCode editor. You can start working on your project in this environment.
4. Monitor the logs in the terminal and once you see the following, you are good to go!
<Col>
<CodeGroup title="The WebApp is running">
```bash
@formbricks/web:dev: ▲ Next.js 13.5.6
@formbricks/web:dev: - Local: http://localhost:3000
@formbricks/web:dev: - Environments: .env
@formbricks/web:dev: - Experiments (use at your own risk):
@formbricks/web:dev: · serverActions
@formbricks/web:dev:
@formbricks/web:dev: ✓ Ready in 9.4s
```
</CodeGroup>
</Col>
5. Right next to the Terminal, you will see a **Ports** tab, click on it to see the ports and their respective URLs. Now access the Forwarded Address for port 3000 and you should be able to visit your Formbricks App!
<MdxImage
src={GithubCodespacePorts}
alt="Github Codespace Ports"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Now make the changes you want to and see them live in action!
---
## Local Machine Setup
<Note>
The below only works for **Mac**, **Linux** & **WSL2** on Windows (not on pure Windows)!
This method is recommended **only for advanced users** & we won't be able to provide official support for this.
</Note>
To get the project running locally on your machine you need to have the following development tools installed:
- Node.JS (we recommend v20)
- [pnpm](https://pnpm.io/)
- [Docker](https://www.docker.com/) (to run PostgreSQL / MailHog)
1. Clone the project & move into the directory:
<Col>
<CodeGroup title="Git clone Formbricks monorepo">
```bash
git clone https://github.com/formbricks/formbricks && cd formbricks
```
</CodeGroup>
</Col>
2. Install Node.JS packages via pnpm. Don't have pnpm? Get it [here](https://pnpm.io/installation)
<Col>
<CodeGroup title="Install dependencies via pnpm">
```bash
pnpm install
```
</CodeGroup>
</Col>
3. Create a `.env` file based on `.env.example`. It's already preset to work with the local development setup but you can also change values if needed.
<Col>
<CodeGroup title="Define environment variables">
```bash
cp .env.example .env
```
</CodeGroup>
</Col>
4. Generate & set some secret values mandatory for the `ENCRYPTION_KEY` & `NEXTAUTH_SECRET` in the .env file. You can use the following command to generate the random string of required length:
<Col>
<CodeGroup title="Set value of ENCRYPTION_KEY">
```bash
sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env
sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env
```
</CodeGroup>
</Col>
5. Make sure you have [`Docker`](https://docs.docker.com/compose/) & [`docker-compose`](https://docs.docker.com/compose/) installed and running on your machine. Then run the following command to start the Formbricks dev setup:
<Col>
<CodeGroup title="Start Formbricks Dev Setup">
```bash
pnpm go
```
</CodeGroup>
</Col>
This starts the Formbricks main app (plus all its dependencies) as well as the following services using Docker:
- A `postgres` container for hosting your database,
- A `mailhog` container that acts as a mock SMTP server and shows received mails in a web UI (forwarded to your host's `localhost:8025`)
- Demo App at [http://localhost:3002](http://localhost:3002)
- Landing Page at [http://localhost:3001](http://localhost:3001)
<Note>
**WSL2 users**: If you encounter connection issues with Prisma, ensure your WSL2 instance's PostgreSQL
service is stopped before running `pnpm go`. Use the command `sudo systemctl stop postgresql` to stop the
service.
</Note>
**You can now access the Formbricks app on [http://localhost:3000](http://localhost:3000)**. You will be automatically redirected to the login. To use your local installation of formbricks, create a new account.
{" "}
<Note>
A fresh setup does not have a default account. Please create a new account and proceed accordingly.
</Note>
For viewing the emails sent by the system, you can access mailhog at [http://localhost:8025](http://localhost:8025)
### Build
To build all apps and packages and check for build errors, run the following command:
<Col>
<CodeGroup title="Build Formbricks stack">
```bash
pnpm build
```
</CodeGroup>
</Col>
---
# Troubleshooting
Here you'll find help with frequently recurring problems
## "The app doesn't work after doing a prisma migration"
This can happen but fear not, the fix is easy: Delete the application storage of your browser and reload the page. This will force the app to re-fetch the data from the server:
<MdxImage
src={ClearAppData}
alt="Demo App Preview"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
## "I ran 'pnpm i' but there seems to be an error with the packages"
If nothing helps, run `pnpm clean` and then `pnpm i` again. This solves a lot.
## "I get a full-screen error with cryptic strings"
This usually happens when the Formbricks Widget wasn't correctly or completely built.
<Col>
<CodeGroup title="Build js library first and then run again">
```bash
pnpm build --filter=@formbricks/js
// Run the app again
pnpm dev
```
</CodeGroup>
</Col>
## My machine struggles with the repository
Since we're working with a monorepo structure, the repository can get quite big. If you're having trouble working with the repository, try the following:
<Col>
<CodeGroup title="Only run the required project">
```bash {{ title: 'Formbricks Web-App' }}
pnpm dev --filter=@formbricks/web...
```
```bash {{ title: 'Formbricks Docs' }}
pnpm dev --filter=@formbricks/docs...
```
```bash {{ title: 'Formbricks Demo App' }}
pnpm dev --filter=@formbricks/demo...
```
</CodeGroup>
</Col>
However, in our experience it's better to run `pnpm dev` than having two terminals open (one with the Formbricks app and one with the demo).
## Uncaught (in promise) SyntaxError: Unexpected token !DOCTYPE ... is not valid JSON
<MdxImage
src={UncaughtPromise}
alt="Uncaught promise"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
This happens when you're using the Demo App and delete the Person within the Formbricks app which the widget is currently connected with. We're fixing it, but you can also just logout your test person and reload the page to get rid of it.
<MdxImage src={Logout} alt="Logout Person" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />

View File

@@ -1,84 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import ClearAppData from "./images/clear-app-data.webp";
import Logout from "./images/logout.webp";
import UncaughtPromise from "./images/uncaught-promise.webp";
export const metadata = {
title: "Formbricks Open Source Contribution Guide: How to Enhance yourself and Contribute to Formbricks",
description:
"Join the Formbricks community and learn how to effectively contribute. From raising issues and feature requests to creating PRs, discover the best practices and communicate with our responsive team on Discord",
};
#### Contributing
# Troubleshooting
Here you'll find help with frequently recurring problems
## "The app doesn't work after doing a prisma migration"
This can happen but fear not, the fix is easy: Delete the application storage of your browser and reload the page. This will force the app to re-fetch the data from the server:
<MdxImage
src={ClearAppData}
alt="Demo App Preview"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
## "I ran 'pnpm i' but there seems to be an error with the packages"
If nothing helps, run `pnpm clean` and then `pnpm i` again. This solves a lot.
## "I get a full-screen error with cryptic strings"
This usually happens when the Formbricks Widget wasn't correctly or completely built.
<Col>
<CodeGroup title="Build js library first and then run again">
```bash
pnpm build --filter=@formbricks/js
// Run the app again
pnpm dev
```
</CodeGroup>
</Col>
## My machine struggles with the repository
Since we're working with a monorepo structure, the repository can get quite big. If you're having trouble working with the repository, try the following:
<Col>
<CodeGroup title="Only run the required project">
```bash {{ title: 'Formbricks Web-App' }}
pnpm dev --filter=@formbricks/web...
```
```bash {{ title: 'Formbricks Docs' }}
pnpm dev --filter=@formbricks/docs...
```
```bash {{ title: 'Formbricks Demo App' }}
pnpm dev --filter=@formbricks/demo...
```
</CodeGroup>
</Col>
However, in our experience it's better to run `pnpm dev` than having two terminals open (one with the Formbricks app and one with the demo).
## Uncaught (in promise) SyntaxError: Unexpected token !DOCTYPE ... is not valid JSON
<MdxImage
src={UncaughtPromise}
alt="Uncaught promise"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
This happens when you're using the Demo App and delete the Person within the Formbricks app which the widget is currently connected with. We're fixing it, but you can also just logout your test person and reload the page to get rid of it.
<MdxImage src={Logout} alt="Logout Person" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -4,7 +4,7 @@ import AddModule from "./add-module.webp";
import CreateNewScenario from "./create-new-scenario.webp";
import CreateWebhook from "./create-webhook.webp";
import DuplicateSurvey from "./duplicate-survey.webp";
import EnterApiKeyAndHost from "./enter-api-key-and-host.webp";
import EnterApiKey from "./enter-api-key.webp";
import Result from "./result.webp";
import SearchFormbricks from "./search-formbricks.webp";
import SelectAction from "./select-action.webp";
@@ -27,8 +27,8 @@ export const metadata = {
Make is a powerful tool to send information between Formbricks and thousands of apps. Here's how to set it up.
<Note>
Nailed down your survey?? Any changes in the survey cause additional work in the _Scenario_. It makes sense
to first settle on the survey you want to run and then get to setting up Make.
Nailed down your survey?? Any changes in the survey cause additional work in the _Scenario_. It
makes sense to first settle on the survey you want to run and then get to setting up Make.
</Note>
## Step 1: Setup your survey incl. `questionId` for every question
@@ -95,10 +95,10 @@ Click "Create a webhook":
className="max-w-full rounded-lg sm:max-w-3xl"
/>
Enter the Formbricks API Host and API Key. API Host is by default set to https://app.formbricks.com but can be modified for self hosting instances. Learn how to get an API Key from the [API Key tutorial](/additional-features/api#how-to-generate-an-api-key).
Enter the Formbricks API key. Learn how to get one from the [API Key tutorial](/additional-features/api#how-to-generate-an-api-key).
<MdxImage
src={EnterApiKeyAndHost}
src={EnterApiKey}
alt="Enter API Key"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"

View File

@@ -112,7 +112,7 @@ Enabling the Slack Integration in a self-hosted environment requires a setup usi
"go": next dev --experimental-https -p 3000
```
- You also need to update the .env file in the `apps/web` directory to include the `WEBAPP_URL` as `https://localhost:3000` instead of `http://localhost: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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -10,17 +10,13 @@ export const metadata = {
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: React Native Apps](/developer-docs/react-native-in-app-surveys)
### [SDK: App Survey](/developer-docs/app-survey-sdk)
The Formbricks React Native SDK for App Surveys is designed for React Native applications, enabling seamless integration of surveys within your mobile apps. Dive into the documentation to learn how to leverage the SDK for app surveys and engage with your users effectively.
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: Formbricks JS](/developer-docs/js-sdk)
### [SDK: Website Survey](/developer-docs/website-survey-sdk)
The Formbricks JS SDK is a versatile solution for both web apps and public websites. It adapts based on how you provide user information.
If a `userId` is provided, the SDK tailors surveys for logged-in users, enabling targeted and identified interactions. This allows for advanced user tracking, providing deeper insights into user behavior within your application.
Alternatively, when no `userId` is supplied, the SDK seamlessly handles surveys for public-facing websites, making it ideal for high-traffic pages without authentication. This enables efficient survey collection without requiring user identification.
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)
@@ -34,7 +30,7 @@ Explore the Formbricks REST API documentation with Postman, providing detailed i
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/get-started)
### [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.

View File

@@ -1,127 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
export const metadata = {
title: "React Native: Formbricks App SDK",
description:
"Integrate Formbricks App Surveys into your React Native apps with the Formbricks React Native SDK.",
};
#### Developer Docs
# React Native: In App Surveys
### Overview
The Formbricks React Native SDK can be used for seamlessly integrating App Surveys into your React Native Apps. Here, w'll explore how to leverage the SDK for in app surveys. The SDK is [available on npm.](https://www.npmjs.com/package/@formbricks/react-native)
### Install
<Col>
<CodeGroup title="npm">
```js {{ title: 'npm' }}
npm install @formbricks/react-native
```
```js {{ title: 'yarn' }}
yarn add @formbricks/react-native
```
```js {{ title: 'pnpm' }}
pnpm add @formbricks/react-native
```
</CodeGroup>
</Col>
## Methods
### Initialize Formbricks
In your React Native app, initialize the Formbricks React Native 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
// other imports
import Formbricks from "@formbricks/react-native";
const config = {
environmentId: "<environment-id>",
apiHost: "<api-host>",
userId: "<user-id>",
};
export default function App() {
return (
<>
{/* Your app content */}
<Formbricks initConfig={config} />
</>
);
}
```
</CodeGroup>
</Col>
The moment you initialise Formbricks, your user will start seeing surveys that get triggered on simpler actions such as on New Session.
### 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>

View File

@@ -6,7 +6,7 @@ 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, 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",
"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
@@ -15,7 +15,15 @@ export const metadata = {
Formbricks offers two types of APIs: the **Public Client API** and the **Management API**. Each API serves a different purpose, has different authentication requirements, and provides access to different data and settings.
View our [API Documentation](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh) in more than 30 frameworks and languages.
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
@@ -23,6 +31,7 @@ The [Public Client API](https://documenter.getpostman.com/view/11026000/2sA3Bq5X
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
@@ -38,7 +47,7 @@ We currently have the following Management API methods exposed and below is thei
- [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, generate multiple suId and Delete Surveys
- [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
@@ -58,8 +67,7 @@ The API requests are authorized with a personal API key. This API key gives you
/>
<Note>
### Store API key safely! Anyone who has your API key has full control over your account. For security
reasons, you cannot view the API key again.
### Store API key safely! Anyone who has your API key has full control over your account. For security reasons, you cannot view the API key again.
</Note>
### Test your API Key

View File

@@ -4,12 +4,12 @@ import I1 from "./images/1-set-up-website-micro-survey-popup.webp";
export const metadata = {
title: "Formbricks Website Survey SDK",
description:
"Run targeted pop-up surveys on your public websites with the Formbricks JS SDK for Website Surveys. Learn how to integrate the SDK, track user actions, and trigger surveys based on user interactions.",
"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: Run Surveys On Public Websites
# SDK: Website Survey
### Overview

View File

@@ -40,7 +40,8 @@ For more information on user roles & permissions, see below:
| Update Member Access | ✅ | ✅ | ❌ | ❌ | ❌ |
| Update Billing | ✅ | ✅ | ❌ | ❌ | ❌ |
| **Product** | | | | | |
| Create Product | ✅ | ✅ | | | ❌ |
| Create Product | ✅ | ✅ | | | ❌ |
| Update Product Name | ✅ | ✅ | ✅ | ❌ | ❌ |
| Update Product Name | ✅ | ✅ | ✅ | ❌ | ❌ |
| Update Product Recontact Options | ✅ | ✅ | ✅ | ✅ | ❌ |
| Update Look & Feel | ✅ | ✅ | ✅ | ✅ | ❌ |
@@ -84,7 +85,7 @@ There are two ways to invite organization members: One by one or in bulk.
src={MenuItem}
alt="Where to find the Menu Item for Organization Settings"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. Click on the `Add Member` button:
@@ -93,7 +94,7 @@ There are two ways to invite organization members: One by one or in bulk.
src={AddMember}
alt="Add Member Button Position"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
3. In the modal, add the Name, Email and Role of the organization member you want to invite:
@@ -102,7 +103,7 @@ There are two ways to invite organization members: One by one or in bulk.
src={IndvInvite}
alt="Individual Invite Modal Tab"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
<Note>
@@ -120,7 +121,7 @@ Formbricks sends an email to the organization member with an invitation link. Th
src={MenuItem}
alt="Where to find the Menu Item for Organization Settings"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. Click on the `Add Member` button:
@@ -129,7 +130,7 @@ Formbricks sends an email to the organization member with an invitation link. Th
src={AddMember}
alt="Add Member Button Position"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
3. In the modal, switch to `Bulk Invite`. You can download an example .CSV file to fill in the Name, Email and Role of the organization members you want to invite:
@@ -138,7 +139,7 @@ Formbricks sends an email to the organization member with an invitation link. Th
src={BulkInvite}
alt="Individual Invite Modal Tab"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
4. Upload the filled .CSV file and invite the organization members in bulk ✅

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