Compare commits
245 Commits
aschaber-c
...
feature/up
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
219f9beb84 | ||
|
|
26591d9b9f | ||
|
|
e2cacfc743 | ||
|
|
9b109bf4d3 | ||
|
|
655b67c3ad | ||
|
|
2dbd7111a9 | ||
|
|
159390e411 | ||
|
|
06ddee42a9 | ||
|
|
47aa84bf8a | ||
|
|
2f7a59817a | ||
|
|
e7a0228bfa | ||
|
|
2367313ff2 | ||
|
|
68e52954e2 | ||
|
|
59ebde49cf | ||
|
|
6ab2560432 | ||
|
|
861d399025 | ||
|
|
35837be21e | ||
|
|
b2f5e5fbe3 | ||
|
|
fc3886fafa | ||
|
|
692e7e3f24 | ||
|
|
0aca213750 | ||
|
|
0bac91a7ef | ||
|
|
d1b47c675c | ||
|
|
ddf7ad8475 | ||
|
|
ad6d5d6c00 | ||
|
|
315aaac395 | ||
|
|
01ceaa13ec | ||
|
|
25774f6f08 | ||
|
|
9a98772210 | ||
|
|
59a29dd3d6 | ||
|
|
e4fceb2e5e | ||
|
|
0b553447e0 | ||
|
|
6b64367d99 | ||
|
|
fe9746ba67 | ||
|
|
e4009d5951 | ||
|
|
b1ed61c247 | ||
|
|
10255aa102 | ||
|
|
774c6f19a5 | ||
|
|
ebf35ea582 | ||
|
|
f13efc954e | ||
|
|
9ee052a229 | ||
|
|
152fbede90 | ||
|
|
c9b8ffa9ef | ||
|
|
04e16d44a1 | ||
|
|
29131f93c2 | ||
|
|
1e2fe7b066 | ||
|
|
426a0a3847 | ||
|
|
80ef504bef | ||
|
|
6ab83e25d3 | ||
|
|
688dc25990 | ||
|
|
c53b58c64f | ||
|
|
61d18edb5d | ||
|
|
07b5dfe28a | ||
|
|
f55cad0121 | ||
|
|
494299cd89 | ||
|
|
5cc071e5a8 | ||
|
|
0532f2744b | ||
|
|
43ea26a33a | ||
|
|
ec54e40a8b | ||
|
|
4b508f02e3 | ||
|
|
eec7e1b62a | ||
|
|
39e87eb8d3 | ||
|
|
780115ffb8 | ||
|
|
c7c4ba6e49 | ||
|
|
b9a7edf1f5 | ||
|
|
86bf2accc9 | ||
|
|
954c435404 | ||
|
|
538c1bd809 | ||
|
|
e0767881f2 | ||
|
|
7d0cbad326 | ||
|
|
0ce7703ab8 | ||
|
|
4362fdf35a | ||
|
|
4bcca2daf4 | ||
|
|
a1d83ac7b9 | ||
|
|
492729baf3 | ||
|
|
4003d21826 | ||
|
|
b10d398728 | ||
|
|
198df84b89 | ||
|
|
211fc22b2a | ||
|
|
4a0a5c9591 | ||
|
|
8f51afe198 | ||
|
|
40b6642ef0 | ||
|
|
0076cbaf54 | ||
|
|
14e0d57091 | ||
|
|
3e79ec9a61 | ||
|
|
42cd7d3b77 | ||
|
|
6f4c65c178 | ||
|
|
863424ffd7 | ||
|
|
c35cfbd170 | ||
|
|
22425726d1 | ||
|
|
94e8c1da68 | ||
|
|
55c305c569 | ||
|
|
ad028947e0 | ||
|
|
212e0753c8 | ||
|
|
711dc83f5c | ||
|
|
6314eeda0a | ||
|
|
cf783ea480 | ||
|
|
899fbef948 | ||
|
|
4a6d7952a7 | ||
|
|
5443226e27 | ||
|
|
89ffe99dcc | ||
|
|
ede306b88e | ||
|
|
0acc49c57d | ||
|
|
2bbeb040c2 | ||
|
|
5689c36b12 | ||
|
|
f4a367d2de | ||
|
|
afe042ecfc | ||
|
|
c108cd4780 | ||
|
|
d84146fd88 | ||
|
|
30e6316e16 | ||
|
|
6835e585b0 | ||
|
|
49d4f43652 | ||
|
|
70dd9c7724 | ||
|
|
f386e47efa | ||
|
|
ec16159497 | ||
|
|
5ba2959eb4 | ||
|
|
e9c5b00628 | ||
|
|
8e1f43eb8b | ||
|
|
3788293bc0 | ||
|
|
89a2e26f25 | ||
|
|
2c453bd491 | ||
|
|
0aebf234f9 | ||
|
|
3e25ef4b5a | ||
|
|
3dc3edb83e | ||
|
|
4ebe144191 | ||
|
|
49cd06a9b4 | ||
|
|
e0208da0ac | ||
|
|
1f41770060 | ||
|
|
3eff06281c | ||
|
|
5848dfb4f3 | ||
|
|
89f27adce5 | ||
|
|
bbab7fa672 | ||
|
|
fb149796fa | ||
|
|
3939013415 | ||
|
|
7fe18e99c3 | ||
|
|
6ddfd29be8 | ||
|
|
46efad94db | ||
|
|
b7ea073204 | ||
|
|
0d9c90ceeb | ||
|
|
3ba23e1787 | ||
|
|
e365718556 | ||
|
|
d65a49a7e7 | ||
|
|
7960aaf5d5 | ||
|
|
32b3a7d1d0 | ||
|
|
53fb976fb6 | ||
|
|
fffe71aa7e | ||
|
|
75b0a3a407 | ||
|
|
158689672a | ||
|
|
24e43dd1a2 | ||
|
|
b34366aaf7 | ||
|
|
2856c8d125 | ||
|
|
4ac1e1d798 | ||
|
|
b15d23035c | ||
|
|
8b2ea63ccb | ||
|
|
b0c65c76e6 | ||
|
|
c65c1af023 | ||
|
|
f10bd9c0d8 | ||
|
|
a6ac78294b | ||
|
|
04c9ead19d | ||
|
|
3c3798ee98 | ||
|
|
8df722ab02 | ||
|
|
dbe5ca60cd | ||
|
|
ec454dc981 | ||
|
|
0988f2145c | ||
|
|
3416c26bdc | ||
|
|
f1a50b7db3 | ||
|
|
f2fa13ba01 | ||
|
|
93fc3bf39e | ||
|
|
695180a2ef | ||
|
|
aeed138294 | ||
|
|
5d347096cf | ||
|
|
75ade97805 | ||
|
|
864d4b3cb7 | ||
|
|
c1492e3429 | ||
|
|
ae266810c2 | ||
|
|
a1d3fe5e06 | ||
|
|
98886ff074 | ||
|
|
b8b7a374a6 | ||
|
|
9d3647f38a | ||
|
|
5332eec7aa | ||
|
|
6bc933532e | ||
|
|
55053cd2b8 | ||
|
|
2e4317a80c | ||
|
|
5ef61f4621 | ||
|
|
4b47a5030a | ||
|
|
27c2dcbee4 | ||
|
|
e17ab16878 | ||
|
|
8c9fff36c8 | ||
|
|
c37ea3fbb6 | ||
|
|
6d6401d1da | ||
|
|
57f90c8b3b | ||
|
|
53883d290a | ||
|
|
ae0408a6f7 | ||
|
|
742abc9032 | ||
|
|
5652965853 | ||
|
|
da0c811846 | ||
|
|
d60dd5f281 | ||
|
|
ec70c6c613 | ||
|
|
aa40b916ab | ||
|
|
fe5242174b | ||
|
|
026cc29e1f | ||
|
|
6055baa0db | ||
|
|
469e6da29f | ||
|
|
6a7fb2d33d | ||
|
|
271ea89c8d | ||
|
|
f94d7f2b03 | ||
|
|
f084e64aed | ||
|
|
294b817957 | ||
|
|
ed85ed394a | ||
|
|
aa495312db | ||
|
|
8ac9b23de3 | ||
|
|
be7090b29c | ||
|
|
1f9b31a6cd | ||
|
|
e83d27f07c | ||
|
|
816cbd2036 | ||
|
|
ec781969fa | ||
|
|
2fc78c9219 | ||
|
|
7b2470cce6 | ||
|
|
31c3fac7f5 | ||
|
|
9d5a7b7dbd | ||
|
|
614710da69 | ||
|
|
f233066e81 | ||
|
|
32ae38ebb2 | ||
|
|
1459229dde | ||
|
|
b8cd602d7e | ||
|
|
647a05f469 | ||
|
|
7cf9885125 | ||
|
|
da72afcd5f | ||
|
|
9f0cdb7ac1 | ||
|
|
482a85565f | ||
|
|
c563d781d3 | ||
|
|
12a6da6558 | ||
|
|
54accbbeff | ||
|
|
6d0bd4a6ed | ||
|
|
73d403d2f1 | ||
|
|
b8fa581665 | ||
|
|
71f661daa4 | ||
|
|
3927867c81 | ||
|
|
60256533e3 | ||
|
|
6a0cabf249 | ||
|
|
a00c696c1a | ||
|
|
7958ef0d1f | ||
|
|
d935cee4db | ||
|
|
d565160124 | ||
|
|
b4cb27cef6 |
33
.env.example
@@ -8,8 +8,8 @@
|
||||
|
||||
WEBAPP_URL=http://localhost:3000
|
||||
|
||||
# Set this if you want to have a shorter link for surveys
|
||||
SHORT_URL_BASE=
|
||||
# Required for next-auth. Should be the same as WEBAPP_URL
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
|
||||
# Encryption keys
|
||||
# Please set both for now, we will change this in the future
|
||||
@@ -17,28 +17,20 @@ SHORT_URL_BASE=
|
||||
# You can use: `openssl rand -hex 32` to generate one
|
||||
ENCRYPTION_KEY=
|
||||
|
||||
# @see: https://next-auth.js.org/configuration/options#nextauth_secret
|
||||
# You can use: `openssl rand -hex 32` to generate a secure one
|
||||
NEXTAUTH_SECRET=
|
||||
|
||||
# API Secret for running cron jobs. (mandatory)
|
||||
# You can use: `openssl rand -hex 32` to generate a secure one
|
||||
CRON_SECRET=
|
||||
|
||||
##############
|
||||
# DATABASE #
|
||||
##############
|
||||
|
||||
DATABASE_URL='postgresql://postgres:postgres@localhost:5432/formbricks?schema=public'
|
||||
|
||||
###############
|
||||
# NEXT AUTH #
|
||||
###############
|
||||
|
||||
# @see: https://next-auth.js.org/configuration/options#nextauth_secret
|
||||
# You can use: `openssl rand -hex 32` to generate a secure one
|
||||
NEXTAUTH_SECRET=RANDOM_STRING
|
||||
|
||||
# Set this to your public-facing URL, e.g., https://example.com
|
||||
# You do not need the NEXTAUTH_URL environment variable in Vercel.
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
|
||||
# Cron Secret
|
||||
# You can use: `openssl rand -hex 32` to generate a secure one
|
||||
CRON_SECRET=
|
||||
|
||||
################
|
||||
# MAIL SETUP #
|
||||
################
|
||||
@@ -54,6 +46,9 @@ SMTP_SECURE_ENABLED=0
|
||||
SMTP_USER=smtpUser
|
||||
SMTP_PASSWORD=smtpPassword
|
||||
|
||||
# If set to 0, the server will accept connections without requiring authorization from the list of supplied CAs (default is 1).
|
||||
# SMTP_REJECT_UNAUTHORIZED_TLS=0
|
||||
|
||||
########################################################################
|
||||
# ------------------------------ OPTIONAL -----------------------------#
|
||||
########################################################################
|
||||
@@ -75,6 +70,8 @@ S3_BUCKET_NAME=
|
||||
# Configure a third party S3 compatible storage service endpoint like StorJ leave empty if you use Amazon S3
|
||||
# e.g., https://gateway.storjshare.io
|
||||
S3_ENDPOINT_URL=
|
||||
# Force path style for S3 compatible storage (0 for disabled, 1 for enabled)
|
||||
S3_FORCE_PATH_STYLE=0
|
||||
|
||||
#####################
|
||||
# Disable Features #
|
||||
|
||||
33
.github/ISSUE_TEMPLATE/oss-gg-hack-submission.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: oss.gg hack submission 🕹️
|
||||
description: "Submit your contribution for the for the oss.gg hackathon"
|
||||
title: "[🕹️]"
|
||||
labels: 🕹️ oss.gg, player submission, hacktoberfest
|
||||
assignees: []
|
||||
body:
|
||||
- type: textarea
|
||||
id: contribution-name
|
||||
attributes:
|
||||
label: What side quest or challenge are you solving?
|
||||
description: Add the name of the side quest or challenge.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: points
|
||||
attributes:
|
||||
label: Points
|
||||
description: How many points are assigned to this contribution?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: What's the task your performed?
|
||||
validations:
|
||||
- type: textarea
|
||||
id: proof
|
||||
attributes:
|
||||
label: Provide proof that you've completed the task
|
||||
description: Screenshots, loom recordings, links to the content you shared or interacted with.
|
||||
validations:
|
||||
required: true
|
||||
10
.github/actions/cache-build-web/action.yml
vendored
@@ -30,6 +30,10 @@ runs:
|
||||
**/dist/**
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}
|
||||
|
||||
- name: Set Cache Hit Status
|
||||
run: echo "cache-hit=${{ steps.cache-build.outputs.cache-hit }}" >> "$GITHUB_OUTPUT"
|
||||
shell: bash
|
||||
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
@@ -37,7 +41,7 @@ runs:
|
||||
if: steps.cache-build.outputs.cache-hit != 'true'
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
uses: pnpm/action-setup@v4
|
||||
if: steps.cache-build.outputs.cache-hit != 'true'
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -49,10 +53,12 @@ runs:
|
||||
run: cp .env.example .env
|
||||
shell: bash
|
||||
|
||||
- name: Fill ENCRYPTION_KE, ENTERPRISE_LICENSE_KEY and E2E_TESTING in .env
|
||||
- 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
|
||||
|
||||
24
.github/workflows/build-web.yml
vendored
@@ -11,24 +11,8 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
- name: Build & Cache Web Binaries
|
||||
uses: ./.github/actions/cache-build-web
|
||||
id: cache-build-web
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
|
||||
- name: create .env
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Generate Random ENCRYPTION_KEY
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Formbricks-web
|
||||
run: pnpm build --filter=@formbricks/web...
|
||||
e2e_testing_mode: "0"
|
||||
|
||||
30
.github/workflows/chromatic.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: "Chromatic"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
chromatic:
|
||||
name: Run Chromatic
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
- name: Install dependencies
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
- name: Run Chromatic
|
||||
uses: chromaui/action@latest
|
||||
with:
|
||||
# ⚠️ Make sure to configure a `CHROMATIC_PROJECT_TOKEN` repository secret
|
||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
workingDir: apps/storybook
|
||||
52
.github/workflows/e2e.yml
vendored
@@ -2,6 +2,8 @@ name: E2E Tests
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
env:
|
||||
TELEMETRY_DISABLED: 1
|
||||
jobs:
|
||||
build:
|
||||
name: Run E2E Tests
|
||||
@@ -25,29 +27,35 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Build & Cache Web Binaries
|
||||
uses: ./.github/actions/cache-build-web
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
e2e_testing_mode: "1"
|
||||
|
||||
- name: Check if pnpm is installed
|
||||
id: pnpm-check
|
||||
run: |
|
||||
if pnpm --version; then
|
||||
echo "pnpm is installed."
|
||||
echo "PNPM_INSTALLED=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "pnpm is not installed."
|
||||
echo "PNPM_INSTALLED=false" >> $GITHUB_ENV
|
||||
fi
|
||||
node-version: 20.x
|
||||
|
||||
- name: Install pnpm
|
||||
if: env.PNPM_INSTALLED == 'false'
|
||||
uses: pnpm/action-setup@v2
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Install dependencies
|
||||
if: env.PNPM_INSTALLED == 'false'
|
||||
run: pnpm install
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
shell: bash
|
||||
|
||||
- name: create .env
|
||||
run: cp .env.example .env
|
||||
shell: bash
|
||||
|
||||
- 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=1" >> .env
|
||||
shell: bash
|
||||
|
||||
- name: Build App
|
||||
run: |
|
||||
pnpm build --filter=@formbricks/web...
|
||||
|
||||
- name: Apply Prisma Migrations
|
||||
run: |
|
||||
@@ -70,15 +78,7 @@ jobs:
|
||||
sleep 10
|
||||
done
|
||||
|
||||
- name: Cache Playwright
|
||||
uses: actions/cache@v3
|
||||
id: playwright-cache
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install Playwright
|
||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
run: pnpm exec playwright install --with-deps
|
||||
|
||||
- name: Run E2E Tests
|
||||
|
||||
130
.github/workflows/kamal-deploy.yml
vendored
@@ -1,130 +0,0 @@
|
||||
name: Kamal Deploy
|
||||
concurrency:
|
||||
group: deploy-to-kamal
|
||||
cancel-in-progress: false
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
#push:
|
||||
# branches:
|
||||
# - main
|
||||
|
||||
jobs:
|
||||
Deploy:
|
||||
runs-on: ubuntu-latest
|
||||
environment: production
|
||||
env:
|
||||
DOCKER_BUILDKIT: 1
|
||||
IS_FORMBRICKS_CLOUD: ${{ vars.IS_FORMBRICKS_CLOUD }}
|
||||
WEBAPP_URL: ${{ vars.WEBAPP_URL }}
|
||||
MIGRATE_DATABASE_URL: ${{ secrets.MIGRATE_DATABASE_URL }}
|
||||
NEXTAUTH_URL: ${{ vars.NEXTAUTH_URL }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
|
||||
ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }}
|
||||
SHORT_URL_BASE: ${{ vars.SHORT_URL_BASE }}
|
||||
MAIL_FROM: ${{ secrets.MAIL_FROM }}
|
||||
SMTP_HOST: ${{ secrets.SMTP_HOST }}
|
||||
SMTP_PORT: ${{ secrets.SMTP_PORT }}
|
||||
SMTP_USER: ${{ secrets.SMTP_USER }}
|
||||
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
|
||||
PRIVACY_URL: ${{ vars.PRIVACY_URL }}
|
||||
TERMS_URL: ${{ vars.TERMS_URL }}
|
||||
IMPRINT_URL: ${{ vars.IMPRINT_URL }}
|
||||
GITHUB_ID: ${{ secrets.FB_GITHUB_ID }}
|
||||
GITHUB_SECRET: ${{ secrets.FB_GITHUB_SECRET }}
|
||||
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
|
||||
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
|
||||
AZUREAD_CLIENT_ID: ${{ secrets.AZUREAD_CLIENT_ID }}
|
||||
AZUREAD_CLIENT_SECRET: ${{ secrets.AZUREAD_CLIENT_SECRET }}
|
||||
AZUREAD_TENANT_ID: ${{ secrets.AZUREAD_TENANT_ID }}
|
||||
OIDC_CLIENT_ID: ${{ secrets.OIDC_CLIENT_ID }}
|
||||
OIDC_CLIENT_SECRET: ${{ secrets.OIDC_CLIENT_SECRET }}
|
||||
OIDC_ISSUER: ${{ secrets.OIDC_ISSUER }}
|
||||
OIDC_DISPLAY_NAME: ${{ secrets.OIDC_DISPLAY_NAME }}
|
||||
OIDC_SIGNING_ALGORITHM: ${{ secrets.OIDC_SIGNING_ALGORITHM }}
|
||||
CRON_SECRET: ${{ secrets.CRON_SECRET }}
|
||||
ASSET_PREFIX_URL: ${{ vars.ASSET_PREFIX_URL }}
|
||||
NOTION_OAUTH_CLIENT_ID: ${{ secrets.NOTION_OAUTH_CLIENT_ID }}
|
||||
NOTION_OAUTH_CLIENT_SECRET: ${{ secrets.NOTION_OAUTH_CLIENT_SECRET }}
|
||||
SLACK_CLIENT_ID: ${{ secrets.SLACK_CLIENT_ID }}
|
||||
SLACK_CLIENT_SECRET: ${{ secrets.SLACK_CLIENT_SECRET }}
|
||||
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ secrets.STRIPE_WEBHOOK_SECRET }}
|
||||
GOOGLE_SHEETS_CLIENT_ID: ${{ secrets.GOOGLE_SHEETS_CLIENT_ID }}
|
||||
GOOGLE_SHEETS_CLIENT_SECRET: ${{ secrets.GOOGLE_SHEETS_CLIENT_SECRET }}
|
||||
GOOGLE_SHEETS_REDIRECT_URL: ${{ secrets.GOOGLE_SHEETS_REDIRECT_URL }}
|
||||
AIRTABLE_CLIENT_ID: ${{ secrets.AIRTABLE_CLIENT_ID }}
|
||||
ENTERPRISE_LICENSE_KEY: ${{ secrets.ENTERPRISE_LICENSE_KEY }}
|
||||
DEFAULT_ORGANIZATION_ID: ${{ vars.DEFAULT_ORGANIZATION_ID }}
|
||||
CUSTOMER_IO_API_KEY: ${{ secrets.CUSTOMER_IO_API_KEY }}
|
||||
CUSTOMER_IO_SITE_ID: ${{ secrets.CUSTOMER_IO_SITE_ID }}
|
||||
NEXT_PUBLIC_POSTHOG_API_KEY: ${{ vars.NEXT_PUBLIC_POSTHOG_API_KEY }}
|
||||
NEXT_PUBLIC_POSTHOG_API_HOST: ${{ vars.NEXT_PUBLIC_POSTHOG_API_HOST }}
|
||||
NEXT_PUBLIC_FORMBRICKS_API_HOST: ${{ vars.NEXT_PUBLIC_FORMBRICKS_API_HOST }}
|
||||
NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID }}
|
||||
NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID }}
|
||||
NEXT_PUBLIC_SENTRY_DSN: ${{ vars.NEXT_PUBLIC_SENTRY_DSN }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
NODE_ENV: production
|
||||
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
|
||||
CLOUDFLARE_DNS_API_TOKEN: ${{ secrets.CLOUDFLARE_DNS_API_TOKEN }}
|
||||
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
|
||||
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||
S3_REGION: ${{ vars.S3_REGION }}
|
||||
S3_BUCKET_NAME: ${{ vars.S3_BUCKET_NAME }}
|
||||
OPENTELEMETRY_LISTENER_URL: ${{ vars.OPENTELEMETRY_LISTENER_URL }}
|
||||
RATE_LIMITING_DISABLED: ${{ vars.RATE_LIMITING_DISABLED }}
|
||||
KAMAL_REGISTRY_PASSWORD: ${{ secrets.KAMAL_REGISTRY_PASSWORD }}
|
||||
DB_HOST: ${{ secrets.DB_HOST }}
|
||||
DB_USER: ${{ secrets.DB_USER }}
|
||||
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
|
||||
DB_NAME: ${{ secrets.DB_NAME }}
|
||||
REDIS_URL: ${{ secrets.REDIS_URL }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.3.0
|
||||
bundler-cache: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
gem install kamal
|
||||
|
||||
- uses: webfactory/ssh-agent@v0.9.0
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Create builder
|
||||
run: docker buildx create --use --name formbricks-gh-actions-builder
|
||||
if: steps.buildx.outputs.should_create_builder == 'true'
|
||||
|
||||
- name: Push env variables to Kamal
|
||||
run: |
|
||||
kamal() { command kamal "$@" -c kamal/deploy.yml; }
|
||||
kamal env push
|
||||
|
||||
- name: Run deploy command
|
||||
run: |
|
||||
kamal() { command kamal "$@" -c kamal/deploy.yml; }
|
||||
set +e
|
||||
DEPLOY_OUTPUT=$(kamal deploy 2>&1)
|
||||
DEPLOY_EXIT_CODE=$?
|
||||
echo "$DEPLOY_OUTPUT"
|
||||
if [[ "$DEPLOY_OUTPUT" == *"container not unhealthy (healthy)"* ]]; then
|
||||
echo "Deployment reported healthy container. Considering as success."
|
||||
kamal lock release
|
||||
exit 0
|
||||
else
|
||||
exit $DEPLOY_EXIT_CODE
|
||||
fi
|
||||
shell: bash
|
||||
127
.github/workflows/kamal-setup.yml
vendored
@@ -1,127 +0,0 @@
|
||||
name: Kamal Setup
|
||||
concurrency:
|
||||
group: setup-kamal
|
||||
cancel-in-progress: false
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Only to be triggered when accessories are updated
|
||||
|
||||
jobs:
|
||||
Setup:
|
||||
runs-on: ubuntu-latest
|
||||
environment: production
|
||||
env:
|
||||
DOCKER_BUILDKIT: 1
|
||||
IS_FORMBRICKS_CLOUD: ${{ vars.IS_FORMBRICKS_CLOUD }}
|
||||
WEBAPP_URL: ${{ vars.WEBAPP_URL }}
|
||||
NEXTAUTH_URL: ${{ vars.NEXTAUTH_URL }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
MIGRATE_DATABASE_URL: ${{ secrets.MIGRATE_DATABASE_URL }}
|
||||
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
|
||||
ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }}
|
||||
SHORT_URL_BASE: ${{ vars.SHORT_URL_BASE }}
|
||||
MAIL_FROM: ${{ secrets.MAIL_FROM }}
|
||||
SMTP_HOST: ${{ secrets.SMTP_HOST }}
|
||||
SMTP_PORT: ${{ secrets.SMTP_PORT }}
|
||||
SMTP_USER: ${{ secrets.SMTP_USER }}
|
||||
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
|
||||
PRIVACY_URL: ${{ vars.PRIVACY_URL }}
|
||||
TERMS_URL: ${{ vars.TERMS_URL }}
|
||||
IMPRINT_URL: ${{ vars.IMPRINT_URL }}
|
||||
GITHUB_ID: ${{ secrets.FB_GITHUB_ID }}
|
||||
GITHUB_SECRET: ${{ secrets.FB_GITHUB_SECRET }}
|
||||
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
|
||||
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
|
||||
AZUREAD_CLIENT_ID: ${{ secrets.AZUREAD_CLIENT_ID }}
|
||||
AZUREAD_CLIENT_SECRET: ${{ secrets.AZUREAD_CLIENT_SECRET }}
|
||||
AZUREAD_TENANT_ID: ${{ secrets.AZUREAD_TENANT_ID }}
|
||||
OIDC_CLIENT_ID: ${{ secrets.OIDC_CLIENT_ID }}
|
||||
OIDC_CLIENT_SECRET: ${{ secrets.OIDC_CLIENT_SECRET }}
|
||||
OIDC_ISSUER: ${{ secrets.OIDC_ISSUER }}
|
||||
OIDC_DISPLAY_NAME: ${{ secrets.OIDC_DISPLAY_NAME }}
|
||||
OIDC_SIGNING_ALGORITHM: ${{ secrets.OIDC_SIGNING_ALGORITHM }}
|
||||
CRON_SECRET: ${{ secrets.CRON_SECRET }}
|
||||
ASSET_PREFIX_URL: ${{ vars.ASSET_PREFIX_URL }}
|
||||
NOTION_OAUTH_CLIENT_ID: ${{ secrets.NOTION_OAUTH_CLIENT_ID }}
|
||||
NOTION_OAUTH_CLIENT_SECRET: ${{ secrets.NOTION_OAUTH_CLIENT_SECRET }}
|
||||
SLACK_CLIENT_ID: ${{ secrets.SLACK_CLIENT_ID }}
|
||||
SLACK_CLIENT_SECRET: ${{ secrets.SLACK_CLIENT_SECRET }}
|
||||
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ secrets.STRIPE_WEBHOOK_SECRET }}
|
||||
GOOGLE_SHEETS_CLIENT_ID: ${{ secrets.GOOGLE_SHEETS_CLIENT_ID }}
|
||||
GOOGLE_SHEETS_CLIENT_SECRET: ${{ secrets.GOOGLE_SHEETS_CLIENT_SECRET }}
|
||||
GOOGLE_SHEETS_REDIRECT_URL: ${{ secrets.GOOGLE_SHEETS_REDIRECT_URL }}
|
||||
AIRTABLE_CLIENT_ID: ${{ secrets.AIRTABLE_CLIENT_ID }}
|
||||
ENTERPRISE_LICENSE_KEY: ${{ secrets.ENTERPRISE_LICENSE_KEY }}
|
||||
DEFAULT_ORGANIZATION_ID: ${{ vars.DEFAULT_ORGANIZATION_ID }}
|
||||
CUSTOMER_IO_API_KEY: ${{ secrets.CUSTOMER_IO_API_KEY }}
|
||||
CUSTOMER_IO_SITE_ID: ${{ secrets.CUSTOMER_IO_SITE_ID }}
|
||||
NEXT_PUBLIC_POSTHOG_API_KEY: ${{ vars.NEXT_PUBLIC_POSTHOG_API_KEY }}
|
||||
NEXT_PUBLIC_POSTHOG_API_HOST: ${{ vars.NEXT_PUBLIC_POSTHOG_API_HOST }}
|
||||
NEXT_PUBLIC_FORMBRICKS_API_HOST: ${{ vars.NEXT_PUBLIC_FORMBRICKS_API_HOST }}
|
||||
NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID }}
|
||||
NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID }}
|
||||
NEXT_PUBLIC_SENTRY_DSN: ${{ vars.NEXT_PUBLIC_SENTRY_DSN }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
NODE_ENV: production
|
||||
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
|
||||
CLOUDFLARE_DNS_API_TOKEN: ${{ secrets.CLOUDFLARE_DNS_API_TOKEN }}
|
||||
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
|
||||
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||
S3_REGION: ${{ vars.S3_REGION }}
|
||||
S3_BUCKET_NAME: ${{ vars.S3_BUCKET_NAME }}
|
||||
OPENTELEMETRY_LISTENER_URL: ${{ vars.OPENTELEMETRY_LISTENER_URL }}
|
||||
RATE_LIMITING_DISABLED: ${{ vars.RATE_LIMITING_DISABLED }}
|
||||
KAMAL_REGISTRY_PASSWORD: ${{ secrets.KAMAL_REGISTRY_PASSWORD }}
|
||||
DB_HOST: ${{ secrets.DB_HOST }}
|
||||
DB_USER: ${{ secrets.DB_USER }}
|
||||
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
|
||||
DB_NAME: ${{ secrets.DB_NAME }}
|
||||
REDIS_URL: ${{ secrets.REDIS_URL }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.3.0
|
||||
bundler-cache: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
gem install kamal
|
||||
|
||||
- uses: webfactory/ssh-agent@v0.9.0
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Create builder
|
||||
run: docker buildx create --use --name formbricks-gh-actions-builder
|
||||
if: steps.buildx.outputs.should_create_builder == 'true'
|
||||
|
||||
- name: Push env variables to Kamal
|
||||
run: |
|
||||
kamal() { command kamal "$@" -c kamal/deploy.yml; }
|
||||
kamal env push
|
||||
|
||||
- name: Run setup command
|
||||
run: |
|
||||
kamal() { command kamal "$@" -c kamal/deploy.yml; }
|
||||
set +e
|
||||
DEPLOY_OUTPUT=$(kamal setup 2>&1)
|
||||
DEPLOY_EXIT_CODE=$?
|
||||
echo "$DEPLOY_OUTPUT"
|
||||
if [[ "$DEPLOY_OUTPUT" == *"container not unhealthy (healthy)"* ]]; then
|
||||
echo "Deployment reported healthy container. Considering as success."
|
||||
kamal lock release
|
||||
exit 0
|
||||
else
|
||||
exit $DEPLOY_EXIT_CODE
|
||||
fi
|
||||
shell: bash
|
||||
14
.github/workflows/lint.yml
vendored
@@ -11,13 +11,13 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Setup Node.js 18.x
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
node-version: 20.x
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
@@ -25,10 +25,12 @@ jobs:
|
||||
- name: create .env
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Generate Random ENCRYPTION_KEY and fill in .env
|
||||
- name: Generate Random ENCRYPTION_KEY, CRON_SECRET & NEXTAUTH_SECRET and fill in .env
|
||||
run: |
|
||||
ENCRYPTION_KEY=$(openssl rand -hex 32)
|
||||
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${ENCRYPTION_KEY}/" .env
|
||||
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
|
||||
|
||||
- name: Lint
|
||||
run: pnpm lint
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
name: Docker for Data Migrations
|
||||
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
@@ -12,7 +7,6 @@ on:
|
||||
- "v*"
|
||||
|
||||
env:
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: formbricks/data-migrations
|
||||
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/formbricks?schema=public"
|
||||
@@ -23,8 +17,6 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
# This is used to complete the identity challenge
|
||||
# with sigstore/fulcio when running outside of PRs.
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
@@ -50,6 +42,7 @@ jobs:
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
type=raw,value=${{ github.ref_name }}
|
||||
type=raw,value=latest
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v3
|
||||
@@ -66,3 +59,4 @@ jobs:
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
run: |
|
||||
cosign sign --yes ghcr.io/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
|
||||
cosign sign --yes ghcr.io/${{ env.IMAGE_NAME }}:latest
|
||||
|
||||
14
.github/workflows/semantic-pull-requests.yml
vendored
@@ -20,6 +20,20 @@ jobs:
|
||||
id: lint_pr_title
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
types: |
|
||||
fix
|
||||
feat
|
||||
chore
|
||||
docs
|
||||
style
|
||||
refactor
|
||||
perf
|
||||
test
|
||||
build
|
||||
ci
|
||||
revert
|
||||
ossgg
|
||||
|
||||
- uses: marocchino/sticky-pull-request-comment@v2
|
||||
# When the previous steps fails, the workflow would stop. By adding this
|
||||
|
||||
10
.github/workflows/test.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
@@ -25,10 +25,12 @@ jobs:
|
||||
- name: create .env
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Generate Random ENCRYPTION_KEY and fill in .env
|
||||
- name: Generate Random ENCRYPTION_KEY, CRON_SECRET & NEXTAUTH_SECRET and fill in .env
|
||||
run: |
|
||||
ENCRYPTION_KEY=$(openssl rand -hex 32)
|
||||
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${ENCRYPTION_KEY}/" .env
|
||||
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
|
||||
|
||||
- name: Test
|
||||
run: pnpm test
|
||||
|
||||
2
.gitignore
vendored
@@ -56,5 +56,5 @@ Zone.Identifier
|
||||
packages/lib/uploads
|
||||
|
||||
# Vite Timestamps
|
||||
vite.config.*.timestamp-*
|
||||
*vite.config.*.timestamp-*
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ tasks:
|
||||
gp sync-await init &&
|
||||
cp .env.example .env &&
|
||||
sed -i -r "s#^(WEBAPP_URL=).*#\1 $(gp url 3000)#" .env &&
|
||||
sed -i -r "s#^(NEXTAUTH_URL=).*#\1 $(gp url 3000)#" .env &&
|
||||
RANDOM_ENCRYPTION_KEY=$(openssl rand -hex 32)
|
||||
sed -i 's/^ENCRYPTION_KEY=.*/ENCRYPTION_KEY='"$RANDOM_ENCRYPTION_KEY"'/' .env
|
||||
turbo --filter "@formbricks/web" go
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
pnpm lint-staged
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# A sample post-deploy hook
|
||||
#
|
||||
# These environment variables are available:
|
||||
# KAMAL_RECORDED_AT
|
||||
# KAMAL_PERFORMER
|
||||
# KAMAL_VERSION
|
||||
# KAMAL_HOSTS
|
||||
# KAMAL_ROLE (if set)
|
||||
# KAMAL_DESTINATION (if set)
|
||||
# KAMAL_RUNTIME
|
||||
|
||||
echo "$KAMAL_PERFORMER deployed $KAMAL_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds"
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Rebooted Traefik on $KAMAL_HOSTS"
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# A sample pre-build hook
|
||||
#
|
||||
# Checks:
|
||||
# 1. We have a clean checkout
|
||||
# 2. A remote is configured
|
||||
# 3. The branch has been pushed to the remote
|
||||
# 4. The version we are deploying matches the remote
|
||||
#
|
||||
# These environment variables are available:
|
||||
# KAMAL_RECORDED_AT
|
||||
# KAMAL_PERFORMER
|
||||
# KAMAL_VERSION
|
||||
# KAMAL_HOSTS
|
||||
# KAMAL_ROLE (if set)
|
||||
# KAMAL_DESTINATION (if set)
|
||||
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo "Git checkout is not clean, aborting..." >&2
|
||||
git status --porcelain >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
first_remote=$(git remote)
|
||||
|
||||
if [ -z "$first_remote" ]; then
|
||||
echo "No git remote set, aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
current_branch=$(git branch --show-current)
|
||||
|
||||
if [ -z "$current_branch" ]; then
|
||||
echo "Not on a git branch, aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
remote_head=$(git ls-remote $first_remote --tags $current_branch | cut -f1)
|
||||
|
||||
if [ -z "$remote_head" ]; then
|
||||
echo "Branch not pushed to remote, aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$KAMAL_VERSION" != "$remote_head" ]; then
|
||||
echo "Version ($KAMAL_VERSION) does not match remote HEAD ($remote_head), aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# A sample pre-connect check
|
||||
#
|
||||
# Warms DNS before connecting to hosts in parallel
|
||||
#
|
||||
# These environment variables are available:
|
||||
# KAMAL_RECORDED_AT
|
||||
# KAMAL_PERFORMER
|
||||
# KAMAL_VERSION
|
||||
# KAMAL_HOSTS
|
||||
# KAMAL_ROLE (if set)
|
||||
# KAMAL_DESTINATION (if set)
|
||||
# KAMAL_RUNTIME
|
||||
|
||||
hosts = ENV["KAMAL_HOSTS"].split(",")
|
||||
results = nil
|
||||
max = 3
|
||||
|
||||
elapsed = Benchmark.realtime do
|
||||
results = hosts.map do |host|
|
||||
Thread.new do
|
||||
tries = 1
|
||||
|
||||
begin
|
||||
Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)
|
||||
rescue SocketError
|
||||
if tries < max
|
||||
puts "Retrying DNS warmup: #{host}"
|
||||
tries += 1
|
||||
sleep rand
|
||||
retry
|
||||
else
|
||||
puts "DNS warmup failed: #{host}"
|
||||
host
|
||||
end
|
||||
end
|
||||
|
||||
tries
|
||||
end
|
||||
end.map(&:value)
|
||||
end
|
||||
|
||||
retries = results.sum - hosts.size
|
||||
nopes = results.count { |r| r == max }
|
||||
|
||||
puts "Prewarmed %d DNS lookups in %.2f sec: %d retries, %d failures" % [ hosts.size, elapsed, retries, nopes ]
|
||||
@@ -1,109 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# A sample pre-deploy hook
|
||||
#
|
||||
# Checks the Github status of the build, waiting for a pending build to complete for up to 720 seconds.
|
||||
#
|
||||
# Fails unless the combined status is "success"
|
||||
#
|
||||
# These environment variables are available:
|
||||
# KAMAL_RECORDED_AT
|
||||
# KAMAL_PERFORMER
|
||||
# KAMAL_VERSION
|
||||
# KAMAL_HOSTS
|
||||
# KAMAL_COMMAND
|
||||
# KAMAL_SUBCOMMAND
|
||||
# KAMAL_ROLE (if set)
|
||||
# KAMAL_DESTINATION (if set)
|
||||
|
||||
# Only check the build status for production deployments
|
||||
if ENV["KAMAL_COMMAND"] == "rollback" || ENV["KAMAL_DESTINATION"] != "production"
|
||||
exit 0
|
||||
end
|
||||
|
||||
require "bundler/inline"
|
||||
|
||||
# true = install gems so this is fast on repeat invocations
|
||||
gemfile(true, quiet: true) do
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "octokit"
|
||||
gem "faraday-retry"
|
||||
end
|
||||
|
||||
MAX_ATTEMPTS = 72
|
||||
ATTEMPTS_GAP = 10
|
||||
|
||||
def exit_with_error(message)
|
||||
$stderr.puts message
|
||||
exit 1
|
||||
end
|
||||
|
||||
class GithubStatusChecks
|
||||
attr_reader :remote_url, :git_sha, :github_client, :combined_status
|
||||
|
||||
def initialize
|
||||
@remote_url = `git config --get remote.origin.url`.strip.delete_prefix("https://github.com/")
|
||||
@git_sha = `git rev-parse HEAD`.strip
|
||||
@github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
|
||||
refresh!
|
||||
end
|
||||
|
||||
def refresh!
|
||||
@combined_status = github_client.combined_status(remote_url, git_sha)
|
||||
end
|
||||
|
||||
def state
|
||||
combined_status[:state]
|
||||
end
|
||||
|
||||
def first_status_url
|
||||
first_status = combined_status[:statuses].find { |status| status[:state] == state }
|
||||
first_status && first_status[:target_url]
|
||||
end
|
||||
|
||||
def complete_count
|
||||
combined_status[:statuses].count { |status| status[:state] != "pending"}
|
||||
end
|
||||
|
||||
def total_count
|
||||
combined_status[:statuses].count
|
||||
end
|
||||
|
||||
def current_status
|
||||
if total_count > 0
|
||||
"Completed #{complete_count}/#{total_count} checks, see #{first_status_url} ..."
|
||||
else
|
||||
"Build not started..."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
$stdout.sync = true
|
||||
|
||||
puts "Checking build status..."
|
||||
attempts = 0
|
||||
checks = GithubStatusChecks.new
|
||||
|
||||
begin
|
||||
loop do
|
||||
case checks.state
|
||||
when "success"
|
||||
puts "Checks passed, see #{checks.first_status_url}"
|
||||
exit 0
|
||||
when "failure"
|
||||
exit_with_error "Checks failed, see #{checks.first_status_url}"
|
||||
when "pending"
|
||||
attempts += 1
|
||||
end
|
||||
|
||||
exit_with_error "Checks are still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds" if attempts == MAX_ATTEMPTS
|
||||
|
||||
puts checks.current_status
|
||||
sleep(ATTEMPTS_GAP)
|
||||
checks.refresh!
|
||||
end
|
||||
rescue Octokit::NotFound
|
||||
exit_with_error "Build status could not be found"
|
||||
end
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Rebooting Traefik on $KAMAL_HOSTS..."
|
||||
10
README.md
@@ -144,6 +144,12 @@ Or you can also deploy Formbricks on [RepoCloud](https://repocloud.io) using the
|
||||
|
||||
[](https://repocloud.io/details/?app_id=254)
|
||||
|
||||
##### Zeabur
|
||||
|
||||
Or you can also deploy Formbricks on [Zeabur](https://zeabur.com) using the button below.
|
||||
|
||||
[](https://zeabur.com/templates/G4TUJL)
|
||||
|
||||
<a id="development"></a>
|
||||
|
||||
## 👨💻 Development
|
||||
@@ -160,7 +166,7 @@ Here is what you need to be able to run Formbricks:
|
||||
|
||||
### Local Setup
|
||||
|
||||
To get started locally, we've got a [guide to help you](https://formbricks.com/docs/contributing/setup).
|
||||
To get started locally, we've got a [guide to help you](https://formbricks.com/docs/developer-docs/contributing/get-started#local-machine-setup).
|
||||
|
||||
### Gitpod Setup
|
||||
|
||||
@@ -184,7 +190,7 @@ Here are a few options:
|
||||
|
||||
- Upvote issues with 👍 reaction so we know what the demand for a particular issue is to prioritize it within the roadmap.
|
||||
|
||||
Please check out [our contribution guide](https://formbricks.com/docs/contributing/introduction) and our [list of open issues](https://github.com/formbricks/formbricks/issues) for more information.
|
||||
Please check out [our contribution guide](https://formbricks.com/docs/developer-docs/contributing/get-started) and our [list of open issues](https://github.com/formbricks/formbricks/issues) for more information.
|
||||
|
||||
## All Thanks To Our Contributors
|
||||
|
||||
|
||||
2
apps/demo-react-native/.env.example
Normal file
@@ -0,0 +1,2 @@
|
||||
EXPO_PUBLIC_API_HOST=http://192.168.178.20:3000
|
||||
EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID=clzr04nkd000bcdl110j0ijyq
|
||||
7
apps/demo-react-native/.eslintrc.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ["@formbricks/eslint-config/react.js"],
|
||||
parserOptions: {
|
||||
project: "tsconfig.json",
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
};
|
||||
35
apps/demo-react-native/.gitignore
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# Expo
|
||||
.expo/
|
||||
dist/
|
||||
web-build/
|
||||
|
||||
# Native
|
||||
*.orig.*
|
||||
*.jks
|
||||
*.p8
|
||||
*.p12
|
||||
*.key
|
||||
*.mobileprovision
|
||||
|
||||
# Metro
|
||||
.metro-health-check*
|
||||
|
||||
# debug
|
||||
npm-debug.*
|
||||
yarn-debug.*
|
||||
yarn-error.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
0
apps/demo-react-native/.npmrc
Normal file
34
apps/demo-react-native/app.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "react-native-demo",
|
||||
"slug": "react-native-demo",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "light",
|
||||
"splash": {
|
||||
"image": "./assets/splash.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"jsEngine": "hermes",
|
||||
"assetBundlePatterns": ["**/*"],
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"infoPlist": {
|
||||
"NSCameraUsageDescription": "Take pictures for certain activities.",
|
||||
"NSPhotoLibraryUsageDescription": "Select pictures for certain activities.",
|
||||
"NSMicrophoneUsageDescription": "Need microphone access for recording videos."
|
||||
}
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
}
|
||||
},
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
apps/demo-react-native/assets/adaptive-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
apps/demo-react-native/assets/favicon.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
apps/demo-react-native/assets/icon.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
apps/demo-react-native/assets/splash.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
6
apps/demo-react-native/babel.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = function babel(api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: ["babel-preset-expo"],
|
||||
};
|
||||
};
|
||||
7
apps/demo-react-native/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import { registerRootComponent } from "expo";
|
||||
import { LogBox } from "react-native";
|
||||
import App from "./src/app";
|
||||
|
||||
registerRootComponent(App);
|
||||
|
||||
LogBox.ignoreAllLogs();
|
||||
21
apps/demo-react-native/metro.config.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// Learn more https://docs.expo.io/guides/customizing-metro
|
||||
const path = require("node:path");
|
||||
const { getDefaultConfig } = require("expo/metro-config");
|
||||
|
||||
// Find the workspace root, this can be replaced with `find-yarn-workspace-root`
|
||||
const workspaceRoot = path.resolve(__dirname, "../..");
|
||||
const projectRoot = __dirname;
|
||||
|
||||
const config = getDefaultConfig(projectRoot);
|
||||
|
||||
// 1. Watch all files within the monorepo
|
||||
config.watchFolders = [workspaceRoot];
|
||||
// 2. Let Metro know where to resolve packages, and in what order
|
||||
config.resolver.nodeModulesPaths = [
|
||||
path.resolve(projectRoot, "node_modules"),
|
||||
path.resolve(workspaceRoot, "node_modules"),
|
||||
];
|
||||
// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths`
|
||||
config.resolver.disableHierarchicalLookup = true;
|
||||
|
||||
module.exports = config;
|
||||
28
apps/demo-react-native/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@formbricks/demo-react-native",
|
||||
"version": "1.0.0",
|
||||
"main": "./index.js",
|
||||
"scripts": {
|
||||
"dev": "expo start",
|
||||
"android": "expo start --android",
|
||||
"ios": "expo start --ios",
|
||||
"web": "expo start --web",
|
||||
"eject": "expo eject",
|
||||
"clean": "rimraf .turbo node_modules .expo"
|
||||
},
|
||||
"dependencies": {
|
||||
"@formbricks/js": "workspace:*",
|
||||
"@formbricks/react-native": "workspace:*",
|
||||
"expo": "^51.0.26",
|
||||
"expo-status-bar": "~1.12.1",
|
||||
"react": "^18.2.0",
|
||||
"react-native": "^0.74.4",
|
||||
"react-native-webview": "13.8.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@types/react": "~18.2.79",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
52
apps/demo-react-native/src/app.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
import { Button, LogBox, StyleSheet, Text, View } from "react-native";
|
||||
import Formbricks, { track } from "@formbricks/react-native";
|
||||
|
||||
LogBox.ignoreAllLogs();
|
||||
|
||||
export default function App(): JSX.Element {
|
||||
if (!process.env.EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID) {
|
||||
throw new Error("EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID is required");
|
||||
}
|
||||
|
||||
if (!process.env.EXPO_PUBLIC_API_HOST) {
|
||||
throw new Error("EXPO_PUBLIC_API_HOST is required");
|
||||
}
|
||||
|
||||
const config = {
|
||||
environmentId: process.env.EXPO_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
|
||||
apiHost: process.env.EXPO_PUBLIC_API_HOST,
|
||||
userId: "random-user-id",
|
||||
attributes: {
|
||||
language: "en",
|
||||
testAttr: "attr-test",
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Formbricks React Native SDK Demo</Text>
|
||||
|
||||
<Button
|
||||
title="Trigger Code Action"
|
||||
onPress={() => {
|
||||
track("code").catch((error: unknown) => {
|
||||
// eslint-disable-next-line no-console -- logging is allowed in demo apps
|
||||
console.error("Error tracking event:", error);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<StatusBar style="auto" />
|
||||
<Formbricks initConfig={config} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#fff",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
});
|
||||
6
apps/demo-react-native/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "expo/tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,8 @@
|
||||
"dependencies": {
|
||||
"@formbricks/js": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"lucide-react": "^0.397.0",
|
||||
"next": "14.2.4",
|
||||
"lucide-react": "^0.446.0",
|
||||
"next": "14.2.13",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { AppProps } from "next/app";
|
||||
import Head from "next/head";
|
||||
import "../styles/globals.css";
|
||||
import "@formbricks/ui/globals.css";
|
||||
|
||||
const App = ({ Component, pageProps }: AppProps) => {
|
||||
return (
|
||||
|
||||
@@ -62,7 +62,7 @@ const AppPage = ({}) => {
|
||||
return (
|
||||
<div className="h-screen bg-white px-12 py-6 dark:bg-slate-800">
|
||||
<div className="flex flex-col justify-between md:flex-row">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex flex-col items-center gap-2 sm:flex-row">
|
||||
<SurveySwitch value="app" formbricks={formbricks} />
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
|
||||
|
||||
@@ -58,7 +58,7 @@ const AppPage = ({}) => {
|
||||
return (
|
||||
<div className="h-screen bg-white px-12 py-6 dark:bg-slate-800">
|
||||
<div className="flex flex-col items-center justify-between md:flex-row">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex flex-col items-center gap-2 sm:flex-row">
|
||||
<SurveySwitch value="website" formbricks={formbricks} />
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
|
||||
@@ -128,6 +128,7 @@ const AppPage = ({}) => {
|
||||
}}>
|
||||
Reset
|
||||
</button>
|
||||
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
If you made a change in Formbricks app and it does not seem to work, hit 'Reset' and
|
||||
try again.
|
||||
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 15 KiB |
@@ -1,26 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* Example on overriding packages/js colors */
|
||||
.dark {
|
||||
--fb-brand-color: red;
|
||||
--fb-brand-text-color: white;
|
||||
--fb-border-color: green;
|
||||
--fb-border-color-highlight: var(--slate-500);
|
||||
--fb-focus-color: red;
|
||||
--fb-heading-color: yellow;
|
||||
--fb-subheading-color: green;
|
||||
--fb-info-text-color: orange;
|
||||
--fb-signature-text-color: blue;
|
||||
--fb-survey-background-color: black;
|
||||
--fb-accent-background-color: rgb(13, 13, 12);
|
||||
--fb-accent-background-color-selected: red;
|
||||
--fb-placeholder-color: white;
|
||||
--fb-shadow-color: yellow;
|
||||
--fb-rating-fill: var(--yellow-300);
|
||||
--fb-rating-hover: var(--yellow-500);
|
||||
--fb-back-btn-border: currentColor;
|
||||
--fb-submit-btn-border: transparent;
|
||||
--fb-rating-selected: black;
|
||||
}
|
||||
@@ -8,26 +8,31 @@ import RideHailing from "./ride-hailing.webp";
|
||||
import UpsellMiro from "./upsell-miro.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Advanced Targeting in Surveys | Formbricks",
|
||||
title: "Advanced Targeting for In-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, user events, metadata , literally anything! This helps you get more relevant feedback and make data-driven decisions. All of this without writing a single line of code.",
|
||||
"Advanced Targeting allows you to show surveys to just the right group of people. You can target surveys based on user attributes, user events, and metadata. This helps you get more relevant feedback and make data-driven decisions.",
|
||||
};
|
||||
|
||||
#### App Surveys
|
||||
|
||||
# Advanced Targeting
|
||||
|
||||
Advanced Targeting allows you to show surveys to the right group of people. You can target surveys based on user attributes, user events, and more instead of spraying and praying. This helps you get more relevant feedback and make data-driven decisions. All of this without writing a single line of code.
|
||||
<Note>
|
||||
Targeting based on actions is deprecated in Advanced Targeting and will be removed soon. We recommend using
|
||||
filters on user attributes to target the survey only to specific groups of users.
|
||||
</Note>
|
||||
|
||||
<ResponsiveVideo title="Formbricks Multi-language Surveys"
|
||||
src="https://www.youtube-nocookie.com/embed/0BQp6N4cXzU?si=KeBM7G7Ch1xtrsOm&controls=0" />
|
||||
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.
|
||||
|
||||
<ResponsiveVideo
|
||||
title="Formbricks Multi-language Surveys"
|
||||
src="https://www.youtube-nocookie.com/embed/0BQp6N4cXzU?si=KeBM7G7Ch1xtrsOm&controls=0"
|
||||
/>
|
||||
|
||||
## How to setup Advanced Targeting
|
||||
|
||||
<Note>
|
||||
Advanced Targeting is available on the Pro plan! Don't worry, you just need to enter your credit card
|
||||
details to start the freemium plan.
|
||||
Advanced Targeting is available on the Pro plan!
|
||||
</Note>
|
||||
|
||||
1. On the Formbricks dashboard, click on **People** tab from the top navigation bar.
|
||||
@@ -66,25 +71,7 @@ Advanced Targeting allows you to show surveys to the right group of people. You
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. Target High Value users who have $100k+ in their bank account, own 20+ stocks, and have are an active user.
|
||||
|
||||
<MdxImage
|
||||
src={Hni}
|
||||
alt="Target Active High Net Worth Individuals"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
4. Target Germans on mobile phones who have regenerated chatGPT answers frequently in the last quarter and did so today.
|
||||
|
||||
<MdxImage
|
||||
src={GermansGpt}
|
||||
alt="Target Germans on Mobile Phones who have regenerated chatGPT answers frequently in the last quarter and did so today"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
5. Sneak Peak: How we at Formbricks automate inviting power users to chat with us
|
||||
3. Sneak Peak: How we at Formbricks automate inviting power users to chat with us
|
||||
|
||||
<MdxImage
|
||||
src={PowerUsers}
|
||||
|
||||
@@ -31,12 +31,18 @@ const libraries = [
|
||||
description: "Simply add us to your router change and sit back!",
|
||||
logo: logoVueJs,
|
||||
},
|
||||
{
|
||||
href: "#react-native",
|
||||
name: "React Native",
|
||||
description: "Easily integrate our SDK with your React Native app for seamless survey support!",
|
||||
logo: logoReactJs,
|
||||
},
|
||||
];
|
||||
|
||||
export const Libraries = () => {
|
||||
return (
|
||||
<div className="my-16 xl:max-w-none">
|
||||
<div className="not-prose mt-4 grid grid-cols-1 gap-x-6 gap-y-10 border-slate-900/5 sm:grid-cols-2 xl:max-w-none xl:grid-cols-3 dark:border-white/5">
|
||||
<div className="not-prose mt-4 grid grid-cols-1 gap-x-6 gap-y-10 border-slate-900/5 xl:max-w-none xl:grid-cols-2 2xl:grid-cols-3 dark:border-white/5">
|
||||
{libraries.map((library) => (
|
||||
<a
|
||||
key={library.name}
|
||||
|
||||
@@ -69,18 +69,18 @@ Refer to our [Example HTML project](https://github.com/formbricks/examples/tree/
|
||||
|
||||
## ReactJS
|
||||
|
||||
Install the Formbricks SDK using one of the package managers ie `npm`,`pnpm`,`yarn`.
|
||||
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
|
||||
npm install @formbricks/js zod
|
||||
```
|
||||
```shell {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/js
|
||||
pnpm add @formbricks/js zod
|
||||
```
|
||||
```shell {{ title: 'yarn' }}
|
||||
yarn add @formbricks/js
|
||||
yarn add @formbricks/js zod
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -142,13 +142,13 @@ Code snippets for the integration for both conventions are provided to further a
|
||||
<Col>
|
||||
<CodeGroup title="Install Formbricks JS library">
|
||||
```shell {{ title: 'npm' }}
|
||||
npm install @formbricks/js
|
||||
npm install @formbricks/js zod
|
||||
```
|
||||
```shell {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/js
|
||||
pnpm add @formbricks/js zod
|
||||
```
|
||||
```shell {{ title: 'yarn' }}
|
||||
yarn add @formbricks/js
|
||||
yarn add @formbricks/js zod
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -164,7 +164,6 @@ yarn add @formbricks/js
|
||||
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import formbricks from "@formbricks/js/app";
|
||||
|
||||
export default function FormbricksProvider() {
|
||||
@@ -218,7 +217,6 @@ Refer to our [Example NextJS App Directory project](https://github.com/formbrick
|
||||
// other import
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import formbricks from "@formbricks/js/app";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
@@ -348,6 +346,66 @@ router.afterEach((to, from) => {
|
||||
|
||||
Refer to our [Example VueJs project](https://github.com/formbricks/examples/tree/main/vuejs) for more help! Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
|
||||
## React Native
|
||||
|
||||
Install the Formbricks React Native SDK using one of the package managers, i.e., npm, pnpm, or yarn.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Install Formbricks JS library">
|
||||
```shell {{ title: 'npm' }}
|
||||
npm install @formbricks/react-native
|
||||
```
|
||||
```shell {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/react-native
|
||||
```
|
||||
```shell {{ title: 'yarn' }}
|
||||
yarn add @formbricks/react-native
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
Now, update your App.js/App.tsx file to initialize Formbricks:
|
||||
<Col>
|
||||
<CodeGroup title="src/App.js">
|
||||
|
||||
```js
|
||||
// other imports
|
||||
import Formbricks from "@formbricks/react-native";
|
||||
|
||||
const config = {
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user-id>",
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<>
|
||||
{/* Your app content */}
|
||||
<Formbricks initConfig={config} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
### Required customizations to be made
|
||||
|
||||
<Properties>
|
||||
<Property name="environment-id" type="string">
|
||||
Formbricks Environment ID.
|
||||
</Property>
|
||||
<Property name="api-host" type="string">
|
||||
URL of the hosted Formbricks instance.
|
||||
</Property>
|
||||
<Property name="userId" type="string">
|
||||
User ID of the user who has active session.
|
||||
</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:
|
||||
|
||||
@@ -19,10 +19,12 @@ export const metadata = {
|
||||
|
||||
# Quickstart
|
||||
|
||||
App surveys have 6-10x better conversion rates than emailed out surveys. This tutorial explains how to run an app survey in your web app in 10 to 15 minutes. Let’s go!
|
||||
App surveys have 6-10x better conversion rates than emailed surveys. This tutorial explains how to run a survey in both your web app and mobile app (React Native) in just 10 to 15 minutes. Let’s go!
|
||||
|
||||
<Note>
|
||||
App Surveys are ideal for websites that **have a user authentication** system. If you are looking to run surveys on your public facing website, head over to the [Website Surveys Quickstart Guide](/website-surveys/quickstart).
|
||||
App Surveys are ideal for websites that **have a user authentication** system. If you are looking to run
|
||||
surveys on your public facing website, head over to the [Website Surveys Quickstart
|
||||
Guide](/website-surveys/quickstart).
|
||||
</Note>
|
||||
|
||||
1. **Create a free Formbricks Cloud account**: While you can [self-host](/self-hosting/deployment) Formbricks, but the quickest and easiest way to get started is with the free Cloud plan. Just [sign up here](https://app.formbricks.com/auth/signup) and you'll be guided to our onboarding like below:
|
||||
@@ -35,7 +37,7 @@ App surveys have 6-10x better conversion rates than emailed out surveys. This tu
|
||||
src={I1}
|
||||
alt="Choose website survey from survey type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. **Connect your App/Website**: Once you get through a couple of onboarding steps, you’ll be asked to connect your app or website. This is where you’ll find the code snippet for both HTML as well as the npm package which you need to embed in your app:
|
||||
|
||||
@@ -129,10 +129,8 @@ Locate that file. We are using the [Tailwind Template “Syntax”](https://tail
|
||||
```tsx
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@formbricks/ui/Popover";
|
||||
|
||||
import { Button } from "@formbricks/ui/components/Button";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@formbricks/ui/components/Popover";
|
||||
import { handleFeedbackSubmit, updateFeedback } from "../../lib/handleFeedbackSubmit";
|
||||
|
||||
export const DocsFeedback = () => {
|
||||
|
||||
@@ -79,28 +79,6 @@ Promise<{ id: string }, NetworkError | Error>
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
- Update Display
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Update Display">
|
||||
|
||||
```javascript {{ title: 'Update Display Method Call'}}
|
||||
await api.client.display.update(
|
||||
displayId: "<your-display-id>",
|
||||
{
|
||||
userId: "<your-user-id>", // optional
|
||||
responseId: "<your-response-id>", // optional
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
```javascript {{ title: 'Update Display Method Return Type' }}
|
||||
Promise<{ }, NetworkError | Error]>
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
## Responses
|
||||
|
||||
- Create Response
|
||||
@@ -173,29 +151,6 @@ Promise<{ }, NetworkError | Error]>
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
## Action
|
||||
|
||||
- Create Action:
|
||||
|
||||
<Note> An environment cannot have 2 actions with the same name. </Note>
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Create Action">
|
||||
|
||||
```javascript {{ title: 'Create Action Method Call'}}
|
||||
await api.client.action.create({
|
||||
name: "<your-action-name>", // required
|
||||
userId: "<your-user-id>", // required
|
||||
});
|
||||
```
|
||||
|
||||
```javascript {{ title: 'Create Action Method Return Type' }}
|
||||
Promise<{ }, NetworkError | Error]>
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
## Attribute
|
||||
|
||||
- Update Attribute
|
||||
|
||||
@@ -7,12 +7,12 @@ import I3 from "./images/3-survey-logs-in-app-survey-popup.webp";
|
||||
export const metadata = {
|
||||
title: "Formbricks App Survey SDK",
|
||||
description:
|
||||
"An overview of all available methods & how to integrate Formbricks App Surveys for frontend developers in web applications. Learn the key methods, configuration settings, and best practices.",
|
||||
"Integrate Formbricks App Surveys into your web apps with the Formbricks JS SDK for App Surveys. Learn how to initialize Formbricks, set attributes, track actions, and troubleshoot common issues.",
|
||||
};
|
||||
|
||||
#### Developer Docs
|
||||
|
||||
# SDK: App Survey
|
||||
# SDK: Run Surveys Inside Your Web Apps
|
||||
|
||||
### Overview
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@formbricks/ui/Accordion";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@formbricks/ui/components/Accordion";
|
||||
import { FaqJsonLdComponent } from "./FAQPageJsonLd";
|
||||
|
||||
const FAQ_DATA = [
|
||||
|
||||
@@ -21,6 +21,7 @@ We are so happy that you are interested in contributing to Formbricks 🤗 There
|
||||
- **How to create a service**: [Read this document to understand how we use services](https://formbricks.notion.site/How-to-create-a-service-8e0c035704bb40cb9ea5e5beeeeabd67?pvs=4). This is particulalry important when you need to write a new one.
|
||||
|
||||
## Talk to us first
|
||||
|
||||
We highly recommend connecting with us on [Discord server](https://formbricks.com/discord) before you ship a contribution. This will increase the likelihood of your PR being merged. And it will decrease the likelihood of you wasting your time :)
|
||||
|
||||
## Contributor License Agreement (CLA)
|
||||
@@ -90,14 +91,31 @@ cp .env.example .env
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
4. Generate & set some secret values mandatory for the `ENCRYPTION_KEY` & `NEXTAUTH_SECRET` in the .env file. You can use the following command to generate the random string of required length:
|
||||
4. Generate & set some secret values mandatory for the `ENCRYPTION_KEY`, `NEXTAUTH_SECRET` and `CRON_SECRET` in the .env file. You can use the following command to generate the random string of required length:
|
||||
|
||||
- For Linux
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Set value of ENCRYPTION_KEY">
|
||||
<CodeGroup title="For Linux">
|
||||
|
||||
```bash
|
||||
sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env
|
||||
sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env
|
||||
sed -i '/^CRON_SECRET=/c\CRON_SECRET='$(openssl rand -hex 32) .env
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
- For Mac
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="For Mac">
|
||||
|
||||
```bash
|
||||
sed -i '' '/^ENCRYPTION_KEY=/s|.*|ENCRYPTION_KEY='$(openssl rand -hex 32)'|' .env
|
||||
sed -i '' '/^NEXTAUTH_SECRET=/s|.*|NEXTAUTH_SECRET='$(openssl rand -hex 32)'|' .env
|
||||
sed -i '' '/^CRON_SECRET=/s|.*|CRON_SECRET='$(openssl rand -hex 32)'|' .env
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -149,4 +167,4 @@ pnpm build
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Col>
|
||||
|
||||
@@ -35,7 +35,7 @@ export const metadata = {
|
||||
3. To prevent the "Init" task from running indefinitely due to prebuild rules, a cleanup `docker compose down` step i.e. `db:down` is added to `turbo.json`. This step is designed to halt the execution of containers that are currently running.
|
||||
- When the workspace starts:
|
||||
1. Initializing environment variables.
|
||||
2. Replacing `NEXT_PUBLIC_WEBAPP_URL` and `NEXTAUTH_URL` to take in Gitpod URL's ports when running on VSCode browser.
|
||||
2. Replacing `NEXT_PUBLIC_WEBAPP_URL` to take in Gitpod URL's ports when running on VSCode browser.
|
||||
3. Starting the `@formbricks/web` dev environment.
|
||||
|
||||
**Demo Component Initialization:**
|
||||
@@ -81,8 +81,8 @@ session.
|
||||
of your workspace. - You can use either choose either VS Code Browser or VS Code Desktop editor with the
|
||||
'Standard Class' for your workspace class. - If you opt for the VS Code Desktop, follow the following steps 1.
|
||||
Gitpod will prompt you to grant access to the VSCode app. Once approved, install the GitPod extension from the
|
||||
VSCode Marketplace and follow the prompts to authorize the integration. 2. Change the `WEBAPP_URL` and the
|
||||
`NEXTAUTH_URL` to `https://localhost:3000`
|
||||
VSCode Marketplace and follow the prompts to authorize the integration. 2. Change the `WEBAPP_URL` to
|
||||
`https://localhost:3000`
|
||||
|
||||
### 4. Gitpod preparing the created Workspace
|
||||
|
||||
@@ -169,4 +169,4 @@ Here are the ports and corresponding URLs for the services within your Gitpod en
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
These URLs and port numbers represent various services and endpoints within your Gitpod environment. You can access and interact with these services by the Port URL for the respective service.
|
||||
These URLs and port numbers represent various services and endpoints within your Gitpod environment. You can access and interact with these services by the Port URL for the respective service.
|
||||
|
||||
|
After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 13 KiB |
@@ -4,7 +4,7 @@ import AddModule from "./add-module.webp";
|
||||
import CreateNewScenario from "./create-new-scenario.webp";
|
||||
import CreateWebhook from "./create-webhook.webp";
|
||||
import DuplicateSurvey from "./duplicate-survey.webp";
|
||||
import EnterApiKey from "./enter-api-key.webp";
|
||||
import EnterApiKeyAndHost from "./enter-api-key-and-host.webp";
|
||||
import Result from "./result.webp";
|
||||
import SearchFormbricks from "./search-formbricks.webp";
|
||||
import SelectAction from "./select-action.webp";
|
||||
@@ -27,8 +27,8 @@ export const metadata = {
|
||||
Make is a powerful tool to send information between Formbricks and thousands of apps. Here's how to set it up.
|
||||
|
||||
<Note>
|
||||
Nailed down your survey?? Any changes in the survey cause additional work in the _Scenario_. It
|
||||
makes sense to first settle on the survey you want to run and then get to setting up Make.
|
||||
Nailed down your survey?? Any changes in the survey cause additional work in the _Scenario_. It makes sense
|
||||
to first settle on the survey you want to run and then get to setting up Make.
|
||||
</Note>
|
||||
|
||||
## Step 1: Setup your survey incl. `questionId` for every question
|
||||
@@ -95,10 +95,10 @@ Click "Create a webhook":
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Enter the Formbricks API key. Learn how to get one from the [API Key tutorial](/additional-features/api#how-to-generate-an-api-key).
|
||||
Enter the Formbricks API Host and API Key. API Host is by default set to https://app.formbricks.com but can be modified for self hosting instances. Learn how to get an API Key from the [API Key tutorial](/additional-features/api#how-to-generate-an-api-key).
|
||||
|
||||
<MdxImage
|
||||
src={EnterApiKey}
|
||||
src={EnterApiKeyAndHost}
|
||||
alt="Enter API Key"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
|
||||
@@ -112,7 +112,7 @@ Enabling the Slack Integration in a self-hosted environment requires a setup usi
|
||||
"go": next dev --experimental-https -p 3000
|
||||
```
|
||||
|
||||
- You also need to update the .env file in the `apps/web` directory to include the `NEXTAUTH_URL` and `WEBAPP_URL` as `https://localhost:3000` instead of `http://localhost:3000`.
|
||||
- You also need to update the .env file in the `apps/web` directory to include the `WEBAPP_URL` as `https://localhost:3000` instead of `http://localhost:3000`.
|
||||
|
||||
- You also need to run the terminal in admin mode to run the `go` script(to acquire the SSL certificate). You can do this by running the terminal as an administrator or using the `sudo` command in Unix-based systems.
|
||||
|
||||
|
||||
@@ -10,11 +10,15 @@ export const metadata = {
|
||||
|
||||
Welcome to the Developer Docs section, your comprehensive resource for integrating and utilizing Formbricks SDKs &APIs, as well as contributing to our open source codebase. Here's what you can expect to find in this section:
|
||||
|
||||
### [SDK: App Survey](/developer-docs/app-survey-sdk)
|
||||
### [SDK: React Native Apps](/developer-docs/react-native-in-app-surveys)
|
||||
|
||||
The Formbricks React Native SDK for App Surveys is designed for React Native applications, enabling seamless integration of surveys within your mobile apps. Dive into the documentation to learn how to leverage the SDK for app surveys and engage with your users effectively.
|
||||
|
||||
### [SDK: Web Apps](/developer-docs/app-survey-sdk)
|
||||
|
||||
The Formbricks JS SDK tailored for App Surveys is designed for applications where users are logged in, allowing for targeted and identified interactions within Formbricks. This SDK is particularly useful for advanced user tracking, enabling deeper insights into user behavior. Learn how to seamlessly integrate Formbricks into your applications and harness valuable insights from your logged-in users.
|
||||
|
||||
### [SDK: Website Survey](/developer-docs/website-survey-sdk)
|
||||
### [SDK: Public Websites](/developer-docs/website-survey-sdk)
|
||||
|
||||
The Formbricks JS SDK for Website Surveys is ideal for public-facing websites without user authentication. It's recommended for pages with high traffic and no authentication walls, facilitating quick and efficient survey collection. Dive into the documentation to discover how to deploy surveys on your website and effectively engage with your audience.
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
export const metadata = {
|
||||
title: "React Native: Formbricks App SDK",
|
||||
description:
|
||||
"Integrate Formbricks App Surveys into your React Native apps with the Formbricks React Native SDK.",
|
||||
};
|
||||
|
||||
#### Developer Docs
|
||||
|
||||
# React Native: In App Surveys
|
||||
|
||||
### Overview
|
||||
|
||||
The Formbricks React Native SDK can be used for seamlessly integrating App Surveys into your React Native Apps. Here, w'll explore how to leverage the SDK for in app surveys. The SDK is [available on npm.](https://www.npmjs.com/package/@formbricks/react-native)
|
||||
|
||||
### Install
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="npm">
|
||||
|
||||
```js {{ title: 'npm' }}
|
||||
npm install @formbricks/react-native
|
||||
```
|
||||
|
||||
```js {{ title: 'yarn' }}
|
||||
yarn add @formbricks/react-native
|
||||
```
|
||||
|
||||
```js {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/react-native
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
## Methods
|
||||
|
||||
### Initialize Formbricks
|
||||
|
||||
In your React Native app, initialize the Formbricks React Native Client for app surveys where you pass the userId (creates a user if not existing in Formbricks) to attribute & target the user based on their actions.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Initialize Formbricks">
|
||||
|
||||
```javascript
|
||||
// other imports
|
||||
import Formbricks from "@formbricks/react-native";
|
||||
|
||||
const config = {
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user-id>",
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<>
|
||||
{/* Your app content */}
|
||||
<Formbricks initConfig={config} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
The moment you initialise Formbricks, your user will start seeing surveys that get triggered on simpler actions such as on New Session.
|
||||
|
||||
### Set Attribute
|
||||
|
||||
You can set custom attributes for the identified user. This can be helpful for segmenting users based on specific characteristics or properties. To learn how to set custom user attributes, please check out our [User Attributes Guide](/app-surveys/user-identification).
|
||||
|
||||
<Col>
|
||||
<CodeGroup>
|
||||
|
||||
```js
|
||||
formbricks.setAttribute("Plan", "Paid");
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
### Track Action
|
||||
|
||||
Track user actions to trigger surveys based on user interactions, such as button clicks or scrolling:
|
||||
|
||||
<Col>
|
||||
<CodeGroup>
|
||||
|
||||
```js
|
||||
formbricks.track("Clicked on Claim");
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
### Logout
|
||||
|
||||
To log out and deinitialize Formbricks, use the formbricks.logout() function. This action clears the current initialization configuration and erases stored frontend information, such as the surveys a user has viewed or completed. It's an important step when a user logs out of your application or when you want to reset Formbricks.
|
||||
|
||||
<Col>
|
||||
<CodeGroup>
|
||||
|
||||
```js
|
||||
formbricks.logout();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
After calling formbricks.logout(), you'll need to reinitialize Formbricks before using any of its features again. Ensure that you properly reinitialize Formbricks to avoid unexpected errors or behavior in your application.
|
||||
|
||||
### Reset
|
||||
|
||||
Reset the current instance and fetch the latest surveys and state again:
|
||||
|
||||
<Col>
|
||||
<CodeGroup>
|
||||
|
||||
```js
|
||||
formbricks.reset();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
@@ -39,7 +39,7 @@ We currently have the following Management API methods exposed and below is thei
|
||||
- [Me API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#79e08365-641d-4b2d-aea2-9a855e0438ec) - Retrieve Account Information
|
||||
- [People API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#cffc27a6-dafb-428f-8ea7-5165bedb911e) - List and Delete People
|
||||
- [Response API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#e544ec0d-8b30-4e33-8d35-2441cb40d676) - List, List by Survey, Update, and Delete Responses
|
||||
- [Survey API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#953189b2-37b5-4429-a7bd-f4d01ceae242) - List, Create, Update, and Delete Surveys
|
||||
- [Survey API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#953189b2-37b5-4429-a7bd-f4d01ceae242) - List, Create, Update, generate multiple suId and Delete Surveys
|
||||
- [Webhook API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#62e6ec65-021b-42a4-ac93-d1434b393c6c) - List, Create, and Delete Webhooks
|
||||
|
||||
## How to Generate an API key
|
||||
|
||||
@@ -4,12 +4,12 @@ import I1 from "./images/1-set-up-website-micro-survey-popup.webp";
|
||||
export const metadata = {
|
||||
title: "Formbricks Website Survey SDK",
|
||||
description:
|
||||
"An overview of all available methods & how to integrate Formbricks Website Surveys for frontend developers in public-facing web applications. Learn the key methods, configuration settings, and best practices.",
|
||||
"Run targeted pop-up surveys on your public websites with the Formbricks JS SDK for Website Surveys. Learn how to integrate the SDK, track user actions, and trigger surveys based on user interactions.",
|
||||
};
|
||||
|
||||
#### Developer Docs
|
||||
|
||||
# SDK: Website Survey
|
||||
# SDK: Run Surveys On Public Websites
|
||||
|
||||
### Overview
|
||||
|
||||
|
||||
@@ -40,8 +40,7 @@ For more information on user roles & permissions, see below:
|
||||
| Update Member Access | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| Update Billing | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| **Product** | | | | | |
|
||||
| Create Product | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Update Product Name | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| Create Product | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| Update Product Name | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| Update Product Recontact Options | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Update Look & Feel | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
@@ -85,7 +84,7 @@ There are two ways to invite organization members: One by one or in bulk.
|
||||
src={MenuItem}
|
||||
alt="Where to find the Menu Item for Organization Settings"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Click on the `Add Member` button:
|
||||
@@ -94,7 +93,7 @@ There are two ways to invite organization members: One by one or in bulk.
|
||||
src={AddMember}
|
||||
alt="Add Member Button Position"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. In the modal, add the Name, Email and Role of the organization member you want to invite:
|
||||
@@ -103,7 +102,7 @@ There are two ways to invite organization members: One by one or in bulk.
|
||||
src={IndvInvite}
|
||||
alt="Individual Invite Modal Tab"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
<Note>
|
||||
@@ -121,7 +120,7 @@ Formbricks sends an email to the organization member with an invitation link. Th
|
||||
src={MenuItem}
|
||||
alt="Where to find the Menu Item for Organization Settings"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Click on the `Add Member` button:
|
||||
@@ -130,7 +129,7 @@ Formbricks sends an email to the organization member with an invitation link. Th
|
||||
src={AddMember}
|
||||
alt="Add Member Button Position"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. In the modal, switch to `Bulk Invite`. You can download an example .CSV file to fill in the Name, Email and Role of the organization members you want to invite:
|
||||
@@ -139,7 +138,7 @@ Formbricks sends an email to the organization member with an invitation link. Th
|
||||
src={BulkInvite}
|
||||
alt="Individual Invite Modal Tab"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
4. Upload the filled .CSV file and invite the organization members in bulk ✅
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import StepOne from "./images/StepOne.webp";
|
||||
import StepThree from "./images/StepThree.webp";
|
||||
import StepTwo from "./images/StepTwo.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Custom Start & End Conditions for Surveys",
|
||||
description:
|
||||
"Optimize your survey management with custom Start & End Conditions in Formbricks. This feature allows you to control exactly when your survey is available for responses and when it should close, making it ideal for time-sensitive or number-of-response-limited surveys.",
|
||||
};
|
||||
|
||||
# Custom Start & End Conditions
|
||||
|
||||
Optimize your survey management with custom Start & End Conditions in Formbricks. This feature allows you to control exactly when your survey is available for responses and when it should close, making it ideal for time-sensitive or number-of-response-limited surveys.
|
||||
|
||||
Configure your surveys to open and close based on specific criteria. Here’s how to set up these conditions:
|
||||
|
||||
### **Opening a Survey**
|
||||
|
||||
**1. Schedule a Start Date:**
|
||||
|
||||
- **How to Set**: Open the Survey Editor, switch to the Settings tab. Scroll down to Response Options, Toggle the “Release Survey on Date”.
|
||||
|
||||
<MdxImage
|
||||
src={StepOne}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
/>
|
||||
|
||||
- **Details**: Choose the date and time when the survey should become available to respondents. All times follow UTC timezone.
|
||||
- **Use Case**: This is useful for launching surveys in alignment with events, product releases, or specific marketing campaigns.
|
||||
|
||||
### **Closing a Survey**
|
||||
|
||||
**1. Limit by Number of Responses:**
|
||||
|
||||
- **How to Set**: Open the Survey Editor, switch to the Settings tab. Scroll down to Response Options, Toggle the “Close survey on response limit”.
|
||||
{" "}
|
||||
<MdxImage
|
||||
src={StepTwo}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
/>
|
||||
- **Details**: Set a specific number of responses after which the survey automatically closes.
|
||||
- **Use Case**: Perfect for limited offers, exclusive surveys, or when you need a precise sample size for statistical significance.
|
||||
|
||||
**2. Schedule an End Date:**
|
||||
|
||||
- **How to Set**: Open the Survey Editor, switch to the Settings tab. Scroll down to Response Options, Toggle the “Close survey on date”.
|
||||
|
||||
<MdxImage
|
||||
src={StepThree}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
/>
|
||||
- **Details**: Define a specific date and time for the survey to close. This also follows UTC timezone. - **Use
|
||||
Case**: Essential for surveys linked to time-bound events or studies where data collection needs to end at a specific
|
||||
point.
|
||||
|
||||
### **Summary**
|
||||
|
||||
Setting up Custom Start & End Conditions in Formbricks allows you to control the availability and duration of your surveys with precision. Whether you are conducting academic research, market analysis, or gathering event feedback, these settings help ensure that your data collection aligns perfectly with your objectives.
|
||||
|
||||
---
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
28
apps/docs/app/global/limit-submissions/page.mdx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import StepOne from "./images/StepOne.webp";
|
||||
import StepThree from "./images/StepThree.webp";
|
||||
import StepTwo from "./images/StepTwo.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.
|
||||
|
||||
---
|
||||
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 17 KiB |
BIN
apps/docs/app/global/logic-editor/images/action-calculate.webp
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
apps/docs/app/global/logic-editor/images/action-jump.webp
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
apps/docs/app/global/logic-editor/images/action-options.webp
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
apps/docs/app/global/logic-editor/images/action-require.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
apps/docs/app/global/logic-editor/images/add-logic.webp
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
apps/docs/app/global/logic-editor/images/condition-chaining.webp
Normal file
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 34 KiB |
BIN
apps/docs/app/global/logic-editor/images/condition-options.webp
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
apps/docs/app/global/logic-editor/images/condition-value.webp
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
apps/docs/app/global/logic-editor/images/conditions.webp
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
apps/docs/app/global/logic-editor/images/editor.webp
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
apps/docs/app/global/logic-editor/images/question-logic.webp
Normal file
|
After Width: | Height: | Size: 41 KiB |
171
apps/docs/app/global/logic-editor/page.mdx
Normal file
@@ -0,0 +1,171 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
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: "Logic Editor",
|
||||
description:
|
||||
"Create complex survey logic with the Logic Editor. Use conditions, actions, and variables to create a personalized survey experience.",
|
||||
};
|
||||
|
||||
# Logic Editor
|
||||
|
||||
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"
|
||||
/>
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 16 KiB |
51
apps/docs/app/global/schedule-start-end-dates/page.mdx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import StepOne from "./images/StepOne.webp";
|
||||
import StepThree from "./images/StepThree.webp";
|
||||
import StepTwo from "./images/StepTwo.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Schedule Start & End Dates for Surveys",
|
||||
description:
|
||||
"Automatically release and close surveys based on specific dates.",
|
||||
};
|
||||
|
||||
# Schedule Start & End Dates
|
||||
|
||||
Optimize your survey management with custom Start & End Conditions in Formbricks. This feature allows you to control exactly when your survey is available for responses and when it should close, making it ideal for time-sensitive or number-of-response-limited surveys.
|
||||
|
||||
Configure your surveys to open and close based on specific criteria. Here’s how to set up these conditions:
|
||||
|
||||
## **Schedule a Survey Release**
|
||||
|
||||
- **How to**: Open the Survey Editor, switch to the Settings tab. Scroll down to Response Options, Toggle the “Release Survey on Date”.
|
||||
|
||||
<MdxImage
|
||||
src={StepOne}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
/>
|
||||
|
||||
- **Details**: Choose the date and time when the survey should become available to respondents. All times follow UTC timezone.
|
||||
- **Use Case**: This is useful for launching surveys in alignment with events, product releases, or specific marketing campaigns.
|
||||
|
||||
## **Automatically Closing a Survey**
|
||||
|
||||
- **How to**: Open the Survey Editor, switch to the Settings tab. Scroll down to Response Options, Toggle the “Close survey on date”.
|
||||
|
||||
<MdxImage
|
||||
src={StepThree}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
/>
|
||||
- **Details**: Define a specific date and time for the survey to close. This also follows UTC timezone. - **Use
|
||||
Case**: Essential for surveys linked to time-bound events or studies where data collection needs to end at a specific
|
||||
point.
|
||||
|
||||
### **Summary**
|
||||
|
||||
Setting up Start & End Dates in Formbricks allows you to control the availability and duration of your surveys with precision. Whether you are conducting academic research, market analysis, or gathering event feedback, these settings help ensure that your data collection aligns perfectly with your objectives.
|
||||
|
||||
---
|
||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 24 KiB |
75
apps/docs/app/global/shareable-dashboards/page.mdx
Normal file
@@ -0,0 +1,75 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
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.
|
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 43 KiB |
@@ -3,13 +3,17 @@ import { TellaVideo } from "@/components/TellaVideo";
|
||||
|
||||
import EmailContentWithSurvey from "./images/email-content-with-survey.webp";
|
||||
import EmailContentWithoutSurvey from "./images/email-content-without-survey.webp";
|
||||
import EmbedModeDisabled from "./images/embed-mode-disabled.webp";
|
||||
import EmbedModeEnabled from "./images/embed-mode-enabled.webp";
|
||||
import EmbedModeToggle from "./images/embed-mode-toggle.webp";
|
||||
import JoSignature from "./images/jo-signature.webp";
|
||||
import PluginAddSurvey from "./images/plugin-add-survey.webp";
|
||||
import PluginSourceTab from "./images/plugin-source-tab.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Embed Surveys in Your Web Page & Email",
|
||||
description: "Embed Formbricks surveys seamlessly into your website using an iframe & Email using code snippets.",
|
||||
description:
|
||||
"Embed Formbricks surveys seamlessly into your website using an iframe & Email using code snippets.",
|
||||
};
|
||||
|
||||
#### Embed Surveys
|
||||
@@ -87,6 +91,43 @@ window.addEventListener("message", (event) => {
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
## Emebd Mode
|
||||
|
||||
Embed your survey with a minimalist design, disregarding padding and background.
|
||||
|
||||
### How to enable it?
|
||||
|
||||
It can be enabled by simply appending **?embed=true** to your survey link or from UI
|
||||
|
||||
1. Open Embed survey tab in survey share modal
|
||||
|
||||
2. Toggle **Embed mode**
|
||||
|
||||
<MdxImage
|
||||
src={EmbedModeToggle}
|
||||
alt="Toggle embed mode"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### With Embed mode enabled
|
||||
|
||||
<MdxImage
|
||||
src={EmbedModeEnabled}
|
||||
alt="Toggle embed mode"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### With Embed mode disabled
|
||||
|
||||
<MdxImage
|
||||
src={EmbedModeDisabled}
|
||||
alt="Toggle embed mode"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Embedding Surveys in Emails
|
||||
|
||||
Embedding Formbricks surveys directly into your emails allows you to collect valuable feedback from your users at every touchpoint. Seamlessly integrate interactive surveys into your email campaigns to gather insights and improve user experience.
|
||||
@@ -127,7 +168,7 @@ Gmail does not support HTML embedding natively. It's a WYSIWYG (What You See Is
|
||||
src={EmailContentWithoutSurvey}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
- Right next to the Send button you will see a new button called **HTML Editor**. Click on it.
|
||||
@@ -139,7 +180,7 @@ Gmail does not support HTML embedding natively. It's a WYSIWYG (What You See Is
|
||||
src={PluginSourceTab}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
- Now paste the copied HTML code from Formbricks into this window. On the right, you will see a preview of how the email will look.
|
||||
@@ -150,7 +191,7 @@ Gmail does not support HTML embedding natively. It's a WYSIWYG (What You See Is
|
||||
src={PluginAddSurvey}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
- Click on the **Close Editor** button to save the changes & close the editor.
|
||||
@@ -161,7 +202,7 @@ Gmail does not support HTML embedding natively. It's a WYSIWYG (What You See Is
|
||||
src={EmailContentWithSurvey}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
- Voila! You have successfully embedded the survey in your email.
|
||||
@@ -199,7 +240,7 @@ Embed a survey link in your email signature to collect feedback subtly yet effec
|
||||
src={JoSignature}
|
||||
alt="Choose a link survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
1. Create a Survey: Adjust an existing survey or create a new one.
|
||||
|
||||
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 12 KiB |
131
apps/docs/app/link-surveys/market-research-panel/page.mdx
Normal file
@@ -0,0 +1,131 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import CopySurveyLink from "./copy-survey-link.webp";
|
||||
import CreateStudy from "./create-study.webp";
|
||||
import HiddenFields from "./hidden-fields.webp";
|
||||
import PreviewComplete from "./preview-complete.webp";
|
||||
import PreviewStudy from "./preview-study.webp";
|
||||
import AddRedirectUrl from "./redirect-url-formbricks.webp";
|
||||
import RedirectUrl from "./redirect-url.webp";
|
||||
import ScreeningOut from "./screening-out.webp";
|
||||
import UrlParameters from "./url-parameters.webp";
|
||||
|
||||
|
||||
export const metadata = {
|
||||
title: "Creating a Research Panel with Prolific",
|
||||
description:
|
||||
"Formbricks surveys can be integrated with Prolifics participant panel easily. This tutorial walks you through the steps on how to access a pool of over 200.000 participants for your research.",
|
||||
};
|
||||
|
||||
#### Research Panel
|
||||
|
||||
# Creating a Research Panel with Prolific
|
||||
|
||||
You need a lot of research participants that match your target audience fast?
|
||||
|
||||
Formbricks integrates well with Prolific. Prolific provides a pool of over 200.000 research participants you can choose from. Run market research with Formbricks within hours, not days.
|
||||
|
||||
<Note>
|
||||
Prolific is a paid service. You need to fund your account to access the pool of participants. The cost depends on the number of participants you want to reach and the demographics you're targeting. You can get an estimate of the cost with the [Prolific price calculator](https://www.prolific.com/calculator)
|
||||
</Note>
|
||||
|
||||
## Purpose
|
||||
|
||||
External research panels are useful when:
|
||||
|
||||
- You don't have access to enough people who match your target audience
|
||||
- You want to reach a specific demographic
|
||||
- You want to reach a large number of people quickly
|
||||
|
||||
## Steps to Follow
|
||||
|
||||
### Step 1: Add hidden fields to the Formbricks survey
|
||||
To be able to attribute a completed answer to a research participant, you need to add hidden fields to your Formbricks survey. To do so, edit your survey and scroll down to the Hidden Fields card.
|
||||
|
||||
Add three fields with the IDs `PROLIFIC_PID`, `STUDY_ID`, and `SESSION_ID`.
|
||||
|
||||
<MdxImage
|
||||
src={HiddenFields}
|
||||
alt="Hidden fields added"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Step 2: Create an account on Prolific
|
||||
Go to [Prolific](https://app.prolific.co/) and create an account.
|
||||
|
||||
### Step 3: Create a study on Prolific
|
||||
Once you're logged in to Prolific, create a new study.
|
||||
<MdxImage
|
||||
src={CreateStudy}
|
||||
alt="Create a study on Prolific"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
|
||||
### Step 4: Copy the Formbricks survey link to the Prolific study
|
||||
We connect the Formbricks survey with the Prolific study by copying the survey link from Formbricks and pasting it into the Prolific study:
|
||||
|
||||
<MdxImage
|
||||
src={CopySurveyLink}
|
||||
alt="Copy the survey link"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Step 5: Choose URL parameters for attribution
|
||||
To attribute responses to the correct participant, you need to add URL parameters to the Formbricks survey link. The parameters are `PROLIFIC_PID`, `STUDY_ID`, and `SESSION_ID`, exactly like the hidden fields you added.
|
||||
<MdxImage
|
||||
src={UrlParameters}
|
||||
alt="Adding URL parameters to the survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Step 6: Update the Formbricks Redirect URL
|
||||
To ensure that participants are redirected back to Prolific after completing the survey, add the redirect URL provided in the Prolific study setup (e.g. `https://app.prolific.co/submissions/complete?cc=I2PWSFRG`)
|
||||
|
||||
Copy from Prolific:
|
||||
<MdxImage
|
||||
src={RedirectUrl}
|
||||
alt="Copy redirect URL"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Set it up as Redirect URL in the Response Options in Formbricks:
|
||||
<MdxImage
|
||||
src={AddRedirectUrl}
|
||||
alt="Add redirect URL to Formbricks"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Step 7: Preview the study
|
||||
Preview the study using Prolific's [Preview-functionality](https://researcher-help.prolific.com/hc/en-gb/articles/360009222853-Previewing-your-study)
|
||||
|
||||
<MdxImage
|
||||
src={PreviewStudy}
|
||||
alt="Preview study"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Got to the success screen? Then you're ready to publish your study!
|
||||
<MdxImage
|
||||
src={PreviewComplete}
|
||||
alt="Preview complete"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Step 8: Publish the study
|
||||
After you've published the study, you'll get the first responses within a few hours.
|
||||
|
||||
<Note>
|
||||
Prolific is a paid service. You need to fund your account to publish your study.
|
||||
</Note>
|
||||
|
||||
### That's it! 🎉
|
||||
Once you've published the survey, you can sit back and watch the responses come in. Prolific will take care of the rest.
|
||||
|
After Width: | Height: | Size: 16 KiB |