Compare commits
216 Commits
v3.1.4
...
fix-hidden
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9dbaa3c28 | ||
|
|
d352d03071 | ||
|
|
ebefe775bb | ||
|
|
0852a961cc | ||
|
|
46f06f4c0e | ||
|
|
afb39e4aba | ||
|
|
2c6a90f82b | ||
|
|
e35f732e48 | ||
|
|
ec8b17dee2 | ||
|
|
947bc1a233 | ||
|
|
7050caa2f3 | ||
|
|
c4fd1a0a54 | ||
|
|
4de5f5c490 | ||
|
|
b3f336c959 | ||
|
|
010784c2b2 | ||
|
|
306f654617 | ||
|
|
60d0563487 | ||
|
|
777210ec42 | ||
|
|
8649522b5b | ||
|
|
71ebde06f4 | ||
|
|
d98eb5b46f | ||
|
|
6a2a8b74c8 | ||
|
|
43d5d3d719 | ||
|
|
5527f184b7 | ||
|
|
7dd5cf8b6e | ||
|
|
aec697f5b9 | ||
|
|
aa2588dd89 | ||
|
|
ed886e1794 | ||
|
|
452709dec7 | ||
|
|
a5cac35cfd | ||
|
|
3ee8485ef0 | ||
|
|
673f61be17 | ||
|
|
db86247510 | ||
|
|
090f6eef71 | ||
|
|
214d18616f | ||
|
|
3b126291a6 | ||
|
|
55a230e127 | ||
|
|
2a107ece7f | ||
|
|
7a3ef93a18 | ||
|
|
6255c9baad | ||
|
|
c322a963ab | ||
|
|
b1e8cb5a07 | ||
|
|
a391089efc | ||
|
|
1894bbe4f7 | ||
|
|
07dba90679 | ||
|
|
ca5ea315d6 | ||
|
|
646fe9c67f | ||
|
|
6a123a2399 | ||
|
|
39aa9f0941 | ||
|
|
625a4dcfae | ||
|
|
7971681d02 | ||
|
|
3dea241d7a | ||
|
|
e5ce6532f5 | ||
|
|
aa910ca3f0 | ||
|
|
c2d237a99a | ||
|
|
a371bdaedd | ||
|
|
dbbd77a8eb | ||
|
|
c28de7c079 | ||
|
|
05f1068e01 | ||
|
|
7103ec9877 | ||
|
|
9cd7a25343 | ||
|
|
2d028d18e5 | ||
|
|
0164eca206 | ||
|
|
f227c9e97e | ||
|
|
aecedfd082 | ||
|
|
e0f180bf04 | ||
|
|
5d0c435a33 | ||
|
|
daa7e7b56a | ||
|
|
655f319083 | ||
|
|
fcfe5682da | ||
|
|
e1140ac436 | ||
|
|
1529f5d478 | ||
|
|
4870dc8d45 | ||
|
|
a25e5dcfcd | ||
|
|
828e23b5c6 | ||
|
|
1921312445 | ||
|
|
0b9a884364 | ||
|
|
da4211f0b0 | ||
|
|
b21827cb32 | ||
|
|
4424a8a21d | ||
|
|
eb030f9ed6 | ||
|
|
333372d61c | ||
|
|
48a92f3e55 | ||
|
|
ddc767e53e | ||
|
|
432425ea59 | ||
|
|
6075fd3ef8 | ||
|
|
f099a46f83 | ||
|
|
fe54ef66c6 | ||
|
|
4eb0e930f6 | ||
|
|
fae925aa25 | ||
|
|
764a3d2fde | ||
|
|
b5a51f1304 | ||
|
|
140aee749b | ||
|
|
4113dd1873 | ||
|
|
0e0d3780d3 | ||
|
|
38ff01aedc | ||
|
|
cdf687ad80 | ||
|
|
a399fc7f80 | ||
|
|
c54a48e70b | ||
|
|
884b6f12ae | ||
|
|
5cae0febc9 | ||
|
|
0e898db710 | ||
|
|
40d54d60d4 | ||
|
|
269e026381 | ||
|
|
8245f2f6af | ||
|
|
8c07e8b1a8 | ||
|
|
e94b0845a2 | ||
|
|
4acc85bd12 | ||
|
|
ffa534d5eb | ||
|
|
fccf0f1e39 | ||
|
|
a5d80d1f02 | ||
|
|
803a73afb6 | ||
|
|
1eb8049d04 | ||
|
|
f9ed0c487f | ||
|
|
fa7d33351f | ||
|
|
e3084760b8 | ||
|
|
8e5addad5c | ||
|
|
6e741018e5 | ||
|
|
98c7c78421 | ||
|
|
16c588138c | ||
|
|
1373863af5 | ||
|
|
75315ea2c5 | ||
|
|
9f6fb8a387 | ||
|
|
b84d3d5806 | ||
|
|
5c2c1bbfcd | ||
|
|
54e84858b5 | ||
|
|
833d0789d7 | ||
|
|
1a974f3dd8 | ||
|
|
146173883f | ||
|
|
ebb02a5723 | ||
|
|
c96f7fed18 | ||
|
|
861eff3cd2 | ||
|
|
b66c0d17d0 | ||
|
|
0e748050f3 | ||
|
|
ae3524b79f | ||
|
|
0ce58b592a | ||
|
|
578346840e | ||
|
|
56bcb46d6c | ||
|
|
91405c48e0 | ||
|
|
b40dff621a | ||
|
|
7d4409e2b4 | ||
|
|
64a385b835 | ||
|
|
ee2573d128 | ||
|
|
d082e7c44d | ||
|
|
cd65850308 | ||
|
|
b91ae7e9b1 | ||
|
|
9baab1bf08 | ||
|
|
fdd4d8b926 | ||
|
|
c26c42d67f | ||
|
|
e1553becbc | ||
|
|
2e845ab0c0 | ||
|
|
79062a5476 | ||
|
|
840495b0e6 | ||
|
|
dd8fdbc7e3 | ||
|
|
a18c2aadf6 | ||
|
|
c7b653f073 | ||
|
|
8201df66c3 | ||
|
|
30e9baf0df | ||
|
|
a92881645b | ||
|
|
9522545152 | ||
|
|
33a09874c1 | ||
|
|
933755b81d | ||
|
|
8a1352d149 | ||
|
|
b47b7d7ea8 | ||
|
|
27cc4b7a5d | ||
|
|
249cc7f276 | ||
|
|
7ee9e92f7e | ||
|
|
588e80a237 | ||
|
|
e3d2d355de | ||
|
|
e8e00691c0 | ||
|
|
216be571e2 | ||
|
|
0176e82b3c | ||
|
|
30d3297002 | ||
|
|
6aa94a55ab | ||
|
|
a747ca42ad | ||
|
|
cd7a056bf1 | ||
|
|
baab774ede | ||
|
|
877c974108 | ||
|
|
d8033762d7 | ||
|
|
47a265016c | ||
|
|
ef78c68ac1 | ||
|
|
bc3f261076 | ||
|
|
4fa8a66c5f | ||
|
|
5885afc4f8 | ||
|
|
f3d21c50ab | ||
|
|
30729db47a | ||
|
|
0ff690a344 | ||
|
|
bec138c4f0 | ||
|
|
2976810fdf | ||
|
|
ae70ff2901 | ||
|
|
ee2642825f | ||
|
|
9cf98df425 | ||
|
|
1229904188 | ||
|
|
9152181a00 | ||
|
|
4843cb8789 | ||
|
|
6d3a489dff | ||
|
|
ea8e98fa0d | ||
|
|
614385da75 | ||
|
|
f6ef3ba7c5 | ||
|
|
22e8a137ef | ||
|
|
69734cc922 | ||
|
|
a9fe05d64a | ||
|
|
8bb3bd9409 | ||
|
|
5219065b8e | ||
|
|
cb8497229d | ||
|
|
25b8920d20 | ||
|
|
9203db88ab | ||
|
|
36378e9c23 | ||
|
|
9c33e77755 | ||
|
|
88cb4c742f | ||
|
|
475cce8253 | ||
|
|
a86c1738d1 | ||
|
|
96a4d02c80 | ||
|
|
bb6df783ab | ||
|
|
9160d63ad4 | ||
|
|
b6fc104357 |
@@ -1,39 +1,56 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
# **/node_modules
|
||||
**/node_modules
|
||||
.pnp
|
||||
.pnp.js
|
||||
.pnpm-store/
|
||||
|
||||
# testing
|
||||
coverage
|
||||
**/coverage
|
||||
|
||||
# next.js
|
||||
**/.next
|
||||
**/out
|
||||
**/.next/
|
||||
**/out/
|
||||
**/build
|
||||
|
||||
# node
|
||||
**/dist
|
||||
**/dist/
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
**/.DS_Store
|
||||
*.pem
|
||||
Zone.Identifier
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# turbo
|
||||
.turbo
|
||||
# local env files
|
||||
**/.env
|
||||
**/.env.local
|
||||
**/.env.development.local
|
||||
**/.env.test.local
|
||||
**/.env.production.local
|
||||
!packages/database/.env
|
||||
!apps/web/.env
|
||||
|
||||
# nixos stuff
|
||||
# build tools
|
||||
.turbo
|
||||
**/*vite.config.*.timestamp-*
|
||||
|
||||
# environment specific
|
||||
.direnv
|
||||
|
||||
.vscode
|
||||
.github
|
||||
**/.turbo
|
||||
# Playwright
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
|
||||
.env
|
||||
# project specific
|
||||
packages/lib/uploads
|
||||
apps/web/public/js
|
||||
packages/database/migrations
|
||||
branch.json
|
||||
26
.env.example
@@ -25,6 +25,9 @@ NEXTAUTH_SECRET=
|
||||
# You can use: `openssl rand -hex 32` to generate a secure one
|
||||
CRON_SECRET=
|
||||
|
||||
# Set the minimum log level(debug, info, warn, error, fatal)
|
||||
LOG_LEVEL=info
|
||||
|
||||
##############
|
||||
# DATABASE #
|
||||
##############
|
||||
@@ -39,6 +42,7 @@ DATABASE_URL='postgresql://postgres:postgres@localhost:5432/formbricks?schema=pu
|
||||
# See optional configurations below if you want to disable these features.
|
||||
|
||||
MAIL_FROM=noreply@example.com
|
||||
MAIL_FROM_NAME=Formbricks
|
||||
SMTP_HOST=localhost
|
||||
SMTP_PORT=1025
|
||||
# Enable SMTP_SECURE_ENABLED for TLS (port 465)
|
||||
@@ -96,6 +100,9 @@ PASSWORD_RESET_DISABLED=1
|
||||
# Organization Invite. Disable the ability for invited users to create an account.
|
||||
# INVITE_DISABLED=1
|
||||
|
||||
# Docker cron jobs. Disable the supercronic cron jobs in the Docker image (useful for cluster setups).
|
||||
# DOCKER_CRON_ENABLED=1
|
||||
|
||||
##########
|
||||
# Other #
|
||||
##########
|
||||
@@ -130,6 +137,9 @@ AZUREAD_TENANT_ID=
|
||||
# OIDC_DISPLAY_NAME=
|
||||
# OIDC_SIGNING_ALGORITHM=
|
||||
|
||||
# Configure SAML SSO
|
||||
# SAML_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/formbricks-saml
|
||||
|
||||
# Configure this when you want to ship JS & CSS files from a complete URL instead of the current domain
|
||||
# ASSET_PREFIX_URL=
|
||||
|
||||
@@ -181,11 +191,16 @@ 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
|
||||
# You can also add more configuration to Redis using the redis.conf file in the root directory
|
||||
REDIS_URL=redis://localhost:6379
|
||||
REDIS_DEFAULT_TTL=86400 # 1 day
|
||||
|
||||
# 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:
|
||||
|
||||
# The below is used for Rate Limiting for management API
|
||||
UNKEY_ROOT_KEY=
|
||||
|
||||
# Disable custom cache handler if necessary (e.g. if deployed on Vercel)
|
||||
# CUSTOM_CACHE_DISABLED=1
|
||||
|
||||
@@ -195,5 +210,10 @@ UNSPLASH_ACCESS_KEY=
|
||||
# AI_AZURE_EMBEDDINGS_DEPLOYMENT_ID=
|
||||
# AI_AZURE_LLM_DEPLOYMENT_ID=
|
||||
|
||||
# NEXT_PUBLIC_INTERCOM_APP_ID=
|
||||
# INTERCOM_SECRET_KEY=
|
||||
# INTERCOM_APP_ID=
|
||||
# INTERCOM_SECRET_KEY=
|
||||
|
||||
# Enable Prometheus metrics
|
||||
# PROMETHEUS_ENABLED=
|
||||
# PROMETHEUS_EXPORTER_PORT=
|
||||
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,6 +1,7 @@
|
||||
name: Bug report
|
||||
description: "Found a bug? Please fill out the sections below. \U0001F44D"
|
||||
type: bug
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: issue-summary
|
||||
|
||||
4
.github/actions/cache-build-web/action.yml
vendored
@@ -56,10 +56,6 @@ runs:
|
||||
- name: Fill ENCRYPTION_KEY, 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
|
||||
|
||||
|
||||
10
.github/workflows/apply-issue-labels-to-pr.yml
vendored
@@ -5,6 +5,9 @@ on:
|
||||
types:
|
||||
- opened
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
label_on_pr:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -15,8 +18,13 @@ jobs:
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Apply labels from linked issue to PR
|
||||
uses: actions/github-script@v5
|
||||
uses: actions/github-script@211cb3fefb35a799baa5156f9321bb774fe56294 # v5.2.0
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
|
||||
32
.github/workflows/build-docs.yml
vendored
@@ -1,32 +0,0 @@
|
||||
name: Build Docs
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
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
|
||||
7
.github/workflows/build-web.yml
vendored
@@ -12,7 +12,12 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Build & Cache Web Binaries
|
||||
|
||||
13
.github/workflows/chromatic.yml
vendored
@@ -11,19 +11,24 @@ jobs:
|
||||
name: Run Chromatic
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- name: Install dependencies
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
- name: Run Chromatic
|
||||
uses: chromaui/action@latest
|
||||
uses: chromaui/action@c93e0bc3a63aa176e14a75b61a31847cbfdd341c # latest
|
||||
with:
|
||||
# ⚠️ Make sure to configure a `CHROMATIC_PROJECT_TOKEN` repository secret
|
||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
|
||||
@@ -18,6 +18,11 @@ jobs:
|
||||
CRON_SECRET: ${{ secrets.CRON_SECRET }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: cURL request
|
||||
if: ${{ env.APP_URL && env.CRON_SECRET }}
|
||||
run: |
|
||||
|
||||
7
.github/workflows/cron-weeklySummary.yml
vendored
@@ -7,6 +7,9 @@ on:
|
||||
schedule:
|
||||
# Runs “At 08:00 on Monday.” (see https://crontab.guru)
|
||||
- cron: "0 8 * * 1"
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
cron-weeklySummary:
|
||||
permissions:
|
||||
@@ -16,6 +19,10 @@ jobs:
|
||||
CRON_SECRET: ${{ secrets.CRON_SECRET }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481
|
||||
with:
|
||||
egress-policy: audit
|
||||
- name: cURL request
|
||||
if: ${{ env.APP_URL && env.CRON_SECRET }}
|
||||
run: |
|
||||
|
||||
27
.github/workflows/dependency-review.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Dependency Review Action
|
||||
#
|
||||
# This Action will scan dependency manifest files that change as part of a Pull Request,
|
||||
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
|
||||
# Once installed, if the workflow run is marked as required,
|
||||
# PRs introducing known-vulnerable packages will be blocked from merging.
|
||||
#
|
||||
# Source repository: https://github.com/actions/dependency-review-action
|
||||
name: 'Dependency Review'
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0
|
||||
64
.github/workflows/deploy-formbricks-cloud.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: Formbricks Cloud Deployment
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
VERSION:
|
||||
description: 'The version of the Docker image to release'
|
||||
required: true
|
||||
type: string
|
||||
REPOSITORY:
|
||||
description: 'The repository to use for the Docker image'
|
||||
required: false
|
||||
type: string
|
||||
default: 'ghcr.io/formbricks/formbricks'
|
||||
workflow_call:
|
||||
inputs:
|
||||
VERSION:
|
||||
description: 'The version of the Docker image to release'
|
||||
required: true
|
||||
type: string
|
||||
REPOSITORY:
|
||||
description: 'The repository to use for the Docker image'
|
||||
required: false
|
||||
type: string
|
||||
default: 'ghcr.io/formbricks/formbricks'
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
helmfile-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
with:
|
||||
role-to-assume: ${{ secrets.AWS_ASSUME_ROLE_ARN }}
|
||||
aws-region: "eu-central-1"
|
||||
|
||||
- name: Setup Cluster Access
|
||||
run: |
|
||||
aws eks update-kubeconfig --name formbricks-prod-eks --region eu-central-1
|
||||
env:
|
||||
AWS_REGION: eu-central-1
|
||||
|
||||
- uses: helmfile/helmfile-action@v2
|
||||
env:
|
||||
VERSION: ${{ inputs.VERSION }}
|
||||
REPOSITORY: ${{ inputs.REPOSITORY }}
|
||||
FORMBRICKS_S3_BUCKET: ${{ secrets.FORMBRICKS_S3_BUCKET }}
|
||||
FORMBRICKS_INGRESS_CERT_ARN: ${{ secrets.FORMBRICKS_INGRESS_CERT_ARN }}
|
||||
FORMBRICKS_ROLE_ARN: ${{ secrets.FORMBRICKS_ROLE_ARN }}
|
||||
with:
|
||||
helm-plugins: >
|
||||
https://github.com/databus23/helm-diff,
|
||||
https://github.com/jkroepke/helm-secrets
|
||||
helmfile-args: apply
|
||||
helmfile-auto-init: "false"
|
||||
helmfile-workdirectory: infra/formbricks-cloud-helm
|
||||
|
||||
27
.github/workflows/e2e.yml
vendored
@@ -43,16 +43,21 @@ jobs:
|
||||
--health-timeout=5s
|
||||
--health-retries=5
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # v3.8.2
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
@@ -84,7 +89,7 @@ jobs:
|
||||
|
||||
- name: Run App
|
||||
run: |
|
||||
NODE_ENV=test pnpm start --filter=@formbricks/web &
|
||||
NODE_ENV=test pnpm start --filter=@formbricks/web | tee app.log 2>&1 &
|
||||
sleep 10 # Optional: gives some buffer for the app to start
|
||||
for attempt in {1..10}; do
|
||||
if [ $(curl -o /dev/null -s -w "%{http_code}" http://localhost:3000/health) -eq 200 ]; then
|
||||
@@ -112,7 +117,7 @@ jobs:
|
||||
|
||||
- name: Azure login
|
||||
if: env.AZURE_ENABLED == 'true'
|
||||
uses: azure/login@v2
|
||||
uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # v2.2.0
|
||||
with:
|
||||
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
||||
@@ -130,9 +135,19 @@ jobs:
|
||||
run: |
|
||||
pnpm test:e2e
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
||||
if: failure()
|
||||
with:
|
||||
name: app-logs
|
||||
path: app.log
|
||||
|
||||
- name: Output App Logs
|
||||
if: failure()
|
||||
run: cat app.log
|
||||
|
||||
33
.github/workflows/formbricks-release.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Build, release & deploy Formbricks images
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
docker-build:
|
||||
name: Build & release stable docker image
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: ./.github/workflows/release-docker-github.yml
|
||||
secrets: inherit
|
||||
|
||||
helm-chart-release:
|
||||
name: Release Helm Chart
|
||||
uses: ./.github/workflows/release-helm-chart.yml
|
||||
secrets: inherit
|
||||
needs:
|
||||
- docker-build
|
||||
with:
|
||||
VERSION: ${{ needs.docker-build.outputs.VERSION }}
|
||||
|
||||
deploy-formbricks-cloud:
|
||||
name: Deploy Helm Chart to Formbricks Cloud
|
||||
secrets: inherit
|
||||
uses: ./.github/workflows/deploy-formbricks-cloud.yml
|
||||
needs:
|
||||
- docker-build
|
||||
- helm-chart-release
|
||||
with:
|
||||
VERSION: ${{ needs.docker-build.outputs.VERSION }}
|
||||
10
.github/workflows/labeler.yml
vendored
@@ -4,6 +4,9 @@ on:
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
name: Pull Request Labeler
|
||||
@@ -12,7 +15,12 @@ jobs:
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
# https://github.com/actions/labeler/issues/442#issuecomment-1297359481
|
||||
|
||||
5
.github/workflows/lint.yml
vendored
@@ -12,6 +12,11 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
|
||||
11
.github/workflows/pr.yml
vendored
@@ -35,11 +35,6 @@ jobs:
|
||||
uses: ./.github/workflows/build-web.yml
|
||||
secrets: inherit
|
||||
|
||||
docs:
|
||||
name: Build Docs
|
||||
uses: ./.github/workflows/build-docs.yml
|
||||
secrets: inherit
|
||||
|
||||
e2e-test:
|
||||
name: Run E2E Tests
|
||||
uses: ./.github/workflows/e2e.yml
|
||||
@@ -47,7 +42,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
|
||||
permissions:
|
||||
@@ -55,6 +50,10 @@ jobs:
|
||||
checks: write
|
||||
statuses: write
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481
|
||||
with:
|
||||
egress-policy: audit
|
||||
- name: fail if conditional jobs failed
|
||||
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'skipped') || contains(needs.*.result, 'cancelled')
|
||||
run: exit 1
|
||||
|
||||
62
.github/workflows/prepare-release.yml
vendored
@@ -1,62 +0,0 @@
|
||||
name: Prepare release
|
||||
run-name: Prepare release ${{ inputs.next_version }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
next_version:
|
||||
required: true
|
||||
type: string
|
||||
description: "Version name"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
prepare_release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Configure git
|
||||
run: |
|
||||
git config --local user.email "github-actions@github.com"
|
||||
git config --local user.name "GitHub Actions"
|
||||
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
|
||||
- name: Bump version
|
||||
run: |
|
||||
cd apps/web
|
||||
pnpm version ${{ inputs.next_version }} --no-workspaces-update
|
||||
|
||||
- name: Commit changes and create a branch
|
||||
run: |
|
||||
branch_name="release-v${{ inputs.next_version }}"
|
||||
git checkout -b "$branch_name"
|
||||
git add .
|
||||
git commit -m "chore: release v${{ inputs.next_version }}"
|
||||
git push origin "$branch_name"
|
||||
|
||||
- name: Create pull request
|
||||
run: |
|
||||
gh pr create \
|
||||
--base main \
|
||||
--head "release-v${{ inputs.next_version }}" \
|
||||
--title "chore: bump version to v${{ inputs.next_version }}" \
|
||||
--body "This PR contains the changes for the v${{ inputs.next_version }} release."
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
13
.github/workflows/release-changesets.yml
vendored
@@ -26,23 +26,28 @@ jobs:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
|
||||
|
||||
- name: Setup Node.js 18.x
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@7c12f8017d5436eb855f1ed4399f037a36fbd9e8 # v2.5.2
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
uses: pnpm/action-setup@c3b53f6a16e57305370b4ae5a540c2077a1d50dd # v2.2.4
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
|
||||
- name: Create Release Pull Request or Publish to npm
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
uses: changesets/action@c8bada60c408975afd1a20b3db81d6eee6789308 # v1.4.9
|
||||
with:
|
||||
# This expects you to have a script called release which does a build for your packages and calls changeset publish
|
||||
publish: pnpm release
|
||||
|
||||
@@ -17,6 +17,9 @@ env:
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/formbricks?schema=public"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -28,23 +31,28 @@ jobs:
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Set up Depot CLI
|
||||
uses: depot/setup-action@v1
|
||||
uses: depot/setup-action@b0b1ea4f69e92ebf5dea3f8713a1b0c37b2126a5 # v1.6.0
|
||||
|
||||
# Install the cosign tool except on PR
|
||||
# https://github.com/sigstore/cosign-installer
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@v3.5.0
|
||||
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3 # v3.0.0
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -54,7 +62,7 @@ jobs:
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5 # v5.0.0
|
||||
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
@@ -62,7 +70,7 @@ jobs:
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: depot/build-push-action@v1
|
||||
uses: depot/build-push-action@636daae76684e38c301daa0c5eca1c095b24e780 # v1.14.0
|
||||
with:
|
||||
project: tw0fqmsx3c
|
||||
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
|
||||
|
||||
45
.github/workflows/release-docker-github.yml
vendored
@@ -6,10 +6,11 @@ name: Docker Release to Github
|
||||
# documentation.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_call:
|
||||
outputs:
|
||||
VERSION:
|
||||
description: release version
|
||||
value: ${{ jobs.build.outputs.VERSION }}
|
||||
|
||||
env:
|
||||
# Use docker.io for Docker Hub if empty
|
||||
@@ -20,6 +21,9 @@ env:
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/formbricks?schema=public"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -30,24 +34,45 @@ jobs:
|
||||
# with sigstore/fulcio when running outside of PRs.
|
||||
id-token: write
|
||||
|
||||
outputs:
|
||||
VERSION: ${{ steps.extract_release_tag.outputs.VERSION }}
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Get Release Tag
|
||||
id: extract_release_tag
|
||||
run: |
|
||||
TAG=${{ github.ref }}
|
||||
TAG=${TAG#refs/tags/v}
|
||||
echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV
|
||||
echo "VERSION=$TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Update package.json version
|
||||
run: |
|
||||
sed -i "s/\"version\": \"0.0.0\"/\"version\": \"${{ env.RELEASE_TAG }}\"/" ./apps/web/package.json
|
||||
cat ./apps/web/package.json | grep version
|
||||
|
||||
- name: Set up Depot CLI
|
||||
uses: depot/setup-action@v1
|
||||
uses: depot/setup-action@b0b1ea4f69e92ebf5dea3f8713a1b0c37b2126a5 # v1.6.0
|
||||
|
||||
# Install the cosign tool except on PR
|
||||
# https://github.com/sigstore/cosign-installer
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@v3.5.0
|
||||
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3 # v3.0.0
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -57,7 +82,7 @@ jobs:
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5 # v5.0.0
|
||||
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
@@ -65,7 +90,7 @@ jobs:
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: depot/build-push-action@v1
|
||||
uses: depot/build-push-action@636daae76684e38c301daa0c5eca1c095b24e780 # v1.14.0
|
||||
with:
|
||||
project: tw0fqmsx3c
|
||||
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
|
||||
|
||||
46
.github/workflows/release-docker.yml
vendored
@@ -1,46 +0,0 @@
|
||||
name: Release on Dockerhub
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
release-image-on-dockerhub:
|
||||
name: Release on Dockerhub
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/formbricks?schema=public"
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Get Release Tag
|
||||
id: extract_release_tag
|
||||
run: |
|
||||
TAG=${{ github.ref }}
|
||||
TAG=${TAG#refs/tags/v}
|
||||
echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./apps/web/Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKER_USERNAME }}/formbricks:${{ env.RELEASE_TAG }}
|
||||
${{ secrets.DOCKER_USERNAME }}/formbricks:latest
|
||||
54
.github/workflows/release-helm-chart.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
name: Publish Helm Chart
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
VERSION:
|
||||
description: 'The version of the Helm chart to release'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Extract release version
|
||||
run: echo "VERSION=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 # v3.5
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io --username ${{ github.actor }} --password-stdin
|
||||
|
||||
- name: Install YQ
|
||||
uses: dcarbone/install-yq-action@4075b4dca348d74bd83f2bf82d30f25d7c54539b # v1.3.1
|
||||
|
||||
- name: Update Chart.yaml with new version
|
||||
run: |
|
||||
yq -i ".version = \"${{ inputs.VERSION }}\"" helm-chart/Chart.yaml
|
||||
yq -i ".appVersion = \"v${{ inputs.VERSION }}\"" helm-chart/Chart.yaml
|
||||
|
||||
- name: Package Helm chart
|
||||
run: |
|
||||
helm package ./helm-chart
|
||||
|
||||
- name: Push Helm chart to GitHub Container Registry
|
||||
run: |
|
||||
helm push formbricks-${{ inputs.VERSION }}.tgz oci://ghcr.io/formbricks/helm-charts
|
||||
81
.github/workflows/scorecard.yml
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
# 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.
|
||||
|
||||
name: Scorecard supply-chain security
|
||||
on:
|
||||
# For Branch-Protection check. Only the default branch is supported. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||
branch_protection_rule:
|
||||
# To guarantee Maintained check is occasionally updated. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||
schedule:
|
||||
- cron: "17 17 * * 6"
|
||||
push:
|
||||
branches: ["main"]
|
||||
workflow_dispatch:
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
# Needed to publish results and get a badge (see publish_results below).
|
||||
id-token: write
|
||||
# Add this permission
|
||||
actions: write # Required for artifact upload
|
||||
# Uncomment the permissions below if installing in a private repository.
|
||||
# contents: read
|
||||
# actions: read
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||
# - you are installing Scorecard on a *private* repository
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
|
||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||
|
||||
# Public repositories:
|
||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||
# - Allows the repository to include the Scorecard badge.
|
||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||
# For private repositories:
|
||||
# - `publish_results` will always be set to `false`, regardless
|
||||
# of the value entered here.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: sarif
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard (optional).
|
||||
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
11
.github/workflows/semantic-pull-requests.yml
vendored
@@ -16,7 +16,12 @@ jobs:
|
||||
name: PR title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v5
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3
|
||||
id: lint_pr_title
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -35,7 +40,7 @@ jobs:
|
||||
revert
|
||||
ossgg
|
||||
|
||||
- uses: marocchino/sticky-pull-request-comment@v2
|
||||
- uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
|
||||
# When the previous steps fails, the workflow would stop. By adding this
|
||||
# condition you can continue the execution with the populated error message.
|
||||
if: always() && (steps.lint_pr_title.outputs.error_message != null)
|
||||
@@ -54,7 +59,7 @@ jobs:
|
||||
|
||||
# Delete a previous comment when the issue has been resolved
|
||||
- if: ${{ steps.lint_pr_title.outputs.error_message == null }}
|
||||
uses: marocchino/sticky-pull-request-comment@v2
|
||||
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
|
||||
with:
|
||||
header: pr-title-lint-error
|
||||
message: |
|
||||
|
||||
12
.github/workflows/sonarqube.yml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
- main
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
merge_group:
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
@@ -13,7 +14,12 @@ jobs:
|
||||
name: SonarQube
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
|
||||
@@ -40,11 +46,7 @@ jobs:
|
||||
|
||||
- name: Run tests with coverage
|
||||
run: |
|
||||
cd apps/web
|
||||
pnpm test:coverage
|
||||
cd ../../
|
||||
# The Vitest coverage config is in your vite.config.mts
|
||||
|
||||
- name: SonarQube Scan
|
||||
uses: SonarSource/sonarqube-scan-action@bfd4e558cda28cda6b5defafb9232d191be8c203
|
||||
env:
|
||||
|
||||
75
.github/workflows/terrafrom-plan-and-apply.yml
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
name: 'Terraform'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# TODO: enable it back when migration is completed.
|
||||
# push:
|
||||
# branches:
|
||||
# - main
|
||||
# pull_request:
|
||||
# branches:
|
||||
# - main
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
terraform:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
with:
|
||||
role-to-assume: ${{ secrets.AWS_ASSUME_ROLE_ARN }}
|
||||
aws-region: "eu-central-1"
|
||||
|
||||
- name: Setup Terraform
|
||||
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
|
||||
|
||||
- name: Terraform Format
|
||||
id: fmt
|
||||
run: terraform fmt -check -recursive
|
||||
continue-on-error: true
|
||||
working-directory: infra/terraform
|
||||
|
||||
- name: Terraform Init
|
||||
id: init
|
||||
run: terraform init
|
||||
working-directory: infra/terraform
|
||||
|
||||
- name: Terraform Validate
|
||||
id: validate
|
||||
run: terraform validate
|
||||
working-directory: infra/terraform
|
||||
|
||||
- name: Terraform Plan
|
||||
id: plan
|
||||
run: terraform plan -out .planfile
|
||||
working-directory: infra/terraform
|
||||
|
||||
# - name: Post PR comment
|
||||
# uses: borchero/terraform-plan-comment@3399d8dbae8b05185e815e02361ede2949cd99c4 # v2.4.0
|
||||
# if: always() && github.ref != 'refs/heads/main' && (steps.validate.outcome == 'success' || steps.validate.outcome == 'failure')
|
||||
# with:
|
||||
# token: ${{ github.token }}
|
||||
# planfile: .planfile
|
||||
# working-directory: "infra/terraform"
|
||||
# skip-comment: true
|
||||
|
||||
- name: Terraform Apply
|
||||
id: apply
|
||||
# if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
||||
run: terraform apply .planfile
|
||||
working-directory: "infra/terraform"
|
||||
|
||||
14
.github/workflows/test.yml
vendored
@@ -1,6 +1,9 @@
|
||||
name: Tests
|
||||
on:
|
||||
workflow_call:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Unit Tests
|
||||
@@ -10,16 +13,21 @@ jobs:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # v3.8.2
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
|
||||
51
.github/workflows/tolgee-missing-key-check.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Check Missing Translations
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
check-missing-translations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.base.ref }}
|
||||
|
||||
- name: Checkout PR
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Install Tolgee CLI
|
||||
run: npm install -g @tolgee/cli
|
||||
|
||||
- name: Compare Tolgee Keys
|
||||
id: compare
|
||||
run: |
|
||||
tolgee compare --api-key ${{ secrets.TOLGEE_API_KEY }} > compare_output.txt
|
||||
cat compare_output.txt
|
||||
|
||||
- name: Check for Missing Translations
|
||||
run: |
|
||||
if grep -q "new key found" compare_output.txt; then
|
||||
echo "New keys found that may require translations:"
|
||||
exit 1
|
||||
else
|
||||
echo "No new keys found."
|
||||
fi
|
||||
87
.github/workflows/tolgee.yml
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
name: Tolgee Tagging on PR Merge
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
tag-production-keys:
|
||||
name: Tag Production Keys
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.merged == true
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0 # This ensures we get the full git history
|
||||
|
||||
- name: Get source branch name
|
||||
id: branch-name
|
||||
run: |
|
||||
RAW_BRANCH="${{ github.head_ref }}"
|
||||
SOURCE_BRANCH=$(echo "$RAW_BRANCH" | sed 's/[^a-zA-Z0-9._\/-]//g')
|
||||
|
||||
|
||||
# Safely add to environment variables using GitHub's recommended method
|
||||
# This prevents environment variable injection attacks
|
||||
echo "SOURCE_BRANCH<<EOF" >> $GITHUB_ENV
|
||||
echo "$SOURCE_BRANCH" >> $GITHUB_ENV
|
||||
echo "EOF" >> $GITHUB_ENV
|
||||
|
||||
echo "Detected source branch: $SOURCE_BRANCH"
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: 18 # Ensure compatibility with your project
|
||||
|
||||
- name: Install Tolgee CLI
|
||||
run: npm install -g @tolgee/cli
|
||||
|
||||
- name: Tag Production Keys
|
||||
run: |
|
||||
npx tolgee tag \
|
||||
--api-key ${{ secrets.TOLGEE_API_KEY }} \
|
||||
--filter-extracted \
|
||||
--filter-tag "draft:${SOURCE_BRANCH}" \
|
||||
--tag production \
|
||||
--untag "draft:${SOURCE_BRANCH}"
|
||||
|
||||
- name: Tag unused production keys as Deprecated
|
||||
run: |
|
||||
npx tolgee tag \
|
||||
--api-key ${{ secrets.TOLGEE_API_KEY }} \
|
||||
--filter-not-extracted --filter-tag production \
|
||||
--tag deprecated --untag production
|
||||
|
||||
- name: Tag unused draft:current-branch keys as Deprecated
|
||||
run: |
|
||||
npx tolgee tag \
|
||||
--api-key ${{ secrets.TOLGEE_API_KEY }} \
|
||||
--filter-not-extracted --filter-tag "draft:${SOURCE_BRANCH}" \
|
||||
--tag deprecated --untag "draft:${SOURCE_BRANCH}"
|
||||
|
||||
- name: Sync with backup
|
||||
run: |
|
||||
npx tolgee sync \
|
||||
--api-key ${{ secrets.TOLGEE_API_KEY }} \
|
||||
--backup ./tolgee-backup \
|
||||
--continue-on-warning \
|
||||
--yes
|
||||
|
||||
- name: Upload backup as artifact
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
||||
with:
|
||||
name: tolgee-backup-${{ github.sha }}
|
||||
path: ./tolgee-backup
|
||||
retention-days: 90
|
||||
@@ -17,7 +17,12 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
if: github.event.action == 'opened'
|
||||
steps:
|
||||
- uses: actions/first-interaction@v1
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/first-interaction@3c71ce730280171fd1cfb57c00c774f8998586f7 # v1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
pr-message: |-
|
||||
|
||||
59
.gitignore
vendored
@@ -1,25 +1,26 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
**/node_modules
|
||||
.pnp
|
||||
.pnp.js
|
||||
.pnpm-store/
|
||||
|
||||
# testing
|
||||
coverage
|
||||
**/coverage
|
||||
|
||||
# next.js
|
||||
.next/
|
||||
out/
|
||||
build
|
||||
**/.next/
|
||||
**/out/
|
||||
**/build
|
||||
|
||||
# node
|
||||
dist/
|
||||
**/dist/
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
**/.DS_Store
|
||||
*.pem
|
||||
Zone.Identifier
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
@@ -27,35 +28,47 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
**/.env
|
||||
**/.env.local
|
||||
**/.env.development.local
|
||||
**/.env.test.local
|
||||
**/.env.production.local
|
||||
!packages/database/.env
|
||||
!apps/web/.env
|
||||
|
||||
# turbo
|
||||
# build tools
|
||||
.turbo
|
||||
**/*vite.config.*.timestamp-*
|
||||
|
||||
# nixos stuff
|
||||
# environment specific
|
||||
.direnv
|
||||
|
||||
Zone.Identifier
|
||||
|
||||
# Playwright
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
|
||||
# uploads
|
||||
# project specific
|
||||
packages/lib/uploads
|
||||
|
||||
# Vite Timestamps
|
||||
*vite.config.*.timestamp-*
|
||||
|
||||
# js compiled assets
|
||||
apps/web/public/js
|
||||
packages/database/migrations
|
||||
branch.json
|
||||
.vercel
|
||||
|
||||
packages/database/migrations
|
||||
# Terraform
|
||||
infra/terraform/.terraform/
|
||||
**/.terraform.lock.hcl
|
||||
**/terraform.tfstate
|
||||
**/terraform.tfstate.*
|
||||
**/crash.log
|
||||
**/override.tf
|
||||
**/override.tf.json
|
||||
**/*.tfvars
|
||||
**/*.tfvars.json
|
||||
**/.terraformrc
|
||||
**/terraform.rc
|
||||
|
||||
# IntelliJ IDEA
|
||||
/.idea/
|
||||
/*.iml
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
images=($(yq eval '.services.*.image' packages/database/docker-compose.yml))
|
||||
images=($(yq eval '.services.*.image' docker-compose.dev.yml))
|
||||
|
||||
pull_image() {
|
||||
docker pull "$1"
|
||||
|
||||
2
.husky/post-checkout
Normal file
@@ -0,0 +1,2 @@
|
||||
echo "{\"branchName\": \"$(git rev-parse --abbrev-ref HEAD)\"}" > ./branch.json
|
||||
prettier --write ./branch.json
|
||||
@@ -1 +1,21 @@
|
||||
pnpm lint-staged
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
# Load environment variables from .env files
|
||||
if [ -f .env ]; then
|
||||
set -a
|
||||
. .env
|
||||
set +a
|
||||
fi
|
||||
|
||||
pnpm lint-staged
|
||||
|
||||
# Run tolgee-pull if branch.json exists and NEXT_PUBLIC_TOLGEE_API_KEY is not set
|
||||
if [ -f branch.json ]; then
|
||||
if [ -z "$NEXT_PUBLIC_TOLGEE_API_KEY" ]; then
|
||||
echo "Skipping tolgee-pull: NEXT_PUBLIC_TOLGEE_API_KEY is not set"
|
||||
else
|
||||
pnpm run tolgee-pull
|
||||
git add packages/lib/messages
|
||||
fi
|
||||
fi
|
||||
39
.tolgeerc.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"$schema": "https://docs.tolgee.io/cli-schema.json",
|
||||
"format": "JSON_TOLGEE",
|
||||
"patterns": ["./apps/web/**/*.ts?(x)"],
|
||||
"projectId": 10304,
|
||||
"pull": {
|
||||
"path": "./packages/lib/messages"
|
||||
},
|
||||
"push": {
|
||||
"files": [
|
||||
{
|
||||
"language": "en-US",
|
||||
"path": "./packages/lib/messages/en-US.json"
|
||||
},
|
||||
{
|
||||
"language": "de-DE",
|
||||
"path": "./packages/lib/messages/de-DE.json"
|
||||
},
|
||||
{
|
||||
"language": "fr-FR",
|
||||
"path": "./packages/lib/messages/fr-FR.json"
|
||||
},
|
||||
{
|
||||
"language": "pt-BR",
|
||||
"path": "./packages/lib/messages/pt-BR.json"
|
||||
},
|
||||
{
|
||||
"language": "zh-Hant-TW",
|
||||
"path": "./packages/lib/messages/zh-Hant-TW.json"
|
||||
},
|
||||
{
|
||||
"language": "pt-PT",
|
||||
"path": "./packages/lib/messages/pt-PT.json"
|
||||
}
|
||||
],
|
||||
"forceMode": "OVERRIDE"
|
||||
},
|
||||
"strictNamespace": false
|
||||
}
|
||||
4
.vscode/extensions.json
vendored
@@ -6,6 +6,8 @@
|
||||
"dbaeumer.vscode-eslint", // eslint plugin
|
||||
"esbenp.prettier-vscode", // prettier plugin
|
||||
"Prisma.prisma", // syntax|format|completion for prisma
|
||||
"yzhang.markdown-all-in-one" // nicer markdown support
|
||||
"yzhang.markdown-all-in-one", // nicer markdown support
|
||||
"vitest.explorer", // run tests directly from the code window
|
||||
"sonarsource.sonarlint-vscode" // sonarqube linter for vscode
|
||||
]
|
||||
}
|
||||
|
||||
2
LICENSE
@@ -3,7 +3,7 @@ Copyright (c) 2024 Formbricks GmbH
|
||||
Portions of this software are licensed as follows:
|
||||
|
||||
- All content that resides under the "apps/web/modules/ee" directory of this repository, if these directories exist, is licensed under the license defined in "apps/web/modules/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/js/", "packages/react-native/", "packages/android/", "packages/ios/" 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.
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<h3 align="center">Formbricks</h3>
|
||||
|
||||
<p align="center">
|
||||
Harvest user-insights, build irresistible experiences.
|
||||
The Open Source Qualtrics Alternative
|
||||
<br />
|
||||
<a href="https://formbricks.com/">Website</a>
|
||||
</p>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
EXPO_PUBLIC_API_HOST=http://192.168.178.20:3000
|
||||
EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID=clzr04nkd000bcdl110j0ijyq
|
||||
EXPO_PUBLIC_APP_URL=http://192.168.0.197:3000
|
||||
EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID=cm5p0cs7r000819182b32j0a1
|
||||
@@ -18,6 +18,7 @@
|
||||
},
|
||||
"jsEngine": "hermes",
|
||||
"name": "react-native-demo",
|
||||
"newArchEnabled": true,
|
||||
"orientation": "portrait",
|
||||
"slug": "react-native-demo",
|
||||
"splash": {
|
||||
|
||||
@@ -13,16 +13,17 @@
|
||||
"dependencies": {
|
||||
"@formbricks/js": "workspace:*",
|
||||
"@formbricks/react-native": "workspace:*",
|
||||
"expo": "52.0.18",
|
||||
"expo-status-bar": "2.0.0",
|
||||
"@react-native-async-storage/async-storage": "2.1.0",
|
||||
"expo": "52.0.28",
|
||||
"expo-status-bar": "2.0.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"react-native": "0.76.5",
|
||||
"react-native": "0.76.6",
|
||||
"react-native-webview": "13.12.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.26.0",
|
||||
"@types/react": "19.0.1",
|
||||
"@types/react": "18.3.18",
|
||||
"typescript": "5.7.2"
|
||||
},
|
||||
"private": true
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
import React, { type JSX } from "react";
|
||||
import { Button, LogBox, StyleSheet, Text, View } from "react-native";
|
||||
import Formbricks, { track } from "@formbricks/react-native";
|
||||
import Formbricks, {
|
||||
logout,
|
||||
setAttribute,
|
||||
setAttributes,
|
||||
setLanguage,
|
||||
setUserId,
|
||||
track,
|
||||
} from "@formbricks/react-native";
|
||||
|
||||
LogBox.ignoreAllLogs();
|
||||
|
||||
@@ -10,35 +17,92 @@ export default function App(): JSX.Element {
|
||||
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");
|
||||
if (!process.env.EXPO_PUBLIC_APP_URL) {
|
||||
throw new Error("EXPO_PUBLIC_APP_URL is required");
|
||||
}
|
||||
|
||||
const config = {
|
||||
environmentId: process.env.EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID as string,
|
||||
apiHost: process.env.EXPO_PUBLIC_API_HOST as string,
|
||||
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);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 10,
|
||||
}}>
|
||||
<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);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title="Set User Id"
|
||||
onPress={() => {
|
||||
setUserId("random-user-id").catch((error: unknown) => {
|
||||
// eslint-disable-next-line no-console -- logging is allowed in demo apps
|
||||
console.error("Error setting user id:", error);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title="Set User Attributess (multiple)"
|
||||
onPress={() => {
|
||||
setAttributes({
|
||||
testAttr: "attr-test",
|
||||
testAttr2: "attr-test-2",
|
||||
testAttr3: "attr-test-3",
|
||||
testAttr4: "attr-test-4",
|
||||
}).catch((error: unknown) => {
|
||||
// eslint-disable-next-line no-console -- logging is allowed in demo apps
|
||||
console.error("Error setting user attributes:", error);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title="Set User Attributes (single)"
|
||||
onPress={() => {
|
||||
setAttribute("testSingleAttr", "testSingleAttr").catch((error: unknown) => {
|
||||
// eslint-disable-next-line no-console -- logging is allowed in demo apps
|
||||
console.error("Error setting user attributes:", error);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title="Logout"
|
||||
onPress={() => {
|
||||
logout().catch((error: unknown) => {
|
||||
// eslint-disable-next-line no-console -- logging is allowed in demo apps
|
||||
console.error("Error logging out:", error);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title="Set Language (de)"
|
||||
onPress={() => {
|
||||
setLanguage("de").catch((error: unknown) => {
|
||||
// eslint-disable-next-line no-console -- logging is allowed in demo apps
|
||||
console.error("Error setting language:", error);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<StatusBar style="auto" />
|
||||
<Formbricks initConfig={config} />
|
||||
|
||||
<Formbricks
|
||||
appUrl={process.env.EXPO_PUBLIC_APP_URL as string}
|
||||
environmentId={process.env.EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID as string}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"dependencies": {
|
||||
"@formbricks/js": "workspace:*",
|
||||
"lucide-react": "0.468.0",
|
||||
"next": "15.1.2",
|
||||
"next": "15.2.3",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0"
|
||||
},
|
||||
|
||||
@@ -9,6 +9,12 @@ declare const window: Window;
|
||||
export default function AppPage(): React.JSX.Element {
|
||||
const [darkMode, setDarkMode] = useState(false);
|
||||
const router = useRouter();
|
||||
const userId = "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING";
|
||||
const userAttributes = {
|
||||
"Attribute 1": "one",
|
||||
"Attribute 2": "two",
|
||||
"Attribute 3": "three",
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (darkMode) {
|
||||
@@ -33,18 +39,9 @@ export default function AppPage(): React.JSX.Element {
|
||||
addFormbricksDebugParam();
|
||||
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const userId = "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING";
|
||||
const userInitAttributes = {
|
||||
language: "de",
|
||||
"Init Attribute 1": "eight",
|
||||
"Init Attribute 2": "two",
|
||||
};
|
||||
|
||||
void formbricks.init({
|
||||
void formbricks.setup({
|
||||
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
|
||||
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
|
||||
userId,
|
||||
attributes: userInitAttributes,
|
||||
appUrl: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -126,19 +123,19 @@ export default function AppPage(): React.JSX.Element {
|
||||
<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">
|
||||
<h3 className="text-lg font-semibold dark:text-white">
|
||||
Reset person / pull data from Formbricks app
|
||||
Set a user ID / 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>.
|
||||
On formbricks.setUserId() the user state will <strong>be fetched from Formbricks</strong> and
|
||||
the local state gets <strong>updated with the user state</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"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
void formbricks.reset();
|
||||
void formbricks.setUserId(userId);
|
||||
}}>
|
||||
Reset
|
||||
Set user ID
|
||||
</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 'Reset' and
|
||||
@@ -158,7 +155,7 @@ export default function AppPage(): React.JSX.Element {
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sends a{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/actions/no-code"
|
||||
href="https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/actions#setting-up-no-code-actions"
|
||||
rel="noopener noreferrer"
|
||||
className="underline dark:text-blue-500"
|
||||
target="_blank">
|
||||
@@ -166,7 +163,7 @@ export default function AppPage(): React.JSX.Element {
|
||||
</a>{" "}
|
||||
as long as you created it beforehand in the Formbricks App.{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/actions/no-code"
|
||||
href="https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/actions#setting-up-no-code-actions"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="underline dark:text-blue-500">
|
||||
@@ -175,6 +172,7 @@ export default function AppPage(): React.JSX.Element {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
<div>
|
||||
<button
|
||||
@@ -190,7 +188,7 @@ export default function AppPage(): React.JSX.Element {
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sets the{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/attributes/custom-attributes"
|
||||
href="https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/user-identification#setting-custom-user-attributes"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline dark:text-blue-500">
|
||||
@@ -215,7 +213,7 @@ export default function AppPage(): React.JSX.Element {
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sets the{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/attributes/custom-attributes"
|
||||
href="https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/user-identification#setting-custom-user-attributes"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline dark:text-blue-500">
|
||||
@@ -240,7 +238,7 @@ export default function AppPage(): React.JSX.Element {
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sets the{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/attributes/identify-users"
|
||||
href="https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/user-identification"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline dark:text-blue-500">
|
||||
@@ -250,6 +248,110 @@ export default function AppPage(): React.JSX.Element {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
void formbricks.setAttributes(userAttributes);
|
||||
}}
|
||||
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 Multiple Attributes
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sets the{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/user-identification#setting-custom-user-attributes"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline dark:text-blue-500">
|
||||
user attributes
|
||||
</a>{" "}
|
||||
to 'one', 'two', 'three'.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
void formbricks.setLanguage("de");
|
||||
}}
|
||||
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 Language to 'de'
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sets the{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/xm-and-surveys/surveys/general-features/multi-language-surveys"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline dark:text-blue-500">
|
||||
language
|
||||
</a>{" "}
|
||||
to 'de'.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
void formbricks.track("code");
|
||||
}}>
|
||||
Code Action
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sends a{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/actions#setting-up-code-actions"
|
||||
rel="noopener noreferrer"
|
||||
className="underline dark:text-blue-500"
|
||||
target="_blank">
|
||||
Code Action
|
||||
</a>{" "}
|
||||
as long as you created it beforehand in the Formbricks App.{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/actions#setting-up-code-actions"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="underline dark:text-blue-500">
|
||||
Here are instructions on how to do it.
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
void formbricks.logout();
|
||||
}}>
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button logs out the user and syncs the local state with Formbricks. (Only works if a
|
||||
userId is set)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
NEXT_PUBLIC_FORMBRICKS_COM_API_HOST=http://localhost:3000
|
||||
NEXT_PUBLIC_FORMBRICKS_COM_ENVIRONMENT_ID=
|
||||
NEXT_PUBLIC_FORMBRICKS_COM_DOCS_FEEDBACK_SURVEY_ID=
|
||||
|
||||
# Strapi API Key
|
||||
STRAPI_API_KEY=
|
||||
|
||||
NEXT_PUBLIC_DOCSEARCH_APP_ID=
|
||||
NEXT_PUBLIC_DOCSEARCH_API_KEY=
|
||||
NEXT_PUBLIC_DOCSEARCH_INDEX_NAME=
|
||||
@@ -1,19 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["@formbricks/eslint-config/next.js"],
|
||||
parserOptions: {
|
||||
project: "tsconfig.json",
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
"import/no-cycle": "off",
|
||||
},
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
typescript: {
|
||||
project: "tsconfig.json",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
38
apps/docs/.gitignore
vendored
@@ -1,38 +0,0 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
public/sitemap*.xml
|
||||
public/robots.txt
|
||||
@@ -1,129 +0,0 @@
|
||||
# Tailwind UI License
|
||||
|
||||
## Personal License
|
||||
|
||||
Tailwind Labs Inc. grants you an on-going, non-exclusive license to use the Components and Templates.
|
||||
|
||||
The license grants permission to **one individual** (the Licensee) to access and use the Components and Templates.
|
||||
|
||||
You **can**:
|
||||
|
||||
- Use the Components and Templates to create unlimited End Products.
|
||||
- Modify the Components and Templates to create derivative components and templates. Those components and templates are subject to this license.
|
||||
- Use the Components and Templates to create unlimited End Products for unlimited Clients.
|
||||
- Use the Components and Templates to create End Products where the End Product is sold to End Users.
|
||||
- Use the Components and Templates to create End Products that are open source and freely available to End Users.
|
||||
|
||||
You **cannot**:
|
||||
|
||||
- Use the Components and Templates to create End Products that are designed to allow an End User to build their own End Products using the Components and Templates or derivatives of the Components and Templates.
|
||||
- Re-distribute the Components and Templates or derivatives of the Components and Templates separately from an End Product, neither in code or as design assets.
|
||||
- Share your access to the Components and Templates with any other individuals.
|
||||
- Use the Components and Templates to produce anything that may be deemed by Tailwind Labs Inc, in their sole and absolute discretion, to be competitive or in conflict with the business of Tailwind Labs Inc.
|
||||
|
||||
### Example usage
|
||||
|
||||
Examples of usage **allowed** by the license:
|
||||
|
||||
- Creating a personal website by yourself.
|
||||
- Creating a website or web application for a client that will be owned by that client.
|
||||
- Creating a commercial SaaS application (like an invoicing app for example) where end users have to pay a fee to use the application.
|
||||
- Creating a commercial self-hosted web application that is sold to end users for a one-time fee.
|
||||
- Creating a web application where the primary purpose is clearly not to simply re-distribute the components (like a conference organization app that uses the components for its UI for example) that is free and open source, where the source code is publicly available.
|
||||
|
||||
Examples of usage **not allowed** by the license:
|
||||
|
||||
- Creating a repository of your favorite Tailwind UI components or templates (or derivatives based on Tailwind UI components or templates) and publishing it publicly.
|
||||
- Creating a React or Vue version of Tailwind UI and making it available either for sale or for free.
|
||||
- Create a Figma or Sketch UI kit based on the Tailwind UI component designs.
|
||||
- Creating a "website builder" project where end users can build their own websites using components or templates included with or derived from Tailwind UI.
|
||||
- Creating a theme, template, or project starter kit using the components or templates and making it available either for sale or for free.
|
||||
- Creating an admin panel tool (like [Laravel Nova](https://nova.laravel.com/) or [ActiveAdmin](https://activeadmin.info/)) that is made available either for sale or for free.
|
||||
|
||||
In simple terms, use Tailwind UI for anything you like as long as it doesn't compete with Tailwind UI.
|
||||
|
||||
### Personal License Definitions
|
||||
|
||||
Licensee is the individual who has purchased a Personal License.
|
||||
|
||||
Components and Templates are the source code and design assets made available to the Licensee after purchasing a Tailwind UI license.
|
||||
|
||||
End Product is any artifact produced that incorporates the Components or Templates or derivatives of the Components or Templates.
|
||||
|
||||
End User is a user of an End Product.
|
||||
|
||||
Client is an individual or entity receiving custom professional services directly from the Licensee, produced specifically for that individual or entity. Customers of software-as-a-service products are not considered clients for the purpose of this document.
|
||||
|
||||
## Team License
|
||||
|
||||
Tailwind Labs Inc. grants you an on-going, non-exclusive license to use the Components and Templates.
|
||||
|
||||
The license grants permission for **up to 25 Employees and Contractors of the Licensee** to access and use the Components and Templates.
|
||||
|
||||
You **can**:
|
||||
|
||||
- Use the Components and Templates to create unlimited End Products.
|
||||
- Modify the Components and Templates to create derivative components and templates. Those components and templates are subject to this license.
|
||||
- Use the Components and Templates to create unlimited End Products for unlimited Clients.
|
||||
- Use the Components and Templates to create End Products where the End Product is sold to End Users.
|
||||
- Use the Components and Templates to create End Products that are open source and freely available to End Users.
|
||||
|
||||
You **cannot**:
|
||||
|
||||
- Use the Components or Templates to create End Products that are designed to allow an End User to build their own End Products using the Components or Templates or derivatives of the Components or Templates.
|
||||
- Re-distribute the Components or Templates or derivatives of the Components or Templates separately from an End Product.
|
||||
- Use the Components or Templates to create End Products that are the property of any individual or entity other than the Licensee or Clients of the Licensee.
|
||||
- Use the Components or Templates to produce anything that may be deemed by Tailwind Labs Inc, in their sole and absolute discretion, to be competitive or in conflict with the business of Tailwind Labs Inc.
|
||||
|
||||
### Example usage
|
||||
|
||||
Examples of usage **allowed** by the license:
|
||||
|
||||
- Creating a website for your company.
|
||||
- Creating a website or web application for a client that will be owned by that client.
|
||||
- Creating a commercial SaaS application (like an invoicing app for example) where end users have to pay a fee to use the application.
|
||||
- Creating a commercial self-hosted web application that is sold to end users for a one-time fee.
|
||||
- Creating a web application where the primary purpose is clearly not to simply re-distribute the components or templates (like a conference organization app that uses the components or a template for its UI for example) that is free and open source, where the source code is publicly available.
|
||||
|
||||
Examples of use **not allowed** by the license:
|
||||
|
||||
- Creating a repository of your favorite Tailwind UI components or template (or derivatives based on Tailwind UI components or templates) and publishing it publicly.
|
||||
- Creating a React or Vue version of Tailwind UI and making it available either for sale or for free.
|
||||
- Creating a "website builder" project where end users can build their own websites using components or templates included with or derived from Tailwind UI.
|
||||
- Creating a theme or template using the components or templates and making it available either for sale or for free.
|
||||
- Creating an admin panel tool (like [Laravel Nova](https://nova.laravel.com/) or [ActiveAdmin](https://activeadmin.info/)) that is made available either for sale or for free.
|
||||
- Creating any End Product that is not the sole property of either your company or a client of your company. For example your employees/contractors can't use your company Tailwind UI license to build their own websites or side projects.
|
||||
|
||||
### Team License Definitions
|
||||
|
||||
Licensee is the business entity who has purchased a Team License.
|
||||
|
||||
Components and Templates are the source code and design assets made available to the Licensee after purchasing a Tailwind UI license.
|
||||
|
||||
End Product is any artifact produced that incorporates the Components or Templates or derivatives of the Components or Templates.
|
||||
|
||||
End User is a user of an End Product.
|
||||
|
||||
Employee is a full-time or part-time employee of the Licensee.
|
||||
|
||||
Contractor is an individual or business entity contracted to perform services for the Licensee.
|
||||
|
||||
Client is an individual or entity receiving custom professional services directly from the Licensee, produced specifically for that individual or entity. Customers of software-as-a-service products are not considered clients for the purpose of this document.
|
||||
|
||||
## Enforcement
|
||||
|
||||
If you are found to be in violation of the license, access to your Tailwind UI account will be terminated, and a refund may be issued at our discretion. When license violation is blatant and malicious (such as intentionally redistributing the Components or Templates through private warez channels), no refund will be issued.
|
||||
|
||||
The copyright of the Components and Templates is owned by Tailwind Labs Inc. You are granted only the permissions described in this license; all other rights are reserved. Tailwind Labs Inc. reserves the right to pursue legal remedies for any unauthorized use of the Components or Templates outside the scope of this license.
|
||||
|
||||
## Liability
|
||||
|
||||
Tailwind Labs Inc.’s liability to you for costs, damages, or other losses arising from your use of the Components or Templates — including third-party claims against you — is limited to a refund of your license fee. Tailwind Labs Inc. may not be held liable for any consequential damages related to your use of the Components or Templates.
|
||||
|
||||
This Agreement is governed by the laws of the Province of Ontario and the applicable laws of Canada. Legal proceedings related to this Agreement may only be brought in the courts of Ontario. You agree to service of process at the e-mail address on your original order.
|
||||
|
||||
## Questions?
|
||||
|
||||
Unsure which license you need, or unsure if your use case is covered by our licenses?
|
||||
|
||||
Email us at [support@tailwindui.com](mailto:support@tailwindui.com) with your questions.
|
||||
@@ -1,173 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
|
||||
import AddMember from "./images/add-member.webp";
|
||||
import BulkInvite from "./images/bulk-invite.webp";
|
||||
import IndvInvite from "./images/individual-invite.webp";
|
||||
import MenuItem from "./images/organization-settings-menu.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "User Management",
|
||||
description:
|
||||
"Assign different roles to organization members to grant them specific rights like creating surveys, viewing responses, or managing organization members.",
|
||||
};
|
||||
|
||||
# Organization Access Roles
|
||||
|
||||
Learn about the different organization-level and team-level roles and how they affect permissions in Formbricks.
|
||||
|
||||
## Memberships
|
||||
|
||||
Permissions in Formbricks are broadly handled using organization-level roles, which apply to all teams and projects in the organization. Users on a self-hosting and Enterprise plan, have access to team-level roles, which enable more granular permissions.
|
||||
|
||||
<Note>
|
||||
Access Roles is a feature of the **Enterprise Edition**. In the **Community Edition** and on the **Free** and **Startup** plan in the Cloud you can invite unlimited organization members as `Owner`.
|
||||
</Note>
|
||||
|
||||
Here are the different access permissions, ranked from highest to lowest access
|
||||
|
||||
1. Owner
|
||||
2. Manager
|
||||
3. Billing
|
||||
4. Member
|
||||
|
||||
### Organisational level
|
||||
|
||||
All users and their organization-level roles are listed in **Organization Settings > General**. Users can hold any of the following org-level roles:
|
||||
|
||||
- **Billing** users can manage payment and compliance details in the organization.
|
||||
- **Org Members** can view most data in the organization and act in the projects they are members of. They cannot join projects on their own and need to be assigned.
|
||||
- **Org Managers** have full management access to all teams and projects. They can also manage the organization's membership. Org Managers can perform Team Admin actions without needing to join the team. They cannot change other organization settings.
|
||||
- **Org Owners** have full access to the organization, its data, and settings. Org Owners can perform Team Admin actions without needing to join the team.
|
||||
|
||||
### Permissions at project level
|
||||
|
||||
- **read**: read access to all resources (except settings) in the project.
|
||||
- **read & write**: read & write access to all resources (except settings) in the project.
|
||||
- **manage**: read & write access to all resources including settings in the project.
|
||||
|
||||
### Team-level Roles
|
||||
|
||||
- **Team Contributors** can view and act on surveys and responses.
|
||||
- **Team Admins** have additional permissions to manage their team's membership and projects. These permissions are granted at the team-level, and don't apply to teams where they're not a Team Admin.
|
||||
|
||||
For more information on user roles & permissions, see below:
|
||||
|
||||
| | Owner | Manager | Billing | Member |
|
||||
| -------------------------------- | ----- | ------- | ------- | ------ |
|
||||
| **Organization** | | | | |
|
||||
| Update organization | ✅ | ❌ | ❌ | ❌ |
|
||||
| Delete organization | ✅ | ❌ | ❌ | ❌ |
|
||||
| Add new Member | ✅ | ✅ | ❌ | ❌ |
|
||||
| Delete Member | ✅ | ✅ | ❌ | ❌ |
|
||||
| Update Member Access | ✅ | ✅ | ❌ | ❌ |
|
||||
| Update Billing | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Project** | | | | |
|
||||
| Create Project | ✅ | ✅ | ❌ | ❌ |
|
||||
| Update Project Name | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Update Project Recontact Options | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Update Look & Feel | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Update Survey Languages | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Delete Project | ✅ | ✅ | ❌ | ❌ |
|
||||
| **Surveys** | | | | |
|
||||
| Create New Survey | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Edit Survey | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Delete Survey | ✅ | ✅ | ❌ | ✅\* |
|
||||
| View survey results | ✅ | ✅ | ❌ | ✅ |
|
||||
| **Response** | | | | |
|
||||
| Delete response | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Add tags on response | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Edit tags on response | ✅ | ✅ | ❌ | ✅\* |
|
||||
| **Actions** | | | | |
|
||||
| Create Action | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Update Action | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Delete Action | ✅ | ✅ | ❌ | ✅\* |
|
||||
| **API Keys** | | | | |
|
||||
| Create API key | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Update API key | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Delete API key | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| **Tags** | | | | |
|
||||
| Create tags | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Update tags | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Delete tags | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| **People** | | | | |
|
||||
| Delete Person | ✅ | ✅ | ❌ | ✅\* |
|
||||
| **Integrations** | | | | |
|
||||
| Manage Integrations | ✅ | ✅ | ❌ | ✅\* |
|
||||
|
||||
\* - for the read & write permissions team members
|
||||
|
||||
\*\* - for the manage permissions team members
|
||||
|
||||
## Inviting organization members
|
||||
|
||||
There are two ways to invite organization members: One by one or in bulk.
|
||||
|
||||
### Invite organization members one by one
|
||||
|
||||
1. Go to the `Organization Settings` page via the menu in the lower right corner:
|
||||
|
||||
<MdxImage
|
||||
src={MenuItem}
|
||||
alt="Where to find the Menu Item for Organization Settings"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Click on the `Add member` button:
|
||||
|
||||
<MdxImage
|
||||
src={AddMember}
|
||||
alt="Add member Button Position"
|
||||
quality="100"
|
||||
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:
|
||||
|
||||
<MdxImage
|
||||
src={IndvInvite}
|
||||
alt="Individual Invite Modal Tab"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
<Note>
|
||||
Access Roles is a feature of the **Enterprise Edition**. In the **Community Edition** and on the **Free** and **Startup** plan in the Cloud you can invite unlimited organization members as `Owners`.
|
||||
</Note>
|
||||
|
||||
Formbricks sends an email to the organization member with an invitation link. The organization member can accept the invitation or create a new account by clicking on the link.
|
||||
|
||||
### Invite organization members in bulk
|
||||
|
||||
1. Go to the `Organization Settings` page via the menu in the lower right corner:
|
||||
|
||||
<MdxImage
|
||||
src={MenuItem}
|
||||
alt="Where to find the Menu Item for Organization Settings"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Click on the `Add member` button:
|
||||
|
||||
<MdxImage
|
||||
src={AddMember}
|
||||
alt="Add member Button Position"
|
||||
quality="100"
|
||||
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:
|
||||
|
||||
<MdxImage
|
||||
src={BulkInvite}
|
||||
alt="Individual Invite Modal Tab"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
4. Upload the filled .CSV file and invite the organization members in bulk ✅
|
||||
|
||||
Formbricks sends an email to each organization member in the CSV. The member can accept the invitation or create a new account by clicking on the link.
|
||||
|
||||
---
|
||||
@@ -1,48 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import AddImageOrVideoToQuestionImage from "./images/add-image-or-video-to-question-image.webp";
|
||||
import AddImageOrVideoToQuestionVideo from "./images/add-image-or-video-to-question-video.webp";
|
||||
import AddImageOrVideoToQuestion from "./images/add-image-or-video-to-question.webp";
|
||||
|
||||
# Add Image or Video to a Question
|
||||
|
||||
Enhance your questions by adding images or videos. This makes instructions clearer and the survey more engaging.
|
||||
|
||||
## How to Add Images
|
||||
|
||||
Click the icon on the right side of the question to add an image or video:
|
||||
|
||||
<MdxImage
|
||||
src={AddImageOrVideoToQuestion}
|
||||
alt="Overview of adding image or video to question"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Upload an image by clicking the upload icon or dragging the file:
|
||||
|
||||
<MdxImage
|
||||
src={AddImageOrVideoToQuestionImage}
|
||||
alt="Overview of adding image to question"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## How to Add Videos
|
||||
|
||||
Toggle to add a video via link:
|
||||
|
||||
<MdxImage
|
||||
src={AddImageOrVideoToQuestionVideo}
|
||||
alt="Overview of adding video to question"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Supported Video Platforms
|
||||
|
||||
We support YouTube, Vimeo, and Loom URLs.
|
||||
|
||||
<Note>
|
||||
**YouTube Privacy Mode**: This option reduces tracking by converting YouTube URLs to no-cookie URLs. It only works with YouTube.
|
||||
</Note>
|
||||
@@ -1,169 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import ActionCalculateOperators from "./images/action-calculate-operators.webp";
|
||||
import ActionCalculateValue from "./images/action-calculate-value.webp";
|
||||
import ActionCalculateVariables from "./images/action-calculate-variables.webp";
|
||||
import ActionCalculate from "./images/action-calculate.webp";
|
||||
import ActionJump from "./images/action-jump.webp";
|
||||
import ActionOptions from "./images/action-options.webp";
|
||||
import ActionRequire from "./images/action-require.webp";
|
||||
import AddLogic from "./images/add-logic.webp";
|
||||
import ConditionChaining from "./images/condition-chaining.webp";
|
||||
import ConditionOperators from "./images/condition-operators.webp";
|
||||
import ConditionOptions from "./images/condition-options.webp";
|
||||
import ConditionValue from "./images/condition-value.webp";
|
||||
import Conditions from "./images/conditions.webp";
|
||||
import Editor from "./images/editor.webp";
|
||||
import QuestionLogic from "./images/question-logic.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Conditional Logic",
|
||||
description:
|
||||
"Create complex survey logic with the Logic Editor. Use conditions, actions, and variables to create a personalized survey experience.",
|
||||
};
|
||||
|
||||
# Conditional Logic
|
||||
|
||||
Create complex survey logic with the Logic Editor. Use conditions, actions, and variables to create a personalized survey experience.
|
||||
|
||||
<MdxImage src={Editor} alt="Logic Editor" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
## Terminology
|
||||
|
||||
- **Condition**: A rule that determines when an action should be executed.
|
||||
- **Action**: A task that is executed when a condition is met.
|
||||
|
||||
## **Creating Logic**
|
||||
|
||||
1. **Add a Logic Block**: Click the `Add logic +` button to add a new logic block.
|
||||
|
||||
<MdxImage src={AddLogic} alt="Add Logic" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
<Note>
|
||||
You can add multiple logic blocks to a survey. Logic blocks are executed in the order they are added. You can rearrange the order of logic blocks.
|
||||
</Note>
|
||||
|
||||
2. **Add Conditions**: Add conditions to the logic block. Conditions are rules that determine when an action should be executed.
|
||||
|
||||
<MdxImage
|
||||
src={Conditions}
|
||||
alt="Add Conditions"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Conditons can be based on:
|
||||
|
||||
- **Question**: The answer to a question.
|
||||
- **Variable**: A variable value.
|
||||
- **Hidden Field**: The value of a hidden field.
|
||||
|
||||
2.a **Condition Options**: Choose from a list of available conditions.
|
||||
|
||||
<MdxImage
|
||||
src={ConditionOptions}
|
||||
alt="Condition Options"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2.b **Condition Operators**: Choose an operator to compare the condition value.
|
||||
|
||||
<MdxImage
|
||||
src={ConditionOperators}
|
||||
alt="Condition Operators"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2.c **Condition Value**: Enter a value to compare the condition against.
|
||||
Comparisons can be made against a fixed value or a dynamic value.
|
||||
Dynamic values can be based on a question, variable, or hidden field.
|
||||
|
||||
<MdxImage
|
||||
src={ConditionValue}
|
||||
alt="Condition Value"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
<Note>
|
||||
- Conditions can be grouped. - Conditions can be combined using AND or OR operators. You can add multiple conditions to a logic block. Conditions are evaluated in the order they are added.
|
||||
</Note>
|
||||
|
||||
<MdxImage
|
||||
src={ConditionChaining}
|
||||
alt="Condition Chaining"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. **Add Actions**: Add actions to the logic block. Actions are tasks that are executed when a condition is met.
|
||||
|
||||
<Note>You can add multiple actions to a logic block. Actions are executed in the order they are added.</Note>
|
||||
|
||||
- 3.a **Action Options**: Choose from a list of available actions.
|
||||
|
||||
<MdxImage
|
||||
src={ActionOptions}
|
||||
alt="Add Actions"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Action is of the following types:
|
||||
|
||||
- **Calculate**: Perform a calculation. These variables are then available for use in other questions.
|
||||
|
||||
- Calculations can be performed on variables.
|
||||
- Calculations can be based on fixed values or dynamic values.
|
||||
<MdxImage
|
||||
src={ActionCalculateVariables}
|
||||
alt="Action Calculate Variables"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
<MdxImage
|
||||
src={ActionCalculateOperators}
|
||||
alt="Action Calculate Variables"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
<MdxImage
|
||||
src={ActionCalculateValue}
|
||||
alt="Action Calculate Variables"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
<MdxImage
|
||||
src={ActionCalculate}
|
||||
alt="Action Calculate"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
- **Require Answer**: Make a question required. Only the optional questions can be marked as required while filling the survey.
|
||||
<MdxImage
|
||||
src={ActionRequire}
|
||||
alt="Action Require"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
- **Jump to Question**: Skip to a specific question. The user will be redirected to the specified question based on the condition.
|
||||
<MdxImage
|
||||
src={ActionJump}
|
||||
alt="Action Jump"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
4. **Save Logic**: Click the `Save` button to save the logic block.
|
||||
|
||||
# Question Logic
|
||||
|
||||
This logic is executed when the user answers the question. Logic can be as simple as showing a follow-up question based on the answer or as complex as calculating a score based on multiple answers.
|
||||
|
||||
<MdxImage
|
||||
src={QuestionLogic}
|
||||
alt="Question Logic"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
@@ -1,48 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
|
||||
import EmailCustomizationSettings from "./email-customization-card.webp";
|
||||
import EmailSample from "./email-sample.webp";
|
||||
import UpdatedLogo from "./updated-logo.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Email Customization",
|
||||
description: "Customize the email that is sent to your users!",
|
||||
};
|
||||
|
||||
# Email Customization
|
||||
|
||||
Email customization is a white-label feature that allows you to customize the email that is sent to your users. You can upload a logo of your company and use it in the email.
|
||||
|
||||
<Note>
|
||||
This feature is a white-label feature. It is only available for users on paid plans or have an enterprise license.
|
||||
</Note>
|
||||
|
||||
## How to Upload a Logo
|
||||
|
||||
1. Go to the Organization Settings page.
|
||||
2. You will see a card called **Email Customization** under the **General** section.
|
||||
|
||||
<MdxImage
|
||||
src={EmailCustomizationSettings}
|
||||
alt="Email Customization Settings"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. Upload a logo of your company.
|
||||
4. Click on the **Save** button.
|
||||
|
||||
<MdxImage src={UpdatedLogo} alt="Updated Logo" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
## Viewing the Logo in the Email
|
||||
|
||||
You can click on the **Send test email** button to get a test email with the logo.
|
||||
|
||||
<MdxImage src={EmailSample} alt="Email Sample" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
<Note>Only the owner and managers of the organization can modify the logo.</Note>
|
||||
|
||||
## Use Cases
|
||||
|
||||
- **White-labeling**: You can use this feature to white-label your emails to your users.
|
||||
- **Branding**: You can use this feature to add your logo to your emails to increase brand recognition.
|
||||
@@ -1,110 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
|
||||
import FilledHiddenFields from "./filled-hidden-fields.webp";
|
||||
import HiddenFieldResponses from "./hidden-field-responses.webp";
|
||||
import HiddenFields from "./hidden-fields.webp";
|
||||
import InputHiddenFields from "./input-hidden-fields.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Hidden Fields",
|
||||
description: "Add hidden fields to your surveys to capture additional data without requiring user inputs!",
|
||||
};
|
||||
|
||||
# Hidden Fields
|
||||
|
||||
Hidden fields are a powerful feature in Formbricks that allows you to add data to a submission without asking the user to type it in. This feature is especially useful when you already have information about a user that you want to use in the analysis of the survey results (e.g. `payment plan` or `email`)
|
||||
|
||||
## How to Add Hidden Fields
|
||||
|
||||
### Enable Hidden Fields
|
||||
|
||||
1. Edit the survey you want to add hidden fields to & switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Hidden Fields**. Make sure to enable it by toggling the switch.
|
||||
|
||||
<MdxImage
|
||||
src={HiddenFields}
|
||||
alt="Enable Hidden Fields"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Add Hidden Field IDs
|
||||
|
||||
2. Now click on it to add a new hidden field ID. You can add as many hidden fields as you want.
|
||||
|
||||
<MdxImage
|
||||
src={InputHiddenFields}
|
||||
alt="Add Hidden Fields"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
<MdxImage
|
||||
src={FilledHiddenFields}
|
||||
alt="Filled Hidden Fields"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Set Hidden Field in Responses
|
||||
|
||||
### Link Surveys
|
||||
|
||||
Single Hidden Field:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Example Screen from which the User filled it">
|
||||
|
||||
```sh
|
||||
https://formbricks.com/clin3dxja02k8l80hpwmx4bjy?screen=pricing
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
Multiple Hidden Fields:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Example Screen from which the User filled it">
|
||||
|
||||
```sh
|
||||
https://formbricks.com/clin3dxja02k8l80hpwmx4bjy?screen=landing_page&job=Founder
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
### App & Website Surveys
|
||||
|
||||
For in-product surveys, you can set hidden fields in the response by adding them to the `formbricks.track` call:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Example Screen from which the User filled it">
|
||||
|
||||
```sh
|
||||
formbricks.track("my event", {
|
||||
hiddenFields: {
|
||||
screen: "landing_page",
|
||||
job: "Founder"
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
## View Hidden Fields in Responses
|
||||
|
||||
These hidden fields will now be visible in the responses tab just like other fields in the Summary as well as the Response Cards, and you can use them to filter and analyze your responses.
|
||||
|
||||
<MdxImage
|
||||
src={HiddenFieldResponses}
|
||||
alt="Hidden Field Responses"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Use Cases
|
||||
|
||||
- **Tracking Source**: You can add a hidden field to track the source of the survey. For a detailed guide on Source Tracking, check out the [Source Tracking](/link-surveys/source-tracking) guide.
|
||||
- **User Metadata**: You can add hidden fields to capture user metadata such as user ID, email, or any other user-specific information.
|
||||
- **Survey Metadata**: You can add hidden fields to capture other metadata, e.g. the screen from which the survey was filled, or any other app specific information.
|
||||
@@ -1,27 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
|
||||
import StepOne from "./images/step-one.webp";
|
||||
import StepThree from "./images/step-three.webp";
|
||||
import StepTwo from "./images/step-two.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Set a Maximum Number of Submissions for Surveys",
|
||||
description: "Limit the number of responses your survey can receive.",
|
||||
};
|
||||
|
||||
# Limit by Number of Submissions
|
||||
|
||||
Automatically close your survey after a specific number of responses with Formbricks. This feature is perfect for limited offers, exclusive surveys, or when you need a precise sample size for statistical significance.
|
||||
|
||||
- **How to**: Open the Survey Editor, switch to the Settings tab. Scroll down to Response Options, Toggle the “Close survey on response limit”.
|
||||
{" "}
|
||||
<MdxImage
|
||||
src={StepTwo}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
- **Details**: Set a specific number of responses after which the survey automatically closes.
|
||||
- **Use Case**: Perfect for limited offers, exclusive surveys, or when you need a precise sample size for statistical significance.
|
||||
|
||||
---
|
||||
@@ -1,65 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import { TellaVideo } from "@/components/tella-video";
|
||||
|
||||
import Filters from "./filters.webp";
|
||||
import MetadataCard from "./metadata-card.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "User Metadata | Formbricks",
|
||||
description:
|
||||
"Understand the metadata of your users when they fill a Formbricks survey (all website, app & link). We currently capture the user's source information, URL, browser, and device details, along with the country & the action that triggered.",
|
||||
};
|
||||
|
||||
# User Metadata
|
||||
|
||||
Formbricks captures metadata of your users for you when they fill a survey.
|
||||
|
||||
This metadata is useful for understanding the context in which the user filled the survey. For example, if you are running a marketing campaign, you can understand which source is driving the most responses. Or if you are running a survey on a specific page, you can understand the user's behavior on that page.
|
||||
|
||||
<TellaVideo tellaVideoIdentifier="clvdr5lv300u90fjq7fmnhs0k" />
|
||||
|
||||
## Metadata Captured
|
||||
|
||||
- **Source**: The source from where the user filled the survey. This could be an App, Link, or a Webpage.
|
||||
- **URL**: The URL of the page where the user filled the survey.
|
||||
- **Browser**: The browser used by the user to fill the survey.
|
||||
- **OS**: The operating system of the device used by the user to fill the survey.
|
||||
- **Device**: The device used by the user to fill the survey.
|
||||
- **Country**: The country of the user.
|
||||
- **Action**: The action that triggered the survey. This is only available for App surveys.
|
||||
|
||||
## View Response Metadata
|
||||
|
||||
1. Go to the Responses tab of your survey.
|
||||
2. Hover over the profile icon of the user on the response card & you should see a tooltip opening up with the metadata details.
|
||||
|
||||
<MdxImage
|
||||
src={MetadataCard}
|
||||
alt="Metadata Card on Response Tab"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Filter Responses by Metadata
|
||||
|
||||
1. Go to the Responses tab of your survey.
|
||||
2. Click on the Filter button.
|
||||
3. Scroll down & Select the metadata field you want to filter by.
|
||||
4. Select the condition & the value you want to filter by.
|
||||
|
||||
<MdxImage
|
||||
src={Filters}
|
||||
alt="Apply Filters on Metadata"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
5. Now you should see the responses filtered based on the metadata you selected. If you want to see a walkthrough, view the video above to see how you can view & filter responses by metadata.
|
||||
|
||||
## Export Metadata
|
||||
|
||||
You can export the metadata of your responses along with the response data. When you export responses, you will see the metadata fields in the exported CSV file.
|
||||
|
||||
---
|
||||
|
||||
**Can’t figure it out?**: **[Get help in Github Discussions](https://github.com/formbricks/formbricks/discussions)**
|
||||
@@ -1,166 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
|
||||
import { ResponsiveVideo } from "@/components/responsive-video";
|
||||
import AddLanguageInSurvey from "./add-language-in-survey.webp";
|
||||
import AddLanguages from "./add-languages.webp";
|
||||
import EditMultiLang from "./edit-multi-lang.webp";
|
||||
import EnableMultiLang from "./enable-multi-lang.webp";
|
||||
import SeeSurveyInLanguage from "./see-survey-in-language.webp";
|
||||
import SurveyLanguagesFromHome from "./survey-languages-from-home.webp";
|
||||
import SurveyLanguageSettings from "./survey-languague-settings.webp";
|
||||
import SurveySharing from "./survey-sharing.webp";
|
||||
import SurveysHome from "./surveys-home.webp";
|
||||
import TranslateAsPerLanguage from "./translate-as-per-language.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Multi-language Surveys | Formbricks",
|
||||
description:
|
||||
"Create multi-language link & app surveys with Formbricks. Get feedback from your users in their preferred language without writing a single line of code.",
|
||||
};
|
||||
|
||||
# Multi-language Surveys
|
||||
|
||||
Multi-Language Surveys allow you to create surveys that support multiple languages using translations. This makes it easier to reach a diverse audience without creating separate surveys for each language. This feature simplifies the creation, delivery, and analysis of surveys for a multilingual audience.
|
||||
|
||||
How to deliver a specific language depends on the survey type (app or link survey):
|
||||
|
||||
- App & Website survey: Set a `language` attribute for the user. [See the guide below for App Surveys](#app-surveys-configuration)
|
||||
- Link survey: Add a `lang` parameter in the survey URL. [See the guide below for Link Surveys](#link-surveys-configuration)
|
||||
|
||||
<ResponsiveVideo
|
||||
title="Formbricks Multi-language Surveys"
|
||||
src="https://www.youtube-nocookie.com/embed/Vol5zjYIoos?si=bdP2y3uk8-xR0uSD&controls=0"
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
## Creating a Multi-language Survey
|
||||
|
||||
1. Open the **Survey Languages** page in the Formbricks settings via the top-right menu:
|
||||
|
||||
<MdxImage
|
||||
src={SurveyLanguagesFromHome}
|
||||
alt="Formbricks Home"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Click on the **Edit languages** button, to add a new language to your survey
|
||||
|
||||
<MdxImage
|
||||
src={SurveyLanguageSettings}
|
||||
alt="Formbricks Home"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. Select the preferred language from the dropdown and assign an identifier Alias. Click the **Add language** button to add the language to your project.
|
||||
|
||||
<MdxImage
|
||||
src={AddLanguages}
|
||||
alt="Add Multiple Languages to your Project"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
You can come back to this page anytime to add more languages or remove existing ones.
|
||||
|
||||
4. Now, return to the dashboard to create a new survey or edit an existing one.
|
||||
|
||||
<MdxImage
|
||||
src={SurveysHome}
|
||||
alt="Add Multiple Languages to your Project"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
5. In the survey editor, scroll down to the **Multiple Languages** section at the bottom and enable the toggle next to it.
|
||||
|
||||
<MdxImage
|
||||
src={EnableMultiLang}
|
||||
alt="Enable Multi-language for a survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
6. Now choose a **Default Language** for your survey. This is the language that will be shown to users who have not selected a preferred language.
|
||||
|
||||
<Note>Changing the default language will reset all the translations you have made for the survey.</Note>
|
||||
|
||||
7. Now, add the languages from the dropdown that you want to support in your survey.
|
||||
|
||||
<MdxImage
|
||||
src={AddLanguageInSurvey}
|
||||
alt="Enable Multi-language for a survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
8. You can now see the survey in the selected language by clicking on the language dropdown in any of the questions.
|
||||
|
||||
<MdxImage
|
||||
src={SeeSurveyInLanguage}
|
||||
alt="Enable Multi-language for a survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
9. You can now translate all survey content, including questions, options, and button placeholders, into the selected language.
|
||||
|
||||
<MdxImage
|
||||
src={TranslateAsPerLanguage}
|
||||
alt="Enable Multi-language for a survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
10. Once you are done, click on the **Publish** button to save the survey.
|
||||
|
||||
## App Surveys Configuration
|
||||
|
||||
1. When you initialise the Formbricks SDK for your user, you can pass a `language` attribute with the language code. This can be either the ISO identifier or the Alias you set when creating the language. The `language` attribute makes sure that this user only sees surveys with a translation in this specific language available.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Configuring Formbricks SDK with Multi-language">
|
||||
|
||||
```js
|
||||
Formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user_id>",
|
||||
attributes: {
|
||||
language: "de", // ISO identifier or Alias set when creating language
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
<Note>
|
||||
If a user has a language assigned, a survey has multi-language activate and it is missing a translation in the language of the user, the survey will not be displayed.
|
||||
</Note>
|
||||
|
||||
2. That's it! Now, users with the language attribute set will see the survey in their preferred language. You can start collecting responses in multiple languages and filter them by language on the summary page.
|
||||
|
||||
---
|
||||
|
||||
## Link Surveys Configuration
|
||||
|
||||
For link surveys, the translation delivery is dependent on the `land` URL parameter.
|
||||
|
||||
After publishing the survey, just copy the survey link and append the `lang` query parameter with the language alias you have set.
|
||||
|
||||
For example, if you have set the alias for French as `fr`, you can share the survey link as
|
||||
|
||||
`https://your-survey-url.com?lang=fr`
|
||||
|
||||
Here are two examples:
|
||||
|
||||
- English: https://app.Formbricks.com/s/clptfos2i1pj516pvhxqyu3bn?lang=en
|
||||
- German: https://app.Formbricks.com/s/clptfos2i1pj516pvhxqyu3bn?lang=de
|
||||
|
||||
Without the `lang` parameter, Formbricks will show the survey in the default language you have set.
|
||||
|
||||
You can now start collecting responses in multiple languages!
|
||||
|
||||
**Can’t figure it out?**: **[Get help in Github Discussions](https://github.com/formbricks/formbricks/discussions)**
|
||||
@@ -1,132 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
|
||||
import StepEleven from "./images/step-eleven.webp";
|
||||
import StepNine from "./images/step-nine.webp";
|
||||
import StepTen from "./images/step-ten.webp";
|
||||
|
||||
import Doggo from "./images/doggo.webp";
|
||||
import HipsterLiving from "./images/hipster-living.webp";
|
||||
import Mario from "./images/mario.webp";
|
||||
import WindowsXp from "./images/windows-xp.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Overwrite Styling Theme on Individual Surveys",
|
||||
description:
|
||||
"Overwrite the global styling theme for individual surveys to create unique styles for each survey.",
|
||||
};
|
||||
|
||||
# Overwrite Styling Theme on Individual Surveys
|
||||
|
||||
Overwrite the global styling theme for individual surveys to create unique styles for each survey.
|
||||
|
||||
<Note>
|
||||
To set a styling theme for all surveys, please see the [Styling Theme](/core-features/global/styling-theme) manual.
|
||||
</Note>
|
||||
|
||||
### Overwrite Styling Theme
|
||||
|
||||
1. In the Survey Editor of the survey you want to style, navigate to the **Styling** tab:
|
||||
|
||||
<MdxImage
|
||||
src={StepNine}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Activate the **Add Custom Styles** toggle to override the default project styling:
|
||||
|
||||
<MdxImage
|
||||
src={StepTen}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. Customize your survey's style as needed:
|
||||
|
||||
<MdxImage
|
||||
src={StepEleven}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Voila! just hit the save button to apply your changes. Your survey is now ready to impress with its unique look!
|
||||
|
||||
## Overwrite CSS Styles for App & Website Surveys
|
||||
|
||||
You can overwrite the default CSS styles for the app & website surveys by adding the following CSS to your global CSS file (eg. `globals.css`):
|
||||
|
||||
Make sure that you do not change the CSS variable names as they are used by Formbricks to identify the CSS variables. You can change the values to your liking. We have filled in some sample values for you to change according to your desired appearance.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Overwrite Formbricks CSS">
|
||||
|
||||
```css
|
||||
/* Formbricks CSS */
|
||||
--fb-brand-color: red;
|
||||
--fb-brand-text-color: white;
|
||||
--fb-border-color: green;
|
||||
--fb-border-color-highlight: rgb(13, 13, 12);
|
||||
--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: var(--fb-brand-color);
|
||||
--fb-rating-fill: rgb(13, 13, 12);
|
||||
--fb-rating-hover: green;
|
||||
--fb-back-btn-border: blue;
|
||||
--fb-submit-btn-border: transparent;
|
||||
--fb-rating-selected: black;
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
We have an example of this in our [Demo project](https://github.com/formbricks/formbricks/blob/main/apps/demo/styles/globals.css) here.
|
||||
|
||||
## Funky Survey Examples
|
||||
|
||||
- **Super Mario:** I guess he won't let himself be limited by radio buttons and do all three things
|
||||
|
||||
<MdxImage
|
||||
src={Mario}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
- **Hipster Living**: Does your monstera get enough water?
|
||||
|
||||
<MdxImage
|
||||
src={HipsterLiving}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
- **Windows XP**: Hach, nostalgia. Made us wanna play Mafia.
|
||||
|
||||
<MdxImage
|
||||
src={WindowsXp}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
- **Whosagooooodbooooy**: Things you've likely said to your dog.
|
||||
|
||||
<MdxImage
|
||||
src={Doggo}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
---
|
||||
@@ -1,39 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import Address from "./images/address.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Address
|
||||
|
||||
The Address question type allows respondents to input their address details, including multiple fields such as address lines, city, state, and country. You can configure the question by adding a title, an optional description, and toggling specific fields to be required.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/m8w91e8wi52pdao8un1f4twu" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={Address}
|
||||
alt="Overview of Address question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Question
|
||||
|
||||
Provide a question to describe the address information you are requesting.
|
||||
|
||||
### Description
|
||||
|
||||
Optionally, add a description to guide the user.
|
||||
|
||||
### Toggle Fields
|
||||
|
||||
You can choose to show and require any or all of the following fields in the form:
|
||||
|
||||
- Address Line 1
|
||||
- Address Line 2
|
||||
- City
|
||||
- State
|
||||
- Zip Code
|
||||
- Country
|
||||
@@ -1,32 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import Consent from "./images/consent.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Consent
|
||||
|
||||
The Consent card is used to obtain user agreement regarding a product, service, or policy. It features a bold statement or question as the title, followed by a brief description. At the end of the card, users can confirm their consent by checking a checkbox to indicate their agreement.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/orxp15pca6x2nfr3v8pttpwm" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={Consent}
|
||||
alt="Overview of Consent question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
A bold statement or question asking for user consent, displayed prominently at the top of the card.
|
||||
|
||||
### Description
|
||||
|
||||
A short explanation or additional context for the consent request, displayed below the title. The text can be formatted, and hyperlinks are allowed within the description.
|
||||
|
||||
### Checkbox
|
||||
|
||||
At the bottom of the card, users can confirm their agreement by checking the box, indicating their consent to the question or statement above. The label for the checkbox is also editable.
|
||||
@@ -1,38 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import Contact from "./images/contact.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Contact Info
|
||||
|
||||
The Contact Info question type allows respondents to provide their basic contact information such as name, email, and phone number. You can customize the form with a title, an optional description, and control which fields to display and require.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/z2zjoonfeythx5n6z5qijbsg" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={Contact}
|
||||
alt="Overview of Contact Info question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Specify a title to describe the information you're collecting.
|
||||
|
||||
### Description
|
||||
|
||||
Optionally, add a description to give additional context.
|
||||
|
||||
### Toggle Fields
|
||||
|
||||
You can choose to show and require any or all of the following fields:
|
||||
|
||||
- First Name
|
||||
- Last Name
|
||||
- Email
|
||||
- Phone Number
|
||||
- Company
|
||||
@@ -1,36 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import Date from "./images/date.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Date
|
||||
|
||||
The Date question type allows respondents to provide a date, such as when they are available or when an event is scheduled. It features a title to guide the respondent on what date to enter, and an optional description to provide further details or context.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/rk844spc8ffls25vzkxzzhse" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={Date}
|
||||
alt="Overview of Date question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Add a clear title to inform the respondent what date you are asking for.
|
||||
|
||||
### Description
|
||||
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Date Format
|
||||
|
||||
Choose from multiple date formats for the input:
|
||||
|
||||
- MM-DD-YYYY
|
||||
- DD-MM-YYYY
|
||||
- YYYY-MM-DD
|
||||
@@ -1,40 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import FileUpload from "./images/file-upload.webp";
|
||||
|
||||
#### Questions Type
|
||||
|
||||
# File Upload
|
||||
|
||||
The File Upload question type allows respondents to upload files related to your survey, such as production documents or requirement specifications. It features a title to guide the user on what to upload and an optional description to provide additional context.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/oo4e6vva48w0trn01ht8krwo" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={FileUpload}
|
||||
alt="Overview of Fill Upload question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Add a clear title that informs the respondent about the purpose of the file upload.
|
||||
|
||||
### Description
|
||||
|
||||
Provide an optional description to give respondents more details or instructions about what files they need to upload.
|
||||
|
||||
### Allow Multiple Files
|
||||
|
||||
Enable this option to allow respondents to upload multiple files at once.
|
||||
|
||||
### Max File Size
|
||||
|
||||
You can set a maximum file size limit, and an input box will appear to specify the size in MB.
|
||||
|
||||
### File Type Restrictions
|
||||
|
||||
You can restrict the allowed file types. An input box will appear where you can specify the file formats, such as `.pdf`, `.jpg`, `.docx`, etc.
|
||||
@@ -1,41 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import Matrix from "./images/matrix.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Matrix
|
||||
|
||||
Matrix questions allow respondents to select a value for each option presented in rows. The values range from 0 to a user-defined maximum (e.g., 0 to X). The selection is made using radio buttons, and users can choose any value within the defined range, including 0.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/obqeey0574jig4lo2gqyv51e" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={Matrix}
|
||||
alt="Overview of Matrix question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Rows
|
||||
|
||||
Define the options shown on the left side of the matrix. These represent the items for which users will select a value.
|
||||
|
||||
### Columns
|
||||
|
||||
Represent the range of values from 0 to X (right side of the screen). Users can choose any value, including 0, using radio buttons.
|
||||
|
||||
### Select ordering
|
||||
|
||||
- Keep current order: This will keep the order of options the same for all respondents.
|
||||
- Randomize all: This will randomize the options for each respondent.
|
||||
@@ -1,39 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import MultiSelect from "./images/multi-select.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Multi Select",
|
||||
description: "Multi select questions allow respondents to select several answers from a list",
|
||||
};
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Multi Select
|
||||
|
||||
Multi select questions allow respondents to select several answers from a list. Displays a title and a list of checkboxes for the respondent to choose from.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/jhyo6lwzf6eh3fyplhlp7h5f" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={MultiSelect}
|
||||
alt="Overview of Multi Select question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Options
|
||||
|
||||
Define the options shown in the list. These represent the items for which users will select.
|
||||
|
||||
Other than the fact that respondents can select multiple options, multi select questions are similar to [single select](/global/question-types/single-select) questions.
|
||||
@@ -1,36 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import NetPromoterScore from "./images/net-promoter-score.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Net Promoter Score
|
||||
|
||||
Net Promoter Score questions allow respondents to rate a question on a scale from 0 to 10. Displays a title and a list of radio buttons for the respondent to choose from.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/vqmpasmnt5qcpsa4enheips0" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={NetPromoterScore}
|
||||
alt="Overview of Net Promoter Score question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Labels
|
||||
|
||||
Add labels for the lower and upper bounds of the score. The default is "Not at all likely" and "Extremely likely".
|
||||
|
||||
### Add color coding
|
||||
|
||||
Add color coding to the score. This will show a color bar above the score.
|
||||
@@ -1,41 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import PictureSelection from "./images/picture-selection.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Picture Selection",
|
||||
description: "Picture selection questions allow respondents to select one or more images from a list",
|
||||
};
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Picture Selection
|
||||
|
||||
Picture selection questions allow respondents to select one or more images from a list. Displays a title and a list of images for the respondent to choose from.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/xtgmwxlk7jxxr4oi6ym7odki" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={PictureSelection}
|
||||
alt="Overview of Picture Selection question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Images
|
||||
|
||||
Images can be uploaded via click or drag and drop. At least two images are required.
|
||||
|
||||
### Allow Multi Select
|
||||
|
||||
This option allows user to select more than one image.
|
||||
@@ -1,37 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import Ranking from "./images/ranking.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Ranking
|
||||
|
||||
Ranking questions let respondents select options in order from 1 to the total number of options. As they make their choices, the list is automatically rearranged in numerical order.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/z6s84x9wbyk0yqqtfaz238px" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={Ranking}
|
||||
alt="Overview of Ranking question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Options
|
||||
|
||||
You need to add at least two options so that users can rearrange them in numerical order based on their selection.
|
||||
|
||||
### Select ordering
|
||||
|
||||
- Keep current order: This will keep the order of options the same for all respondents.
|
||||
- Randomize all: This will randomize the options for each respondent.
|
||||
@@ -1,36 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import ScheduleCall from "./images/schedule-call.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Schedule A Meeting
|
||||
|
||||
The Schedule A Meeting question type allows respondents to book a meeting by selecting a date and time. It includes a title to guide the respondent, along with an optional description to provide additional context for the meeting setup.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/hx08x27c2aghywh57rroe6fi" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={ScheduleCall}
|
||||
alt="Overview of Schedule question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Cal.com Username/Event
|
||||
|
||||
Add an input box where users can enter their [`cal.com`](https://cal.com/) username and event URL (e.g., `username/event`).
|
||||
|
||||
### Custom Hostname (Optional)
|
||||
|
||||
Enable an input box for adding a custom hostname, which is necessary if using a self-hosted instance of [`cal.com`](https://cal.com/docs/self-hosting/installation).
|
||||
@@ -1,33 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import StatementCTA from "./images/statement-cta.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Statement (Call to Action)
|
||||
|
||||
The Statement question type allows you to display descriptive information in your survey, such as a message or instruction. It consists of a title (can be Question or Short Note) and a description, which can be a brief note(realted to CTA) or guideline. Instead of collecting input, this type includes a call to action button for further steps, such as booking an interview call.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/k3p7r7riyy504u4zziqat8zj" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={StatementCTA}
|
||||
alt="Overview of Statement question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
This is the main question or heading that appears at the top of the card.
|
||||
|
||||
### Description
|
||||
|
||||
A brief note or instruction displayed under the title, typically used to provide context or instructions for the next step.
|
||||
|
||||
### Button Options
|
||||
|
||||
- Button to continue in survey: This will continue respondent with the survey, form or fillups.
|
||||
- Button to link to external URL: Selecting this option will open-up URL input box below when us set URL the button will redirect to your setted link.
|
||||
@@ -1,83 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
import SurveyEmbed from "@/components/survey-embed";
|
||||
import StepOne from "./images/step-one.webp";
|
||||
import StepThree from "./images/step-three.webp";
|
||||
import StepTwo from "./images/step-two.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Recall Data in Formbricks Surveys",
|
||||
description:
|
||||
"Personalize your surveys by dynamically inserting data from URL parameters or previous answers into questions and descriptions. The Recall Data feature helps create engaging, adaptive survey experiences tailored to each respondent.",
|
||||
};
|
||||
|
||||
# Recall Data
|
||||
|
||||
Personalize your surveys by dynamically inserting data from URL parameters or previous answers into questions and descriptions. The Recall Data feature helps create engaging, adaptive survey experiences tailored to each respondent.
|
||||
|
||||
## Recall Sources
|
||||
|
||||
You can recall data from the following sources:
|
||||
|
||||
- From a previous question
|
||||
- From a [Hidden Field](/docs/link-surveys/global/hidden-fields)
|
||||
- From a [Variable](/docs/link-surveys/global/variables)
|
||||
|
||||
## Recalling from a previous question
|
||||
|
||||
<Note>
|
||||
The recall functionality is disabled on the first question of the survey since there’s no preceding question to recall data from.
|
||||
</Note>
|
||||
|
||||
### **Pre-requisite**
|
||||
|
||||
Ensure the answer you wish to recall precedes the question in which it will be recalled. Here’s an example of setting up the first question:
|
||||
|
||||
<MdxImage
|
||||
src={StepThree}
|
||||
alt="Survey setup example with link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### **Step 1: Recall Data**
|
||||
|
||||
Type **`@`** in the question or description field where you want to insert a recall. This triggers a dropdown menu listing all preceding questions. Select the question you want to recall data from.
|
||||
|
||||
<MdxImage
|
||||
src={StepTwo}
|
||||
alt="Dropdown menu for recalling data in survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### **Step 2: Set a Fallback**
|
||||
|
||||
To ensure the survey remains coherent when a response is missing (or the question is optional), you should set a fallback option.
|
||||
|
||||
<MdxImage
|
||||
src={StepOne}
|
||||
alt="Setting fallback option in survey question"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Recalling from the URL
|
||||
|
||||
1. Create a hidden field, [here is how →](/docs/global/hidden-fields)
|
||||
2. Use the `@` symbol in a question or description to recall the value of the hidden field
|
||||
3. Set a fallback in case the hidden field is not being filled by a URL parameter
|
||||
4. Use [Data Prefilling](/docs/link-surveys/data-prefilling) to set the hidden field value when the survey is accessed
|
||||
|
||||
## Recalling from a Variable
|
||||
|
||||
1. Create a variable, [here is how →](/docs/link-surveys/global/variables)
|
||||
2. Use the `@` symbol in a question or description to recall the value of the variable
|
||||
3. Set a fallback in case the variable is not being filled by a URL parameter
|
||||
|
||||
## Live Demo
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/cm393eiiq0001kxphzc6lbbku" />
|
||||
|
||||
## **Conclusion**
|
||||
|
||||
Recall Data in Formbricks surveys allows for a conversational and customized survey experience that enhances engagement and improves the quality of feedback. By integrating previous responses into new questions, you create a more interactive and relevant environment for respondents.
|
||||
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 19 KiB |
@@ -1,74 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
|
||||
import StepOne from "./images/1-publish-to-web.webp";
|
||||
import StepTwo from "./images/2-warning-publish.webp";
|
||||
import StepThree from "./images/3-share-link.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Shareable Dashboards",
|
||||
description: "Create shareable links to dashboards of specific surveys.",
|
||||
};
|
||||
|
||||
# Shareable Dashboards
|
||||
|
||||
Formbricks allows you to create public, shareable versions of your survey results dashboards. This feature enables you to easily share survey results with stakeholders, team members, or the public without granting access to your Formbricks account.
|
||||
|
||||
## How To Publish Survey Results
|
||||
|
||||
1. **Go to survey summary**: Choose the survey for which you want to create a shareable dashboard and go to its summary page.
|
||||
|
||||
2. **Share results**: Click the "Share results" and then "Publish to web".
|
||||
|
||||
<MdxImage
|
||||
src={StepOne}
|
||||
alt="Go to survey summary"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. **Confirm**: Click "Publish to public web" (it's public).
|
||||
|
||||
<MdxImage
|
||||
src={StepTwo}
|
||||
alt="Go to survey summary"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
4. **Share link**: Formbricks has generated a unique URL for your public dashboard. Share it around.
|
||||
|
||||
<MdxImage
|
||||
src={StepThree}
|
||||
alt="Go to survey summary"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
<Note>Whoever has access to the link can access the survey results.</Note>
|
||||
|
||||
## How To Unpublish Survey Results
|
||||
|
||||
Unpublish is very simple: Go to "Share results" -> "Unpublish from web" -> "Unpublish".
|
||||
|
||||
<MdxImage
|
||||
src={StepThree}
|
||||
alt="Go to survey summary"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Read-only access**: Viewers can see survey results but cannot modify data or settings.
|
||||
- **Real-time updates**: The shared dashboard reflects current survey data in real-time.
|
||||
- **Filters included**: Visitors can access all filters to dissect the data.
|
||||
- **Revocable access**: You can disable the shared link at any time to restrict access.
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Share results with clients or stakeholders
|
||||
- Publish survey findings to your website or blog
|
||||
- Collaborate with team members without sharing account credentials
|
||||
- Create transparency by making certain survey results public
|
||||
|
||||
Shareable dashboards provide a simple yet powerful way to disseminate survey insights while maintaining control over your Formbricks account and data.
|
||||
@@ -1,74 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
|
||||
import StepOne from "./images/step-one.webp";
|
||||
import StepTwo from "./images/step-two.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Show Survey to % of Users",
|
||||
description:
|
||||
"To target specific segments of your audience or manage survey exposure, Formbricks allows you to display surveys to only a percentage of your targeted users.",
|
||||
};
|
||||
|
||||
# Show Survey to % of Users
|
||||
|
||||
To target specific segments of your audience or manage survey exposure, Formbricks allows you to display surveys to only a percentage of your targeted users.
|
||||
|
||||
<Note>
|
||||
This feature is applicable for website surveys and app surveys, where managing participant engagement and response volume is crucial.
|
||||
</Note>
|
||||
|
||||
## **Enabling Percentage-Based Visibility**
|
||||
|
||||
Set up this feature to control how many users see your survey, using a simple slider to specify the percentage of your targeted audience that should be prompted to participate.
|
||||
|
||||
### **Steps to Set Up Percentage-Based Visibility**
|
||||
|
||||
1. **Open Survey Editor**: Navigate to the survey where you wish to configure visibility settings & click on Edit.
|
||||
2. **Access Settings**: In the Survey Editor, click on the **`Settings`** tab
|
||||
3. **Navigate to Survey Trigger Options**:
|
||||
|
||||
{" "}
|
||||
|
||||
<MdxImage
|
||||
src={StepOne}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
- Select **`Survey Trigger`** from the menu options.
|
||||
- Choose **`Survey Display Settings`** to access visibility controls.
|
||||
|
||||
4. **Adjust User Visibility Percentage**:
|
||||
|
||||
- Find the **`Show Survey to % of Users`** toggle. Enable it.
|
||||
- Enter the desired percentage (from 0.01% to 100%) of users to whom the survey will be shown.
|
||||
|
||||
{" "}
|
||||
|
||||
<MdxImage
|
||||
src={StepTwo}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
<Note>
|
||||
Please note that this feature operates based on mathematical probabilistic functions, which may result in slight variations in the exact percentage of users who see the survey.
|
||||
</Note>
|
||||
|
||||
### **Example Usage**
|
||||
|
||||
For instance, if you want to expose your survey to only half of your targeted user base, simply adjust the slider to show the survey to 50% of your users. This functionality allows you to conduct A/B testing or control the rollout of new surveys to gauge initial reactions before a wider release.
|
||||
|
||||
### **Application**
|
||||
|
||||
It's effective for:
|
||||
|
||||
- **A/B Testing**: Compare different user experiences by showing different surveys or survey variations to different segments of your audience.
|
||||
- **Gradual Rollouts**: Gradually introduce a new survey to a portion of your users to monitor initial responses and adjust based on feedback before full deployment.
|
||||
- **Load Management**: Manage server load and response processing by limiting the number of responses collected at any given time.
|
||||
|
||||
## **Conclusion**
|
||||
|
||||
Using the **Show Survey to % of Users** feature allows for precise control over who sees your Formbricks surveys, making it an invaluable feature for targeted data collection and user experience management. By adjusting survey visibility settings, you can strategically engage segments of your audience, enhance survey testing phases, and optimize overall survey effectiveness.
|
||||
@@ -1,68 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useTheme } from "next-themes";
|
||||
import { useState } from "react";
|
||||
import { RedocStandalone } from "redoc";
|
||||
import { LoadingSpinner } from "@/components/icons/loading-spinner";
|
||||
import { Button } from "@/components/button";
|
||||
import "./style.css";
|
||||
|
||||
export function ApiDocs() {
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
const redocTheme = {
|
||||
hideDownloadButton: true,
|
||||
hideLoading: true,
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: "transparent",
|
||||
textColor: resolvedTheme === "dark" ? "rgb(203, 213, 225)" : "rgb(51, 51, 51)",
|
||||
activeTextColor: "#2dd4bf",
|
||||
},
|
||||
rightPanel: {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
colors: {
|
||||
primary: { main: "#2dd4bf" },
|
||||
text: {
|
||||
primary: resolvedTheme === "dark" ? "#ffffff" : "rgb(51, 51, 51)",
|
||||
},
|
||||
responses: {
|
||||
success: { color: "#22c55e" },
|
||||
error: { color: "#ef4444" },
|
||||
info: { color: "#3b82f6" },
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
fontSize: "16px",
|
||||
lineHeight: "2rem",
|
||||
fontFamily: "Jost, system-ui, -apple-system, sans-serif",
|
||||
headings: {
|
||||
fontFamily: "Jost, system-ui, -apple-system, sans-serif",
|
||||
fontWeight: "600",
|
||||
},
|
||||
code: {
|
||||
fontSize: "16px",
|
||||
fontFamily: "ui-monospace, monospace",
|
||||
},
|
||||
},
|
||||
codeBlock: {
|
||||
backgroundColor: "rgb(24, 35, 58)",
|
||||
},
|
||||
spacing: { unit: 5 },
|
||||
},
|
||||
};
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
return (
|
||||
<div className="px-4">
|
||||
<Button href="/developer-docs/rest-api" arrow="left" className="mb-4 mt-8">
|
||||
Back to docs
|
||||
</Button>
|
||||
<RedocStandalone specUrl="/docs/openapi.yaml" onLoaded={() => { setLoading(false); }} options={redocTheme} />
|
||||
{loading ? <LoadingSpinner /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
:root[data-theme="light"] {
|
||||
--text-color: rgb(51, 65, 85);
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] {
|
||||
--text-color: rgb(203, 213, 225);
|
||||
}
|
||||
|
||||
h5,
|
||||
.sc-dhCplO,
|
||||
.sc-dpBQxM {
|
||||
color: var(--text-color) !important;
|
||||
}
|
||||
|
||||
.tab-success,
|
||||
.react-tabs__tab,
|
||||
.tab-error {
|
||||
background-color: transparent !important;
|
||||
border: 1px solid var(--text-color) !important;
|
||||
margin: 10px 5px !important;
|
||||
}
|
||||
|
||||
.sc-dwGkES,
|
||||
.sc-ePpfBx {
|
||||
background-color: rgb(24, 24, 27) !important;
|
||||
border: 1px solid var(--text-color) !important;
|
||||
}
|
||||
.sc-ePpfBx,
|
||||
.corVrN {
|
||||
background-color: rgb(24, 24, 27) !important;
|
||||
border: none !important;
|
||||
}
|
||||
.cqdCbT {
|
||||
display: none !important;
|
||||
}
|
||||
.kiMaJz, .iZNUDY {
|
||||
align-items: center !important;
|
||||
}
|
||||
|
||||
.react-tabs__tab-panel > div {
|
||||
padding: 0 !important;
|
||||
border-radius: 8px !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
.sc-Rjrgp {
|
||||
background-color: rgb(15, 23, 42) !important;
|
||||
display: flex !important;
|
||||
justify-content: center !important;
|
||||
flex-direction: column !important;
|
||||
padding: 8px 16px !important;
|
||||
}
|
||||
.cugBNu {
|
||||
position: static !important;
|
||||
}
|
||||
.daIHdK {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.kqHNPM {
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
.sc-iwXfZk,
|
||||
.redoc-json {
|
||||
padding: 1rem !important;
|
||||
background-color: rgb(24, 35, 58) !important;
|
||||
}
|
||||
.sc-uYFMi {
|
||||
background-color: rgb(24, 35, 58) !important;
|
||||
padding: 0.5rem 0 !important;
|
||||
color: #2dd4bf !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
.token {
|
||||
color: #2dd4bf !important;
|
||||
}
|
||||
|
||||
.property {
|
||||
color: rgb(203, 213, 225) !important;
|
||||
}
|
||||
.sc-iPHsxv {
|
||||
background-color: rgb(15, 23, 42) !important;
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.sc-hSyjfr {
|
||||
background-color: rgb(15, 23, 42) !important;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { ApiDocs } from "./components/api-docs";
|
||||
|
||||
export default function ApiDocsPage() {
|
||||
return <ApiDocs />;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,121 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
|
||||
import I1 from "./images/i1.webp";
|
||||
import I2 from "./images/i2.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Using Actions in Formbricks",
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
## **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.
|
||||
|
||||
## **Why Are Actions Useful?**
|
||||
|
||||
Actions are invaluable for enhancing survey relevance and effectiveness:
|
||||
|
||||
- **Personalized Engagement**: Surveys triggered by user actions ensure content is highly relevant and engaging, matching each user’s 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.
|
||||
|
||||
## **Setting Up No-Code Actions**
|
||||
|
||||
Formbricks offers an intuitive No-Code interface that allows you to configure actions without needing to write any code.
|
||||
|
||||
To add a No-Code Action:
|
||||
|
||||
1. Visit the Formbricks Dashboard & switch to the Actions tab:
|
||||
|
||||
<MdxImage
|
||||
src={I1}
|
||||
alt="setup checklist ui of survey popup for app surveys"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Now click on “Add Action”
|
||||
|
||||
<MdxImage
|
||||
src={I2}
|
||||
alt="setup checklist ui of survey popup for app surveys"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Here are four types of No-Code actions you can set up:
|
||||
|
||||
### **1. Click Action**
|
||||
|
||||
Click Action is triggered when a user clicks on a specific element within your application. You can define the element's inner text or CSS selector to trigger the survey.
|
||||
|
||||
- **Inner Text**: Checks if the innerText of a clicked HTML element, like a button label, matches a specific text. This action allows you to display a survey based on text interactions within your application.
|
||||
|
||||
- **CSS Selector**: Verifies if a clicked HTML element matches a provided CSS selector, such as a class, ID, or any other CSS selector used in your website. It enables survey triggers based on element interactions.
|
||||
|
||||
### **2. Page view Action**
|
||||
|
||||
This action is triggered when a user visits a page within your application.
|
||||
|
||||
### **3. Exit Intent Action**
|
||||
|
||||
This action is triggered when a user is about to leave your application. It helps capture user feedback before they exit, providing valuable insights into user experiences and potential improvements.
|
||||
|
||||
### **4. 50% Scroll Action**
|
||||
|
||||
This action is triggered when a user scrolls through 50% of a page within your application. It helps capture user feedback at a specific point in their journey, enabling you to gather insights based on user interactions.
|
||||
|
||||
This action is triggered when a user visits a specific page within your application. You can define the URL match conditions as follows:
|
||||
|
||||
<Note>
|
||||
You can combine the url filters with any of the no-code actions to trigger the survey based on the URL match conditions.
|
||||
|
||||
### **URL Match Conditions**
|
||||
|
||||
- **exactMatch**: Triggers the action when the URL exactly matches the specified string.
|
||||
- **contains**: Activates when the URL contains the specified substring.
|
||||
- **startsWith**: Fires when the URL starts with the specified string.
|
||||
- **endsWith**: Executes when the URL ends with the specified string.
|
||||
- **notMatch**: Triggers when the URL does not match the specified condition.
|
||||
- **notContains**: Activates when the URL does not contain the specified substring.
|
||||
|
||||
</Note>
|
||||
|
||||
## **Setting Up Code Actions**
|
||||
|
||||
For more granular control, you can implement actions directly in your codebase:
|
||||
|
||||
1. **Configure the Action**: First, add the action via the Formbricks web interface to make it available for survey configuration.
|
||||
After that you can fire an action using `formbricks.track()`
|
||||
|
||||
2. **Track an Action**: Use formbricks.track() to send an action event to Formbricks.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Track an action">
|
||||
|
||||
```javascript
|
||||
formbricks.track("Action Name");
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
Here is an example of how to fire an action when a user clicks a button:
|
||||
<Col>
|
||||
<CodeGroup title="Track Button Click">
|
||||
|
||||
```javascript
|
||||
const handleClick = () => {
|
||||
formbricks.track("Button Clicked");
|
||||
};
|
||||
|
||||
return <button onClick={handleClick}>Click Me</button>;
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 17 KiB |
@@ -1,29 +0,0 @@
|
||||
export const metadata = {
|
||||
title: "Advanced Targeting for App 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
|
||||
|
||||
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.
|
||||
|
||||
## How to setup Advanced Targeting
|
||||
|
||||
<Note>Advanced Targeting is only available on the Pro plan!</Note>
|
||||
|
||||
1. On the Formbricks dashboard, click on **People** tab from the top navigation bar.
|
||||
|
||||
2. Switch to the **Segments** tab & click on **Create Segment**.
|
||||
|
||||
3. Give your segment a title & a description to help you remember what this segment is about.
|
||||
|
||||
4. Now click on the **Add Filter** button to add a filter. You can filter based on user attributes, other segments, devices, and more.
|
||||
|
||||
5. To group a set of filters together, click on the Three Dots icon on the right side of the filter and click on **Create Group**.
|
||||
|
||||
6. Try playing around with different filters & conditions that we have provided to see how the segment size changes.
|
||||
|
||||
7. Once you are happy with the segment, click on **Save Segment**.
|
||||
|
||||
8. Now, when you create a survey, you can select this segment to target your survey to.
|
||||
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 32 KiB |
@@ -1,66 +0,0 @@
|
||||
import Image from "next/image";
|
||||
import { Button } from "@/components/button";
|
||||
import logoHtml from "@/images/frameworks/html5.svg";
|
||||
import logoNextjs from "@/images/frameworks/nextjs.svg";
|
||||
import logoReactJs from "@/images/frameworks/reactjs.svg";
|
||||
import logoVueJs from "@/images/frameworks/vuejs.svg";
|
||||
|
||||
const libraries = [
|
||||
{
|
||||
href: "#html",
|
||||
name: "HTML",
|
||||
description: "All you need to do is add 3 lines of code to your HTML script and thats it, you're done!",
|
||||
logo: logoHtml as string,
|
||||
},
|
||||
{
|
||||
href: "#react-js",
|
||||
name: "React.js",
|
||||
description: "Load the our Js library with your environment ID and you're ready to go!",
|
||||
logo: logoReactJs as string,
|
||||
},
|
||||
{
|
||||
href: "#next-js",
|
||||
name: "Next.js",
|
||||
description:
|
||||
"Natively add us to your NextJs project with support for both App as well as Pages project structure!",
|
||||
logo: logoNextjs as string,
|
||||
},
|
||||
{
|
||||
href: "#vue-js",
|
||||
name: "Vue.js",
|
||||
description: "Simply add us to your router change and sit back!",
|
||||
logo: logoVueJs as string,
|
||||
},
|
||||
{
|
||||
href: "#react-native",
|
||||
name: "React Native",
|
||||
description: "Easily integrate our SDK with your React Native app for seamless survey support!",
|
||||
logo: logoReactJs as string,
|
||||
},
|
||||
];
|
||||
|
||||
export function Libraries() {
|
||||
return (
|
||||
<div className="my-16 xl:max-w-none">
|
||||
<div className="not-prose mt-4 grid grid-cols-1 gap-x-6 gap-y-10 border-slate-900/5 xl:max-w-none xl:grid-cols-2 2xl:grid-cols-3 dark:border-white/5">
|
||||
{libraries.map((library) => (
|
||||
<a
|
||||
key={library.name}
|
||||
href={library.href}
|
||||
className="flex flex-row-reverse gap-6 rounded-2xl p-6 transition-all duration-100 ease-in-out hover:cursor-pointer hover:bg-slate-100/50 dark:hover:bg-slate-800/50">
|
||||
<div className="flex-auto">
|
||||
<h3 className="text-sm font-semibold text-slate-900 dark:text-white">{library.name}</h3>
|
||||
<p className="mt-1 text-sm text-slate-600 dark:text-slate-400">{library.description}</p>
|
||||
<p className="mt-4">
|
||||
<Button href={library.href} variant="text" arrow="right">
|
||||
Read more
|
||||
</Button>
|
||||
</p>
|
||||
</div>
|
||||
<Image src={library.logo} alt="" className="h-12 w-12" unoptimized />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 8.0 KiB |
@@ -1,453 +0,0 @@
|
||||
import { MdxImage } from "@/components/mdx-image";
|
||||
|
||||
import { Libraries } from "./components/libraries";
|
||||
|
||||
import ReactApp from "./images/react-in-app-survey-app-popup-form.webp";
|
||||
import WidgetConnected from "./images/widget-connected.webp";
|
||||
import WidgetNotConnected from "./images/widget-not-connected.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Integrate Formbricks: Comprehensive Framework Guide & Integration Tutorial",
|
||||
description:
|
||||
"Master the integration of Formbricks into your application with our detailed guides. From HTML to ReactJS, NextJS, and VueJS, get step-by-step instructions and ensure seamless setup.",
|
||||
};
|
||||
|
||||
# Framework Guides
|
||||
|
||||
One can integrate Formbricks App Survey SDK into their app using multiple options! Checkout the options below that we provide! If you are looking
|
||||
for something else, please [open a new Github Discussion](https://github.com/formbricks/formbricks/discussions) and we would be glad to help.
|
||||
|
||||
<Libraries />
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before getting started, make sure you have:
|
||||
|
||||
1. A web application (behind your user authentication system) in your desired framework is set up and running.
|
||||
2. A Formbricks account with access to your environment ID and API host. You can find these in the **Setup Checklist** in the Settings.
|
||||
|
||||
---
|
||||
|
||||
## HTML
|
||||
|
||||
All you need to do is copy a `<script>` tag to your HTML head, and that’s about it!
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="HTML">
|
||||
```html {{ title: 'index.html' }}
|
||||
<!-- START Formbricks Surveys -->
|
||||
<script type="text/javascript">
|
||||
!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)}();
|
||||
</script>
|
||||
<!-- END Formbricks Surveys -->
|
||||
```
|
||||
</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>
|
||||
|
||||
Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Install Formbricks JS library">
|
||||
```shell {{ title: 'npm' }}
|
||||
npm install @formbricks/js zod
|
||||
```
|
||||
```shell {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/js zod
|
||||
```
|
||||
```shell {{ title: 'yarn' }}
|
||||
yarn add @formbricks/js zod
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
Now, update your App.js/ts file to initialise Formbricks.
|
||||
<Col>
|
||||
<CodeGroup title="src/App.js">
|
||||
|
||||
```js
|
||||
// other imports
|
||||
import formbricks from "@formbricks/js";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user-id>", //optional
|
||||
});
|
||||
}
|
||||
|
||||
function App() {
|
||||
// your own app
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
</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>
|
||||
|
||||
Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
|
||||
---
|
||||
|
||||
## NextJS
|
||||
|
||||
NextJs projects typically follow two main conventions: the App Directory and the Pages Directory.
|
||||
To ensure smooth integration with the Formbricks SDK, which operates solely on the client side, follow the
|
||||
guidelines for each convention below:
|
||||
|
||||
- App directory: You will have to define a new component in `app/formbricks.tsx` file and call it in your `app/layout.tsx` file.
|
||||
- Pages directory: You will have to visit your `_app.tsx` and just initialise Formbricks there.
|
||||
|
||||
Code snippets for the integration for both conventions are provided to further assist you.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Install Formbricks JS library">
|
||||
```shell {{ title: 'npm' }}
|
||||
npm install @formbricks/js zod
|
||||
```
|
||||
```shell {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/js zod
|
||||
```
|
||||
```shell {{ title: 'yarn' }}
|
||||
yarn add @formbricks/js zod
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
### App Directory
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="app/formbricks.tsx">
|
||||
|
||||
```tsx {{title: 'Typescript'}}
|
||||
"use client";
|
||||
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
import formbricks from "@formbricks/js";
|
||||
|
||||
export default function FormbricksProvider() {
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
useEffect(() => {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user-id>", //optional
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
formbricks?.registerRouteChange();
|
||||
}, [pathname, searchParams]);
|
||||
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="app/layout.tsx">
|
||||
```tsx {{title: 'Typescript'}}
|
||||
// other imports
|
||||
import FormbricksProvider from "./formbricks";
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<FormbricksProvider />
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
### Pages Directory
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="src/pages/_app.tsx">
|
||||
|
||||
```tsx {{ title: 'Typescript' }}
|
||||
// other import
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect } from "react";
|
||||
import formbricks from "@formbricks/js";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user-id>", //optional
|
||||
});
|
||||
}
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
// Connect next.js router to Formbricks
|
||||
const handleRouteChange = formbricks?.registerRouteChange;
|
||||
router.events.on("routeChangeComplete", handleRouteChange);
|
||||
|
||||
return () => {
|
||||
router.events.off("routeChangeComplete", handleRouteChange);
|
||||
};
|
||||
}, []);
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
```
|
||||
|
||||
</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>
|
||||
|
||||
First we initialize the Formbricks SDK, ensuring that it only runs on the client side.
|
||||
To connect the Next.js router to Formbricks and ensure the SDK can keep track of every page change, we are registering the route change event.
|
||||
|
||||
Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
|
||||
---
|
||||
|
||||
## VueJs
|
||||
|
||||
Integrating the Formbricks SDK with Vue.js is a straightforward process.
|
||||
We will make sure the SDK is only loaded and used on the client side, as it's not intended for server-side usage.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Install Formbricks JS library">
|
||||
```shell {{ title: 'npm' }}
|
||||
npm install @formbricks/js
|
||||
````
|
||||
|
||||
```shell {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/js
|
||||
```
|
||||
|
||||
```shell {{ title: 'yarn' }}
|
||||
yarn add @formbricks/js
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="src/formbricks.js">
|
||||
|
||||
```js
|
||||
import formbricks from "@formbricks/js";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user-id>", //optional
|
||||
});
|
||||
}
|
||||
|
||||
export default formbricks;
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="src/main.js">
|
||||
|
||||
```js
|
||||
// other imports
|
||||
import formbricks from "@/formbricks";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(router);
|
||||
|
||||
app.mount("#app");
|
||||
|
||||
router.afterEach((to, from) => {
|
||||
if (typeof formbricks !== "undefined") {
|
||||
formbricks.registerRouteChange();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
### Required customizations to be made
|
||||
|
||||
<Properties>
|
||||
<Property name="environment-id" type="string">
|
||||
Formbricks Environment ID.
|
||||
</Property>
|
||||
</Properties>
|
||||
<Properties>
|
||||
<Property name="api-host" type="string">
|
||||
URL of the hosted Formbricks instance.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
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>", // optional
|
||||
};
|
||||
|
||||
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:
|
||||
|
||||
<MdxImage
|
||||
src={WidgetNotConnected}
|
||||
alt="Widget isnt connected"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
To this:
|
||||
|
||||
<MdxImage
|
||||
src={WidgetConnected}
|
||||
alt="Widget is connected"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Debugging Formbricks Integration
|
||||
|
||||
Enabling Formbricks debug mode in your browser is a useful troubleshooting step for identifying and resolving complex issues. This section outlines how to activate debug mode, covers common use cases, and provides insights into specific debug log messages.
|
||||
|
||||
### Activate Debug Mode
|
||||
|
||||
To activate Formbricks debug mode:
|
||||
|
||||
1. **Via URL Parameter:**
|
||||
|
||||
- Enable debug mode mode by adding `?formbricksDebug=true` to your application's URL (e.g. `https://example.com?formbricksDebug=true` or `https://example.com?page=123&formbricksDebug=true`). This parameter will enable debugging for the current page.
|
||||
|
||||
2. **View Debug Logs:**
|
||||
|
||||
- Open your browser's developer tools by pressing `F12` or right-clicking and selecting "Inspect."
|
||||
- Navigate to the "Console" tab to view Formbricks debugging information.
|
||||
|
||||
**How to Open Browser Console:**
|
||||
|
||||
- **Google Chrome:** Press `F12` or right-click, select "Inspect," and go to the "Console" tab.
|
||||
- **Firefox:** Press `F12` or right-click, select "Inspect Element," and go to the "Console" tab.
|
||||
- **Safari:** Press `Option + Command + C` to open the developer tools and navigate to the "Console" tab.
|
||||
- **Edge:** Press `F12` or right-click, select "Inspect Element," and go to the "Console" tab.
|
||||
|
||||
### Common Use Cases
|
||||
|
||||
Debug mode is beneficial for scenarios such as:
|
||||
|
||||
- Verifying Formbricks initialization.
|
||||
- Identifying survey trigger issues.
|
||||
- Troubleshooting unexpected behavior.
|
||||
|
||||
### Debug Log Messages
|
||||
|
||||
Debug log messages provide insights into:
|
||||
|
||||
- API calls and responses.
|
||||
- Event tracking, survey triggers and form interactions.
|
||||
- Initialization errors.
|
||||
|
||||
**Can’t figure it out?**: **[Get help in Github Discussions](https://github.com/formbricks/formbricks/discussions)**
|
||||
|
||||
---
|
||||
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 26 KiB |