Compare commits
116 Commits
hotfix/pro
...
v2.0.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db03ce70d2 | ||
|
|
a44198539d | ||
|
|
7dbac97883 | ||
|
|
df6cf5a1c5 | ||
|
|
ffa774db6a | ||
|
|
6d6a47a5ac | ||
|
|
50e373a98a | ||
|
|
b56b2adb54 | ||
|
|
af09e315c5 | ||
|
|
1848e062f1 | ||
|
|
c8f2f94361 | ||
|
|
be52763be4 | ||
|
|
5dd5816c34 | ||
|
|
16f5ce40d9 | ||
|
|
223937adcc | ||
|
|
4544cba858 | ||
|
|
1284adf91d | ||
|
|
4b13d19ed9 | ||
|
|
12a606a443 | ||
|
|
052f86b19f | ||
|
|
27b37a5f27 | ||
|
|
c37d3ae0f9 | ||
|
|
e69bb3501d | ||
|
|
eda9c00548 | ||
|
|
6a7e0d3ecb | ||
|
|
48859facf4 | ||
|
|
732b8b599f | ||
|
|
00ad4c3895 | ||
|
|
4858bdd838 | ||
|
|
eee78a79d9 | ||
|
|
aa890affc9 | ||
|
|
10aed2d9d8 | ||
|
|
4d78b904b8 | ||
|
|
473cc7334b | ||
|
|
afdcac2465 | ||
|
|
e539ac82f3 | ||
|
|
c2fbb20787 | ||
|
|
084307bdb2 | ||
|
|
fd78cec5ac | ||
|
|
0b87d35877 | ||
|
|
9849a96f32 | ||
|
|
b5287f7f01 | ||
|
|
11888f3e38 | ||
|
|
d2b27b046b | ||
|
|
8f4f26c143 | ||
|
|
514d0a9e5a | ||
|
|
bc99f15094 | ||
|
|
ba0b68cbfb | ||
|
|
fb33005051 | ||
|
|
5da9091aee | ||
|
|
a91a5e7014 | ||
|
|
87a623a796 | ||
|
|
ed75089ee0 | ||
|
|
a04e031f9e | ||
|
|
3c91dd52a0 | ||
|
|
c282f630c4 | ||
|
|
49bf9ec8a9 | ||
|
|
2b74054f4b | ||
|
|
64793132c7 | ||
|
|
ed946da338 | ||
|
|
95f8c2b49f | ||
|
|
5fb97008f3 | ||
|
|
555f5c3ea0 | ||
|
|
50407498ec | ||
|
|
556ee870b1 | ||
|
|
0cad316fca | ||
|
|
d98df5ed3b | ||
|
|
e718217ec4 | ||
|
|
d4dea7c2cc | ||
|
|
6bfd02794d | ||
|
|
b016d80cb2 | ||
|
|
f529f5eda3 | ||
|
|
3a1683eebd | ||
|
|
2ca38b1918 | ||
|
|
82504e54b1 | ||
|
|
61d8970420 | ||
|
|
5c265aacb9 | ||
|
|
bb2c884150 | ||
|
|
7c388c975a | ||
|
|
fc18950885 | ||
|
|
386436ad5f | ||
|
|
328579f530 | ||
|
|
bc28936b2a | ||
|
|
a9a09f3d24 | ||
|
|
8a2d196319 | ||
|
|
e707713385 | ||
|
|
fc150170d0 | ||
|
|
0e102ead33 | ||
|
|
1cba959d9b | ||
|
|
2c2d3839f9 | ||
|
|
fb5474f61e | ||
|
|
518d6cc336 | ||
|
|
2262370354 | ||
|
|
48afdd1639 | ||
|
|
fc5adde0a9 | ||
|
|
ff78e63b24 | ||
|
|
8b5443671c | ||
|
|
8ef6dc0a07 | ||
|
|
686031e61a | ||
|
|
e95a8c760c | ||
|
|
7751a3fcfd | ||
|
|
5baa2369b4 | ||
|
|
f5236426ee | ||
|
|
a6568ea539 | ||
|
|
460c046f0a | ||
|
|
d41d60d877 | ||
|
|
c517eff308 | ||
|
|
0f99a59ea5 | ||
|
|
3836b529fd | ||
|
|
15e6e60b62 | ||
|
|
5856a77064 | ||
|
|
1192936be2 | ||
|
|
4c351f8461 | ||
|
|
c6c6c31d6d | ||
|
|
19cf9972d6 | ||
|
|
7b789904f8 |
13
.github/actions/cache-build-web/action.yml
vendored
@@ -1,5 +1,13 @@
|
||||
name: Build & Cache Web App
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
e2e_testing_mode:
|
||||
description: "Set E2E Testing Mode"
|
||||
required: false
|
||||
default: "0"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
@@ -41,6 +49,11 @@ runs:
|
||||
run: cp .env.example .env
|
||||
shell: bash
|
||||
|
||||
- name: Add E2E Testing Mode
|
||||
run: |
|
||||
echo "E2E_TESTING=${{ inputs.e2e_testing_mode }}" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Generate Random ENCRYPTION_KEY
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
|
||||
26
.github/workflows/build-formbricks-com.yml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Build formbricks-com
|
||||
on:
|
||||
workflow_call:
|
||||
jobs:
|
||||
build:
|
||||
name: Build Formbricks-com
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
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: Build Formbricks-com
|
||||
run: pnpm build --filter=formbricks-com...
|
||||
2
.github/workflows/e2e.yml
vendored
@@ -13,6 +13,8 @@ jobs:
|
||||
|
||||
- name: Build & Cache Web Binaries
|
||||
uses: ./.github/actions/cache-build-web
|
||||
with:
|
||||
e2e_testing_mode: "1"
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
|
||||
131
.github/workflows/kamal-deploy.yml
vendored
@@ -1,131 +0,0 @@
|
||||
name: Kamal Deploy
|
||||
concurrency:
|
||||
group: deploy-to-kamal
|
||||
cancel-in-progress: false
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
Deploy:
|
||||
runs-on: ubuntu-latest
|
||||
environment: production
|
||||
env:
|
||||
DOCKER_BUILDKIT: 1
|
||||
IS_FORMBRICKS_CLOUD: ${{ vars.IS_FORMBRICKS_CLOUD }}
|
||||
WEBAPP_URL: ${{ vars.WEBAPP_URL }}
|
||||
MIGRATE_DATABASE_URL: ${{ secrets.MIGRATE_DATABASE_URL }}
|
||||
NEXTAUTH_URL: ${{ vars.NEXTAUTH_URL }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
|
||||
ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }}
|
||||
SHORT_URL_BASE: ${{ vars.SHORT_URL_BASE }}
|
||||
MAIL_FROM: ${{ secrets.MAIL_FROM }}
|
||||
SMTP_HOST: ${{ secrets.SMTP_HOST }}
|
||||
SMTP_PORT: ${{ secrets.SMTP_PORT }}
|
||||
SMTP_USER: ${{ secrets.SMTP_USER }}
|
||||
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
|
||||
PRIVACY_URL: ${{ vars.PRIVACY_URL }}
|
||||
TERMS_URL: ${{ vars.TERMS_URL }}
|
||||
IMPRINT_URL: ${{ vars.IMPRINT_URL }}
|
||||
GITHUB_ID: ${{ secrets.FB_GITHUB_ID }}
|
||||
GITHUB_SECRET: ${{ secrets.FB_GITHUB_SECRET }}
|
||||
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
|
||||
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
|
||||
AZUREAD_CLIENT_ID: ${{ secrets.AZUREAD_CLIENT_ID }}
|
||||
AZUREAD_CLIENT_SECRET: ${{ secrets.AZUREAD_CLIENT_SECRET }}
|
||||
AZUREAD_TENANT_ID: ${{ secrets.AZUREAD_TENANT_ID }}
|
||||
OIDC_CLIENT_ID: ${{ secrets.OIDC_CLIENT_ID }}
|
||||
OIDC_CLIENT_SECRET: ${{ secrets.OIDC_CLIENT_SECRET }}
|
||||
OIDC_ISSUER: ${{ secrets.OIDC_ISSUER }}
|
||||
OIDC_DISPLAY_NAME: ${{ secrets.OIDC_DISPLAY_NAME }}
|
||||
OIDC_SIGNING_ALGORITHM: ${{ secrets.OIDC_SIGNING_ALGORITHM }}
|
||||
CRON_SECRET: ${{ secrets.CRON_SECRET }}
|
||||
ASSET_PREFIX_URL: ${{ vars.ASSET_PREFIX_URL }}
|
||||
NOTION_OAUTH_CLIENT_ID: ${{ secrets.NOTION_OAUTH_CLIENT_ID }}
|
||||
NOTION_OAUTH_CLIENT_SECRET: ${{ secrets.NOTION_OAUTH_CLIENT_SECRET }}
|
||||
SLACK_CLIENT_ID: ${{ secrets.SLACK_CLIENT_ID }}
|
||||
SLACK_CLIENT_SECRET: ${{ secrets.SLACK_CLIENT_SECRET }}
|
||||
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ secrets.STRIPE_WEBHOOK_SECRET }}
|
||||
GOOGLE_SHEETS_CLIENT_ID: ${{ secrets.GOOGLE_SHEETS_CLIENT_ID }}
|
||||
GOOGLE_SHEETS_CLIENT_SECRET: ${{ secrets.GOOGLE_SHEETS_CLIENT_SECRET }}
|
||||
GOOGLE_SHEETS_REDIRECT_URL: ${{ secrets.GOOGLE_SHEETS_REDIRECT_URL }}
|
||||
AIRTABLE_CLIENT_ID: ${{ secrets.AIRTABLE_CLIENT_ID }}
|
||||
ENTERPRISE_LICENSE_KEY: ${{ secrets.ENTERPRISE_LICENSE_KEY }}
|
||||
DEFAULT_TEAM_ID: ${{ vars.DEFAULT_TEAM_ID }}
|
||||
ONBOARDING_DISABLED: ${{ vars.ONBOARDING_DISABLED }}
|
||||
CUSTOMER_IO_API_KEY: ${{ secrets.CUSTOMER_IO_API_KEY }}
|
||||
CUSTOMER_IO_SITE_ID: ${{ secrets.CUSTOMER_IO_SITE_ID }}
|
||||
NEXT_PUBLIC_POSTHOG_API_KEY: ${{ vars.NEXT_PUBLIC_POSTHOG_API_KEY }}
|
||||
NEXT_PUBLIC_POSTHOG_API_HOST: ${{ vars.NEXT_PUBLIC_POSTHOG_API_HOST }}
|
||||
NEXT_PUBLIC_FORMBRICKS_API_HOST: ${{ vars.NEXT_PUBLIC_FORMBRICKS_API_HOST }}
|
||||
NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID }}
|
||||
NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID }}
|
||||
NEXT_PUBLIC_SENTRY_DSN: ${{ vars.NEXT_PUBLIC_SENTRY_DSN }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
NODE_ENV: production
|
||||
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
|
||||
CLOUDFLARE_DNS_API_TOKEN: ${{ secrets.CLOUDFLARE_DNS_API_TOKEN }}
|
||||
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
|
||||
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||
S3_REGION: ${{ vars.S3_REGION }}
|
||||
S3_BUCKET_NAME: ${{ vars.S3_BUCKET_NAME }}
|
||||
OPENTELEMETRY_LISTENER_URL: ${{ vars.OPENTELEMETRY_LISTENER_URL }}
|
||||
RATE_LIMITING_DISABLED: ${{ vars.RATE_LIMITING_DISABLED }}
|
||||
KAMAL_REGISTRY_PASSWORD: ${{ secrets.KAMAL_REGISTRY_PASSWORD }}
|
||||
DB_HOST: ${{ secrets.DB_HOST }}
|
||||
DB_USER: ${{ secrets.DB_USER }}
|
||||
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
|
||||
DB_NAME: ${{ secrets.DB_NAME }}
|
||||
REDIS_URL: ${{ secrets.REDIS_URL }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.3.0
|
||||
bundler-cache: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
gem install kamal
|
||||
|
||||
- uses: webfactory/ssh-agent@v0.9.0
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Create builder
|
||||
run: docker buildx create --use --name formbricks-gh-actions-builder
|
||||
if: steps.buildx.outputs.should_create_builder == 'true'
|
||||
|
||||
- name: Push env variables to Kamal
|
||||
run: |
|
||||
kamal() { command kamal "$@" -c kamal/deploy.yml; }
|
||||
kamal env push
|
||||
|
||||
- name: Run deploy command
|
||||
run: |
|
||||
kamal() { command kamal "$@" -c kamal/deploy.yml; }
|
||||
set +e
|
||||
DEPLOY_OUTPUT=$(kamal deploy 2>&1)
|
||||
DEPLOY_EXIT_CODE=$?
|
||||
echo "$DEPLOY_OUTPUT"
|
||||
if [[ "$DEPLOY_OUTPUT" == *"container not unhealthy (healthy)"* ]]; then
|
||||
echo "Deployment reported healthy container. Considering as success."
|
||||
kamal lock release
|
||||
exit 0
|
||||
else
|
||||
exit $DEPLOY_EXIT_CODE
|
||||
fi
|
||||
shell: bash
|
||||
128
.github/workflows/kamal-setup.yml
vendored
@@ -1,128 +0,0 @@
|
||||
name: Kamal Setup
|
||||
concurrency:
|
||||
group: setup-kamal
|
||||
cancel-in-progress: false
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Only to be triggered when accessories are updated
|
||||
|
||||
jobs:
|
||||
Setup:
|
||||
runs-on: ubuntu-latest
|
||||
environment: production
|
||||
env:
|
||||
DOCKER_BUILDKIT: 1
|
||||
IS_FORMBRICKS_CLOUD: ${{ vars.IS_FORMBRICKS_CLOUD }}
|
||||
WEBAPP_URL: ${{ vars.WEBAPP_URL }}
|
||||
NEXTAUTH_URL: ${{ vars.NEXTAUTH_URL }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
MIGRATE_DATABASE_URL: ${{ secrets.MIGRATE_DATABASE_URL }}
|
||||
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
|
||||
ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }}
|
||||
SHORT_URL_BASE: ${{ vars.SHORT_URL_BASE }}
|
||||
MAIL_FROM: ${{ secrets.MAIL_FROM }}
|
||||
SMTP_HOST: ${{ secrets.SMTP_HOST }}
|
||||
SMTP_PORT: ${{ secrets.SMTP_PORT }}
|
||||
SMTP_USER: ${{ secrets.SMTP_USER }}
|
||||
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
|
||||
PRIVACY_URL: ${{ vars.PRIVACY_URL }}
|
||||
TERMS_URL: ${{ vars.TERMS_URL }}
|
||||
IMPRINT_URL: ${{ vars.IMPRINT_URL }}
|
||||
GITHUB_ID: ${{ secrets.FB_GITHUB_ID }}
|
||||
GITHUB_SECRET: ${{ secrets.FB_GITHUB_SECRET }}
|
||||
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
|
||||
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
|
||||
AZUREAD_CLIENT_ID: ${{ secrets.AZUREAD_CLIENT_ID }}
|
||||
AZUREAD_CLIENT_SECRET: ${{ secrets.AZUREAD_CLIENT_SECRET }}
|
||||
AZUREAD_TENANT_ID: ${{ secrets.AZUREAD_TENANT_ID }}
|
||||
OIDC_CLIENT_ID: ${{ secrets.OIDC_CLIENT_ID }}
|
||||
OIDC_CLIENT_SECRET: ${{ secrets.OIDC_CLIENT_SECRET }}
|
||||
OIDC_ISSUER: ${{ secrets.OIDC_ISSUER }}
|
||||
OIDC_DISPLAY_NAME: ${{ secrets.OIDC_DISPLAY_NAME }}
|
||||
OIDC_SIGNING_ALGORITHM: ${{ secrets.OIDC_SIGNING_ALGORITHM }}
|
||||
CRON_SECRET: ${{ secrets.CRON_SECRET }}
|
||||
ASSET_PREFIX_URL: ${{ vars.ASSET_PREFIX_URL }}
|
||||
NOTION_OAUTH_CLIENT_ID: ${{ secrets.NOTION_OAUTH_CLIENT_ID }}
|
||||
NOTION_OAUTH_CLIENT_SECRET: ${{ secrets.NOTION_OAUTH_CLIENT_SECRET }}
|
||||
SLACK_CLIENT_ID: ${{ secrets.SLACK_CLIENT_ID }}
|
||||
SLACK_CLIENT_SECRET: ${{ secrets.SLACK_CLIENT_SECRET }}
|
||||
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ secrets.STRIPE_WEBHOOK_SECRET }}
|
||||
GOOGLE_SHEETS_CLIENT_ID: ${{ secrets.GOOGLE_SHEETS_CLIENT_ID }}
|
||||
GOOGLE_SHEETS_CLIENT_SECRET: ${{ secrets.GOOGLE_SHEETS_CLIENT_SECRET }}
|
||||
GOOGLE_SHEETS_REDIRECT_URL: ${{ secrets.GOOGLE_SHEETS_REDIRECT_URL }}
|
||||
AIRTABLE_CLIENT_ID: ${{ secrets.AIRTABLE_CLIENT_ID }}
|
||||
ENTERPRISE_LICENSE_KEY: ${{ secrets.ENTERPRISE_LICENSE_KEY }}
|
||||
DEFAULT_TEAM_ID: ${{ vars.DEFAULT_TEAM_ID }}
|
||||
ONBOARDING_DISABLED: ${{ vars.ONBOARDING_DISABLED }}
|
||||
CUSTOMER_IO_API_KEY: ${{ secrets.CUSTOMER_IO_API_KEY }}
|
||||
CUSTOMER_IO_SITE_ID: ${{ secrets.CUSTOMER_IO_SITE_ID }}
|
||||
NEXT_PUBLIC_POSTHOG_API_KEY: ${{ vars.NEXT_PUBLIC_POSTHOG_API_KEY }}
|
||||
NEXT_PUBLIC_POSTHOG_API_HOST: ${{ vars.NEXT_PUBLIC_POSTHOG_API_HOST }}
|
||||
NEXT_PUBLIC_FORMBRICKS_API_HOST: ${{ vars.NEXT_PUBLIC_FORMBRICKS_API_HOST }}
|
||||
NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID }}
|
||||
NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID: ${{ vars.NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID }}
|
||||
NEXT_PUBLIC_SENTRY_DSN: ${{ vars.NEXT_PUBLIC_SENTRY_DSN }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
NODE_ENV: production
|
||||
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
|
||||
CLOUDFLARE_DNS_API_TOKEN: ${{ secrets.CLOUDFLARE_DNS_API_TOKEN }}
|
||||
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
|
||||
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||
S3_REGION: ${{ vars.S3_REGION }}
|
||||
S3_BUCKET_NAME: ${{ vars.S3_BUCKET_NAME }}
|
||||
OPENTELEMETRY_LISTENER_URL: ${{ vars.OPENTELEMETRY_LISTENER_URL }}
|
||||
RATE_LIMITING_DISABLED: ${{ vars.RATE_LIMITING_DISABLED }}
|
||||
KAMAL_REGISTRY_PASSWORD: ${{ secrets.KAMAL_REGISTRY_PASSWORD }}
|
||||
DB_HOST: ${{ secrets.DB_HOST }}
|
||||
DB_USER: ${{ secrets.DB_USER }}
|
||||
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
|
||||
DB_NAME: ${{ secrets.DB_NAME }}
|
||||
REDIS_URL: ${{ secrets.REDIS_URL }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.3.0
|
||||
bundler-cache: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
gem install kamal
|
||||
|
||||
- uses: webfactory/ssh-agent@v0.9.0
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Create builder
|
||||
run: docker buildx create --use --name formbricks-gh-actions-builder
|
||||
if: steps.buildx.outputs.should_create_builder == 'true'
|
||||
|
||||
- name: Push env variables to Kamal
|
||||
run: |
|
||||
kamal() { command kamal "$@" -c kamal/deploy.yml; }
|
||||
kamal env push
|
||||
|
||||
- name: Run setup command
|
||||
run: |
|
||||
kamal() { command kamal "$@" -c kamal/deploy.yml; }
|
||||
set +e
|
||||
DEPLOY_OUTPUT=$(kamal setup 2>&1)
|
||||
DEPLOY_EXIT_CODE=$?
|
||||
echo "$DEPLOY_OUTPUT"
|
||||
if [[ "$DEPLOY_OUTPUT" == *"container not unhealthy (healthy)"* ]]; then
|
||||
echo "Deployment reported healthy container. Considering as success."
|
||||
kamal lock release
|
||||
exit 0
|
||||
else
|
||||
exit $DEPLOY_EXIT_CODE
|
||||
fi
|
||||
shell: bash
|
||||
@@ -33,9 +33,7 @@ jobs:
|
||||
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@6e04d228eb30da1757ee4e1dd75a0ec73a653e06 #v3.1.1
|
||||
with:
|
||||
cosign-release: "v2.1.1"
|
||||
uses: sigstore/cosign-installer@v3.5.0
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
|
||||
6
.github/workflows/release-docker-github.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Docker
|
||||
name: Docker Release to Github
|
||||
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
@@ -41,9 +41,7 @@ jobs:
|
||||
# https://github.com/sigstore/cosign-installer
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@6e04d228eb30da1757ee4e1dd75a0ec73a653e06 #v3.1.1
|
||||
with:
|
||||
cosign-release: "v2.1.1"
|
||||
uses: sigstore/cosign-installer@v3.5.0
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
|
||||
@@ -224,7 +224,7 @@ Additional to the AGPL licensed Formbricks core, this repository contains code l
|
||||
|
||||
### White-Labeling Formbricks and Other Licensing Needs
|
||||
|
||||
If you have other licensing requirements such as White-Labeling please [send us an email](mailto:hola@formbricks.com).
|
||||
We currently do not offer Formbricks white-labeled. Any other needs? [Send us an email](mailto:hola@formbricks.com).
|
||||
|
||||
### Why charge for Enterprise Features?
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Sidebar from "./Sidebar";
|
||||
import { Sidebar } from "./Sidebar";
|
||||
|
||||
export default function LayoutApp({ children }: { children: React.ReactNode }) {
|
||||
export const LayoutApp = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<div className="min-h-full">
|
||||
{/* Static sidebar for desktop */}
|
||||
@@ -10,4 +10,4 @@ export default function LayoutApp({ children }: { children: React.ReactNode }) {
|
||||
<div className="flex flex-1 flex-col lg:pl-64">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ const secondaryNavigation = [
|
||||
{ name: "Privacy", href: "#", icon: ShieldCheckIcon },
|
||||
];
|
||||
|
||||
export default function Sidebar({}) {
|
||||
export const Sidebar = () => {
|
||||
return (
|
||||
<div className="flex flex-grow flex-col overflow-y-auto bg-cyan-700 pb-4 pt-5">
|
||||
<nav
|
||||
@@ -63,4 +63,4 @@ export default function Sidebar({}) {
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,12 +13,16 @@ export const SurveySwitch = ({ value, formbricks }: SurveySwitchProps) => {
|
||||
formbricks.logout();
|
||||
window.location.href = `/${v}`;
|
||||
}}>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectTrigger className="w-[180px] px-4">
|
||||
<SelectValue placeholder="Theme" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="website">Website Surveys</SelectItem>
|
||||
<SelectItem value="app">App Surveys</SelectItem>
|
||||
<SelectItem value="website" className="h-10 px-4 hover:bg-slate-100">
|
||||
Website Surveys
|
||||
</SelectItem>
|
||||
<SelectItem value="app" className="hover:bg-slate-10 h-10 px-4">
|
||||
App Surveys
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export function classNames(...classes: any) {
|
||||
export const classNames = (...classes: any) => {
|
||||
return classes.filter(Boolean).join(" ");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
"dependencies": {
|
||||
"@formbricks/js": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"lucide-react": "^0.373.0",
|
||||
"lucide-react": "^0.378.0",
|
||||
"next": "14.2.3",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-config-formbricks": "workspace:*",
|
||||
|
||||
@@ -3,7 +3,7 @@ import Head from "next/head";
|
||||
|
||||
import "../styles/globals.css";
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
const App = ({ Component, pageProps }: AppProps) => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
@@ -18,4 +18,6 @@ export default function App({ Component, pageProps }: AppProps) {
|
||||
<Component {...pageProps} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Head, Html, Main, NextScript } from "next/document";
|
||||
|
||||
export default function Document() {
|
||||
const Document = () => {
|
||||
return (
|
||||
<Html lang="en" className="h-full bg-slate-50">
|
||||
<Head />
|
||||
@@ -10,4 +10,6 @@ export default function Document() {
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Document;
|
||||
|
||||
@@ -2,14 +2,14 @@ import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import formbricksApp from "@formbricks/js/app";
|
||||
import formbricks from "@formbricks/js/app";
|
||||
|
||||
import { SurveySwitch } from "../../components/SurveySwitch";
|
||||
import fbsetup from "../../public/fb-setup.png";
|
||||
|
||||
declare const window: any;
|
||||
|
||||
export default function AppPage({}) {
|
||||
const AppPage = ({}) => {
|
||||
const [darkMode, setDarkMode] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
@@ -36,9 +36,13 @@ export default function AppPage({}) {
|
||||
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const userId = "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING";
|
||||
const userInitAttributes = { language: "de", "Init Attribute 1": "eight", "Init Attribute 2": "two" };
|
||||
const userInitAttributes = {
|
||||
language: "de",
|
||||
"Init Attribute 1": "eight",
|
||||
"Init Attribute 2": "two",
|
||||
};
|
||||
|
||||
formbricksApp.init({
|
||||
formbricks.init({
|
||||
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
|
||||
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
|
||||
userId,
|
||||
@@ -48,7 +52,7 @@ export default function AppPage({}) {
|
||||
|
||||
// Connect next.js router to Formbricks
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const handleRouteChange = formbricksApp?.registerRouteChange;
|
||||
const handleRouteChange = formbricks?.registerRouteChange;
|
||||
router.events.on("routeChangeComplete", handleRouteChange);
|
||||
|
||||
return () => {
|
||||
@@ -61,7 +65,7 @@ export default function AppPage({}) {
|
||||
<div className="h-screen bg-white px-12 py-6 dark:bg-slate-800">
|
||||
<div className="flex flex-col justify-between md:flex-row">
|
||||
<div className="flex items-center gap-2">
|
||||
<SurveySwitch value="app" formbricks={formbricksApp} />
|
||||
<SurveySwitch value="app" formbricks={formbricks} />
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
|
||||
Formbricks In-product Survey Demo App
|
||||
@@ -115,7 +119,7 @@ export default function AppPage({}) {
|
||||
</div>
|
||||
|
||||
<div className="md:grid md:grid-cols-3">
|
||||
<div className="col-span-3 rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-800">
|
||||
<div className="col-span-3 self-start rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-800">
|
||||
<h3 className="text-lg font-semibold dark:text-white">
|
||||
Reset person / pull data from Formbricks app
|
||||
</h3>
|
||||
@@ -126,7 +130,7 @@ export default function AppPage({}) {
|
||||
<button
|
||||
className="my-4 rounded-lg bg-slate-500 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
formbricksApp.reset();
|
||||
formbricks.reset();
|
||||
}}>
|
||||
Reset
|
||||
</button>
|
||||
@@ -136,26 +140,6 @@ export default function AppPage({}) {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
<div>
|
||||
<button
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
formbricksApp.track("Code Action");
|
||||
}}>
|
||||
Code Action
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sends a{" "}
|
||||
<a href="https://formbricks.com/docs/actions/code" className="underline" target="_blank">
|
||||
Code Action
|
||||
</a>{" "}
|
||||
to the Formbricks API called 'Code Action'. You will find it in the Actions Tab.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<div>
|
||||
<button className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
|
||||
@@ -185,7 +169,7 @@ export default function AppPage({}) {
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
formbricksApp.setAttribute("Plan", "Free");
|
||||
formbricks.setAttribute("Plan", "Free");
|
||||
}}
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
|
||||
Set Plan to 'Free'
|
||||
@@ -208,7 +192,7 @@ export default function AppPage({}) {
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
formbricksApp.setAttribute("Plan", "Paid");
|
||||
formbricks.setAttribute("Plan", "Paid");
|
||||
}}
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
|
||||
Set Plan to 'Paid'
|
||||
@@ -231,7 +215,7 @@ export default function AppPage({}) {
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
formbricksApp.setEmail("test@web.com");
|
||||
formbricks.setEmail("test@web.com");
|
||||
}}
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
|
||||
Set Email
|
||||
@@ -254,4 +238,6 @@ export default function AppPage({}) {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default AppPage;
|
||||
|
||||
@@ -2,14 +2,14 @@ import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import formbricksWebsite from "@formbricks/js/website";
|
||||
import formbricks from "@formbricks/js/website";
|
||||
|
||||
import { SurveySwitch } from "../../components/SurveySwitch";
|
||||
import fbsetup from "../../public/fb-setup.png";
|
||||
|
||||
declare const window: any;
|
||||
|
||||
export default function AppPage({}) {
|
||||
const AppPage = ({}) => {
|
||||
const [darkMode, setDarkMode] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
@@ -39,7 +39,7 @@ export default function AppPage({}) {
|
||||
language: "de",
|
||||
};
|
||||
|
||||
formbricksWebsite.init({
|
||||
formbricks.init({
|
||||
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
|
||||
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
|
||||
attributes: defaultAttributes,
|
||||
@@ -48,7 +48,7 @@ export default function AppPage({}) {
|
||||
|
||||
// Connect next.js router to Formbricks
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const handleRouteChange = formbricksWebsite?.registerRouteChange;
|
||||
const handleRouteChange = formbricks?.registerRouteChange;
|
||||
router.events.on("routeChangeComplete", handleRouteChange);
|
||||
|
||||
return () => {
|
||||
@@ -61,7 +61,7 @@ export default function AppPage({}) {
|
||||
<div className="h-screen bg-white px-12 py-6 dark:bg-slate-800">
|
||||
<div className="flex flex-col items-center justify-between md:flex-row">
|
||||
<div className="flex items-center gap-2">
|
||||
<SurveySwitch value="website" formbricks={formbricksWebsite} />
|
||||
<SurveySwitch value="website" formbricks={formbricks} />
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
|
||||
Formbricks Website Survey Demo App
|
||||
@@ -115,7 +115,7 @@ export default function AppPage({}) {
|
||||
</div>
|
||||
|
||||
<div className="md:grid md:grid-cols-3">
|
||||
<div className="col-span-3 rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-800">
|
||||
<div className="col-span-3 self-start rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-800">
|
||||
<h3 className="text-lg font-semibold dark:text-white">
|
||||
Reset person / pull data from Formbricks app
|
||||
</h3>
|
||||
@@ -126,7 +126,7 @@ export default function AppPage({}) {
|
||||
<button
|
||||
className="my-4 rounded-lg bg-slate-500 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
formbricksWebsite.reset();
|
||||
formbricks.reset();
|
||||
}}>
|
||||
Reset
|
||||
</button>
|
||||
@@ -135,62 +135,10 @@ export default function AppPage({}) {
|
||||
try again.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="pt-6">
|
||||
<div>
|
||||
<button
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
formbricksWebsite.track("New Session");
|
||||
}}>
|
||||
Track New Session
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sends an Action to the Formbricks API called 'New Session'. You will
|
||||
find it in the Actions Tab.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-6">
|
||||
<div>
|
||||
<button
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
formbricksWebsite.track("Exit Intent");
|
||||
}}>
|
||||
Track Exit Intent
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sends an Action to the Formbricks API called 'Exit Intent'. You can also
|
||||
move your mouse to the top of the browser to trigger the exit intent.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-6">
|
||||
<div>
|
||||
<button
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
formbricksWebsite.track("50% Scroll");
|
||||
}}>
|
||||
Track 50% Scroll
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sends an Action to the Formbricks API called '50% Scroll'. You can also
|
||||
scroll down to trigger the 50% scroll.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default AppPage;
|
||||
|
||||
@@ -35,3 +35,4 @@ yarn-error.log*
|
||||
next-env.d.ts
|
||||
|
||||
public/sitemap*.xml
|
||||
public/robots.txt
|
||||
BIN
apps/docs/app/app-surveys/actions/images/I1.webp
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
apps/docs/app/app-surveys/actions/images/I2.webp
Normal file
|
After Width: | Height: | Size: 34 KiB |
116
apps/docs/app/app-surveys/actions/page.mdx
Normal file
@@ -0,0 +1,116 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import I1 from "./images/I1.webp";
|
||||
import I2 from "./images/I2.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Using Actions in Formbricks | Fine-tuning User Moments",
|
||||
description:
|
||||
"Dive deep into how actions in Formbricks help products and teams to engage users at precise moments in their journey. Discover the power of actions, from coding to no-code setups, to refine user targeting and generate richer, more detailed user insights.",
|
||||
};
|
||||
|
||||
#### App Surveys
|
||||
|
||||
# Actions & Targeting
|
||||
|
||||
Understanding user thoughts and feelings at critical moments in their journey is pivotal. To achieve this, Formbricks uses user-centric actions that trigger surveys at precisely the right time. Actions are essentially notifications sent from your application to Formbricks when predefined user activities occur, making it possible to gather insights during key interactions.
|
||||
|
||||
<Note>
|
||||
Ensure that you’ve **initialized Formbricks with a userId** to fully utilize this feature along with other
|
||||
app survey capabilities.
|
||||
</Note>
|
||||
|
||||
## **How Do Actions Work?**
|
||||
|
||||
Actions in Formbricks App Surveys are deeply integrated with user activities within your app. When a user performs a specified action, the Formbricks widget detects this activity and can present a survey to that specific user if the trigger conditions match of that survey, while also recording the event. This capability ensures that surveys are not only triggered at the right time but are also tailored to the user’s recent interactions within the app. You can set up these actions through a user-friendly No-Code interface within the Formbricks dashboard.
|
||||
|
||||
## **Why Are Actions Useful?**
|
||||
|
||||
Actions are invaluable for enhancing survey relevance and effectiveness:
|
||||
|
||||
- **Personalized Engagement**: Surveys triggered by user actions ensure content is highly relevant and engaging, matching each user’s current context.
|
||||
- **User Attributes**: By tying surveys to specific user attributes, such as activity levels or feature usage, you can customize the survey experience to reflect individual user profiles.
|
||||
- **User Segments**: Analyze action data to create detailed user segments, targeting specific groups with surveys that are pertinent to their behaviors or interactions within the app.
|
||||
- **User Targeting**: Precise targeting based on user actions and attributes ensures that surveys are shown only to users who meet certain criteria, enhancing the relevance and effectiveness of each survey.
|
||||
|
||||
## **Setting Up No-Code Actions**
|
||||
|
||||
Formbricks offers an intuitive No-Code interface that allows you to configure actions without needing to write any code.
|
||||
|
||||
To add a No-Code Action:
|
||||
|
||||
1. Visit the Formbricks Dashboard & switch to the Actions tab:
|
||||
|
||||
<MdxImage
|
||||
src={I1}
|
||||
alt="setup checklist ui of survey popup for app surveys"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Now click on “Add Action”
|
||||
|
||||
<MdxImage
|
||||
src={I2}
|
||||
alt="setup checklist ui of survey popup for app surveys"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Here are three types of No-Code actions you can set up:
|
||||
|
||||
### **1. Page URL Action**
|
||||
|
||||
This action is triggered when a user visits a specific page within your application. You can define the URL match conditions as follows:
|
||||
|
||||
- **exactMatch**: Triggers the action when the URL exactly matches the specified string.
|
||||
- **contains**: Activates when the URL contains the specified substring.
|
||||
- **startsWith**: Fires when the URL starts with the specified string.
|
||||
- **endsWith**: Executes when the URL ends with the specified string.
|
||||
- **notMatch**: Triggers when the URL does not match the specified condition.
|
||||
- **notContains**: Activates when the URL does not contain the specified substring.
|
||||
|
||||
### **2. innerText Action**
|
||||
|
||||
Checks if the innerText of a clicked HTML element, like a button label, matches a specific text. This action allows you to display a survey based on text interactions within your application.
|
||||
|
||||
### **3. CSS Selector Action**
|
||||
|
||||
This action verifies if a clicked HTML element matches a provided CSS selector, such as a class, ID, or any other CSS selector used in your website. It enables survey triggers based on element interactions.
|
||||
|
||||
<Note>You can have an action use combination of the 3 types as you wish</Note>
|
||||
|
||||
## **Setting Up Code Actions**
|
||||
|
||||
For more granular control, you can implement actions directly in your codebase:
|
||||
|
||||
1. **Configure the Action**: First, add the action via the Formbricks web interface to make it available for survey configuration.
|
||||
After that you can fire an action using `formbricks.track()`
|
||||
|
||||
2. **Track an Action**: Use formbricks.track() to send an action event to Formbricks.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Track an action">
|
||||
|
||||
```javascript
|
||||
formbricks.track("Action Name");
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
Here is an example of how to fire an action when a user clicks a button:
|
||||
<Col>
|
||||
<CodeGroup title="Track Button Click">
|
||||
|
||||
```javascript
|
||||
const handleClick = () => {
|
||||
formbricks.track("Button Clicked");
|
||||
};
|
||||
|
||||
return <button onClick={handleClick}>Click Me</button>;
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
This documentation frames actions around user interactions, emphasizing the connection between the user's activities and the survey experience. By leveraging user-centric actions, you can create highly targeted and timely surveys that resonate with users and yield valuable insights.
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@@ -1,4 +1,5 @@
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import { ResponsiveVideo } from "@/components/ResponsiveVideo";
|
||||
|
||||
import GermansGpt from "./germans-gpt.webp";
|
||||
import Hni from "./hni.webp";
|
||||
@@ -12,19 +13,15 @@ export const metadata = {
|
||||
"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.",
|
||||
};
|
||||
|
||||
#### In-App Surveys
|
||||
#### 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.
|
||||
|
||||
<iframe
|
||||
width="700"
|
||||
height="450"
|
||||
src="https://www.youtube.com/embed/0BQp6N4cXzU?si=gyeEZRXZ6Kei1zzm"
|
||||
title="YouTube video player: Formbricks"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe>
|
||||
<ResponsiveVideo title="Formbricks Multi-language Surveys"
|
||||
src="https://www.youtube-nocookie.com/embed/0BQp6N4cXzU?si=KeBM7G7Ch1xtrsOm&controls=0" />
|
||||
|
||||
|
||||
## How to setup Advanced Targeting
|
||||
|
||||
@@ -33,7 +30,7 @@ Advanced Targeting allows you to show surveys to the right group of people. You
|
||||
details to start the freemium plan.
|
||||
</Note>
|
||||
|
||||
1. On the Formbricks dashboard, click on **People & Segments** tab from the top navigation bar.
|
||||
1. On the Formbricks dashboard, click on **People** tab from the top navigation bar.
|
||||
|
||||
2. Switch to the **Segments** tab & click on **Create Segment**.
|
||||
|
||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
@@ -1,11 +1,10 @@
|
||||
import logoHtml from "@/images/logos/html5.svg";
|
||||
import logoNextjs from "@/images/logos/nextjs.svg";
|
||||
import logoReactJs from "@/images/logos/reactjs.svg";
|
||||
import logoVueJs from "@/images/logos/vuejs.svg";
|
||||
import { Button } from "@/components/Button";
|
||||
import logoHtml from "@/images/frameworks/html5.svg";
|
||||
import logoNextjs from "@/images/frameworks/nextjs.svg";
|
||||
import logoReactJs from "@/images/frameworks/reactjs.svg";
|
||||
import logoVueJs from "@/images/frameworks/vuejs.svg";
|
||||
import Image from "next/image";
|
||||
|
||||
import { Button } from "./Button";
|
||||
|
||||
const libraries = [
|
||||
{
|
||||
href: "#html",
|
||||
@@ -34,7 +33,7 @@ const libraries = [
|
||||
},
|
||||
];
|
||||
|
||||
export function Libraries() {
|
||||
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">
|
||||
@@ -58,4 +57,4 @@ export function Libraries() {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
BIN
apps/docs/app/app-surveys/framework-guides/images/env-id.webp
Normal file
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
@@ -1,10 +1,10 @@
|
||||
import { Libraries } from "@/components/docs/Libraries";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import SetupChecklist from "./env-id.webp";
|
||||
import ReactApp from "./react-in-app-survey-app-popup-form.webp";
|
||||
import WidgetConnected from "./widget-connected.webp";
|
||||
import WidgetNotConnected from "./widget-not-connected.webp";
|
||||
import { Libraries } from "./components/Libraries";
|
||||
|
||||
import ReactApp from "./images/react-in-app-survey-app-popup-form.webp";
|
||||
import WidgetConnected from "./images/widget-connected.webp";
|
||||
import WidgetNotConnected from "./images/widget-not-connected.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Integrate Formbricks: Comprehensive Framework Guide & Integration Tutorial",
|
||||
@@ -14,8 +14,8 @@ export const metadata = {
|
||||
|
||||
# Framework Guides
|
||||
|
||||
One can integrate Formbricks into their app using multiple options! Checkout the options below that we provide! If you are looking
|
||||
for something else, please [join our Discord!](https://formbricks.com/discord) and we would be glad to help. {{ className: 'lead' }}
|
||||
One can integrate Formbricks App Survey SDK into their app using multiple options! Checkout the options below that we provide! If you are looking
|
||||
for something else, please [join our Discord!](https://formbricks.com/discord) and we would be glad to help.
|
||||
|
||||
<Libraries />
|
||||
|
||||
@@ -25,15 +25,8 @@ for something else, please [join our Discord!](https://formbricks.com/discord) a
|
||||
|
||||
Before getting started, make sure you have:
|
||||
|
||||
1. A web application in your desired framework is set up and running.
|
||||
2. A Formbricks account with access to your environment ID and API host. You can find these in the **Setup Checklist** in the Settings:
|
||||
|
||||
<MdxImage
|
||||
src={SetupChecklist}
|
||||
alt="Step 2 - Setup Checklist"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
1. A web application (behind your user authentication system) in your desired framework is set up and running.
|
||||
2. A Formbricks account with access to your environment ID and API host. You can find these in the **Setup Checklist** in the Settings.
|
||||
|
||||
---
|
||||
|
||||
@@ -46,7 +39,11 @@ All you need to do is copy a `<script>` tag to your HTML head, and that’s abou
|
||||
```html {{ title: 'index.html' }}
|
||||
<!-- START Formbricks Surveys -->
|
||||
<script type="text/javascript">
|
||||
!function(){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="https://unpkg.com/@formbricks/js@^1.6.0/dist/index.umd.js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: "<your-environment-id>", apiHost: "<api-host>"})},500)}();
|
||||
!function(){
|
||||
var apiHost = "https://app.formbricks.com";
|
||||
var environmentId = "<your-environment-id>";
|
||||
var userId = "<your-user-id>";
|
||||
var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=apiHost+"/api/packages/app";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: environmentId, apiHost: apiHost, userId: userId})},500)}();
|
||||
</script>
|
||||
<!-- END Formbricks Surveys -->
|
||||
```
|
||||
@@ -58,11 +55,12 @@ All you need to do is copy a `<script>` tag to your HTML head, and that’s abou
|
||||
<Property name="environment-id" type="string">
|
||||
Formbricks Environment ID.
|
||||
</Property>
|
||||
</Properties>
|
||||
<Properties>
|
||||
<Property name="api-host" type="string">
|
||||
URL of the hosted Formbricks instance.
|
||||
</Property>
|
||||
<Property name="userId" type="string">
|
||||
User ID of the user who has active session.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
Refer to our [Example HTML project](https://github.com/formbricks/examples/tree/main/html) for more help! Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
@@ -93,12 +91,13 @@ Now, update your App.js/ts file to initialise Formbricks.
|
||||
|
||||
```js
|
||||
// other imports
|
||||
import formbricks from "@formbricks/js";
|
||||
import formbricks from "@formbricks/js/app";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user-id>",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -117,24 +116,14 @@ export default App;
|
||||
<Property name="environment-id" type="string">
|
||||
Formbricks Environment ID.
|
||||
</Property>
|
||||
</Properties>
|
||||
<Properties>
|
||||
<Property name="api-host" type="string">
|
||||
URL of the hosted Formbricks instance.
|
||||
</Property>
|
||||
<Property name="userId" type="string">
|
||||
User ID of the user who has active session.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### What are we doing here?
|
||||
|
||||
The app initializes 'formbricks' when it's loaded in a browser environment (due to the typeof window !== "undefined" check) and then renders your components or content.
|
||||
|
||||
<MdxImage
|
||||
src={ReactApp}
|
||||
alt="In-app survey in React app for micro surveys"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Refer to our [Example ReactJs project](https://github.com/formbricks/examples/tree/main/reactjs) for more help! Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
|
||||
---
|
||||
@@ -153,7 +142,7 @@ 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
|
||||
```
|
||||
```shell {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/js
|
||||
@@ -164,34 +153,40 @@ yarn add @formbricks/js
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
### App Directory
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="app/formbricks.tsx">
|
||||
|
||||
```tsx {{title: 'Typescript'}}
|
||||
"use client";
|
||||
import formbricks from "@formbricks/js";
|
||||
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import formbricks from "@formbricks/js/app";
|
||||
|
||||
export default function FormbricksProvider() {
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
useEffect(() => {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
});
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user-id>",
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
formbricks?.registerRouteChange();
|
||||
}, [pathname, searchParams]);
|
||||
useEffect(() => {
|
||||
formbricks?.registerRouteChange();
|
||||
}, [pathname, searchParams]);
|
||||
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
````
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="app/layout.tsx">
|
||||
@@ -207,7 +202,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
</html>
|
||||
);
|
||||
}
|
||||
````
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
@@ -224,12 +219,13 @@ Refer to our [Example NextJS App Directory project](https://github.com/formbrick
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import formbricks from "@formbricks/js";
|
||||
import formbricks from "@formbricks/js/app";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user-id>",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -259,16 +255,15 @@ Refer to our [Example NextJS Pages Directory project](https://github.com/formbri
|
||||
<Property name="environment-id" type="string">
|
||||
Formbricks Environment ID.
|
||||
</Property>
|
||||
</Properties>
|
||||
<Properties>
|
||||
<Property name="api-host" type="string">
|
||||
URL of the hosted Formbricks instance.
|
||||
</Property>
|
||||
<Property name="userId" type="string">
|
||||
User ID of the user who has active session.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### What are we doing here?
|
||||
|
||||
First we need to initialize the Formbricks SDK, making sure it only runs on the client side.
|
||||
First we initialize the Formbricks SDK, ensuring that it only runs on the client side.
|
||||
To connect the Next.js router to Formbricks and ensure the SDK can keep track of every page change, we are registering the route change event.
|
||||
|
||||
Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
@@ -283,7 +278,7 @@ We will make sure the SDK is only loaded and used on the client side, as it's no
|
||||
<Col>
|
||||
<CodeGroup title="Install Formbricks JS library">
|
||||
```shell {{ title: 'npm' }}
|
||||
npm install @formbricks/js
|
||||
npm install @formbricks/js
|
||||
````
|
||||
|
||||
```shell {{ title: 'pnpm' }}
|
||||
@@ -299,12 +294,13 @@ yarn add @formbricks/js
|
||||
<CodeGroup title="src/formbricks.js">
|
||||
|
||||
```js
|
||||
import formbricks from "@formbricks/js";
|
||||
import formbricks from "@formbricks/js/app";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user-id>",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -345,6 +341,9 @@ router.afterEach((to, from) => {
|
||||
<Property name="api-host" type="string">
|
||||
URL of the hosted Formbricks instance.
|
||||
</Property>
|
||||
<Property name="userId" type="string">
|
||||
User ID of the user who has active session.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
Refer to our [Example VueJs project](https://github.com/formbricks/examples/tree/main/vuejs) for more help! Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
@@ -409,43 +408,6 @@ Debug log messages provide insights into:
|
||||
- Event tracking, survey triggers and form interactions.
|
||||
- Initialization errors.
|
||||
|
||||
## Overwrite CSS Styles for In-App Surveys
|
||||
|
||||
You can overwrite the default CSS styles for the in-app surveys by adding the following CSS to your global CSS file (eg. `globals.css`):
|
||||
|
||||
Make sure that you do not change the CSS variable names as they are used by Formbricks to identify the CSS variables. You can change the values to your liking. We have filled in some sample values for you to change according to your desired appearance.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Overwrite Formbricks CSS">
|
||||
|
||||
```css
|
||||
/* Formbricks CSS */
|
||||
--fb-brand-color: red;
|
||||
--fb-brand-text-color: white;
|
||||
--fb-border-color: green;
|
||||
--fb-border-color-highlight: rgb(13, 13, 12);
|
||||
--fb-focus-color: red;
|
||||
--fb-heading-color: yellow;
|
||||
--fb-subheading-color: green;
|
||||
--fb-info-text-color: orange;
|
||||
--fb-signature-text-color: blue;
|
||||
--fb-survey-background-color: black;
|
||||
--fb-accent-background-color: rgb(13, 13, 12);
|
||||
--fb-accent-background-color-selected: red;
|
||||
--fb-placeholder-color: white;
|
||||
--fb-shadow-color: var(--fb-brand-color);
|
||||
--fb-rating-fill: rgb(13, 13, 12);
|
||||
--fb-rating-hover: green;
|
||||
--fb-back-btn-border: blue;
|
||||
--fb-submit-btn-border: transparent;
|
||||
--fb-rating-selected: black;
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
We have an example of this in our [Demo project](https://github.com/formbricks/formbricks/blob/main/apps/demo/styles/globals.css.) here.
|
||||
|
||||
**Can’t figure it out? [Join our Discord!](https://formbricks.com/discord)**
|
||||
|
||||
---
|
||||
BIN
apps/docs/app/app-surveys/quickstart/images/I1.webp
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
apps/docs/app/app-surveys/quickstart/images/I2.webp
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
apps/docs/app/app-surveys/quickstart/images/I3.webp
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
apps/docs/app/app-surveys/quickstart/images/I4.webp
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
apps/docs/app/app-surveys/quickstart/images/I5.webp
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
apps/docs/app/app-surveys/quickstart/images/I6.webp
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
apps/docs/app/app-surveys/quickstart/images/I7.webp
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
apps/docs/app/app-surveys/quickstart/images/I8.webp
Normal file
|
After Width: | Height: | Size: 23 KiB |
117
apps/docs/app/app-surveys/quickstart/page.mdx
Normal file
@@ -0,0 +1,117 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import I1 from "./images/I1.webp";
|
||||
import I2 from "./images/I2.webp";
|
||||
import I3 from "./images/I3.webp";
|
||||
import I4 from "./images/I4.webp";
|
||||
import I5 from "./images/I5.webp";
|
||||
import I6 from "./images/I6.webp";
|
||||
import I7 from "./images/I7.webp";
|
||||
import I8 from "./images/I8.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks Quickstart Guide: App Surveys Made Easier & Faster",
|
||||
description:
|
||||
"Formbricks is the easiest way to create and manage app surveys. This quickstart guide will show you how to create your first app survey in under 5 minutes.",
|
||||
};
|
||||
|
||||
#### App Surveys
|
||||
|
||||
# Quickstart
|
||||
|
||||
App surveys have 6-10x better conversion rates than emailed out surveys. This tutorial explains how to run an app survey in your web app in 10 to 15 minutes. 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).
|
||||
</Note>
|
||||
|
||||
1. **Create a free Formbricks Cloud account**: While you can [self-host](/self-hosting/deployment) Formbricks, but the quickest and easiest way to get started is with the free Cloud plan. Just [sign up here](https://app.formbricks.com/auth/signup) and you'll be guided to our onboarding like below:
|
||||
|
||||
<Note>
|
||||
Website & App Surveys have the same integration process. The difference will come when we setup our survey.
|
||||
</Note>
|
||||
|
||||
<MdxImage
|
||||
src={I1}
|
||||
alt="Choose website survey from survey type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
/>
|
||||
|
||||
2. **Connect your App/Website**: Once you get through a couple of onboarding steps, 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:
|
||||
|
||||
<MdxImage
|
||||
src={I2}
|
||||
alt="Code snippet for connecting app with Formbricks"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Paste the code snippet in your app and reload the page. You should now see the Formbricks widget in the lower right corner of your app! The integration is now complete.
|
||||
|
||||
<MdxImage
|
||||
src={I3}
|
||||
alt="App connected with Formbricks"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Onboarding is complete! Now let’s create our first survey as you should see templates to choose from after clicking on **Next**:
|
||||
|
||||
<MdxImage
|
||||
src={I4}
|
||||
alt="Choose a survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. **Create your first survey**: To be able to see a survey in your app, you need to create one. We’ll choose one of the templates and head over to the survey settings:
|
||||
|
||||
Pick the Survey Type as **App Survey**.
|
||||
|
||||
<MdxImage
|
||||
src={I5}
|
||||
alt="Survey settings for app survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
4. **Set Trigger for the Survey**: Scroll down to Survey Trigger and click on **+ Add action**, choose **New Session**. This will cause this survey to appear when the Formbricks Widget tracks a new user session:
|
||||
|
||||
<MdxImage
|
||||
src={I6}
|
||||
alt="Survey trigger settings for app survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
5. **Set Recontact Options for debugging**: In Recontact Options we choose the following settings, so that we can play around with the survey more easily. By default, each survey will be shown only once to each user to prevent survey fatigue:
|
||||
|
||||
<Note>
|
||||
Please change this setting later on after testing your survey to prevent survey fatigue for your users.
|
||||
</Note>
|
||||
|
||||
<MdxImage
|
||||
src={I7}
|
||||
alt="Recontact options for app survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
6. **Publish your survey**: Now hit **Publish** and you’ll be forwarded to the Summary Page. This is where you’ll find the responses to this survey.
|
||||
|
||||
<MdxImage
|
||||
src={I8}
|
||||
alt="Survey published successfully"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
- We offer framework guides for various frontend tech, head over to the the [App Survey Framework Guides](/app-survey/framework-guides) to get started with your app survey.
|
||||
- Head over to our App Survey SDK documentation to get started with the [App Survey JS SDK](/developer-docs/app-survey-sdk).
|
||||
|
||||
Still struggling or something not working as expected? [Join our Discord!](https://formbricks.com/discord) and we'd be glad to assist you!
|
||||
BIN
apps/docs/app/app-surveys/recontact/app-survey.webp
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
apps/docs/app/app-surveys/recontact/global-wait-time.webp
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
apps/docs/app/app-surveys/recontact/ignore-wait-time.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
107
apps/docs/app/app-surveys/recontact/page.mdx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import AppSurvey from "./app-survey.webp";
|
||||
import GlobalWaitTime from "./global-wait-time.webp";
|
||||
import IgnoreWaitTime from "./ignore-wait-time.webp";
|
||||
import SurveyRecontact from "./survey-recontact.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Recontact Options in Formbricks: When to show a survey again to a user",
|
||||
description:
|
||||
"Explore how to configure Recontact options in Formbricks to control the frequency of survey exposure to users, ensuring effective feedback collection without compromising user experience.",
|
||||
};
|
||||
|
||||
#### App Surveys
|
||||
|
||||
# Recontact Options
|
||||
|
||||
Recontact options in Formbricks enable you to manage how often and under what conditions a survey is shown to a user. This feature is crucial for balancing effective feedback collection with a positive user experience by preventing survey fatigue.
|
||||
|
||||
## When do Recontact Options come into play?
|
||||
|
||||
Recontact options are the last layer of the logic that determines if a survey is shown to the current user. The logic goes as follows:
|
||||
|
||||
1. Targeting: Does the current user targeted to fill out this survey? If yes...
|
||||
2. Trigger: Is the survey triggered? If yes...
|
||||
3. **Recontact Options:** Should the survey be shown (again) to this user? That's dependent on:
|
||||
|
||||
- Did the user see any survey recently (meaning, has Global Waiting Time passed)?
|
||||
- Did the user see this specific survey already?
|
||||
- How many times did the user see this specific survey already?
|
||||
- Has the user already responded to this survey?
|
||||
|
||||
As you can see, there are a lot of different cases to cover. Let's have a closer look 👇
|
||||
|
||||
## Recontact Options
|
||||
|
||||
<Note>By default, a survey is shown to each user only once.</Note>
|
||||
|
||||
You can adjust the default behavior by modifying the Recontact Options for each survey in the settings:
|
||||
|
||||
1. Open the Survey Editor for the survey you want to see & modify the Recontact Options for.
|
||||
2. Select the Settings Tab.
|
||||
3. Ensure your Survey type is set to **App Survey**.
|
||||
|
||||
<MdxImage
|
||||
src={AppSurvey}
|
||||
alt="Choose Survey Type as App Survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
4. Scroll down to the Recontact Options section.
|
||||
|
||||
Available Recontact Options include:
|
||||
|
||||
- **Show only once**: (default) Displays the survey a single time, regardless of whether it was completed.
|
||||
- **Until they Submit a Response**: If tareting matches and trigger fires, Formbricks keeps showing the survey until the user submits a response.
|
||||
- **Keep Showing while Conditions Match**: Always shows the survey while specific conditions are met. Useful for continuous feedback collection, such as in [Docs Feedback Survey](/best-practices/docs-feedback) or the [Feedback Box](/best-practices/feedback-box).
|
||||
|
||||
<MdxImage
|
||||
src={SurveyRecontact}
|
||||
alt="Choose Recontanct Options for the Survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Product-wide Global Waiting Time
|
||||
|
||||
The Global Waiting Time is a universal blocker to make sure that no user sees too many surveys. This is particularly helpful when several teams of large organisations use Formbricks at the same time.
|
||||
|
||||
<Note>The default Global Waiting Time is set to 7 days.</Note>
|
||||
|
||||
To adjust the Global Waiting Time:
|
||||
|
||||
1. Visit Formbricks Settings
|
||||
2. Go to Product Settings
|
||||
3. Find the **Recontact Waiting Time** section
|
||||
4. Modify the interval (in days) as needed.
|
||||
|
||||
<MdxImage
|
||||
src={GlobalWaitTime}
|
||||
alt="Formbricks Product-Wide Wait Time"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Overriding Global Waiting Time for a Specific Survey
|
||||
|
||||
For specific surveys, you may need to override the default waiting time. Below is how you can do that:
|
||||
|
||||
1. In the Survey Editor, access the Settings Tab.
|
||||
2. Find the Ignore Waiting Time between Surveys toggle under Recontact Options.
|
||||
3. Enable this toggle to bypass the global setting.
|
||||
4. Set a custom recontact period:
|
||||
- **Always Show Survey**: Displays the survey whenever triggered, ignoring the waiting time.
|
||||
- **Wait `X` days before showing this survey again**: Sets a specific interval before the survey can be shown again.
|
||||
|
||||
<MdxImage
|
||||
src={IgnoreWaitTime}
|
||||
alt="Ignore Global Waiting Time for a Specific Survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
Still struggling or something not working as expected? [Join our Discord!](https://formbricks.com/discord) and we'd be glad to assist you!
|
||||
BIN
apps/docs/app/app-surveys/recontact/survey-recontact.webp
Normal file
|
After Width: | Height: | Size: 31 KiB |
@@ -1,10 +1,10 @@
|
||||
export const metadata = {
|
||||
title: "Identifying Users in Formbricks In-App Surveys",
|
||||
title: "Identifying Users in Formbricks App Surveys",
|
||||
description:
|
||||
"Dive into the importance of user identification in surveys. Boost your survey response rates and target the right users with Formbricks.",
|
||||
};
|
||||
|
||||
#### In-App Surveys
|
||||
#### App Surveys
|
||||
|
||||
# User Identification
|
||||
|
||||
@@ -12,6 +12,11 @@ User Identification helps you to not only segment your users but also to see mor
|
||||
|
||||
### Understanding Identified vs Unidentified Users
|
||||
|
||||
<Note>
|
||||
Formbricks App Surveys can **only be used with identified users**. If you are looking to run surveys on your
|
||||
public-facing website, head over to the [Website Surveys](/website-surveys/quickstart) section.
|
||||
</Note>
|
||||
|
||||
In Formbricks, understanding the distinction between identified and unidentified users is crucial for effective survey segmentation and targeted feedback collection.
|
||||
|
||||
| Feature | Unidentified Users | Identified Users |
|
||||
@@ -25,36 +30,18 @@ In Formbricks, understanding the distinction between identified and unidentified
|
||||
| Recommended for **public-facing websites** | ✅ | ❌ |
|
||||
| Recommended for **web apps after login** | ❌ | ✅ |
|
||||
|
||||
## Unidentified Users
|
||||
|
||||
Unidentified users are those without a specific userId set. Surveys can still be presented to these users based on trigger actions, but without the granularity of user-specific targeting.
|
||||
|
||||
This method is recommended for public-facing websites where users are not required to log in.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Initialization without a user ID">
|
||||
|
||||
```javascript
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
});
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
## Identified Users
|
||||
|
||||
Identified users are those for whom specific information has been set, notably the userId. This identification allows for more precise targeting of surveys and a deeper understanding of the feedback provided. When enabled, all information specified by you and all actions are sent to Formbricks.
|
||||
|
||||
This method is recommended for applications where users are required to log in and will often return.
|
||||
|
||||
**Setting the User ID:**
|
||||
To identify a user, set the `userId` in the Formbricks initialization call. The userId should be a unique string, such as a database ID or an email address. This is essential for the user to be visible on the Formbricks dashboard.
|
||||
### Setting User ID
|
||||
|
||||
To enable the User identification feature you need to set the `userId` in the init() call of Formbricks. Only when the `userId` is set the person will be visible in the Formbricks dashboard. The `userId` can be any string and it's best to use the default identifier you use in your app (e.g. unique id from database or the email address if it's unique) but you can also anonymize these as long as they are unique for every user.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Initialization with a user ID">
|
||||
<CodeGroup title="Setting User ID">
|
||||
|
||||
```javascript
|
||||
formbricks.init({
|
||||
@@ -67,8 +54,63 @@ formbricks.init({
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
**Logging Out Users:**
|
||||
When a user logs out of your application, ensure they are also logged out of Formbricks. This prevents the association of their activities with the wrong user profile.
|
||||
### Enhanced Initialization with User Attributes
|
||||
|
||||
In addition to setting the `userId`, Formbricks allows you to set user attributes right at the initialization. This ensures that your user data is seamlessly integrated from the start. Here's how you can include user attributes in the `init()` function:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Enhanced Initialization with User Attributes">
|
||||
|
||||
```javascript
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user_id>",
|
||||
attributes: {
|
||||
// your custom attributes
|
||||
Plan: "premium",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
## Setting Custom User Attributes
|
||||
|
||||
You can use the setAttribute function to set any custom attribute for the user (e.g. name, plan, etc.):
|
||||
|
||||
<Note>
|
||||
Please note that the number of different attribute classes (e.g., "Plan," "First Name," etc.) is currently
|
||||
limited to 150 attributes per environment.
|
||||
</Note>
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Setting Custom Attributes">
|
||||
|
||||
```javascript
|
||||
formbricks.setAttribute("Plan", "free");
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
Generally speaking, the setAttribute function works like this:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Setting Custom Attributes">
|
||||
|
||||
```javascript
|
||||
formbricks.setAttribute("attribute_key", "attribute_value");
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
Where `attributeName` is the name of the attribute you want to set, and `attributeValue` is the value of the attribute you want to set.
|
||||
|
||||
### Logging Out Users
|
||||
|
||||
When a user logs out of your webpage, make sure to log them out of Formbricks as well. This will prevent new activity from being associated with an incorrect user. Use the logout function:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Logging out User">
|
||||
@@ -79,8 +121,3 @@ formbricks.logout();
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
<Note>
|
||||
To set other custom attributes for a user, view our <a href="/docs/in-app-surveys/attributes">Attributes</a>{" "}
|
||||
documentation.
|
||||
</Note>
|
||||
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
@@ -1,5 +1,4 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import ChangeText from "./change-text.webp";
|
||||
import CreateChurnFlow from "./create-cancel-flow.webp";
|
||||
@@ -26,10 +25,6 @@ Churn is hard, but can teach you a lot. Whenever a user decides that your produc
|
||||
|
||||
The Churn Survey is among the most effective ways to identify weaknesses in your offering. People were willing to pay but now are not anymore: What changed? Let’s find out!
|
||||
|
||||
## Preview
|
||||
|
||||
<DemoPreview template="Churn Survey" />
|
||||
|
||||
## Formbricks Approach
|
||||
|
||||
- Ask at exactly the right point in time
|
||||
@@ -46,9 +41,9 @@ To run the Churn Survey in your app you want to proceed as follows:
|
||||
4. Prevent that churn!
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? We assume that you have already installed the Formbricks Widget in your web
|
||||
app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(takes 15mins max.)](/docs/getting-started/quickstart-in-app-survey)
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(takes 15mins max.)](/app-surveys/quickstart)
|
||||
</Note>
|
||||
|
||||
### 1. Create new Churn Survey
|
||||
@@ -116,7 +111,7 @@ To create the trigger for your Churn Survey, you have two options to choose from
|
||||
|
||||
Whenever a user visits this page, matches the filter conditions above and the recontact options (below) the survey will be displayed ✅
|
||||
|
||||
Here is our complete [Actions manual](/docs/actions/why) covering [Code](/docs/actions/code) and [No-Code](/docs/actions/no-code) Actions.
|
||||
Here is our complete [Actions manual](/actions/why) covering [Code](/actions/code) and [No-Code](/actions/no-code) Actions.
|
||||
|
||||
<Note>
|
||||
## Pre-churn flow coming soon We’re currently building full-screen survey pop-ups. You’ll be able to prevent
|
||||
@@ -157,8 +152,7 @@ These settings make sure the survey is always displayed, when a user wants to Ca
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? You need to have the Formbricks Widget installed to display the Churn Survey
|
||||
in your app. Please follow [this tutorial (Step 4 onwards)](/docs/getting-started/quickstart-in-app-survey)
|
||||
to install the widget.
|
||||
in your app. Please follow [this tutorial (Step 4 onwards)](/app-surveys/quickstart) to install the widget.
|
||||
</Note>
|
||||
|
||||
###
|
||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 44 KiB |
BIN
apps/docs/app/best-practices/docs-feedback/add-action.webp
Normal file
|
After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@@ -1,14 +1,13 @@
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import DocsFeedback from "@/components/docs/DocsFeedback";
|
||||
import AddAction from "./add-action.webp";
|
||||
import ChangeId from "./change-id.webp";
|
||||
import CopyIds from "./copy-ids.webp";
|
||||
import DocsNavi from "./docs-navi.webp";
|
||||
import DocsTemplate from "./docs-template.webp";
|
||||
import SelectNonevent from "./select-nonevent.webp";
|
||||
import SelectAction from "./select-action.webp";
|
||||
import SurveyTrigger from "./survey-trigger.webp";
|
||||
import SwitchToDev from "./switch-to-dev.webp";
|
||||
import WhenToAsk from "./when-to-ask.webp";
|
||||
import CopyIds from "./copy-ids.webp";
|
||||
|
||||
export const metadata = {
|
||||
title:
|
||||
@@ -27,10 +26,6 @@ Docs Feedback allows you to measure how clear your documentation is.
|
||||
|
||||
Unlike yourself, your users don't spend 5-7 days per week thinking about your product. To fight the "Curse of Knowledge" you have to measure how clear your docs are.
|
||||
|
||||
## Preview
|
||||
|
||||
<DocsFeedback />
|
||||
|
||||
## Installation
|
||||
|
||||
To get this running, you'll need a bit of time. Here are the steps we're going through:
|
||||
@@ -78,10 +73,10 @@ To get this running, you'll need a bit of time. Here are the steps we're going t
|
||||
choices accordingly. They have to be identical to the frontend we're building in the next step.
|
||||
</Note>
|
||||
|
||||
6. Click on “Continue to Settings or select the audience tab manually. Scroll down to “When to ask” and create a new Action:
|
||||
6. Click on “Continue to Settings or select the audience tab manually. Scroll down to “Survey Trigger” and create a new Action:
|
||||
|
||||
<MdxImage
|
||||
src={WhenToAsk}
|
||||
src={SurveyTrigger}
|
||||
alt="set up when to ask card"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
@@ -89,18 +84,12 @@ To get this running, you'll need a bit of time. Here are the steps we're going t
|
||||
|
||||
7. Our goal is to create an event that never fires. This is a bit nonsensical because it is a workaround. Stick with me 😃 Fill the action out like on the screenshot:
|
||||
|
||||
<MdxImage
|
||||
src={AddAction}
|
||||
alt="add action"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
className="rounded"
|
||||
/>
|
||||
<MdxImage src={AddAction} alt="add action" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
8. Select the Non-Event in the dropdown. Now you see that the “Publish survey” button is active. Publish your survey 🤝
|
||||
|
||||
<MdxImage
|
||||
src={SelectNonevent}
|
||||
src={SelectAction}
|
||||
alt="select nonevent"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
@@ -128,28 +117,25 @@ This allows us to capture and analyze partial feedback where the user is not wil
|
||||
|
||||
2. Likely, you have a template file or similar which renders the navigation at the bottom of the page:
|
||||
|
||||
<MdxImage
|
||||
src={DocsNavi}
|
||||
alt="doc navigation"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
className="rounded"
|
||||
/>
|
||||
<MdxImage src={DocsNavi} alt="doc navigation" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
Locate that file. We are using the [Tailwind Template “Syntax”](https://tailwindui.com/templates/syntax) for our docs. Here is our [Layout.tsx](https://github.com/formbricks/formbricks/blob/main/apps/formbricks-com/components/docs/Layout.tsx) file.
|
||||
|
||||
3. Write the frontend code for the widget. Here is the full component (we break it down right below):
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Entire Widget">
|
||||
|
||||
```tsx
|
||||
import { useState } from "react";
|
||||
import { handleFeedbackSubmit, updateFeedback } from "../../lib/handleFeedbackSubmit";
|
||||
import { Popover, PopoverTrigger, PopoverContent } from "@formbricks/ui/Popover";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function DocsFeedback() {
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@formbricks/ui/Popover";
|
||||
|
||||
import { handleFeedbackSubmit, updateFeedback } from "../../lib/handleFeedbackSubmit";
|
||||
|
||||
export const DocsFeedback = () => {
|
||||
const router = useRouter();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [sharedFeedback, setSharedFeedback] = useState(false);
|
||||
@@ -213,7 +199,7 @@ export default function DocsFeedback() {
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -221,6 +207,7 @@ export default function DocsFeedback() {
|
||||
**Let’s break it down!**
|
||||
|
||||
Setting the local states and getting the current URL:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="State Management">
|
||||
|
||||
@@ -311,9 +298,10 @@ return (
|
||||
</Col>
|
||||
## 3. Connecting to the Formbricks API
|
||||
|
||||
The last step is to hook up your sparkling new frontend to the Formbricks API. To do so, we followed the “[Create Response](/docs/api/client/responses#create-a-response)” and “[Update Response](/docs/api/client/responses#update-a-response)” pages in our docs.
|
||||
The last step is to hook up your sparkling new frontend to the Formbricks API. To do so, we followed the “[Create Response](/api/client/responses#create-a-response)” and “[Update Response](/api/client/responses#update-a-response)” pages in our docs.
|
||||
|
||||
Here is the code for the `handleFeedbackSubmit` function with comments:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="handleFeedbackSubmit() function definition">
|
||||
|
||||
@@ -415,6 +403,7 @@ When you are on the survey detail page, you’ll find both of them in the URL:
|
||||
<MdxImage src={CopyIds} alt="copy IDs" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
Now, you have to replace the IDs and the API host accordingly in your `handleFeedbackSubmit`:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Replace the ID and API accordingly">
|
||||
|
||||
BIN
apps/docs/app/best-practices/docs-feedback/select-action.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
apps/docs/app/best-practices/docs-feedback/survey-trigger.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
BIN
apps/docs/app/best-practices/feature-chaser/action-css.webp
Normal file
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
@@ -1,8 +1,7 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import ActionCSS from "./action-css.webp";
|
||||
import ActionText from "./action-text.webp";
|
||||
import ActionText from "./action-innertext.webp";
|
||||
import ChangeText from "./change-text.webp";
|
||||
import CreateSurvey from "./create-survey.webp";
|
||||
import Publish from "./publish.webp";
|
||||
@@ -25,10 +24,6 @@ Following up on specific features only makes sense with very targeted surveys. F
|
||||
|
||||
Product analytics never tell you why a feature is used - and why not. Following up on specific features with highly relevant questions is a great way to gather feedback and improve your product.
|
||||
|
||||
## Preview
|
||||
|
||||
<DemoPreview template="Feature Chaser" />
|
||||
|
||||
## Formbricks Approach
|
||||
|
||||
- Trigger survey at exactly the right point in the user journey
|
||||
@@ -43,9 +38,9 @@ To run the Feature Chaser survey in your app you want to proceed as follows:
|
||||
2. Setup a user action to display survey at the right point in time
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? We assume that you have already installed the Formbricks Widget in your web
|
||||
app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(takes 15mins max.)](/docs/getting-started/quickstart-in-app-survey)
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web wapp. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(takes 15mins max.)](/app-surveys/quickstart)
|
||||
</Note>
|
||||
|
||||
### 1. Create new Feature Chaser
|
||||
@@ -78,7 +73,7 @@ Save, and move over to where the magic happens: The “Audience” tab.
|
||||
|
||||
Before setting the right trigger, you need to identify a user action in your app which signals, that they have just used the feature you want to understand better. In most cases, it is clicking a specific button in your product.
|
||||
|
||||
You can create [Code Actions](/docs/actions/code) and [No Code Actions](/docs/actions/no-code) to follow users through your app. In this example, we will create a No Code Action.
|
||||
You can create [Code Actions](/actions/code) and [No Code Actions](/actions/no-code) to follow users through your app. In this example, we will create a No Code Action.
|
||||
|
||||
There are two ways to track a button:
|
||||
|
||||
@@ -100,7 +95,7 @@ There are two ways to track a button:
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Please follow our [Actions manual](/docs/actions/why) for an in-depth description of how Actions work.
|
||||
Please follow our [Actions manual](/actions/why) for an in-depth description of how Actions work.
|
||||
|
||||
### 4. Select Action in the “When to ask” card
|
||||
|
||||
@@ -128,8 +123,7 @@ Lastly, scroll down to “Recontact Options”. Here you have full freedom to de
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? You need to have the Formbricks Widget installed to display the Feature Chaser
|
||||
in your app. Please follow [this tutorial (Step 4 onwards)](/docs/getting-started/quickstart-in-app-survey)
|
||||
to install the widget.
|
||||
in your app. Please follow [this tutorial (Step 4 onwards)](/app-surveys/quickstart) to install the widget.
|
||||
</Note>
|
||||
|
||||
###
|
||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
BIN
apps/docs/app/best-practices/feature-chaser/select-action.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
apps/docs/app/best-practices/feedback-box/action-css.webp
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
apps/docs/app/best-practices/feedback-box/action-innertext.webp
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
apps/docs/app/best-practices/feedback-box/add-action.webp
Normal file
|
After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
@@ -1,14 +1,13 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import Link from "next/link";
|
||||
|
||||
import ActionCSS from "./action-css.webp";
|
||||
import ActionText from "./action-innertext.webp";
|
||||
import AddAction from "./add-action.webp";
|
||||
import AddCSSAction from "./add-css-action.webp";
|
||||
import AddHTMLAction from "./add-html-action.webp";
|
||||
import ChangeTextContent from "./change-text-content.webp";
|
||||
import CreateFeedbackBox from "./create-feedback-box-by-template.webp";
|
||||
import PublishSurvey from "./publish-survey.webp";
|
||||
import SelectAction from "./select-feedback-button-action.webp";
|
||||
import SelectAction from "./select-action.webp";
|
||||
import RecontactOptions from "./set-recontact-options.webp";
|
||||
|
||||
export const metadata = {
|
||||
@@ -27,10 +26,6 @@ The Feedback Box gives your users a direct channel to share their feedback and f
|
||||
|
||||
A low friction way to gather feedback helps catching even the smallest points of frustration in user experiences. Use automations to react rapidly and make users feel heard.
|
||||
|
||||
## Preview
|
||||
|
||||
<DemoPreview template="Feedback Box" />
|
||||
|
||||
## Formbricks Approach
|
||||
|
||||
- Make it easy: 2 clicks to share feedback
|
||||
@@ -74,20 +69,14 @@ Go to the “Audience” tab, find the “When to send” card and choose “Add
|
||||
|
||||
<MdxImage src={AddAction} alt="Add action" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
<Note>
|
||||
## You can also add actions in your code You can also create [Code Actions](/docs/actions/code) using
|
||||
`formbricks.track("Eventname")` - they will automatically appear in your Actions overview as long as the SDK
|
||||
is embedded.
|
||||
</Note>
|
||||
|
||||
We have two options to track the Feedback Button in your application: innerText and CSS-Selector:
|
||||
|
||||
1. **innerText:** This means that whenever a user clicks any HTML item in your app which has an `innerText` of `Feedback` the Feedback Box will be displayed.
|
||||
2. **CSS-Selector:** This means that when an element with a specific CSS-Selector like `#feedback-button` is clicked, your Feedback Box is triggered.
|
||||
|
||||
<div className="grid max-w-full grid-cols-2 space-x-2 sm:max-w-3xl">
|
||||
<MdxImage src={AddHTMLAction} alt="Add HTML action" quality="100" className="rounded-lg" />
|
||||
<MdxImage src={AddCSSAction} alt="Add CSS action" quality="100" className="rounded-lg" />
|
||||
<MdxImage src={ActionText} alt="Add HTML action" quality="100" className="rounded-lg" />
|
||||
<MdxImage src={ActionCSS} alt="Add CSS action" quality="100" className="rounded-lg" />
|
||||
</div>
|
||||
|
||||
### 4. Select action in the “When to ask” card
|
||||
@@ -123,8 +112,7 @@ Scroll down to “Recontact Options”. Here you have to choose the right settin
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? You need to have the Formbricks Widget installed to display the Feedback Box
|
||||
in your app. Please follow [this tutorial (Step 4 onwards)](/docs/getting-started/quickstart-in-app-survey)
|
||||
to install the widget.
|
||||
in your app. Please follow [this tutorial (Step 4 onwards)](/app-surveys/quickstart) to install the widget.
|
||||
</Note>
|
||||
|
||||
###
|
||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
BIN
apps/docs/app/best-practices/feedback-box/select-action.webp
Normal file
|
After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
@@ -1,5 +1,4 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import NewsletterSurveyType from "./choose-survey-type.webp";
|
||||
import NewsletterSurveyEmbedCode from "./embed-survey-code-in-your-email.webp";
|
||||
@@ -23,10 +22,6 @@ Email remains the predominant way to communicate with your customers. Measure th
|
||||
|
||||
Measuring the content quality of both transactional and marketing email is a key element for improving customer communication.
|
||||
|
||||
## Preview
|
||||
|
||||
<DemoPreview template="Improve Newsletter Content" />
|
||||
|
||||
## Formbricks Approach
|
||||
|
||||
- Embed the survey into your email so it’s part of the newsletter.
|
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
@@ -1,5 +1,4 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
|
||||
import ActionText from "./action-innertext.webp";
|
||||
import ActionPageurl from "./action-pageurl.webp";
|
||||
@@ -25,10 +24,6 @@ When a user doesn't convert, you want to know why. A micro-survey displayed at e
|
||||
|
||||
The better you understand why free users don’t convert to paid users, the higher your revenue. You can make an informed decision about what to change in your offering to make more people pay for your service.
|
||||
|
||||
## Preview
|
||||
|
||||
<DemoPreview template="Improve Trial Conversion" />
|
||||
|
||||
## Formbricks Approach
|
||||
|
||||
- Ask at exactly the right point in time
|
||||
@@ -43,9 +38,9 @@ To display the Trial Conversion Survey in your app you want to proceed as follow
|
||||
3. Print that 💸
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? We assume that you have already installed the Formbricks Widget in your web
|
||||
app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(takes 15mins max.)](/docs/getting-started/quickstart-in-app-survey)
|
||||
## Formbricks Widget running?
|
||||
We assume that you have already installed the Formbricks Widget in your web app. It’s required to display messages and surveys in your app. If not, please follow the [Quick Start Guide
|
||||
(takes 15mins max.)](/app-surveys/quickstart)
|
||||
</Note>
|
||||
|
||||
### 1. Create new Trial Conversion Survey
|
||||
@@ -109,7 +104,7 @@ Whenever a user visits this page, the survey will be displayed ✅
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Please have a look at our complete [Actions manual](/docs/actions/why) if you have questions.
|
||||
Please have a look at our complete [Actions manual](/actions/why) if you have questions.
|
||||
|
||||
### 5. Select Action in the “When to ask” card
|
||||
|
||||
@@ -137,8 +132,7 @@ Lastly, scroll down to “Recontact Options”. Here you have to choose the corr
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? You need to have the Formbricks Widget installed to display the Feedback Box
|
||||
in your app. Please follow [this tutorial (Step 4 onwards)](/docs/getting-started/quickstart-in-app-survey)
|
||||
to install the widget.
|
||||
in your app. Please follow [this tutorial (Step 4 onwards)](/app-surveys/quickstart) to install the widget.
|
||||
</Note>
|
||||
|
||||
###
|
||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
BIN
apps/docs/app/best-practices/improve-trial-cr/select-action.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |