Compare commits
462 Commits
delete-res
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7725d3d8a2 | ||
|
|
d722e9de9e | ||
|
|
560b8904f7 | ||
|
|
b68dcdf2dc | ||
|
|
2da2758255 | ||
|
|
b322f014ab | ||
|
|
d408d42f00 | ||
|
|
27875deb44 | ||
|
|
dcc98b671e | ||
|
|
4f5acbcddc | ||
|
|
a9bf8fcdaa | ||
|
|
87f2f8d870 | ||
|
|
4ae38546f0 | ||
|
|
68c6dad26b | ||
|
|
3f9ff9c59b | ||
|
|
86c8da3494 | ||
|
|
4ac60db896 | ||
|
|
7ca4aee9a7 | ||
|
|
0e6cfbfaa5 | ||
|
|
4f0edcd473 | ||
|
|
855342c1d1 | ||
|
|
dbcc030480 | ||
|
|
dc2ce17aa0 | ||
|
|
e2d5727cfc | ||
|
|
f86e7c6738 | ||
|
|
d1aec18776 | ||
|
|
2ff17c2b22 | ||
|
|
c9a8d022b4 | ||
|
|
1307e42078 | ||
|
|
5f40f8913b | ||
|
|
4ee27f9618 | ||
|
|
ed509d3a9a | ||
|
|
34ebfe4fd8 | ||
|
|
e48ddbad5d | ||
|
|
c6f9a6cdfc | ||
|
|
e6ee81a683 | ||
|
|
82853c8a07 | ||
|
|
06f2d85f8e | ||
|
|
687e12ad9b | ||
|
|
bb2d7b7a00 | ||
|
|
83b9400479 | ||
|
|
0b26475934 | ||
|
|
505c1d0223 | ||
|
|
8e31710604 | ||
|
|
b3883e8c9a | ||
|
|
d3f566237f | ||
|
|
49fe0dab67 | ||
|
|
0c86df1ce1 | ||
|
|
e475179884 | ||
|
|
b7299a6d31 | ||
|
|
9508db92f3 | ||
|
|
7f438afc30 | ||
|
|
1ddd1cfc3d | ||
|
|
d22eab1548 | ||
|
|
2fca750931 | ||
|
|
294b67a6cc | ||
|
|
e8e701c567 | ||
|
|
4fc8ee8181 | ||
|
|
74b4be99a4 | ||
|
|
1bd9b8a485 | ||
|
|
4b1652655b | ||
|
|
b114e4797e | ||
|
|
5add263e6f | ||
|
|
529144fe36 | ||
|
|
c2ea2716d3 | ||
|
|
933ea87456 | ||
|
|
31e595972d | ||
|
|
27ba9114df | ||
|
|
a068a2176b | ||
|
|
008fafabf7 | ||
|
|
f07dffab07 | ||
|
|
fa0cadb166 | ||
|
|
8ef74fdaff | ||
|
|
1b5d3c216f | ||
|
|
ee15c2676c | ||
|
|
04e43725d1 | ||
|
|
4100949bf6 | ||
|
|
bfb6012048 | ||
|
|
425d970e38 | ||
|
|
24bde119cb | ||
|
|
668c74f3d6 | ||
|
|
b153acaede | ||
|
|
18d3985e06 | ||
|
|
95fe94fb7f | ||
|
|
74829183ea | ||
|
|
ff60ff9e0b | ||
|
|
27ce171dc3 | ||
|
|
496d1b3c2e | ||
|
|
015d4c7663 | ||
|
|
214917cdb8 | ||
|
|
bfa0130672 | ||
|
|
25b41b4d3a | ||
|
|
f93c5b3c55 | ||
|
|
08ce026c7a | ||
|
|
c44c0b83e3 | ||
|
|
425d3819d7 | ||
|
|
de82762aeb | ||
|
|
4cd23e62bb | ||
|
|
62da30246a | ||
|
|
1e81b1df8e | ||
|
|
35d0d65022 | ||
|
|
37568f333e | ||
|
|
160b3f6353 | ||
|
|
171469e26a | ||
|
|
bd5f5032f8 | ||
|
|
9b27d6f84b | ||
|
|
91822c6ced | ||
|
|
d36e5615a7 | ||
|
|
7e6fe63f6a | ||
|
|
9f7cb7c1b9 | ||
|
|
9e06dde2fc | ||
|
|
3a8aced70d | ||
|
|
8d675bb91c | ||
|
|
f2c6bfd80f | ||
|
|
bc86249047 | ||
|
|
2a35feb127 | ||
|
|
1e0c90ca6f | ||
|
|
d94e003244 | ||
|
|
2463ed8500 | ||
|
|
20eb679842 | ||
|
|
c8ab6644bf | ||
|
|
98e0006f88 | ||
|
|
ec5f6301d3 | ||
|
|
5dc9a4da2f | ||
|
|
c33892b41b | ||
|
|
cebc386de3 | ||
|
|
4c118784be | ||
|
|
85e5828cc8 | ||
|
|
dfb1f86ddb | ||
|
|
6004505502 | ||
|
|
6122d88469 | ||
|
|
f15a4b237d | ||
|
|
a1e9425a3e | ||
|
|
7219402aad | ||
|
|
0f95f1c98c | ||
|
|
a9e45c0086 | ||
|
|
dddc730ef4 | ||
|
|
b99b499cde | ||
|
|
784930d9fc | ||
|
|
54fe0081ae | ||
|
|
52a41dc458 | ||
|
|
f2dc157d54 | ||
|
|
a70810cb91 | ||
|
|
a1e5060518 | ||
|
|
46f062e81d | ||
|
|
b7ba2e09ef | ||
|
|
855685fedd | ||
|
|
1a15d3f6f9 | ||
|
|
7a93af3f25 | ||
|
|
6451bc5833 | ||
|
|
308e889c85 | ||
|
|
69227bd91e | ||
|
|
1a21f40e5d | ||
|
|
18f1bc5490 | ||
|
|
dadc337955 | ||
|
|
b72cda05c1 | ||
|
|
520d6bee78 | ||
|
|
4dcf4612b3 | ||
|
|
fa370c6900 | ||
|
|
f5ef6b9c02 | ||
|
|
cf8e22779a | ||
|
|
10ac00940a | ||
|
|
00beeb0501 | ||
|
|
db63d98b00 | ||
|
|
3c80eb35d2 | ||
|
|
96b6b53301 | ||
|
|
4dc5ace3f8 | ||
|
|
26b8c4c7d5 | ||
|
|
90f978bcd6 | ||
|
|
917847b5da | ||
|
|
f22e3fd549 | ||
|
|
7b2cf9f3d8 | ||
|
|
33f5da8c94 | ||
|
|
4a9f77f56a | ||
|
|
a99b53ae32 | ||
|
|
1925382980 | ||
|
|
d982ebca9d | ||
|
|
5810f9517e | ||
|
|
8f18e05075 | ||
|
|
c611ed5cfe | ||
|
|
65dedfe500 | ||
|
|
f494661235 | ||
|
|
4abe080db2 | ||
|
|
6c84850a7e | ||
|
|
63708ec92b | ||
|
|
8b5328aa74 | ||
|
|
5c9e59b136 | ||
|
|
7123a620c2 | ||
|
|
6609b57084 | ||
|
|
9123e3c866 | ||
|
|
92d0c6bce6 | ||
|
|
ae3f1885c2 | ||
|
|
3ca6ec8b56 | ||
|
|
83a46d7313 | ||
|
|
b55b37b874 | ||
|
|
c76bcecca0 | ||
|
|
3776397468 | ||
|
|
4704c4a077 | ||
|
|
034ca1d639 | ||
|
|
e5862a2064 | ||
|
|
0332a2efe3 | ||
|
|
be8e461f55 | ||
|
|
722ee68b4c | ||
|
|
e4078a3307 | ||
|
|
907a9dc563 | ||
|
|
f6df94081d | ||
|
|
2436192995 | ||
|
|
f54e2e032a | ||
|
|
1a28660dfd | ||
|
|
f98a57582a | ||
|
|
0cc365261e | ||
|
|
6f78049c1f | ||
|
|
2f11aa6c14 | ||
|
|
09cb61ae1e | ||
|
|
65a152e518 | ||
|
|
92d88271d7 | ||
|
|
a56c354e84 | ||
|
|
29a9b7e23e | ||
|
|
94a419249b | ||
|
|
12907c9061 | ||
|
|
0aa468f8f3 | ||
|
|
91447e1502 | ||
|
|
84ea14820a | ||
|
|
8fb472c37c | ||
|
|
6efb6d4e7b | ||
|
|
99da20f831 | ||
|
|
52d1dc9ed9 | ||
|
|
5633bb18ef | ||
|
|
b2cb0ecff3 | ||
|
|
2089b339b4 | ||
|
|
2e83adc846 | ||
|
|
189cbcecd7 | ||
|
|
5aebde79e7 | ||
|
|
5cce4a1db4 | ||
|
|
c6ff74f166 | ||
|
|
e8aad9f469 | ||
|
|
455a061f35 | ||
|
|
a9f35df278 | ||
|
|
82124a8b1c | ||
|
|
f3f93faf1d | ||
|
|
57d117eb98 | ||
|
|
d01b293a27 | ||
|
|
a9f5289672 | ||
|
|
1df1419827 | ||
|
|
f20a0d2ff7 | ||
|
|
b9e5a6f9b9 | ||
|
|
b2eaf1f6a3 | ||
|
|
a873974f0d | ||
|
|
09974e1a10 | ||
|
|
45d5980527 | ||
|
|
73a25a412c | ||
|
|
f0647ce240 | ||
|
|
7c09dd9d10 | ||
|
|
c5bdbc89ca | ||
|
|
673832a7e1 | ||
|
|
6c1989b527 | ||
|
|
96bc0e669c | ||
|
|
9791490449 | ||
|
|
ee053e6642 | ||
|
|
56f6dbe9a6 | ||
|
|
49c18023bd | ||
|
|
3f5f29122b | ||
|
|
2ed03bc8da | ||
|
|
5aa72a4c76 | ||
|
|
4a8fdcbbbc | ||
|
|
5855804291 | ||
|
|
9fdb7452a2 | ||
|
|
7573b2d0ba | ||
|
|
cdd93ee86b | ||
|
|
dbbd450b62 | ||
|
|
255f1cee61 | ||
|
|
36ac4ecdb9 | ||
|
|
4edb92365a | ||
|
|
89eee21978 | ||
|
|
a8563ad905 | ||
|
|
06eebe36ee | ||
|
|
5fc18fc445 | ||
|
|
53d3be3b27 | ||
|
|
078c5db2b0 | ||
|
|
356d237e60 | ||
|
|
e799aa9b37 | ||
|
|
b36a263ef6 | ||
|
|
6e2fa40155 | ||
|
|
df2cb9e26c | ||
|
|
e33d640620 | ||
|
|
32dcb75ef8 | ||
|
|
b1c2f90feb | ||
|
|
8064e1ecf6 | ||
|
|
21787f2af5 | ||
|
|
5acdf018d3 | ||
|
|
47ec19b46d | ||
|
|
60b474a4f9 | ||
|
|
a027d1ef3d | ||
|
|
7f68b4f800 | ||
|
|
71717c6b02 | ||
|
|
8ad1ecfcb9 | ||
|
|
338b21620b | ||
|
|
78ed91b7c3 | ||
|
|
dbe249e6ce | ||
|
|
241716b4f3 | ||
|
|
f19e1960b7 | ||
|
|
70b7f6614e | ||
|
|
a680a62220 | ||
|
|
cb17e185f1 | ||
|
|
8b2990a16f | ||
|
|
6111e02b1b | ||
|
|
186feefdb5 | ||
|
|
312858e278 | ||
|
|
61ca42eb83 | ||
|
|
7f21e65625 | ||
|
|
cdf8e91dad | ||
|
|
aa55ced425 | ||
|
|
1d2c8719c3 | ||
|
|
09ede38509 | ||
|
|
be14678cd0 | ||
|
|
d2e6238ad7 | ||
|
|
f69e8e82e3 | ||
|
|
96808b3464 | ||
|
|
3ce4e7f7a2 | ||
|
|
606ca4ea98 | ||
|
|
acf279d3ba | ||
|
|
2425dc5459 | ||
|
|
6ae782b984 | ||
|
|
eadf63b47e | ||
|
|
12e5f097a5 | ||
|
|
4c1e688f12 | ||
|
|
3b2cf7c0da | ||
|
|
4cc3ee278d | ||
|
|
95493608ed | ||
|
|
101a029344 | ||
|
|
92fe0adf1e | ||
|
|
0e41ebf849 | ||
|
|
969fb0241a | ||
|
|
d588a61be5 | ||
|
|
82207d8f52 | ||
|
|
c85ae57697 | ||
|
|
e6fe027e57 | ||
|
|
3090151c50 | ||
|
|
f899cb0478 | ||
|
|
f5c5ce23b0 | ||
|
|
084b17e950 | ||
|
|
a643d90a2b | ||
|
|
10b61be19a | ||
|
|
f0833786d9 | ||
|
|
ad9296a00c | ||
|
|
bf51e578b2 | ||
|
|
000a11c8bc | ||
|
|
531facd74c | ||
|
|
7843e2da99 | ||
|
|
77e2472175 | ||
|
|
336480a338 | ||
|
|
f102901b90 | ||
|
|
14b162aabc | ||
|
|
07f28d0971 | ||
|
|
40d3ac19d1 | ||
|
|
7c0a9bed46 | ||
|
|
c372108b91 | ||
|
|
0bccee23e9 | ||
|
|
831bf148d8 | ||
|
|
4b1bbf0ba4 | ||
|
|
5ef9b574ab | ||
|
|
d55611ce02 | ||
|
|
07228c4575 | ||
|
|
7bd15053e5 | ||
|
|
548251a2ba | ||
|
|
fd6322652b | ||
|
|
8b1718c9b3 | ||
|
|
82aba726db | ||
|
|
b264b2473b | ||
|
|
e80d71e654 | ||
|
|
3472033c7e | ||
|
|
3db4f59b0a | ||
|
|
5c023d58d9 | ||
|
|
6a9968bd97 | ||
|
|
9c90c9faf1 | ||
|
|
b51e9ccdb9 | ||
|
|
967680263b | ||
|
|
8a4bbfbd1c | ||
|
|
9f63822038 | ||
|
|
9756aed94f | ||
|
|
97562118a1 | ||
|
|
fd217308e1 | ||
|
|
6d4098b8b8 | ||
|
|
2f7b70516c | ||
|
|
9761483530 | ||
|
|
6cea8a2246 | ||
|
|
b7250a284a | ||
|
|
1402f4a48b | ||
|
|
70fe0fb7a7 | ||
|
|
5471324cfe | ||
|
|
0a78848612 | ||
|
|
f553bce7f1 | ||
|
|
43566a54b6 | ||
|
|
51a811ac8e | ||
|
|
74fba30d5f | ||
|
|
22ea797b15 | ||
|
|
0ce10e8824 | ||
|
|
ca0d63a0fc | ||
|
|
2a9b34104d | ||
|
|
16cbc3365b | ||
|
|
0122ccb797 | ||
|
|
fc2beb3d19 | ||
|
|
698da4c3a1 | ||
|
|
07f6f1d04b | ||
|
|
6dcd06534b | ||
|
|
1fb165e5ad | ||
|
|
3775b3e142 | ||
|
|
92417d4d97 | ||
|
|
6340d499b9 | ||
|
|
4dfe1d9af0 | ||
|
|
ee5a519120 | ||
|
|
c29c580fbe | ||
|
|
48cf9de000 | ||
|
|
1945b6ddf5 | ||
|
|
f8d4c45631 | ||
|
|
d8bd42297f | ||
|
|
f386de1bd7 | ||
|
|
cc8669c886 | ||
|
|
3d6e9740aa | ||
|
|
6ea7486bb1 | ||
|
|
2f17c87a80 | ||
|
|
6ac60a9858 | ||
|
|
78c2cf451b | ||
|
|
64db29417d | ||
|
|
aa63c89a6a | ||
|
|
1fd339e5a0 | ||
|
|
8ebbad4314 | ||
|
|
f1535d3993 | ||
|
|
cad32d19e9 | ||
|
|
64ddcb64b7 | ||
|
|
5ab55bb2b3 | ||
|
|
2c008d544c | ||
|
|
59bb977b3b | ||
|
|
64ff49acf3 | ||
|
|
69293e2d1a | ||
|
|
7111480820 | ||
|
|
55f4ff6fee | ||
|
|
e3056ed403 | ||
|
|
7059d3843d | ||
|
|
c89d030222 | ||
|
|
6a76330c84 | ||
|
|
bd256b9426 | ||
|
|
c4ace07765 | ||
|
|
8745fd8b92 | ||
|
|
2baa9a0108 | ||
|
|
f91a7b2c7a | ||
|
|
542e4da878 | ||
|
|
41aa82814d | ||
|
|
998773be6b | ||
|
|
f35b007e98 | ||
|
|
f2800632e3 | ||
|
|
e30f16cec2 | ||
|
|
3586818fda | ||
|
|
602238f6a5 | ||
|
|
1901313873 | ||
|
|
8652eb69de | ||
|
|
e896a737f4 | ||
|
|
4f61b4320f | ||
|
|
9d1cb8f595 | ||
|
|
81e9ac0e12 | ||
|
|
be4534da2d | ||
|
|
f4a31ad563 |
@@ -1,8 +0,0 @@
|
||||
# Changesets
|
||||
|
||||
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
||||
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
||||
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
||||
|
||||
We have a quick list of common questions to get you started engaging with this project in
|
||||
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
||||
@@ -1,7 +1,7 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
**/node_modules
|
||||
# **/node_modules
|
||||
.pnp
|
||||
.pnp.js
|
||||
.pnpm-store/
|
||||
|
||||
60
.env.example
@@ -1,8 +1,7 @@
|
||||
########################################################################
|
||||
# ------------ MANDATORY (CHANGE ACCORDING TO YOUR SETUP) ------------#
|
||||
# ------------ MANDATORY (CHANGE ACCORDING TO YOUR SETUP) ------------ #
|
||||
########################################################################
|
||||
|
||||
|
||||
############
|
||||
# BASICS #
|
||||
############
|
||||
@@ -51,13 +50,28 @@ SMTP_SECURE_ENABLED=0
|
||||
SMTP_USER=smtpUser
|
||||
SMTP_PASSWORD=smtpPassword
|
||||
|
||||
|
||||
########################################################################
|
||||
# ------------------------------ OPTIONAL -----------------------------#
|
||||
########################################################################
|
||||
|
||||
# Uncomment the variables you would like to use and customize the values.
|
||||
|
||||
# Custom local storage path for file uploads
|
||||
#UPLOADS_DIR=
|
||||
|
||||
##############
|
||||
# S3 STORAGE #
|
||||
##############
|
||||
|
||||
# S3 Storage is required for the file upload in serverless environments like Vercel
|
||||
S3_ACCESS_KEY=
|
||||
S3_SECRET_KEY=
|
||||
S3_REGION=
|
||||
S3_BUCKET_NAME=
|
||||
# Configure a third party S3 compatible storage service endpoint like StorJ leave empty if you use Amazon S3
|
||||
# e.g., https://gateway.storjshare.io
|
||||
S3_ENDPOINT_URL=
|
||||
|
||||
#####################
|
||||
# Disable Features #
|
||||
#####################
|
||||
@@ -71,6 +85,9 @@ PASSWORD_RESET_DISABLED=1
|
||||
# Signup. Disable the ability for new users to create an account.
|
||||
# SIGNUP_DISABLED=1
|
||||
|
||||
# Email login. Disable the ability for users to login with email.
|
||||
# EMAIL_AUTH_DISABLED=1
|
||||
|
||||
# Team Invite. Disable the ability for invited users to create an account.
|
||||
# INVITE_DISABLED=1
|
||||
|
||||
@@ -84,21 +101,25 @@ TERMS_URL=
|
||||
IMPRINT_URL=
|
||||
|
||||
# Configure Github Login
|
||||
GITHUB_AUTH_ENABLED=0
|
||||
GITHUB_ID=
|
||||
GITHUB_SECRET=
|
||||
|
||||
# Configure Google Login
|
||||
GOOGLE_AUTH_ENABLED=0
|
||||
GOOGLE_CLIENT_ID=
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
|
||||
# Configure Azure Active Directory Login
|
||||
AZUREAD_AUTH_ENABLED=0
|
||||
AZUREAD_CLIENT_ID=
|
||||
AZUREAD_CLIENT_SECRET=
|
||||
AZUREAD_TENANT_ID=
|
||||
|
||||
# OpenID Connect (OIDC) configuration
|
||||
# OIDC_CLIENT_ID=
|
||||
# OIDC_CLIENT_SECRET=
|
||||
# OIDC_ISSUER=
|
||||
# OIDC_DISPLAY_NAME=
|
||||
# OIDC_SIGNING_ALGORITHM=
|
||||
|
||||
# Cron Secret
|
||||
CRON_SECRET=
|
||||
|
||||
@@ -118,14 +139,18 @@ NEXT_PUBLIC_FORMBRICKS_API_HOST=
|
||||
NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID=
|
||||
NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID=
|
||||
|
||||
# Oauth credentials for Google sheet integration
|
||||
# Oauth credentials for Google sheet integration
|
||||
GOOGLE_SHEETS_CLIENT_ID=
|
||||
GOOGLE_SHEETS_CLIENT_SECRET=
|
||||
GOOGLE_SHEETS_REDIRECT_URL=
|
||||
|
||||
# Oauth credentials for Airtable integration
|
||||
# Oauth credentials for Airtable integration
|
||||
AIRTABLE_CLIENT_ID=
|
||||
|
||||
# Oauth credentials for Slack integration
|
||||
SLACK_CLIENT_ID=
|
||||
SLACK_CLIENT_SECRET=
|
||||
|
||||
# Enterprise License Key
|
||||
ENTERPRISE_LICENSE_KEY=
|
||||
|
||||
@@ -137,3 +162,22 @@ ENTERPRISE_LICENSE_KEY=
|
||||
|
||||
# set to 1 to skip onboarding for new users
|
||||
# ONBOARDING_DISABLED=1
|
||||
|
||||
# Send new users to customer.io
|
||||
# CUSTOMER_IO_API_KEY=
|
||||
# CUSTOMER_IO_SITE_ID=
|
||||
|
||||
# Ignore Rate Limiting across the Formbricks app
|
||||
# RATE_LIMITING_DISABLED=1
|
||||
|
||||
# OpenTelemetry URL for tracing
|
||||
# OPENTELEMETRY_LISTENER_URL=http://localhost:4318/v1/traces
|
||||
|
||||
# Unsplash API Key
|
||||
UNSPLASH_ACCESS_KEY=
|
||||
|
||||
# The below is used for Next Caching (uses In-Memory from Next Cache if not provided)
|
||||
# REDIS_URL:
|
||||
|
||||
# The below is used for Rate Limiting (uses In-Memory LRU Cache if not provided) (You can use a service like Webdis for this)
|
||||
# REDIS_HTTP_URL:
|
||||
|
||||
5
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -42,7 +42,6 @@ body:
|
||||
- First time: Please read our [introductory blog post](https://formbricks.com/blog/join-the-formtribe)
|
||||
- All UI components are in the package `formbricks/ui`
|
||||
- Run `pnpm go` to find a demo app to test in-app surveys at `localhost:3002`
|
||||
- Everything is type-safe
|
||||
- We use **chatGPT** to help refactor code. Use our [Formbricks ✨ megaprompt ✨](https://github.com/formbricks/formbricks/blob/main/megaprompt.md) to create the right
|
||||
context before you write your prompt.
|
||||
- Everything is type-safe.
|
||||
- We use **chatGPT** to help refactor code.
|
||||
- Anything unclear? [Ask in Discord](https://formbricks.com/discord)
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -32,7 +32,7 @@ Fixes # (issue)
|
||||
- [ ] Removed all `console.logs`
|
||||
- [ ] Merged the latest changes from main onto my branch with `git pull origin main`
|
||||
- [ ] My changes don't cause any responsiveness issues
|
||||
- [ ] First PR at Formbricks? [Please sign the CLA!](https://formbricks.com/clmyhzfrymr4ko00hycsg1tvx) Without it we wont be able to merge it 🙏
|
||||
- [ ] First PR at Formbricks? [Please sign the CLA!](https://cla-assistant.io/formbricks/formbricks) Without it we wont be able to merge it 🙏
|
||||
|
||||
### Appreciated
|
||||
|
||||
|
||||
55
.github/actions/cache-build-web/action.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
name: Build & Cache Web App
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Cache Build
|
||||
uses: actions/cache@v3
|
||||
id: cache-build
|
||||
env:
|
||||
cache-name: prod-build
|
||||
key-1: ${{ hashFiles('pnpm-lock.yaml') }}
|
||||
key-2: ${{ hashFiles('apps/**/**.[jt]s', 'apps/**/**.[jt]sx', 'packages/**/**.[jt]s', 'packages/**/**.[jt]sx', '!**/node_modules') }}
|
||||
with:
|
||||
path: |
|
||||
${{ github.workspace }}/apps/web/.next
|
||||
**/.turbo/**
|
||||
**/dist/**
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}
|
||||
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20.x
|
||||
if: steps.cache-build.outputs.cache-hit != 'true'
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
if: steps.cache-build.outputs.cache-hit != 'true'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --config.platform=linux --config.architecture=x64
|
||||
if: steps.cache-build.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
|
||||
- name: create .env
|
||||
run: cp .env.example .env
|
||||
shell: bash
|
||||
|
||||
- name: Generate Random ENCRYPTION_KEY
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
|
||||
echo "ENTERPRISE_LICENSE_KEY=$SECRET" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- run: |
|
||||
pnpm build --filter=web...
|
||||
|
||||
if: steps.cache-build.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
10
.github/actions/dangerous-git-checkout/action.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
name: Dangerous git Checkout
|
||||
description: "Git Checkout from PR code so we can run checks from forks"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 2
|
||||
6
.github/workflows/build-formbricks-com.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Build
|
||||
name: Build formbricks-com
|
||||
on:
|
||||
workflow_call:
|
||||
jobs:
|
||||
@@ -11,10 +11,10 @@ jobs:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js 18.x
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
node-version: 20.x
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
|
||||
12
.github/workflows/build-web.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Build
|
||||
name: Build web
|
||||
on:
|
||||
workflow_call:
|
||||
jobs:
|
||||
@@ -8,13 +8,13 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Setup Node.js 18.x
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
node-version: 20.x
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
- name: create .env
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Generate Random NEXTAUTH_SECRET
|
||||
- name: Generate Random ENCRYPTION_KEY
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
name: Cron - reportUsageToStripe
|
||||
name: Cron - Report usage to Stripe
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# "Scheduled workflows run on the latest commit on the default or base branch."
|
||||
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
|
||||
schedule:
|
||||
# This will run the job at 22:00 UTC every day of every month.
|
||||
- cron: "0 22 * * *"
|
||||
# schedule:
|
||||
# This will run the job at 20:00 UTC every day of every month.
|
||||
# - cron: "0 20 * * *"
|
||||
jobs:
|
||||
cron-reportUsageToStripe:
|
||||
env:
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
name: Cron - closeOnDate
|
||||
name: Cron - Survey status update
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# "Scheduled workflows run on the latest commit on the default or base branch."
|
||||
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
|
||||
schedule:
|
||||
# Runs “At 00:00.” (see https://crontab.guru)
|
||||
- cron: "0 0 * * *"
|
||||
# schedule:
|
||||
# Runs “At 00:00.” (see https://crontab.guru)
|
||||
# - cron: "0 0 * * *"
|
||||
jobs:
|
||||
cron-weeklySummary:
|
||||
env:
|
||||
@@ -16,7 +17,7 @@ jobs:
|
||||
- name: cURL request
|
||||
if: ${{ env.APP_URL && env.CRON_SECRET }}
|
||||
run: |
|
||||
curl ${{ env.APP_URL }}/api/cron/close_surveys \
|
||||
curl ${{ env.APP_URL }}/api/cron/survey-status \
|
||||
-X POST \
|
||||
-H 'content-type: application/json' \
|
||||
-H 'x-api-key: ${{ env.CRON_SECRET }}' \
|
||||
11
.github/workflows/cron-weeklySummary.yml
vendored
@@ -1,11 +1,12 @@
|
||||
name: Cron - weeklySummary
|
||||
name: Cron - Weekly summary
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# "Scheduled workflows run on the latest commit on the default or base branch."
|
||||
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
|
||||
schedule:
|
||||
# Runs “At 08:00 on Monday.” (see https://crontab.guru)
|
||||
- cron: "0 8 * * 1"
|
||||
# schedule:
|
||||
# Runs “At 08:00 on Monday.” (see https://crontab.guru)
|
||||
# - cron: "0 8 * * 1"
|
||||
jobs:
|
||||
cron-weeklySummary:
|
||||
env:
|
||||
@@ -16,7 +17,7 @@ jobs:
|
||||
- name: cURL request
|
||||
if: ${{ env.APP_URL && env.CRON_SECRET }}
|
||||
run: |
|
||||
curl ${{ env.APP_URL }}/api/cron/weekly_summary \
|
||||
curl ${{ env.APP_URL }}/api/cron/weekly-summary \
|
||||
-X POST \
|
||||
-H 'content-type: application/json' \
|
||||
-H 'x-api-key: ${{ env.CRON_SECRET }}' \
|
||||
|
||||
75
.github/workflows/e2e.yml
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
name: E2E Tests
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
name: Run E2E Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Build & Cache Web Binaries
|
||||
uses: ./.github/actions/cache-build-web
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Start PostgreSQL
|
||||
run: |
|
||||
cd packages/database && pnpm db:up &
|
||||
for attempt in {1..20}; do
|
||||
if nc -zv localhost 5432; then
|
||||
echo "Ready"
|
||||
break
|
||||
fi
|
||||
echo "Waiting..."
|
||||
sleep 5
|
||||
done
|
||||
pnpm db:migrate:dev
|
||||
- name: Serve packages for lazy loading
|
||||
run: |
|
||||
cd packages/surveys && pnpm serve &
|
||||
|
||||
- name: Run App
|
||||
run: |
|
||||
NODE_ENV=test pnpm start --filter=web &
|
||||
for attempt in {1..20}; do
|
||||
if [ $(curl -o /dev/null -s -w "%{http_code}" http://localhost:3000/health) -eq 200 ]; then
|
||||
echo "Ready"
|
||||
break
|
||||
fi
|
||||
echo "Waiting..."
|
||||
sleep 10
|
||||
done
|
||||
|
||||
- name: Test Serve endpoints
|
||||
run: |
|
||||
curl -s http://localhost:3003
|
||||
|
||||
- name: Cache Playwright
|
||||
uses: actions/cache@v3
|
||||
id: playwright-cache
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install Playwright
|
||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
run: pnpm exec playwright install --with-deps
|
||||
|
||||
- name: Run E2E Tests
|
||||
run: |
|
||||
pnpm test:e2e
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
131
.github/workflows/kamal-deploy.yml
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
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
Normal file
@@ -0,0 +1,128 @@
|
||||
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
|
||||
4
.github/workflows/lint.yml
vendored
@@ -8,8 +8,8 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Setup Node.js 18.x
|
||||
uses: actions/setup-node@v3
|
||||
|
||||
40
.github/workflows/playwright.yml
vendored
@@ -1,40 +0,0 @@
|
||||
name: E2E Tests
|
||||
on:
|
||||
workflow_call:
|
||||
jobs:
|
||||
build:
|
||||
name: Run E2E Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install Docker Compose
|
||||
run: sudo apt-get update && sudo apt-get install -y docker-compose
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install -g pnpm && pnpm install
|
||||
|
||||
- name: Build Formricks JS package
|
||||
run: pnpm build --filter=js
|
||||
|
||||
- name: Build Formbricks Image & Run
|
||||
run: docker-compose up -d
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: pnpm exec playwright install --with-deps
|
||||
|
||||
- name: Run Playwright tests
|
||||
run: pnpm test:e2e
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
32
.github/workflows/pr.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: PR Update
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
merge_group:
|
||||
@@ -12,27 +12,53 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
outputs:
|
||||
has-files-requiring-all-checks: ${{ steps.filter.outputs.has-files-requiring-all-checks }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
has-files-requiring-all-checks:
|
||||
- "!(**.md|.github/CODEOWNERS)"
|
||||
|
||||
test:
|
||||
name: Run Tests
|
||||
name: Run Unit Tests
|
||||
needs: [changes]
|
||||
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
|
||||
uses: ./.github/workflows/test.yml
|
||||
secrets: inherit
|
||||
|
||||
lint:
|
||||
name: Run Linters
|
||||
needs: [changes]
|
||||
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
|
||||
uses: ./.github/workflows/lint.yml
|
||||
secrets: inherit
|
||||
|
||||
build:
|
||||
name: Build Formbricks-web
|
||||
needs: [changes]
|
||||
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
|
||||
uses: ./.github/workflows/build-web.yml
|
||||
secrets: inherit
|
||||
|
||||
e2e-test:
|
||||
name: Run E2E Tests
|
||||
uses: ./.github/workflows/playwright.yml
|
||||
needs: [changes]
|
||||
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
|
||||
uses: ./.github/workflows/e2e.yml
|
||||
secrets: inherit
|
||||
|
||||
required:
|
||||
name: PR Check Summary
|
||||
needs: [lint, test, build, e2e-test]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
70
.github/workflows/release-docker-github-data-migration.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: Docker for Data Migrations
|
||||
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
env:
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: formbricks/data-migrations
|
||||
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/formbricks?schema=public"
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
# This is used to complete the identity challenge
|
||||
# with sigstore/fulcio when running outside of PRs.
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@6e04d228eb30da1757ee4e1dd75a0ec73a653e06 #v3.1.1
|
||||
with:
|
||||
cosign-release: "v2.1.1"
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
type=raw,value=${{ github.ref_name }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
file: ./packages/database/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
DATABASE_URL=${{ env.DATABASE_URL }}
|
||||
|
||||
- name: Sign the published Docker image
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
run: |
|
||||
cosign sign --yes ghcr.io/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
|
||||
34
.github/workflows/release-docker-github.yml
vendored
@@ -31,19 +31,12 @@ jobs:
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Generate Random NEXTAUTH_SECRET
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "NEXTAUTH_SECRET=$SECRET" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate Random ENCRYPTION_KEY
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Depot CLI
|
||||
uses: depot/setup-action@v1
|
||||
|
||||
# Install the cosign tool except on PR
|
||||
# https://github.com/sigstore/cosign-installer
|
||||
- name: Install cosign
|
||||
@@ -52,17 +45,6 @@ jobs:
|
||||
with:
|
||||
cosign-release: "v2.1.1"
|
||||
|
||||
# Add support for more platforms with QEMU (optional)
|
||||
# https://github.com/docker/setup-qemu-action
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
# Set up BuildKit Docker container builder to be able to build
|
||||
# multi-platform images and export cache
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3 # v3.0.0
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
@@ -85,20 +67,18 @@ jobs:
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v5 # v5.0.0
|
||||
uses: depot/build-push-action@v1
|
||||
with:
|
||||
project: tw0fqmsx3c
|
||||
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
|
||||
context: .
|
||||
file: ./apps/web/Dockerfile
|
||||
# platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
NEXTAUTH_SECRET=${{ env.NEXTAUTH_SECRET }}
|
||||
DATABASE_URL=${{ env.DATABASE_URL }}
|
||||
ENCRYPTION_KEY=${{ env.ENCRYPTION_KEY }}
|
||||
|
||||
# Sign the resulting Docker image digest except on PRs.
|
||||
# This will only write to the public Rekor transparency log when the Docker
|
||||
|
||||
14
.github/workflows/release-docker.yml
vendored
@@ -14,16 +14,6 @@ jobs:
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/formbricks?schema=public"
|
||||
steps:
|
||||
- name: Generate Random NEXTAUTH_SECRET
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "NEXTAUTH_SECRET=$SECRET" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate Random ENCRYPTION_KEY
|
||||
run: |
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
@@ -52,7 +42,3 @@ jobs:
|
||||
tags: |
|
||||
${{ secrets.DOCKER_USERNAME }}/formbricks:${{ env.RELEASE_TAG }}
|
||||
${{ secrets.DOCKER_USERNAME }}/formbricks:latest
|
||||
build-args: |
|
||||
NEXTAUTH_SECRET=${{ env.NEXTAUTH_SECRET }}
|
||||
DATABASE_URL=${{ env.DATABASE_URL }}
|
||||
ENCRYPTION_KEY=${{ env.ENCRYPTION_KEY }}
|
||||
|
||||
17
.github/workflows/test.yml
vendored
@@ -3,22 +3,18 @@ on:
|
||||
workflow_call:
|
||||
jobs:
|
||||
build:
|
||||
name: Tests
|
||||
name: Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
|
||||
- name: Setup Node.js 18.x
|
||||
- name: Setup Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
node-version: 20.x
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
@@ -34,8 +30,5 @@ jobs:
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
echo "ENCRYPTION_KEY=$SECRET" >> $GITHUB_ENV
|
||||
|
||||
- name: Build formbricks-js dependencies
|
||||
run: pnpm build --filter=js
|
||||
|
||||
- name: Test
|
||||
run: pnpm test
|
||||
|
||||
7
.gitignore
vendored
@@ -51,3 +51,10 @@ Zone.Identifier
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
|
||||
# uploads
|
||||
packages/lib/uploads
|
||||
|
||||
# Vite Timestamps
|
||||
vite.config.*.timestamp-*
|
||||
|
||||
|
||||
14
.kamal/hooks/post-deploy.sample
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
# A sample post-deploy hook
|
||||
#
|
||||
# These environment variables are available:
|
||||
# KAMAL_RECORDED_AT
|
||||
# KAMAL_PERFORMER
|
||||
# KAMAL_VERSION
|
||||
# KAMAL_HOSTS
|
||||
# KAMAL_ROLE (if set)
|
||||
# KAMAL_DESTINATION (if set)
|
||||
# KAMAL_RUNTIME
|
||||
|
||||
echo "$KAMAL_PERFORMER deployed $KAMAL_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds"
|
||||
3
.kamal/hooks/post-traefik-reboot.sample
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Rebooted Traefik on $KAMAL_HOSTS"
|
||||
51
.kamal/hooks/pre-build.sample
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/bin/sh
|
||||
|
||||
# A sample pre-build hook
|
||||
#
|
||||
# Checks:
|
||||
# 1. We have a clean checkout
|
||||
# 2. A remote is configured
|
||||
# 3. The branch has been pushed to the remote
|
||||
# 4. The version we are deploying matches the remote
|
||||
#
|
||||
# These environment variables are available:
|
||||
# KAMAL_RECORDED_AT
|
||||
# KAMAL_PERFORMER
|
||||
# KAMAL_VERSION
|
||||
# KAMAL_HOSTS
|
||||
# KAMAL_ROLE (if set)
|
||||
# KAMAL_DESTINATION (if set)
|
||||
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo "Git checkout is not clean, aborting..." >&2
|
||||
git status --porcelain >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
first_remote=$(git remote)
|
||||
|
||||
if [ -z "$first_remote" ]; then
|
||||
echo "No git remote set, aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
current_branch=$(git branch --show-current)
|
||||
|
||||
if [ -z "$current_branch" ]; then
|
||||
echo "Not on a git branch, aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
remote_head=$(git ls-remote $first_remote --tags $current_branch | cut -f1)
|
||||
|
||||
if [ -z "$remote_head" ]; then
|
||||
echo "Branch not pushed to remote, aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$KAMAL_VERSION" != "$remote_head" ]; then
|
||||
echo "Version ($KAMAL_VERSION) does not match remote HEAD ($remote_head), aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
47
.kamal/hooks/pre-connect.sample
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# A sample pre-connect check
|
||||
#
|
||||
# Warms DNS before connecting to hosts in parallel
|
||||
#
|
||||
# These environment variables are available:
|
||||
# KAMAL_RECORDED_AT
|
||||
# KAMAL_PERFORMER
|
||||
# KAMAL_VERSION
|
||||
# KAMAL_HOSTS
|
||||
# KAMAL_ROLE (if set)
|
||||
# KAMAL_DESTINATION (if set)
|
||||
# KAMAL_RUNTIME
|
||||
|
||||
hosts = ENV["KAMAL_HOSTS"].split(",")
|
||||
results = nil
|
||||
max = 3
|
||||
|
||||
elapsed = Benchmark.realtime do
|
||||
results = hosts.map do |host|
|
||||
Thread.new do
|
||||
tries = 1
|
||||
|
||||
begin
|
||||
Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)
|
||||
rescue SocketError
|
||||
if tries < max
|
||||
puts "Retrying DNS warmup: #{host}"
|
||||
tries += 1
|
||||
sleep rand
|
||||
retry
|
||||
else
|
||||
puts "DNS warmup failed: #{host}"
|
||||
host
|
||||
end
|
||||
end
|
||||
|
||||
tries
|
||||
end
|
||||
end.map(&:value)
|
||||
end
|
||||
|
||||
retries = results.sum - hosts.size
|
||||
nopes = results.count { |r| r == max }
|
||||
|
||||
puts "Prewarmed %d DNS lookups in %.2f sec: %d retries, %d failures" % [ hosts.size, elapsed, retries, nopes ]
|
||||
109
.kamal/hooks/pre-deploy.sample
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# A sample pre-deploy hook
|
||||
#
|
||||
# Checks the Github status of the build, waiting for a pending build to complete for up to 720 seconds.
|
||||
#
|
||||
# Fails unless the combined status is "success"
|
||||
#
|
||||
# These environment variables are available:
|
||||
# KAMAL_RECORDED_AT
|
||||
# KAMAL_PERFORMER
|
||||
# KAMAL_VERSION
|
||||
# KAMAL_HOSTS
|
||||
# KAMAL_COMMAND
|
||||
# KAMAL_SUBCOMMAND
|
||||
# KAMAL_ROLE (if set)
|
||||
# KAMAL_DESTINATION (if set)
|
||||
|
||||
# Only check the build status for production deployments
|
||||
if ENV["KAMAL_COMMAND"] == "rollback" || ENV["KAMAL_DESTINATION"] != "production"
|
||||
exit 0
|
||||
end
|
||||
|
||||
require "bundler/inline"
|
||||
|
||||
# true = install gems so this is fast on repeat invocations
|
||||
gemfile(true, quiet: true) do
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "octokit"
|
||||
gem "faraday-retry"
|
||||
end
|
||||
|
||||
MAX_ATTEMPTS = 72
|
||||
ATTEMPTS_GAP = 10
|
||||
|
||||
def exit_with_error(message)
|
||||
$stderr.puts message
|
||||
exit 1
|
||||
end
|
||||
|
||||
class GithubStatusChecks
|
||||
attr_reader :remote_url, :git_sha, :github_client, :combined_status
|
||||
|
||||
def initialize
|
||||
@remote_url = `git config --get remote.origin.url`.strip.delete_prefix("https://github.com/")
|
||||
@git_sha = `git rev-parse HEAD`.strip
|
||||
@github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
|
||||
refresh!
|
||||
end
|
||||
|
||||
def refresh!
|
||||
@combined_status = github_client.combined_status(remote_url, git_sha)
|
||||
end
|
||||
|
||||
def state
|
||||
combined_status[:state]
|
||||
end
|
||||
|
||||
def first_status_url
|
||||
first_status = combined_status[:statuses].find { |status| status[:state] == state }
|
||||
first_status && first_status[:target_url]
|
||||
end
|
||||
|
||||
def complete_count
|
||||
combined_status[:statuses].count { |status| status[:state] != "pending"}
|
||||
end
|
||||
|
||||
def total_count
|
||||
combined_status[:statuses].count
|
||||
end
|
||||
|
||||
def current_status
|
||||
if total_count > 0
|
||||
"Completed #{complete_count}/#{total_count} checks, see #{first_status_url} ..."
|
||||
else
|
||||
"Build not started..."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
$stdout.sync = true
|
||||
|
||||
puts "Checking build status..."
|
||||
attempts = 0
|
||||
checks = GithubStatusChecks.new
|
||||
|
||||
begin
|
||||
loop do
|
||||
case checks.state
|
||||
when "success"
|
||||
puts "Checks passed, see #{checks.first_status_url}"
|
||||
exit 0
|
||||
when "failure"
|
||||
exit_with_error "Checks failed, see #{checks.first_status_url}"
|
||||
when "pending"
|
||||
attempts += 1
|
||||
end
|
||||
|
||||
exit_with_error "Checks are still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds" if attempts == MAX_ATTEMPTS
|
||||
|
||||
puts checks.current_status
|
||||
sleep(ATTEMPTS_GAP)
|
||||
checks.refresh!
|
||||
end
|
||||
rescue Octokit::NotFound
|
||||
exit_with_error "Build status could not be found"
|
||||
end
|
||||
3
.kamal/hooks/pre-traefik-reboot.sample
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Rebooting Traefik on $KAMAL_HOSTS..."
|
||||
116
README.md
@@ -1,50 +1,46 @@
|
||||
<div id="top"></div>
|
||||
<div id="top"></div>
|
||||
|
||||
<p align="center">
|
||||
<p align="center">
|
||||
|
||||
<a href="https://formbricks.com">
|
||||
<a href="https://formbricks.com">
|
||||
|
||||
<img width="120" alt="Open Source Privacy First Experience Management Solution Qualtrics Alternative Logo" src="https://github.com/formbricks/formbricks/assets/72809645/0086704f-bee7-4d38-9cc8-fa42ee59e004">
|
||||
<img width="120" alt="Open Source Privacy First Experience Management Solution Qualtrics Alternative Logo" src="https://github.com/formbricks/formbricks/assets/72809645/0086704f-bee7-4d38-9cc8-fa42ee59e004">
|
||||
|
||||
</a>
|
||||
|
||||
<h3 align="center">Formbricks</h3>
|
||||
<h3 align="center">Formbricks</h3>
|
||||
|
||||
<p align="center">
|
||||
<p align="center">
|
||||
Harvest user-insights, build irresistible experiences.
|
||||
<br />
|
||||
<a href="https://formbricks.com/">Website</a> | <a href="https://formbricks.com/discord">Join Discord community</a>
|
||||
<br />
|
||||
<a href="https://formbricks.com/">Website</a> | <a href="https://formbricks.com/discord">Join Discord community</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/formbricks/formbricks/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-AGPL-purple" alt="License"></a> <a href="https://formbricks.com/discord"><img src="https://img.shields.io/discord/979077669410979880?label=Discord&logo=discord&logoColor=%23fff" alt="Join Formbricks Discord"></a> <a href="https://github.com/formbricks/formbricks/stargazers"><img src="https://img.shields.io/github/stars/formbricks/formbricks?logo=github" alt="Github Stars"></a>
|
||||
<a href="https://news.ycombinator.com/item?id=32303986"><img src="https://img.shields.io/badge/Hacker%20News-122-%23FF6600" alt="Hacker News"></a>
|
||||
<a href="[https://www.producthunt.com/products/formbricks](https://www.producthunt.com/posts/formbricks)"><img src="https://img.shields.io/badge/Product%20Hunt-455-orange?logo=producthunt&logoColor=%23fff" alt="Product Hunt"></a>
|
||||
<a href="https://github.blog/2023-04-12-github-accelerator-our-first-cohort-and-whats-next/"><img src="https://img.shields.io/badge/2023-blue?logo=github&label=Github%20Accelerator" alt="Github Accelerator"></a>
|
||||
<a href="https://github.com/formbricks/formbricks/issues?q=is:issue+is:open+label:%22%F0%9F%99%8B%F0%9F%8F%BB%E2%80%8D%E2%99%82%EF%B8%8Fhelp+wanted%22"><img src="https://img.shields.io/badge/Help%20Wanted-Contribute-blue"></a>
|
||||
<p align="center">
|
||||
<a href="https://github.com/formbricks/formbricks/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-AGPL-purple" alt="License"></a> <a href="https://formbricks.com/discord"><img src="https://img.shields.io/discord/979077669410979880?label=Discord&logo=discord&logoColor=%23fff" alt="Join Formbricks Discord"></a> <a href="https://github.com/formbricks/formbricks/stargazers"><img src="https://img.shields.io/github/stars/formbricks/formbricks?logo=github" alt="Github Stars"></a>
|
||||
<a href="https://news.ycombinator.com/item?id=32303986"><img src="https://img.shields.io/badge/Hacker%20News-122-%23FF6600" alt="Hacker News"></a>
|
||||
<a href="[https://www.producthunt.com/products/formbricks](https://www.producthunt.com/posts/formbricks)"><img src="https://img.shields.io/badge/Product%20Hunt-455-orange?logo=producthunt&logoColor=%23fff" alt="Product Hunt"></a>
|
||||
<a href="https://github.blog/2023-04-12-github-accelerator-our-first-cohort-and-whats-next/"><img src="https://img.shields.io/badge/2023-blue?logo=github&label=Github%20Accelerator" alt="Github Accelerator"></a>
|
||||
<a href="https://github.com/formbricks/formbricks/issues?q=is:issue+is:open+label:%22%F0%9F%99%8B%F0%9F%8F%BB%E2%80%8D%E2%99%82%EF%B8%8Fhelp+wanted%22"><img src="https://img.shields.io/badge/Help%20Wanted-Contribute-blue"></a>
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
<div style="background-color:#f8fafc; border-radius:5px;">
|
||||
<p align="center">
|
||||
<i>Trusted by</i>
|
||||
<a href="https://flixbus.com"><img src="https://github.com/formbricks/formbricks/assets/72809645/d6c91d89-7633-4845-ae1e-03bbd2ce0946" height="35px"></a>
|
||||
<a href="https://github.com/calcom/cal.com/"><img src="https://github.com/formbricks/formbricks/assets/675065/1a8763cf-f47e-4960-90f6-334f6dc12a17#gh-light-mode-only" height="20px"></a>
|
||||
<a href="https://github.com/CrowdDotDev/crowd.dev"><img src="https://github.com/formbricks/formbricks/assets/675065/59b1a4d4-25e4-4ef3-b0bf-4426446fbfd0#gh-light-mode-only" height="20px"></a>
|
||||
<a href="https://neverinstall.com/"><img src="https://github.com/formbricks/formbricks/assets/675065/72e5e37b-8ef7-4340-b06e-f1d12a05330f#gh-light-mode-only" height="20px"></a>
|
||||
<a href="https://clovyr.io/"><img src="https://github.com/formbricks/formbricks/assets/675065/9291c8df-9aac-423a-a430-a9a581240075" height="20px"></a>
|
||||
<p align="center">
|
||||
<i>Trusted by</i><br/>
|
||||
<img width="867" alt="clients-hi-res" src="https://github.com/formbricks/formbricks/assets/72809645/924d3693-f66a-4063-bb31-6e5789a8175a">
|
||||
</p>
|
||||
<div>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/2570" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2570" alt="Trendshift Badge for formbricks/formbricks" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/2570" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2570" alt="Trendshift Badge for formbricks/formbricks" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
</p>
|
||||
|
||||
## ✨ About Formbricks
|
||||
|
||||
<img width="1527" alt="formbricks-sneak" src="https://github-production-user-asset-6210df.s3.amazonaws.com/675065/249441967-ccb89ea3-82b4-4bf2-8d2c-528721ec313b.png">
|
||||
<img width="1527" alt="formbricks-sneak" src="https://github-production-user-asset-6210df.s3.amazonaws.com/675065/249441967-ccb89ea3-82b4-4bf2-8d2c-528721ec313b.png">
|
||||
|
||||
Formbricks provides a free and open source surveying platform. Gather feedback at every point in the user journey with beautiful in-app, website, link and email surveys. Build on top of Formbricks or leverage prebuilt data analysis capabilities.
|
||||
|
||||
@@ -70,11 +66,11 @@ Formbricks is both a free and open source survey platform - and a privacy-first
|
||||
|
||||
- [Contact](#contact-us)
|
||||
|
||||
- [License](#license)
|
||||
|
||||
- [Security](#security)
|
||||
|
||||
<a id="features"></a>
|
||||
- [License](#license)
|
||||
|
||||
<a id="features"></a>
|
||||
|
||||
### Features
|
||||
|
||||
@@ -108,26 +104,26 @@ Formbricks is both a free and open source survey platform - and a privacy-first
|
||||
|
||||
- 🧘♂️ [Zod](https://zod.dev/)
|
||||
|
||||
<a id="getting-started"></a>
|
||||
- 🐛 [Vitest](https://vitest.dev/)
|
||||
|
||||
<a id="getting-started"></a>
|
||||
|
||||
## 🚀 Getting started
|
||||
|
||||
We've got several options depending on your need to help you quickly get started with Formbricks.
|
||||
|
||||
<a id="cloud-version"></a>
|
||||
<a id="cloud-version"></a>
|
||||
|
||||
### ☁️ Cloud Version
|
||||
|
||||
Formbricks has a hosted cloud offering with a generous free plan to get you up and running as quickly as possible. To get started, please visit [formbricks.com](https://app.formbricks.com/auth/signup).
|
||||
|
||||
<a id="self-hosted-version"></a>
|
||||
<a id="self-hosted-version"></a>
|
||||
|
||||
### 🐳 Self-hosting Formbricks
|
||||
|
||||
Formbricks is available Open-Source under AGPLv3 license. You can host Formbricks on your own servers using Docker without a subscription.
|
||||
|
||||
(In the future we may develop additional features that aren't in the free Open-Source version).
|
||||
|
||||
If you opt for self-hosting Formbricks, here are a few options to consider:
|
||||
|
||||
#### Docker
|
||||
@@ -142,11 +138,17 @@ You can deploy Formbricks on [Railway](https://railway.app) using the button bel
|
||||
|
||||
[](https://railway.app/new/template/PPDzCd)
|
||||
|
||||
<a id="development"></a>
|
||||
##### RepoCloud
|
||||
|
||||
### 👨💻 Development
|
||||
Or you can also deploy Formbricks on [RepoCloud](https://repocloud.io) using the button below.
|
||||
|
||||
#### Prerequisites
|
||||
[](https://repocloud.io/details/?app_id=254)
|
||||
|
||||
<a id="development"></a>
|
||||
|
||||
## 👨💻 Development
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Here is what you need to be able to run Formbricks:
|
||||
|
||||
@@ -156,11 +158,11 @@ Here is what you need to be able to run Formbricks:
|
||||
|
||||
- [Docker](https://www.docker.com/) - to run PostgreSQL and MailHog
|
||||
|
||||
#### Local Setup
|
||||
### Local Setup
|
||||
|
||||
To get started locally, we've got a [guide to help you](https://formbricks.com/docs/contributing/setup).
|
||||
|
||||
#### Gitpod Setup
|
||||
### Gitpod Setup
|
||||
|
||||
1. Click the button below to open this project in Gitpod.
|
||||
|
||||
@@ -168,7 +170,7 @@ To get started locally, we've got a [guide to help you](https://formbricks.com/d
|
||||
|
||||
[](https://gitpod.io/#https://github.com/formbricks/formbricks)
|
||||
|
||||
<a id="contribution"></a>
|
||||
<a id="contribution"></a>
|
||||
|
||||
## ✍️ Contribution
|
||||
|
||||
@@ -186,30 +188,46 @@ Please check out [our contribution guide](https://formbricks.com/docs/contributi
|
||||
|
||||
## All Thanks To Our Contributors
|
||||
|
||||
<a href="https://github.com/formbricks/formbricks/graphs/contributors">
|
||||
<a href="https://github.com/formbricks/formbricks/graphs/contributors">
|
||||
|
||||
<img src="https://contrib.rocks/image?repo=formbricks/formbricks" />
|
||||
<img src="https://contrib.rocks/image?repo=formbricks/formbricks" />
|
||||
|
||||
</a>
|
||||
|
||||
<a id="contact-us"></a>
|
||||
<a id="contact-us"></a>
|
||||
|
||||
## 📆 Contact us
|
||||
|
||||
Let's have a chat about your survey needs and get you started.
|
||||
|
||||
<a href="https://cal.com/johannes/onboarding?utm_source=banner&utm_campaign=oss"><img alt="Book us with Cal.com" src="https://cal.com/book-with-cal-dark.svg" /></a>
|
||||
<a href="https://cal.com/johannes/onboarding?utm_source=banner&utm_campaign=oss"><img alt="Book us with Cal.com" src="https://cal.com/book-with-cal-dark.svg" /></a>
|
||||
|
||||
<a id="license"></a>
|
||||
<a id="license"></a>
|
||||
|
||||
## ⚖️ License
|
||||
|
||||
Distributed under the AGPLv3 License. See [`LICENSE`](./LICENSE) for more information.
|
||||
|
||||
<a id="security"></a>
|
||||
<a id="security"></a>
|
||||
|
||||
## 🔒 Security
|
||||
|
||||
We take security very seriously. If you come across any security vulnerabilities, please disclose them by sending an email to security@formbricks.com. We appreciate your help in making our platform as secure as possible and are committed to working with you to resolve any issues quickly and efficiently. See [`SECURITY.md`](./SECURITY.md) for more information.
|
||||
|
||||
<p align="right"><a href="#top">🔼 Back to top</a></p>
|
||||
<a id="license"></a>
|
||||
|
||||
## 👩⚖️ License
|
||||
|
||||
### The AGPL Formbricks Core
|
||||
|
||||
The Formbricks core application is licensed under the [AGPLv3 Open Source License](https://github.com/formbricks/formbricks/blob/main/LICENSE). The core application is fully functional and includes everything you need to design & run link surveys, website surveys and in-app surveys. You can use the software for free for personal and commercial use. You're also allowed to create and distribute modified versions as long as you document the changes you make incl. date. The AGPL license requires you to publish your modified version under the AGPLv3 license as well.
|
||||
|
||||
### The Enterprise Edition
|
||||
|
||||
Additional to the AGPL licensed Formbricks core, this repository contains code licensed under an Enterprise license. The [code](https://github.com/formbricks/formbricks/tree/main/packages/ee) and [license](https://github.com/formbricks/formbricks/blob/main/packages/ee/LICENSE) for the enterprise functionality can be found in the `/packages/ee` folder of this repository. This additional functionality is not part of the AGPLv3 licensed Formbricks core and is designed to meet the needs of larger teams and enterprises. This advanced functionality is already included in the Docker images, but you need an [Enterprise License Key](https://formbricks.com/docs/self-hosting/enterprise) to unlock it.
|
||||
|
||||
### 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).
|
||||
|
||||
### Why charge for Enterprise Features?
|
||||
|
||||
The Enterprise Edition and White-Label Licenses allow us to fund the development of Formbricks sustainably. It guarantees that the open-source surveying infrastructure we're building will be around for decades to come.
|
||||
|
||||
<p align="right"><a href="#top">🔼 Back to top</a></p>
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
import { classNames } from "@/lib/utils";
|
||||
import {
|
||||
ClockIcon,
|
||||
CogIcon,
|
||||
CreditCardIcon,
|
||||
DocumentChartBarIcon,
|
||||
FileBarChartIcon,
|
||||
HelpCircleIcon,
|
||||
HomeIcon,
|
||||
QuestionMarkCircleIcon,
|
||||
ScaleIcon,
|
||||
ShieldCheckIcon,
|
||||
UserGroupIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
UsersIcon,
|
||||
} from "lucide-react";
|
||||
|
||||
import { classNames } from "../lib/utils";
|
||||
|
||||
const navigation = [
|
||||
{ name: "Home", href: "#", icon: HomeIcon, current: true },
|
||||
{ name: "History", href: "#", icon: ClockIcon, current: false },
|
||||
{ name: "Balances", href: "#", icon: ScaleIcon, current: false },
|
||||
{ name: "Cards", href: "#", icon: CreditCardIcon, current: false },
|
||||
{ name: "Recipients", href: "#", icon: UserGroupIcon, current: false },
|
||||
{ name: "Reports", href: "#", icon: DocumentChartBarIcon, current: false },
|
||||
{ name: "Recipients", href: "#", icon: UsersIcon, current: false },
|
||||
{ name: "Reports", href: "#", icon: FileBarChartIcon, current: false },
|
||||
];
|
||||
const secondaryNavigation = [
|
||||
{ name: "Settings", href: "#", icon: CogIcon },
|
||||
{ name: "Help", href: "#", icon: QuestionMarkCircleIcon },
|
||||
{ name: "Help", href: "#", icon: HelpCircleIcon },
|
||||
{ name: "Privacy", href: "#", icon: ShieldCheckIcon },
|
||||
];
|
||||
|
||||
|
||||
25
apps/demo/components/SurveySwitch.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@formbricks/ui/Select";
|
||||
|
||||
interface SurveySwitchProps {
|
||||
value: "website" | "app";
|
||||
formbricks: any;
|
||||
}
|
||||
|
||||
export const SurveySwitch = ({ value, formbricks }: SurveySwitchProps) => {
|
||||
return (
|
||||
<Select
|
||||
value={value}
|
||||
onValueChange={(v) => {
|
||||
formbricks.logout();
|
||||
window.location.href = `/${v}`;
|
||||
}}>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Theme" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="website">Website Surveys</SelectItem>
|
||||
<SelectItem value="app">App Surveys</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
transpilePackages: ["@formbricks/ui"],
|
||||
async redirects() {
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@formbricks/js": "workspace:*",
|
||||
"@heroicons/react": "^2.1.1",
|
||||
"next": "14.0.4",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"lucide-react": "^0.368.0",
|
||||
"next": "14.2.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-config-formbricks": "workspace:*"
|
||||
"eslint-config-formbricks": "workspace:*",
|
||||
"@formbricks/tsconfig": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Head, Html, Main, NextScript } from "next/document";
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en" className="h-full bg-gray-50">
|
||||
<Html lang="en" className="h-full bg-slate-50">
|
||||
<Head />
|
||||
<body className="h-full">
|
||||
<Main />
|
||||
|
||||
@@ -2,8 +2,9 @@ import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import formbricks from "@formbricks/js";
|
||||
import formbricksApp from "@formbricks/js/app";
|
||||
|
||||
import { SurveySwitch } from "../../components/SurveySwitch";
|
||||
import fbsetup from "../../public/fb-setup.png";
|
||||
|
||||
declare const window: any;
|
||||
@@ -21,23 +22,33 @@ export default function AppPage({}) {
|
||||
}, [darkMode]);
|
||||
|
||||
useEffect(() => {
|
||||
// enable Formbricks debug mode by adding formbricksDebug=true GET parameter
|
||||
const addFormbricksDebugParam = () => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (!urlParams.has("formbricksDebug")) {
|
||||
urlParams.set("formbricksDebug", "true");
|
||||
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
|
||||
window.history.replaceState({}, "", newUrl);
|
||||
}
|
||||
};
|
||||
|
||||
addFormbricksDebugParam();
|
||||
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const isUserId = window.location.href.includes("userId=true");
|
||||
const userId = isUserId ? "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING" : undefined;
|
||||
const attributes = isUserId ? { "Init Attribute 1": "eight", "Init Attribute 2": "two" } : undefined;
|
||||
formbricks.init({
|
||||
const userId = "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING";
|
||||
const userInitAttributes = { language: "de", "Init Attribute 1": "eight", "Init Attribute 2": "two" };
|
||||
|
||||
formbricksApp.init({
|
||||
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
|
||||
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
|
||||
userId,
|
||||
debug: true,
|
||||
attributes,
|
||||
attributes: userInitAttributes,
|
||||
});
|
||||
window.formbricks = formbricks;
|
||||
}
|
||||
|
||||
// Connect next.js router to Formbricks
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const handleRouteChange = formbricks?.registerRouteChange;
|
||||
const handleRouteChange = formbricksApp?.registerRouteChange;
|
||||
router.events.on("routeChangeComplete", handleRouteChange);
|
||||
|
||||
return () => {
|
||||
@@ -49,15 +60,19 @@ export default function AppPage({}) {
|
||||
return (
|
||||
<div className="h-screen bg-white px-12 py-6 dark:bg-slate-800">
|
||||
<div className="flex flex-col justify-between md:flex-row">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
|
||||
Formbricks In-product Survey Demo App
|
||||
</h1>
|
||||
<p className="text-slate-700 dark:text-slate-300">
|
||||
This app helps you test your in-app surveys. You can create and test user actions, create and
|
||||
update user attributes, etc.
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<SurveySwitch value="app" formbricks={formbricksApp} />
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
|
||||
Formbricks In-product Survey Demo App
|
||||
</h1>
|
||||
<p className="text-slate-700 dark:text-slate-300">
|
||||
This app helps you test your app surveys. You can create and test user actions, create and
|
||||
update user attributes, etc.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="mt-2 rounded-lg bg-slate-200 px-6 py-1 dark:bg-slate-700 dark:text-slate-100"
|
||||
onClick={() => setDarkMode(!darkMode)}>
|
||||
@@ -70,7 +85,7 @@ export default function AppPage({}) {
|
||||
<div className="rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-900">
|
||||
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">1. Setup .env</h3>
|
||||
<p className="text-slate-700 dark:text-slate-300">
|
||||
Copy the environment ID of your Formbricks app to the env variable in demo/.env
|
||||
Copy the environment ID of your Formbricks app to the env variable in /apps/demo/.env
|
||||
</p>
|
||||
<Image src={fbsetup} alt="fb setup" className="mt-4 rounded" priority />
|
||||
|
||||
@@ -81,7 +96,7 @@ export default function AppPage({}) {
|
||||
{process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID}
|
||||
</strong>
|
||||
<span className="relative ml-2 flex h-3 w-3">
|
||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75"></span>
|
||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-500 opacity-75"></span>
|
||||
<span className="relative inline-flex h-3 w-3 rounded-full bg-green-500"></span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -100,22 +115,22 @@ 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-gray-600 dark:bg-gray-800">
|
||||
<div className="col-span-3 rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-800">
|
||||
<h3 className="text-lg font-semibold dark:text-white">
|
||||
Reset person / pull data from Formbricks app
|
||||
</h3>
|
||||
<p className="text-slate-700 dark:text-gray-300">
|
||||
On formbricks.reset() a few things happen: <strong>New person is created</strong> and{" "}
|
||||
<strong>surveys & no-code actions are pulled from Formbricks:</strong>.
|
||||
<p className="text-slate-700 dark:text-slate-300">
|
||||
On formbricks.reset() the local state will <strong>be deleted</strong> and formbricks gets{" "}
|
||||
<strong>reinitialized</strong>.
|
||||
</p>
|
||||
<button
|
||||
className="my-4 rounded-lg bg-slate-500 px-6 py-3 text-white hover:bg-slate-700 dark:bg-gray-700 dark:hover:bg-gray-600"
|
||||
className="my-4 rounded-lg bg-slate-500 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
formbricks.reset();
|
||||
formbricksApp.reset();
|
||||
}}>
|
||||
Reset
|
||||
</button>
|
||||
<p className="text-xs text-slate-700 dark:text-gray-300">
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
If you made a change in Formbricks app and it does not seem to work, hit 'Reset' and
|
||||
try again.
|
||||
</p>
|
||||
@@ -124,15 +139,15 @@ export default function AppPage({}) {
|
||||
<div className="p-6">
|
||||
<div>
|
||||
<button
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-gray-700 dark:hover:bg-gray-600"
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
formbricks.track("Code Action");
|
||||
formbricksApp.track("Code Action");
|
||||
}}>
|
||||
Code Action
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-gray-300">
|
||||
<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
|
||||
@@ -143,12 +158,12 @@ export default function AppPage({}) {
|
||||
</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-gray-700 dark:hover:bg-gray-600">
|
||||
<button className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
|
||||
No-Code Action
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-gray-300">
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sends a{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/actions/no-code"
|
||||
@@ -170,14 +185,14 @@ export default function AppPage({}) {
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
formbricks.setAttribute("Plan", "Free");
|
||||
formbricksApp.setAttribute("Plan", "Free");
|
||||
}}
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-gray-700 dark:hover:bg-gray-600">
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
|
||||
Set Plan to 'Free'
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-gray-300">
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sets the{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/attributes/custom-attributes"
|
||||
@@ -193,14 +208,14 @@ export default function AppPage({}) {
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
formbricks.setAttribute("Plan", "Paid");
|
||||
formbricksApp.setAttribute("Plan", "Paid");
|
||||
}}
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-gray-700 dark:hover:bg-gray-600">
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
|
||||
Set Plan to 'Paid'
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-gray-300">
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sets the{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/attributes/custom-attributes"
|
||||
@@ -216,14 +231,14 @@ export default function AppPage({}) {
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
formbricks.setEmail("test@web.com");
|
||||
formbricksApp.setEmail("test@web.com");
|
||||
}}
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-gray-700 dark:hover:bg-gray-600">
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600">
|
||||
Set Email
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-gray-300">
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
This button sets the{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/attributes/identify-users"
|
||||
@@ -235,41 +250,6 @@ export default function AppPage({}) {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
{router.query.userId === "true" ? (
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
window.location.href = "/app";
|
||||
}}
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-gray-700 dark:hover:bg-gray-600">
|
||||
Deactivate User Identification
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
window.location.href = "/app?userId=true";
|
||||
}}
|
||||
className="mb-4 rounded-lg bg-slate-800 px-6 py-3 text-white hover:bg-slate-700 dark:bg-gray-700 dark:hover:bg-gray-600">
|
||||
Activate User Identification
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<p className="text-xs text-slate-700 dark:text-gray-300">
|
||||
This button activates/deactivates{" "}
|
||||
<a
|
||||
href="https://formbricks.com/docs/attributes/identify-users"
|
||||
target="_blank"
|
||||
className="underline dark:text-blue-500">
|
||||
user identification
|
||||
</a>{" "}
|
||||
with the userId 'THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING'
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
197
apps/demo/pages/website/index.tsx
Normal file
@@ -0,0 +1,197 @@
|
||||
import { MonitorIcon } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import formbricksWebsite from "@formbricks/js/website";
|
||||
|
||||
import { SurveySwitch } from "../../components/SurveySwitch";
|
||||
import fbsetup from "../../public/fb-setup.png";
|
||||
|
||||
declare const window: any;
|
||||
|
||||
export default function AppPage({}) {
|
||||
const [darkMode, setDarkMode] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (darkMode) {
|
||||
document.body.classList.add("dark");
|
||||
} else {
|
||||
document.body.classList.remove("dark");
|
||||
}
|
||||
}, [darkMode]);
|
||||
|
||||
useEffect(() => {
|
||||
// enable Formbricks debug mode by adding formbricksDebug=true GET parameter
|
||||
const addFormbricksDebugParam = () => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (!urlParams.has("formbricksDebug")) {
|
||||
urlParams.set("formbricksDebug", "true");
|
||||
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
|
||||
window.history.replaceState({}, "", newUrl);
|
||||
}
|
||||
};
|
||||
|
||||
addFormbricksDebugParam();
|
||||
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const defaultAttributes = {
|
||||
language: "de",
|
||||
};
|
||||
|
||||
formbricksWebsite.init({
|
||||
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
|
||||
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
|
||||
attributes: defaultAttributes,
|
||||
});
|
||||
}
|
||||
|
||||
// Connect next.js router to Formbricks
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const handleRouteChange = formbricksWebsite?.registerRouteChange;
|
||||
router.events.on("routeChangeComplete", handleRouteChange);
|
||||
|
||||
return () => {
|
||||
router.events.off("routeChangeComplete", handleRouteChange);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="h-screen bg-white px-12 py-6 dark:bg-slate-800">
|
||||
<div className="flex flex-col items-center justify-between md:flex-row">
|
||||
<div className="flex items-center gap-2">
|
||||
<SurveySwitch value="website" formbricks={formbricksWebsite} />
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">
|
||||
Formbricks Website Survey Demo App
|
||||
</h1>
|
||||
<p className="text-slate-700 dark:text-slate-300">
|
||||
This app helps you test your app surveys. You can create and test user actions, create and
|
||||
update user attributes, etc.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="mt-2 rounded-lg bg-slate-200 px-6 py-1 dark:bg-slate-700 dark:text-slate-100"
|
||||
onClick={() => setDarkMode(!darkMode)}>
|
||||
{darkMode ? "Toggle Light Mode" : "Toggle Dark Mode"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="my-4 grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||
<div>
|
||||
<div className="rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-900">
|
||||
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">1. Setup .env</h3>
|
||||
<p className="text-slate-700 dark:text-slate-300">
|
||||
Copy the environment ID of your Formbricks app to the env variable in /apps/demo/.env
|
||||
</p>
|
||||
<Image src={fbsetup} alt="fb setup" className="mt-4 rounded" priority />
|
||||
|
||||
<div className="mt-4 flex-col items-start text-sm text-slate-700 sm:flex sm:items-center sm:text-base dark:text-slate-300">
|
||||
<p className="mb-1 sm:mb-0 sm:mr-2">You're connected with env:</p>
|
||||
<div className="flex items-center">
|
||||
<strong className="w-32 truncate sm:w-auto">
|
||||
{process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID}
|
||||
</strong>
|
||||
<span className="relative ml-2 flex h-3 w-3">
|
||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-500 opacity-75"></span>
|
||||
<span className="relative inline-flex h-3 w-3 rounded-full bg-green-500"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-900">
|
||||
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">2. Widget Logs</h3>
|
||||
<p className="text-slate-700 dark:text-slate-300">
|
||||
Look at the logs to understand how the widget works.{" "}
|
||||
<strong className="dark:text-white">Open your browser console</strong> to see the logs.
|
||||
</p>
|
||||
{/* <div className="max-h-[40vh] overflow-y-auto py-4">
|
||||
<LogsContainer />
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="md:grid md:grid-cols-3">
|
||||
<div className="col-span-3 rounded-lg border border-slate-300 bg-slate-100 p-6 dark:border-slate-600 dark:bg-slate-800">
|
||||
<h3 className="text-lg font-semibold dark:text-white">
|
||||
Reset person / pull data from Formbricks app
|
||||
</h3>
|
||||
<p className="text-slate-700 dark:text-slate-300">
|
||||
On formbricks.reset() the local state will <strong>be deleted</strong> and formbricks gets{" "}
|
||||
<strong>reinitialized</strong>.
|
||||
</p>
|
||||
<button
|
||||
className="my-4 rounded-lg bg-slate-500 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
|
||||
onClick={() => {
|
||||
formbricksWebsite.reset();
|
||||
}}>
|
||||
Reset
|
||||
</button>
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300">
|
||||
If you made a change in Formbricks app and it does not seem to work, hit 'Reset' and
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -1,23 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"extends": "@formbricks/tsconfig/nextjs.json",
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -4,3 +4,7 @@ NEXT_PUBLIC_FORMBRICKS_COM_DOCS_FEEDBACK_SURVEY_ID=
|
||||
|
||||
# Strapi API Key
|
||||
STRAPI_API_KEY=
|
||||
|
||||
NEXT_PUBLIC_DOCSEARCH_APP_ID=
|
||||
NEXT_PUBLIC_DOCSEARCH_API_KEY=
|
||||
NEXT_PUBLIC_DOCSEARCH_INDEX_NAME=
|
||||
|
||||
5
apps/formbricks-com/app/[surveyId]/route.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export async function GET(_: Request, { params }: { params: { surveyId: string } }) {
|
||||
const surveyId = params.surveyId;
|
||||
// redirect to Formbricks Cloud
|
||||
return Response.redirect(`https://app.formbricks.com/s/${surveyId}`, 301);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
export const metadata = {
|
||||
title: "Implementing Code Actions in Formbricks | Real-time User Action Tracking",
|
||||
description:
|
||||
"Dive into the world of Formbricks' code actions. Learn how to seamlessly integrate formbricks.track() method into your codebase, enabling real-time tracking of user actions like button clicks, visiting a specific URL. Up your survey game with precise and exact triggers.",
|
||||
};
|
||||
|
||||
#### Actions
|
||||
|
||||
# Code Actions
|
||||
|
||||
Actions can also be set in the codebase to trigger surveys. Please add the code action first in the Formbricks web interface to be able to configure your surveys to use this action.
|
||||
|
||||
After that you can fire an action using `formbricks.track()`
|
||||
|
||||
<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>
|
||||
@@ -1,30 +0,0 @@
|
||||
export const metadata = {
|
||||
title: "Implementing No-Code Actions in Formbricks | Real-time User Action Tracking",
|
||||
description:
|
||||
"Discover the power of Formbricks' No-Code Actions. Easily set up triggers based on Page URL, innerText, and CSS Selectors without touching a line of code. Inccrease user engagement and get insights at precise moments in the user journey.",
|
||||
};
|
||||
|
||||
#### Actions
|
||||
|
||||
# No-Code Actions
|
||||
|
||||
No-Code actions can be set up within Formbricks with just a few clicks. There are three types of No-Code actions:
|
||||
|
||||
## Page URL Action
|
||||
|
||||
The page URL action is triggered, when a user visits a specific page in your application. There are several match conditions:
|
||||
|
||||
- `exactMatch`: The URL should exactly match the provided string.
|
||||
- `contains`: The URL should contain the specified string as a substring.
|
||||
- `startsWith`: The URL should start with the specified string.
|
||||
- `endsWith`: The URL should end with the specified string.
|
||||
- `notMatch`: The URL should not match the specified condition.
|
||||
- `notContains`: The URL should not contain the specified string as a substring.
|
||||
|
||||
## innerText Action
|
||||
|
||||
The innerText action checks if the `innerText` of a clicked HTML element matches a specific text, e.g. the label of a button. Display a survey on any button click!
|
||||
|
||||
## CSS Selector Action
|
||||
|
||||
The CSS Selector action checks if the provided CSS selector matches the selector of a clicked HTML element. The CSS selector can be a class, id or any other CSS selector within your website. Display a survey on any element click!
|
||||
@@ -1,23 +0,0 @@
|
||||
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.",
|
||||
};
|
||||
|
||||
#### Actions
|
||||
|
||||
# What are actions and why are they useful?
|
||||
|
||||
You want to understand what your users think and feel during specific moments in the user journey. To be able to ask at exactly the right point in time, you need actions.
|
||||
|
||||
## What are actions?
|
||||
|
||||
Actions are a little notification sent from your application to Formbricks. You decide which actions are sent either in your [Code](/docs/actions/code) or by setting up a [No-Code](/docs/actions/no-code) action within Formbricks.
|
||||
|
||||
## How do actions work?
|
||||
|
||||
When a predefined action happens in your app, the Formbricks widget notices. This action can then trigger a survey to be shown to the user and is stored in the database.
|
||||
|
||||
## Why are actions useful?
|
||||
|
||||
Actions help you to display your surveys at the right time. Later on, you will be able to segment your users based on the actions they have triggered in the past. This way, you can create much more granular user segments, e.g. only target users that already have used a specific feature.
|
||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
137
apps/formbricks-com/app/docs/additional-features/api/page.mdx
Normal file
@@ -0,0 +1,137 @@
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
import AddApiKey from "./add-api-key.webp";
|
||||
import ApiKeySecret from "./api-key-secret.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks API Overview: Public Client & Management API Breakdown",
|
||||
description:
|
||||
"Formbricks provides a powerful API to manage your surveys, responses, users, displays, actions, attributes & webhooks programmatically. Get a detailed understanding of Formbricks' dual API offerings: the unauthenticated Public Client API optimized for client-side tasks and the secured Management API for advanced account operations. Choose the perfect fit for your integration needs and ensure robust data handling",
|
||||
};
|
||||
|
||||
#### API
|
||||
|
||||
# API Overview
|
||||
|
||||
Formbricks offers two types of APIs: the **Public Client API** and the **Management API**. Each API serves a different purpose, has different authentication requirements, and provides access to different data and settings.
|
||||
|
||||
View our [API Documentation](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh) in more than 30 frameworks and languages. Or directly try out our APIs in Postman by clicking the button below:
|
||||
|
||||
<div className="max-w-full sm:max-w-3xl">
|
||||
<a target="_blank" href="https://formbricks.postman.co/collection/11026000-927c954f-85a9-4f8f-b0ec-14191b903737?source=rip_html">
|
||||
<img alt="Run in Postman" src="https://run.pstmn.io/button.svg"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## Public Client API
|
||||
|
||||
The [Public Client API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#5c981d9e-5e7d-455d-9795-b9c45bc2f930) is designed for our SDKs and **does not require authentication**. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
|
||||
|
||||
We currently have the following Client API methods exposed and below is their documentation attached in Postman:
|
||||
|
||||
- [Actions API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#b8f3a10e-1642-4d82-a629-fef0a8c6c86c) - Create actions for a Person
|
||||
- [Displays API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#949272bf-daec-4d72-9b52-47af3d74a62c) - Mark Survey as Displayed or Update an existing Display by linking it with a Response for a Person
|
||||
- [People API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#ee3d2188-4253-4bca-9238-6b76455805a9) - Create & Update a Person (e.g. attributes, email, userId, etc)
|
||||
- [Responses API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#8c773032-536c-483c-a237-c7697347946e) - Create & Update a Response for a Survey
|
||||
|
||||
## Management API
|
||||
|
||||
The [Management API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#98fce5a1-1365-4125-8de1-acdb28206766) provides access to all data and settings that your account has access to in the Formbricks app. This API **requires a personal API Key** for authentication, which can be generated in the Settings section of the Formbricks app. Checkout the [API Key Setup](#how-to-generate-an-api-key) below to generate & manage API Keys.
|
||||
|
||||
We currently have the following Management API methods exposed and below is their documentation attached in Postman:
|
||||
|
||||
- [Action Class API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#81947f69-99fc-41c9-a184-f3260e02be48) - Create, List, and Delete Action Classes
|
||||
- [Attribute Class API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#31089010-d468-4a7c-943e-8ebe71b9a36e) - Create, List, and Delete Attribute Classes
|
||||
- [Me API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#79e08365-641d-4b2d-aea2-9a855e0438ec) - Retrieve Account Information
|
||||
- [People API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#cffc27a6-dafb-428f-8ea7-5165bedb911e) - List and Delete People
|
||||
- [Response API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#e544ec0d-8b30-4e33-8d35-2441cb40d676) - List, List by Survey, Update, and Delete Responses
|
||||
- [Survey API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#953189b2-37b5-4429-a7bd-f4d01ceae242) - List, Create, Update, and Delete Surveys
|
||||
- [Webhook API](https://documenter.getpostman.com/view/11026000/2sA3Bq5XEh#62e6ec65-021b-42a4-ac93-d1434b393c6c) - List, Create, and Delete Webhooks
|
||||
|
||||
## How to Generate an API key
|
||||
|
||||
The API requests are authorized with a personal API key. This API key gives you the same rights as if you were logged in at formbricks.com - **don't share it around!**
|
||||
|
||||
1. Go to your settings on [app.formbricks.com](https://app.formbricks.com).
|
||||
2. Go to page “API keys”
|
||||
<MdxImage src={AddApiKey} alt="Add API Key" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
3. Create a key for the development or production environment.
|
||||
4. Copy the key immediately. You won’t be able to see it again.
|
||||
<MdxImage
|
||||
src={ApiKeySecret}
|
||||
alt="API Key Secret"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
<Note>
|
||||
### Store API key safely!
|
||||
Anyone who has your API key has full control over your account. For security reasons, you cannot view the API key again.
|
||||
</Note>
|
||||
|
||||
### Test your API Key
|
||||
|
||||
Hit the below request to verify that you are authenticated with your API Key and the server is responding.
|
||||
|
||||
## Get My Profile {{ tag: 'GET', label: '/api/v1/me' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Get the product details and environment type of your account.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Delete a personal API key
|
||||
|
||||
1. Go to settings on [app.formbricks.com](https://app.formbricks.com/).
|
||||
2. Go to page “API keys”.
|
||||
3. Find the key you wish to revoke and select “Delete”.
|
||||
4. Your API key will stop working immediately.
|
||||
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/me">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/me' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"id": "cll2m30r70004mx0huqkitgqv",
|
||||
"createdAt": "2023-08-08T18:04:59.922Z",
|
||||
"updatedAt": "2023-08-08T18:04:59.922Z",
|
||||
"type": "production",
|
||||
"product": {
|
||||
"id": "cll2m30r60003mx0hnemjfckr",
|
||||
"name": "My Product"
|
||||
},
|
||||
"widgetSetupCompleted": false
|
||||
}
|
||||
```
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
Not authenticated
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
Can’t figure it out? Join our [Discord](https://discord.com/invite/3YFcABF2Ts) and we'd be glad to assist you!
|
||||
|
||||
---
|
||||
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,174 @@
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import AddLanguageInSurvey from "./add-language-in-survey.webp";
|
||||
import AddLanguages from "./add-languages.webp";
|
||||
import EditMultiLang from "./edit-multi-lang.webp";
|
||||
import EnableMultiLang from "./enable-multi-lang.webp";
|
||||
import SeeSurveyInLanguage from "./see-survey-in-language.webp";
|
||||
import SurveyLanguagesFromHome from "./survey-languages-from-home.webp";
|
||||
import SurveyLanguageSettings from "./survey-languague-settings.webp";
|
||||
import SurveySharing from "./survey-sharing.webp";
|
||||
import SurveysHome from "./surveys-home.webp";
|
||||
import TranslateAsPerLanguage from "./translate-as-per-language.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Multi-language Surveys | Formbricks",
|
||||
description:
|
||||
"Create multi-language link & in-app surveys with Formbricks. Get feedback from your users in their preferred language without writing a single line of code.",
|
||||
};
|
||||
|
||||
#### Additional Features
|
||||
|
||||
# Multi-language Surveys
|
||||
|
||||
Multi-Language Surveys allow you to create surveys that support multiple languages using translations. This makes it easier to reach a diverse audience without creating separate surveys for each language. This feature simplifies the creation, delivery, and analysis of surveys for a multilingual audience.
|
||||
|
||||
How to deliver a specific language depends on the survey type (in-app or link survey):
|
||||
|
||||
- In-app survey: Set a `language` attribute for the user. [See the guide below for In-App Surveys](#in-app-surveys-configuration)
|
||||
- Link survey: Add a `lang` parameter in the survey URL. [See the guide below for Link Surveys](#link-surveys-configuration)
|
||||
|
||||
<Note>
|
||||
Multi-Language is feature of the Enterprise Edition. You can use it for **free** by adding your credit card details
|
||||
on the Formbricks Cloud.
|
||||
</Note>
|
||||
|
||||
<iframe
|
||||
width="700"
|
||||
height="450"
|
||||
src="https://www.youtube.com/embed/Vol5zjYIoos?si=FOeDSqcy_OgtaUyM"
|
||||
title="YouTube video player: Formbricks"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe>
|
||||
|
||||
---
|
||||
|
||||
## Creating a Multi-language Survey
|
||||
|
||||
1. Open the **Survey Languages** page in the Formbricks settings via the top-right menu:
|
||||
|
||||
<MdxImage
|
||||
src={SurveyLanguagesFromHome}
|
||||
alt="Formbricks Home"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Click on the **Edit Languages** button, to add a new language to your survey
|
||||
|
||||
<MdxImage
|
||||
src={SurveyLanguageSettings}
|
||||
alt="Formbricks Home"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. Select the preferred language from the dropdown and assign an identifier Alias. Click the **Add Language** button to add the language to your product.
|
||||
|
||||
<MdxImage
|
||||
src={AddLanguages}
|
||||
alt="Add Multiple Languages to your Product"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
You can come back to this page anytime to add more languages or remove existing ones.
|
||||
|
||||
4. Now, return to the dashboard to create a new survey or edit an existing one.
|
||||
|
||||
<MdxImage
|
||||
src={SurveysHome}
|
||||
alt="Add Multiple Languages to your Product"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
5. In the survey editor, scroll down to the **Multiple Languages** section at the bottom and enable the toggle next to it.
|
||||
|
||||
<MdxImage
|
||||
src={EnableMultiLang}
|
||||
alt="Enable Multi-language for a survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
6. Now choose a **Default Language** for your survey. This is the language that will be shown to users who have not selected a preferred language.
|
||||
|
||||
<Note>Changing the default language will reset all the translations you have made for the survey.</Note>
|
||||
|
||||
7. Now, add the languages from the dropdown that you want to support in your survey.
|
||||
|
||||
<MdxImage
|
||||
src={AddLanguageInSurvey}
|
||||
alt="Enable Multi-language for a survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
8. You can now see the survey in the selected language by clicking on the language dropdown in any of the questions.
|
||||
|
||||
<MdxImage
|
||||
src={SeeSurveyInLanguage}
|
||||
alt="Enable Multi-language for a survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
9. You can now translate all survey content, including questions, options, and button placeholders, into the selected language.
|
||||
|
||||
<MdxImage
|
||||
src={TranslateAsPerLanguage}
|
||||
alt="Enable Multi-language for a survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
10. Once you are done, click on the **Publish** button to save the survey.
|
||||
|
||||
## In-App Surveys Configuration
|
||||
|
||||
1. When you initialise the Formbricks SDK for your user, you can pass a `language` attribute with the language code. This can be either the ISO identifier or the Alias you set when creating the language. The `language` attribute makes sure that this user only sees surveys with a translation in this specific language available.
|
||||
<Col>
|
||||
<CodeGroup title="Configuring Formbricks SDK with Multi-language">
|
||||
|
||||
```js
|
||||
Formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user_id>",
|
||||
attributes: {
|
||||
language: "de", // ISO identifier or Alias set when creating language
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
|
||||
<Note>If a user has a language assigned, a survey has multi-language activate and it is missing a translation in the language of the user, the survey will not be displayed.</Note>
|
||||
|
||||
|
||||
2. That's it! Now, users with the language attribute set will see the survey in their preferred language. You can start collecting responses in multiple languages and filter them by language on the summary page.
|
||||
|
||||
---
|
||||
|
||||
## Link Surveys Configuration
|
||||
|
||||
For link surveys, the translation delivery is dependent on the `land` URL parameter.
|
||||
|
||||
After publishing the survey, just copy the survey link and append the `lang` query parameter with the language alias you have set.
|
||||
|
||||
For example, if you have set the alias for French as `fr`, you can share the survey link as
|
||||
|
||||
`https://your-survey-url.com?lang=fr`
|
||||
|
||||
Here are two examples:
|
||||
|
||||
- English: https://app.Formbricks.com/s/clptfos2i1pj516pvhxqyu3bn?lang=en
|
||||
- German: https://app.Formbricks.com/s/clptfos2i1pj516pvhxqyu3bn?lang=de
|
||||
|
||||
Without the `lang` parameter, Formbricks will show the survey in the default language you have set.
|
||||
|
||||
You can now start collecting responses in multiple languages!
|
||||
|
||||
Can’t figure it out? Join our [Discord](https://discord.com/invite/3YFcABF2Ts)!
|
||||
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 15 KiB |
@@ -1,87 +0,0 @@
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks Actions API Documentation - Manage Your Survey Data Seamlessly",
|
||||
description:
|
||||
"Unlock the full potential of Formbricks' Client Actions API. Create Actions right from the API.",
|
||||
};
|
||||
|
||||
#### Client API
|
||||
|
||||
# Actions API
|
||||
|
||||
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
|
||||
|
||||
This API can be used to:
|
||||
|
||||
- [Add Action for User](#add-action-for-user)
|
||||
|
||||
---
|
||||
|
||||
## Add Action for User {{ tag: 'POST', label: '/api/v1/client/<environment-id>/actions' }}
|
||||
|
||||
Adds an Actions for a given User by their User ID
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
### Mandatory Body Fields
|
||||
|
||||
<Properties>
|
||||
<Property name="userId" type="string">
|
||||
The id of the user for whom the action is being created.
|
||||
</Property>
|
||||
<Property name="name" type="string">
|
||||
The name of the Action being created.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/api/v1/client/<environment-id>/actions">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location --request POST 'https://app.formbricks.com/api/v1/client/<environment-id>/actions' \
|
||||
--data-raw '{
|
||||
"userId": "1",
|
||||
"name": "new_action_v2",
|
||||
"properties":{}
|
||||
|
||||
}'
|
||||
```
|
||||
|
||||
```json {{ title: 'Example Request Body' }}
|
||||
{
|
||||
"userId": "1",
|
||||
"name": "new_action_v3",
|
||||
"properties":{}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{ title: '200 Success' }}
|
||||
{
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '400 Bad Request' }}
|
||||
{
|
||||
"code": "bad_request",
|
||||
"message": "Fields are missing or incorrectly formatted",
|
||||
"details": {
|
||||
"name": "Required"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
@@ -1,145 +0,0 @@
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks Public Client API Guide: Manage Survey Displays & Responses",
|
||||
description:
|
||||
"Dive deep into Formbricks' Public Client API designed for customisation. This comprehensive guide provides detailed instructions on how to mark create and update survey displays for users.",
|
||||
};
|
||||
|
||||
#### Client API
|
||||
|
||||
# Displays API
|
||||
|
||||
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
|
||||
|
||||
This set of API can be used to
|
||||
- [Create Display](#create-display)
|
||||
- [Update Display](#update-display)
|
||||
|
||||
---
|
||||
|
||||
## Create Display {{ tag: 'POST', label: '/api/v1/client/<environment-id>/diplays' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Create Display of survey for a user
|
||||
|
||||
### Mandatory Request Body JSON Keys
|
||||
<Properties>
|
||||
<Property name="surveyId" type="string">
|
||||
Survey ID to mark as viewed for a person
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Optional Request Body JSON Keys
|
||||
<Properties>
|
||||
<Property name="userId" type="string">
|
||||
Already existing user's ID to mark as viewed for a survey
|
||||
</Property>
|
||||
<Property name="responseId" type="string">
|
||||
Already existing response's ID to link with this new Display
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/api/v1/client/<environment-id>/displays">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST \
|
||||
'https://app.formbricks.com/api/v1/client/displays' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"surveyId":"<survey-id>",
|
||||
"userId":"<user-id>"
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "clphzz6oo00083zdmc7e0nwzi"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '400 Bad Request' }}
|
||||
{
|
||||
"code": "bad_request",
|
||||
"message": "Fields are missing or incorrectly formatted",
|
||||
"details": {
|
||||
"surveyId": "Required"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Update Display {{ tag: 'PUT', label: '/api/v1/client/<environment-id>/diplays/<display-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Update a display by it's ID
|
||||
|
||||
### Optional Request Body JSON Keys
|
||||
<Properties>
|
||||
<Property name="userId" type="string">
|
||||
Already existing user's ID to mark as viewed for a survey
|
||||
</Property>
|
||||
<Property name="responseId" type="string">
|
||||
Already existing response's ID to link with this new Display
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="PUT" label="/api/v1/client/<environment-id>/displays/<display-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST \
|
||||
'https://app.formbricks.com/api/v1/client/<environment-id>/displays/<display-id>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"userId":"<user-id>"
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '400 Bad Request' }}
|
||||
{
|
||||
"code": "bad_request",
|
||||
"message": "Fields are missing or incorrectly formatted",
|
||||
"details": {
|
||||
"surveyId": "Required"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
@@ -1,47 +0,0 @@
|
||||
export const metadata = {
|
||||
title: "Formbricks API Overview: Public Client & Management API Breakdown",
|
||||
description:
|
||||
"Get a detailed understanding of Formbricks' dual API offerings: the unauthenticated Public Client API optimized for client-side tasks and the secured Management API for advanced account operations. Choose the perfect fit for your integration needs and ensure robust data handling",
|
||||
};
|
||||
|
||||
#### API
|
||||
|
||||
# API Overview
|
||||
|
||||
Formbricks offers two types of APIs: the **Public Client API** and the **Management API**. Each API serves a different purpose, has different authentication requirements, and provides access to different data and settings.
|
||||
|
||||
Checkout the [API Key Setup](/docs/api/management/api-key-setup) - to generate, store, or delete API Keys.
|
||||
|
||||
## Public Client API
|
||||
|
||||
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
|
||||
|
||||
- [Actions API](/docs/api/client/actions) - Create actions for a person
|
||||
- [Displays API](/docs/api/client/displays) - Mark Survey as Displayed or Responded for a Person
|
||||
- [People API](/docs/api/client/people) - Create & update people (e.g. attributes)
|
||||
- [Responses API](/docs/api/client/responses) - Create & update responses for a survey
|
||||
|
||||
## Management API
|
||||
|
||||
The Management API provides access to all data and settings that are visible in the Formbricks App. This API requires a personal API Key for authentication, which can be generated in the Settings section of the Formbricks App. With the Management API, you can manage your Formbricks account programmatically, accessing and modifying data and settings as needed.
|
||||
|
||||
**Auth:** Personal API Key
|
||||
|
||||
API requests made to the Management API are authorized using a personal API key. This key grants the same rights and access as if you were logged in at formbricks.com. It's essential to keep your API key secure and not share it with others.
|
||||
|
||||
To generate, store, or delete an API key, follow the instructions provided on the following page [API Key](/docs/api/management/api-key-setup).
|
||||
|
||||
- [Action Class API](/docs/api/management/action-classes) - Create, Update, and Delete Action Classes
|
||||
- [Attribute Class API](/docs/api/management/attribute-classes) - Create, Update, and Delete Attribute Classes
|
||||
- [Me API](/docs/api/management/me) - Retrieve Account Information
|
||||
- [People API](/docs/api/management/people) - Create, Update, and Delete People
|
||||
- [Responses API](/docs/api/management/responses) - Create, Update, and Delete Responses
|
||||
- [Surveys API](/docs/api/management/surveys) - Create, Update, and Delete Surveys
|
||||
- [Webhook API](/docs/api/management/webhooks) - Create, Update, and Delete Webhooks
|
||||
|
||||
<Note>
|
||||
By understanding the differences between these two APIs, you can choose the appropriate one for your needs,
|
||||
ensuring a secure and efficient integration with the Formbricks platform.
|
||||
</Note>
|
||||
|
||||
---
|
||||
@@ -1,130 +0,0 @@
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks Public Client API Guide: Manage Users",
|
||||
description:
|
||||
"Dive deep into Formbricks' Public Client API designed for customisation. This comprehensive guide provides detailed instructions on creating and updating users to help in user identification.",
|
||||
};
|
||||
|
||||
#### Client API
|
||||
|
||||
# People API
|
||||
|
||||
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
|
||||
|
||||
This set of API can be used to
|
||||
- [Create Person](#create-person)
|
||||
- [Update Person](#update-person)
|
||||
|
||||
---
|
||||
|
||||
## Create Person {{ tag: 'POST', label: '/api/v1/client/<environment-id>/people' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Create User with your own User ID
|
||||
|
||||
### Mandatory Request Body JSON Keys
|
||||
<Properties>
|
||||
<Property name="userId" type="string">
|
||||
User ID which you would like to identify the person with
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/api/v1/client/<environment-id>/people">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST \
|
||||
'https://app.formbricks.com/api/v1/client/<environment-id>/people' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"userId":"docs_user"
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"userId": "docs_user"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '400 Bad Request' }}
|
||||
{
|
||||
"code": "bad_request",
|
||||
"message": "Fields are missing or incorrectly formatted",
|
||||
"details": {
|
||||
"surveyId": "Required"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Update Person {{ tag: 'POST', label: '/api/v1/client/<environment-id>/people/<user-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Update Person by their User ID
|
||||
|
||||
### Mandatory Request Body JSON Keys
|
||||
<Properties>
|
||||
<Property name="attributes" type="JSON">
|
||||
Key Value pairs of attributes to add to the user
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/api/v1/client/<environment-id>/people/<user-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST \
|
||||
--location \
|
||||
'https://app.formbricks.com/api/v1/client/<environment-id>/people/<user-id>'
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"attributes":{
|
||||
"welcome_to":"formbricks"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '500 Internal Server Error' }}
|
||||
{
|
||||
"code": "internal_server_error",
|
||||
"message": "Database operation failed",
|
||||
"details": {}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
@@ -1,200 +0,0 @@
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks Responses API Documentation - Manage Your Survey Data Seamlessly",
|
||||
description:
|
||||
"Unlock the full potential of Formbricks' Responses API. From fetching to updating survey responses, our comprehensive guide helps you integrate and manage survey data efficiently without compromising security. Ideal for client-side interactions.",
|
||||
};
|
||||
|
||||
#### Client API
|
||||
|
||||
# Responses API
|
||||
|
||||
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
|
||||
|
||||
This set of API can be used to
|
||||
- [Create Response](#create-response)
|
||||
- [Update Response](#update-response)
|
||||
|
||||
---
|
||||
|
||||
## Create Response {{ tag: 'POST', label: '/api/v1/client/<environment-id>/responses' }}
|
||||
|
||||
Add a new response to a survey.
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
### Mandatory Body Fields
|
||||
|
||||
<Properties>
|
||||
<Property name="surveyId" type="string">
|
||||
The id of the survey the response belongs to.
|
||||
</Property>
|
||||
<Property name="finished" type="boolean">
|
||||
Marks whether the response is complete or not.
|
||||
</Property>
|
||||
<Property name="data" type="string">
|
||||
The data of the response as JSON object (key: questionId, value: answer).
|
||||
</Property>
|
||||
|
||||
</Properties>
|
||||
|
||||
### Optional Body Fields
|
||||
|
||||
<Properties>
|
||||
<Property name="userId" type="string" required>
|
||||
Pre-existing User ID to identify the user sending the response
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Parameters Explained
|
||||
|
||||
| field name | required | default | description |
|
||||
| ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| data | yes | - | The response data object (answers to the survey). In this object the key is the questionId, the value the answer of the user to this question. |
|
||||
| userId | no | - | The person this response is connected to. |
|
||||
| surveyId | yes | - | The survey this response is connected to. |
|
||||
| finished | yes | false | Mark a response as complete to be able to filter accordingly. |
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/api/v1/client/<environment-id>/responses">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location --request POST 'https://app.formbricks.com/api/v1/client/<environment-id>/responses' \
|
||||
--data-raw '{
|
||||
"surveyId":"cloqzeuu70000z8khcirufo60",
|
||||
"userId": "1",
|
||||
"finished": true,
|
||||
"data": {
|
||||
"clfqjny0v0003yzgscnog1j9i": 10,
|
||||
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
```json {{ title: 'Example Request Body' }}
|
||||
{
|
||||
"userId": "1",
|
||||
"surveyId": "cloqzeuu70000z8khcirufo60",
|
||||
"finished": true,
|
||||
"data": {
|
||||
"clfqjny0v0003yzgscnog1j9i": 10,
|
||||
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{ title: '200 Success' }}
|
||||
{
|
||||
"data": {
|
||||
"id": "clp84xdld0002px36fkgue5ka",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '400 Bad Request' }}
|
||||
{
|
||||
"code": "bad_request",
|
||||
"message": "surveyId was not provided.",
|
||||
"details": {
|
||||
"surveyId": "This field is required."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Update Response {{ tag: 'PUT', label: '/api/v1/client/<environment-id>/responses/<response-id>' }}
|
||||
|
||||
Update an existing response in a survey.
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
### Mandatory Body Fields
|
||||
|
||||
<Properties>
|
||||
<Property name="finished" type="boolean">
|
||||
Marks whether the response is complete or not.
|
||||
</Property>
|
||||
<Property name="data" type="string">
|
||||
The data of the response as JSON object (key: questionId, value: answer).
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Parameters Explained
|
||||
|
||||
| field name | required | default | description |
|
||||
| ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| data | yes | - | The response data object (answers to the survey). In this object the key is the questionId, the value the answer of the user to this question. |
|
||||
| finished | yes | false | Mark a response as complete to be able to filter accordingly. |
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="PUT" label="/api/v1/client/<environment-id>/responses/<response-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location --request PUT 'https://app.formbricks.com/api/v1/client/<environment-id>/responses/<response-id>' \
|
||||
--data-raw '{
|
||||
"finished":false,
|
||||
"data": {
|
||||
"clfqjny0v0003yzgscnog1j9i": 10,
|
||||
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
```json {{ title: 'Example Request Body' }}
|
||||
{
|
||||
"finished":false,
|
||||
"data": {
|
||||
"clfqjny0v0003yzgscnog1j9i": 10,
|
||||
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{ title: '200 Success' }}
|
||||
{
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '400 Bad Request' }}
|
||||
{
|
||||
"code": "bad_request",
|
||||
"message": "data was not provided.",
|
||||
"details": {
|
||||
"data": "This field is required."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '404 Not Found' }}
|
||||
{
|
||||
"code": "not_found",
|
||||
"message": "Response not found"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
@@ -1,297 +0,0 @@
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import {generateManagementApiMetadata} from "@/lib/utils"
|
||||
export const metadata = generateManagementApiMetadata("Action Class",["Fetch","Create","Delete"])
|
||||
|
||||
#### Management API
|
||||
|
||||
# Action Classes API
|
||||
|
||||
This set of API can be used to
|
||||
- [List Actions](#get-all-action-classes)
|
||||
- [Get Action](#get-action-class-by-id)
|
||||
- [Create Actions](#create-action-class)
|
||||
- [Delete Actions](#delete-action-class)
|
||||
|
||||
<Note>You will need an API Key to interact with these APIs.</Note>
|
||||
|
||||
---
|
||||
|
||||
## Get all Action Classes {{ tag: 'GET', label: '/api/v1/management/action-classes' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Get all the existing action classes in your environment.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/action-classes">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/action-classes' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "cln8k0t47000gz87nw4ibwv35",
|
||||
"createdAt": "2023-10-02T07:13:19.207Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.207Z",
|
||||
"name": "New Session",
|
||||
"description": "Gets fired when a new session is created",
|
||||
"type": "automatic",
|
||||
"noCodeConfig": null,
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck"
|
||||
},
|
||||
{
|
||||
"id": "cln8k0t55000uz87noerwdooj",
|
||||
"createdAt": "2023-10-02T07:13:19.241Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.241Z",
|
||||
"name": "Invited Team Member",
|
||||
"description": "Person invited a team member",
|
||||
"type": "noCode",
|
||||
"noCodeConfig": {
|
||||
"type": "innerHtml",
|
||||
"innerHtml": {
|
||||
"value": "Add Team Member"
|
||||
}
|
||||
},
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck"
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Unauthorized' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Get Action Class by ID {{ tag: 'GET', label: '/api/v1/management/action-classes/<action-class-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Fetch an action class by its ID.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/action-classes/<action-class-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/action-classes/<action-class-id>' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "cln8k0t55000uz87noerwdooj",
|
||||
"createdAt": "2023-10-02T07:13:19.241Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.241Z",
|
||||
"name": "Invited Team Member",
|
||||
"description": "Person invited a team member",
|
||||
"type": "noCode",
|
||||
"noCodeConfig": {
|
||||
"type": "innerHtml",
|
||||
"innerHtml": {
|
||||
"value": "Add Team Member"
|
||||
}
|
||||
},
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Unauthorized' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Create Action Class {{ tag: 'POST', label: '/api/v1/management/action-classes/' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Create an action class.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Body
|
||||
|
||||
<CodeGroup title="Request Body">
|
||||
```json {{ title: 'cURL' }}
|
||||
{
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck",
|
||||
"name": "My Action from API",
|
||||
"type": "code"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/api/v1/management/action-classes/">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST https://app.formbricks.com/api/v1/management/action-classes/ \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'x-api-key: <your-api-key>' \
|
||||
-d '{"environmentId": "cln8k0t47000fz87njmmu2bck", "name": "My Action from API", "type": "code"}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "cln9w1cno0008z8zu79nk5w0c",
|
||||
"createdAt": "2023-10-03T05:37:26.100Z",
|
||||
"updatedAt": "2023-10-03T05:37:26.100Z",
|
||||
"name": "My Action from API",
|
||||
"description": null,
|
||||
"type": "code",
|
||||
"noCodeConfig": null,
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Unauthorized' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Delete Action Class {{ tag: 'DELETE', label: '/api/v1/management/action-classes/<action-class-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Delete an action class by its ID.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="DELETE" label="/api/v1/management/action-classes/<action-class-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X DELETE https://app.formbricks.com/api/v1/management/action-classes/<action-class-id> \
|
||||
--header 'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "cln9w1cno0008z8zu79nk5w0c",
|
||||
"createdAt": "2023-10-03T05:37:26.100Z",
|
||||
"updatedAt": "2023-10-03T05:37:26.100Z",
|
||||
"name": "My Action from API",
|
||||
"description": null,
|
||||
"type": "code",
|
||||
"noCodeConfig": null,
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Unauthorized' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
@@ -1,103 +0,0 @@
|
||||
import Image from "next/image";
|
||||
|
||||
import AddApiKey from "./add-api-key.webp";
|
||||
import ApiKeySecret from "./api-key-secret.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks API Key: Setup and Testing",
|
||||
description:
|
||||
"This guide provides step-by-step instructions to generate, store, and delete API keys, ensuring safe and authenticated access to your Formbricks account.",
|
||||
};
|
||||
|
||||
#### API
|
||||
|
||||
# API Key Setup
|
||||
|
||||
## Auth: Personal API key
|
||||
|
||||
The API requests are authorized with a personal API key. This API key gives you the same rights as if you were logged in at formbricks.com - **don't share it around!**
|
||||
|
||||
### How to generate an API key
|
||||
|
||||
1. Go to your settings on [app.formbricks.com](https://app.formbricks.com).
|
||||
2. Go to page “API keys”
|
||||
<Image src={AddApiKey} alt="Add API Key" quality="100" className="rounded-lg max-w-full sm:max-w-3xl" />
|
||||
3. Create a key for the development or production environment.
|
||||
4. Copy the key immediately. You won’t be able to see it again.
|
||||
<Image
|
||||
src={ApiKeySecret}
|
||||
alt="API Key Secret"
|
||||
quality="100"
|
||||
className="rounded-lg max-w-full sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
<Note>
|
||||
### Store API key safely
|
||||
Anyone who has your API key has full control over your account.
|
||||
For security reasons, you cannot view the API key again.
|
||||
</Note>
|
||||
|
||||
### Test your API Key
|
||||
|
||||
Hit the below request to verify that you are authenticated with your API Key and the server is responding.
|
||||
|
||||
## Get My Profile {{ tag: 'GET', label: '/api/v1/me' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Get the product details and environment type of your account.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/me">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/me' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"id": "cll2m30r70004mx0huqkitgqv",
|
||||
"createdAt": "2023-08-08T18:04:59.922Z",
|
||||
"updatedAt": "2023-08-08T18:04:59.922Z",
|
||||
"type": "production",
|
||||
"product": {
|
||||
"id": "cll2m30r60003mx0hnemjfckr",
|
||||
"name": "My Product"
|
||||
},
|
||||
"widgetSetupCompleted": false
|
||||
}
|
||||
```
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
Not authenticated
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
### Delete a personal API key
|
||||
|
||||
1. Go to settings on [app.formbricks.com](https://app.formbricks.com/).
|
||||
2. Go to page “API keys”.
|
||||
3. Find the key you wish to revoke and select “Delete”.
|
||||
4. Your API key will stop working immediately.
|
||||
@@ -1,289 +0,0 @@
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import {generateManagementApiMetadata} from "@/lib/utils"
|
||||
|
||||
export const metadata = generateManagementApiMetadata("Attribute Class",["Fetch","Create","Delete"])
|
||||
|
||||
#### Management API
|
||||
|
||||
# Attribute Classes API
|
||||
|
||||
This set of API can be used to
|
||||
- [List Attributes](#get-all-attribute-classes)
|
||||
- [Get Attributes](#get-attribute-class-by-id)
|
||||
- [Create Attributes](#create-attribute-class)
|
||||
- [Delete Attributes](#delete-attribute-class)
|
||||
|
||||
<Note>You will need an API Key to interact with these APIs.</Note>
|
||||
|
||||
---
|
||||
|
||||
## Get all Attribute Classes {{ tag: 'GET', label: '/api/v1/management/attribute-classes' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Get all the existing attribute classes in your environment.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/attribute-classes">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/attribute-classes' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "cln8k0t47000kz87n3lh23zf0",
|
||||
"createdAt": "2023-10-02T07:13:19.207Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.207Z",
|
||||
"name": "email",
|
||||
"description": "The email of the person",
|
||||
"archived": false,
|
||||
"type": "automatic",
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck"
|
||||
},
|
||||
{
|
||||
"id": "cln8k0t55000xz87nrtwbo7sf",
|
||||
"createdAt": "2023-10-02T07:13:19.241Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.241Z",
|
||||
"name": "Name",
|
||||
"description": "Full Name of the Person",
|
||||
"archived": false,
|
||||
"type": "code",
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck"
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Unauthorized' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Get Attribute Class by ID {{ tag: 'GET', label: '/api/v1/management/attribute-classes/<attribute-class-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Fetch an Attribute class by its ID.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/attribute-classes/<attribute-class-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/attribute-classes/<attribute-class-id>' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "cln8k0t47000jz87nfwcey6mh",
|
||||
"createdAt": "2023-10-02T07:13:19.207Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.207Z",
|
||||
"name": "userId",
|
||||
"description": "The internal ID of the person",
|
||||
"archived": false,
|
||||
"type": "automatic",
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Unauthorized' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Create Attribute Class {{ tag: 'POST', label: '/api/v1/management/attribute-classes/' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Create an Attribute class.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Body
|
||||
|
||||
<CodeGroup title="Request Body">
|
||||
```json {{ title: 'cURL' }}
|
||||
{
|
||||
"environmentId": "clmlmwdqq0003196ufewo6ibg",
|
||||
"name": "My Attribute from API",
|
||||
"type": "code",
|
||||
"description": "My description"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/api/v1/management/attribute-classes/">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST https://app.formbricks.com/api/v1/management/attribute-classes/ \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'x-api-key: <your-api-key>' \
|
||||
-d '{"environmentId": "clmlmwdqq0003196ufewo6ibg", "name": "My Attribute from API", "type": "code", "description":"My description"}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "clna0hd7z0009z8zue2z3a7wy",
|
||||
"createdAt": "2023-10-03T07:41:51.792Z",
|
||||
"updatedAt": "2023-10-03T07:41:51.792Z",
|
||||
"name": "My Attribute from API",
|
||||
"description": null,
|
||||
"archived": false,
|
||||
"type": "code",
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Unauthorized' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Delete Attribute Class {{ tag: 'DELETE', label: '/api/v1/management/attribute-classes/<attribute-class-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Delete an Attribute class by its ID.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="DELETE" label="/api/v1/management/attribute-classes/<attribute-class-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X DELETE https://app.formbricks.com/api/v1/management/attribute-classes/<attribute-class-id> \
|
||||
--header 'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "clna0hd7z0009z8zue2z3a7wy",
|
||||
"createdAt": "2023-10-03T07:41:51.792Z",
|
||||
"updatedAt": "2023-10-03T07:41:51.792Z",
|
||||
"name": "My Attribute from API",
|
||||
"description": null,
|
||||
"archived": false,
|
||||
"type": "code",
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Unauthorized' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
@@ -1,78 +0,0 @@
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks Me API: Fetch your environment details",
|
||||
description:
|
||||
"Dive into Formbricks' Me API within the Public Client API suite. Seamlessly fetch your own current environment details.",
|
||||
};
|
||||
|
||||
#### Management API
|
||||
|
||||
# Me API
|
||||
|
||||
This API can be used to get your own current environment details.
|
||||
|
||||
<Note>You will need an API Key to interact with these APIs.</Note>
|
||||
|
||||
---
|
||||
|
||||
## Get Environment {{ tag: 'GET', label: '/api/v1/management/me' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Get your current environment details.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/me">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/me' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"id": "cln8k0t47000fz87njmmu2bck",
|
||||
"createdAt": "2023-10-02T07:13:19.207Z",
|
||||
"updatedAt": "2023-10-02T07:14:14.162Z",
|
||||
"type": "production",
|
||||
"product": {
|
||||
"id": "cln8k0t47000ez87n57aqywvz",
|
||||
"name": "Demo Product"
|
||||
},
|
||||
"widgetSetupCompleted": true
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Unauthorized' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
@@ -1,232 +0,0 @@
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import {generateManagementApiMetadata} from "@/lib/utils"
|
||||
|
||||
export const metadata = generateManagementApiMetadata("People",["Fetch","Delete"])
|
||||
|
||||
|
||||
#### Management API
|
||||
|
||||
# People API
|
||||
|
||||
This set of API can be used to
|
||||
- [List People](#list-people)
|
||||
- [Get Person](#get-person)
|
||||
- [Delete Person](#delete-person)
|
||||
|
||||
<Note>You will need an API Key to interact with these APIs.</Note>
|
||||
|
||||
---
|
||||
|
||||
## List People {{ tag: 'GET', label: '/api/v1/management/people' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
List People
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/people">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/people' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "b4wgrzl363dn3zb6yy5gf265",
|
||||
"attributes": {
|
||||
"userId": "CYO618",
|
||||
"email": "sophia@amazon.com",
|
||||
"Name": "Sophia Johnson",
|
||||
"Role": "Designer",
|
||||
"Company": "Amazon",
|
||||
"Experience": "7 years",
|
||||
"Usage Frequency": "Yearly",
|
||||
"Company Size": "1628 employees",
|
||||
"Product Satisfaction Score": "62",
|
||||
"Recommendation Likelihood": "9"
|
||||
},
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck",
|
||||
"createdAt": "2023-10-02T07:13:19.444Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.444Z"
|
||||
},
|
||||
{
|
||||
"id": "jrb5iyzqvnkg9322ckhde3j4",
|
||||
"attributes": {
|
||||
"userId": "CYO511",
|
||||
"email": "antonio@ibm.com",
|
||||
"Name": "Antonio García",
|
||||
"Role": "Designer",
|
||||
"Company": "IBM",
|
||||
"Experience": "1 years",
|
||||
"Usage Frequency": "Weekly",
|
||||
"Company Size": "4023 employees",
|
||||
"Product Satisfaction Score": "77",
|
||||
"Recommendation Likelihood": "4"
|
||||
},
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck",
|
||||
"createdAt": "2023-10-02T07:13:19.444Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.444Z"
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '400 Bad Request' }}
|
||||
{
|
||||
"code": "bad_request",
|
||||
"message": "Fields are missing or incorrectly formatted",
|
||||
"details": {
|
||||
"userId": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Get Person {{ tag: 'GET', label: '/api/v1/management/people/<person-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Get Person by ID
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/people/<person-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/people/<person-id>' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "jrb5iyzqvnkg9322ckhde3j4",
|
||||
"attributes": {
|
||||
"userId": "CYO511",
|
||||
"email": "antonio@ibm.com",
|
||||
"Name": "Antonio García",
|
||||
"Role": "Designer",
|
||||
"Company": "IBM",
|
||||
"Experience": "1 years",
|
||||
"Usage Frequency": "Weekly",
|
||||
"Company Size": "4023 employees",
|
||||
"Product Satisfaction Score": "77",
|
||||
"Recommendation Likelihood": "4"
|
||||
},
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck",
|
||||
"createdAt": "2023-10-02T07:13:19.444Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.444Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '404 Not Found' }}
|
||||
{
|
||||
"code": "not_found",
|
||||
"message": "Person not found",
|
||||
"details": {
|
||||
"resource_id": "clmlmykc2000019vz5o3jglsa",
|
||||
"resource_type": "Person"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Delete Person {{ tag: 'DELETE', label: '/api/v1/management/people/<person-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Delete Person by ID
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="DELETE" label="/api/v1/management/people/<person-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X DELETE https://app.formbricks.com/api/v1/management/people/<person-id> \
|
||||
--header 'x-api-key: <your-api-key>'
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"success": "Person deleted successfully"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '404 Not Found' }}
|
||||
{
|
||||
"code": "not_found",
|
||||
"message": "Person not found",
|
||||
"details": {
|
||||
"resource_id": "clmlmykc2000019vz5o3jglsa",
|
||||
"resource_type": "Person"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
@@ -1,286 +0,0 @@
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import {generateManagementApiMetadata} from "@/lib/utils"
|
||||
|
||||
export const metadata = generateManagementApiMetadata("Responses",["Fetch","Delete"])
|
||||
|
||||
#### Management API
|
||||
|
||||
# Responses API
|
||||
|
||||
This set of API can be used to
|
||||
- [List Responses](#list-all-responses)
|
||||
- [Get Response](#get-response-by-id)
|
||||
- [Delete Response](#delete-a-response)
|
||||
|
||||
<Note>You will need an API Key to interact with these APIs.</Note>
|
||||
|
||||
---
|
||||
|
||||
## List all Responses {{ tag: 'GET', label: '/api/v1/management/responses' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Retrieve all the responses you have received in your environment.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/responses">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/responses' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data":[
|
||||
{
|
||||
"id": "cln8k0tqv00pcz87no4qrw333",
|
||||
"createdAt": "2023-10-02T07:13:20.023Z",
|
||||
"updatedAt": "2023-10-02T07:13:20.023Z",
|
||||
"surveyId": "cln8k0tqu00p7z87nqr4thi3k",
|
||||
"finished": true,
|
||||
"data": {
|
||||
"interview-prompt": "clicked"
|
||||
},
|
||||
"meta": {
|
||||
"userAgent": {
|
||||
"os": "MacOS",
|
||||
"browser": "Chrome"
|
||||
}
|
||||
},
|
||||
"personAttributes": null,
|
||||
"person": {
|
||||
"id": "e0x4i5tvsp8puxfztyrwykvn",
|
||||
"attributes": {
|
||||
"userId": "CYO675",
|
||||
"email": "ravi@netflix.com",
|
||||
"Name": "Ravi Kumar",
|
||||
"Role": "Manager",
|
||||
"Company": "Netflix",
|
||||
"Experience": "6 years",
|
||||
"Usage Frequency": "Monthly",
|
||||
"Company Size": "4610 employees",
|
||||
"Product Satisfaction Score": "43",
|
||||
"Recommendation Likelihood": "4"
|
||||
},
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck",
|
||||
"createdAt": "2023-10-02T07:13:19.444Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.444Z"
|
||||
},
|
||||
"notes": [],
|
||||
"tags": []
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Get Response by ID {{ tag: 'GET', label: '/api/v1/management/responses/<response-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Retrieve a response by its ID.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/responses/<response-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/responses/<response-id>' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data":
|
||||
{
|
||||
"id": "cln8k0tqv00pbz87nwo5lr72b",
|
||||
"createdAt": "2023-10-02T07:13:20.023Z",
|
||||
"updatedAt": "2023-10-02T07:13:20.023Z",
|
||||
"surveyId": "cln8k0tqu00p7z87nqr4thi3k",
|
||||
"finished": true,
|
||||
"data": {
|
||||
"interview-prompt": "clicked"
|
||||
},
|
||||
"meta": {
|
||||
"userAgent": {
|
||||
"os": "Windows",
|
||||
"browser": "Edge"
|
||||
}
|
||||
},
|
||||
"personAttributes": null,
|
||||
"person": {
|
||||
"id": "hsx38f15v50ua8383uadagq5",
|
||||
"attributes": {
|
||||
"userId": "CYO278",
|
||||
"email": "jorge@facebook.com",
|
||||
"Name": "Jorge Sanchez",
|
||||
"Role": "Product Manager",
|
||||
"Company": "Facebook",
|
||||
"Experience": "10 years",
|
||||
"Usage Frequency": "Daily",
|
||||
"Company Size": "1685 employees",
|
||||
"Product Satisfaction Score": "84",
|
||||
"Recommendation Likelihood": "6"
|
||||
},
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck",
|
||||
"createdAt": "2023-10-02T07:13:19.444Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.444Z"
|
||||
},
|
||||
"notes": [],
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Delete a response {{ tag: 'DELETE', label: '/api/v1/client/responses/<response-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Delete Response by ID
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="DELETE" label="/api/v1/client/responses/<response-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X DELETE https://app.formbricks.com/api/v1/management/responses/<response-id> \
|
||||
--header 'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{ title: '200 Success' }}
|
||||
{
|
||||
"data": {
|
||||
"id": "cln8k0tqv00pbz87nwo5lr72b",
|
||||
"createdAt": "2023-10-02T07:13:20.023Z",
|
||||
"updatedAt": "2023-10-02T07:13:20.023Z",
|
||||
"surveyId": "cln8k0tqu00p7z87nqr4thi3k",
|
||||
"finished": true,
|
||||
"data": {
|
||||
"interview-prompt": "clicked"
|
||||
},
|
||||
"meta": {
|
||||
"userAgent": {
|
||||
"os": "Windows",
|
||||
"browser": "Edge"
|
||||
}
|
||||
},
|
||||
"personAttributes": null,
|
||||
"person": {
|
||||
"id": "hsx38f15v50ua8383uadagq5",
|
||||
"attributes": {
|
||||
"userId": "CYO278",
|
||||
"email": "jorge@facebook.com",
|
||||
"Name": "Jorge Sanchez",
|
||||
"Role": "Product Manager",
|
||||
"Company": "Facebook",
|
||||
"Experience": "10 years",
|
||||
"Usage Frequency": "Daily",
|
||||
"Company Size": "1685 employees",
|
||||
"Product Satisfaction Score": "84",
|
||||
"Recommendation Likelihood": "6"
|
||||
},
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck",
|
||||
"createdAt": "2023-10-02T07:13:19.444Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.444Z"
|
||||
},
|
||||
"notes": [],
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '400 Bad Request' }}
|
||||
{
|
||||
"code": "bad_request",
|
||||
"message": "surveyId was not provided.",
|
||||
"details": {
|
||||
"surveyId": "This field is required."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
@@ -1,780 +0,0 @@
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import {generateManagementApiMetadata} from "@/lib/utils"
|
||||
|
||||
export const metadata = generateManagementApiMetadata("Surveys",["Fetch","Create","Update","Delete"])
|
||||
|
||||
#### Management API
|
||||
|
||||
# Surveys API
|
||||
|
||||
This set of API can be used to
|
||||
- [List All Surveys](#list-all-surveys)
|
||||
- [Get Survey](#get-survey-by-id)
|
||||
- [Create Survey](#create-survey)
|
||||
- [Update Survey](#update-survey-by-id)
|
||||
- [Delete Survey](#delete-survey-by-id)
|
||||
|
||||
<Note>You will need an API Key to interact with these APIs.</Note>
|
||||
|
||||
---
|
||||
|
||||
## List all surveys {{ tag: 'GET', label: '/api/v1/management/surveys' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Retrieve all the surveys you have for the environment.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/surveys">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/surveys' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "cllnfy2780fromy0hy7uoxvtn",
|
||||
"createdAt": "2023-08-23T07:56:20.516Z",
|
||||
"updatedAt": "2023-08-23T07:56:26.947Z",
|
||||
"name": "Product Market Fit (Superhuman)",
|
||||
"type": "link",
|
||||
"environmentId": "cll2m30r70004mx0huqkitgqv",
|
||||
"status": "inProgress",
|
||||
"attributeFilters": [],
|
||||
"displayOption": "displayOnce",
|
||||
"autoClose": null,
|
||||
"triggers": [],
|
||||
"redirectUrl": null,
|
||||
"recontactDays": null,
|
||||
"questions": [
|
||||
{
|
||||
"id": "gml6mgy71efgtq8np3s9je5p",
|
||||
"type": "cta",
|
||||
"headline": "You are one of our power users! Do you have 5 minutes?",
|
||||
"required": false,
|
||||
"buttonLabel": "Happy to help!",
|
||||
"logic": [
|
||||
{
|
||||
"condition": "skipped",
|
||||
"destination": "end"
|
||||
}
|
||||
],
|
||||
"html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We would love to understand your user experience better. Sharing your insight helps a lot!</span></p>",
|
||||
"buttonExternal": false,
|
||||
"dismissButtonLabel": "No, thanks."
|
||||
},
|
||||
{
|
||||
"id": "kp62fbqe8cfzmvy8qwpr81b2",
|
||||
"type": "multipleChoiceSingle",
|
||||
"headline": "How disappointed would you be if you could no longer use My Product?",
|
||||
"subheader": "Please select one of the following options:",
|
||||
"required": true,
|
||||
"choices": [
|
||||
{
|
||||
"id": "bdgy1hnwd7uwmfxk1ljqp1n5",
|
||||
"label": "Not at all disappointed"
|
||||
},
|
||||
{
|
||||
"id": "poabnvgtwenp8rb2v70gj4hj",
|
||||
"label": "Somewhat disappointed"
|
||||
},
|
||||
{
|
||||
"id": "opfiqyqz8wrqn0i0f7t24d3n",
|
||||
"label": "Very disappointed"
|
||||
}
|
||||
],
|
||||
"shuffleOption": "none"
|
||||
},
|
||||
{
|
||||
"id": "klvpwd4x08x8quesihvw5l92",
|
||||
"type": "multipleChoiceSingle",
|
||||
"headline": "What is your role?",
|
||||
"subheader": "Please select one of the following options:",
|
||||
"required": true,
|
||||
"choices": [
|
||||
{
|
||||
"id": "c8nerw6l9gpsxcmqkn10f9hy",
|
||||
"label": "Founder"
|
||||
},
|
||||
{
|
||||
"id": "ebjqezei6a2axtuq86cleetn",
|
||||
"label": "Executive"
|
||||
},
|
||||
{
|
||||
"id": "ctiijjblyhlp22snypfamqt1",
|
||||
"label": "Product Manager"
|
||||
},
|
||||
{
|
||||
"id": "ibalyr0mhemfkkr82vypmg40",
|
||||
"label": "Product Owner"
|
||||
},
|
||||
{
|
||||
"id": "fipk606aegslbd0e7yhc0xjx",
|
||||
"label": "Software Engineer"
|
||||
}
|
||||
],
|
||||
"shuffleOption": "none"
|
||||
},
|
||||
{
|
||||
"id": "ryo75306flyg72iaeditbv51",
|
||||
"type": "openText",
|
||||
"headline": "What type of people do you think would most benefit from My Product?",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"id": "lkjaxb73ulydzeumhd51sx9g",
|
||||
"type": "openText",
|
||||
"headline": "What is the main benefit you receive from My Product?",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"id": "ec7agikkr58j8uonhioinkyk",
|
||||
"type": "openText",
|
||||
"headline": "How can we improve My Product for you?",
|
||||
"subheader": "Please be as specific as possible.",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"thankYouCard": {
|
||||
"enabled": true,
|
||||
"headline": "Thank you!",
|
||||
"subheader": "We appreciate your feedback."
|
||||
},
|
||||
"delay": 0,
|
||||
"autoComplete": null,
|
||||
"closeOnDate": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Get Survey by ID {{ tag: 'GET', label: '/api/v1/management/surveys/<survey-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Get a specific survey by its ID.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/management/surveys/<survey-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/management/surveys/<survey-id>' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "cln8k0tjz00n5z87nwq527h3z",
|
||||
"createdAt": "2023-10-02T07:13:19.775Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.775Z",
|
||||
"name": "Churn Survey",
|
||||
"type": "link",
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck",
|
||||
"status": "inProgress",
|
||||
"attributeFilters": [],
|
||||
"displayOption": "displayOnce",
|
||||
"autoClose": null,
|
||||
"triggers": [],
|
||||
"redirectUrl": null,
|
||||
"recontactDays": null,
|
||||
"questions": [
|
||||
{
|
||||
"id": "churn-reason",
|
||||
"type": "multipleChoiceSingle",
|
||||
"headline": "Why did you cancel your subscription?",
|
||||
"subheader": "We're sorry to see you leave. Help us do better:",
|
||||
"required": true,
|
||||
"logic": [
|
||||
{
|
||||
"condition": "equals",
|
||||
"value": "Difficult to use",
|
||||
"destination": "easier-to-use"
|
||||
},
|
||||
{
|
||||
"condition": "equals",
|
||||
"value": "It's too expensive",
|
||||
"destination": "30-off"
|
||||
},
|
||||
{
|
||||
"condition": "equals",
|
||||
"value": "I am missing features",
|
||||
"destination": "missing-features"
|
||||
},
|
||||
{
|
||||
"condition": "equals",
|
||||
"value": "Poor customer service",
|
||||
"destination": "poor-service"
|
||||
},
|
||||
{
|
||||
"condition": "equals",
|
||||
"value": "I just didn't need it anymore",
|
||||
"destination": "end"
|
||||
}
|
||||
],
|
||||
"choices": [
|
||||
{
|
||||
"id": "isud2xethsw63dlwl89kr4kj",
|
||||
"label": "Difficult to use"
|
||||
},
|
||||
{
|
||||
"id": "opuu4ba3dlele3n0gjkuh27c",
|
||||
"label": "It's too expensive"
|
||||
},
|
||||
{
|
||||
"id": "gnypapo0rhvkt8pwosrphvbl",
|
||||
"label": "I am missing features"
|
||||
},
|
||||
{
|
||||
"id": "wkgsrsrazd9kfunqhzjezx6t",
|
||||
"label": "Poor customer service"
|
||||
},
|
||||
{
|
||||
"id": "pykmgyyw74vg0gaeryj6bo4c",
|
||||
"label": "I just didn't need it anymore"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "easier-to-use",
|
||||
"type": "openText",
|
||||
"headline": "What would have made {{productName}} easier to use?",
|
||||
"subheader": "",
|
||||
"required": true,
|
||||
"buttonLabel": "Send",
|
||||
"logic": [
|
||||
{
|
||||
"condition": "submitted",
|
||||
"destination": "end"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "30-off",
|
||||
"type": "cta",
|
||||
"headline": "Get 30% off for the next year!",
|
||||
"required": true,
|
||||
"buttonLabel": "Get 30% off",
|
||||
"logic": [
|
||||
{
|
||||
"condition": "clicked",
|
||||
"destination": "end"
|
||||
}
|
||||
],
|
||||
"html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We'd love to keep you as a customer. Happy to offer a 30% discount for the next year.</span></p>",
|
||||
"buttonUrl": "https://formbricks.com",
|
||||
"buttonExternal": true,
|
||||
"dismissButtonLabel": "Skip"
|
||||
},
|
||||
{
|
||||
"id": "missing-features",
|
||||
"type": "openText",
|
||||
"headline": "What features are you missing?",
|
||||
"subheader": "",
|
||||
"required": true,
|
||||
"logic": [
|
||||
{
|
||||
"condition": "submitted",
|
||||
"destination": "end"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "poor-service",
|
||||
"type": "cta",
|
||||
"headline": "So sorry to hear 😔 Talk to our CEO directly!",
|
||||
"required": true,
|
||||
"buttonLabel": "Send email to CEO",
|
||||
"logic": [
|
||||
{
|
||||
"condition": "clicked",
|
||||
"destination": "end"
|
||||
}
|
||||
],
|
||||
"html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We aim to provide the best possible customer service. Please email our CEO and she will personally handle your issue.</span></p>",
|
||||
"buttonUrl": "mailto:ceo@company.com",
|
||||
"buttonExternal": true,
|
||||
"dismissButtonLabel": "Skip"
|
||||
}
|
||||
],
|
||||
"thankYouCard": {
|
||||
"enabled": false
|
||||
},
|
||||
"delay": 0,
|
||||
"autoComplete": null,
|
||||
"closeOnDate": null,
|
||||
"surveyClosedMessage": null,
|
||||
"verifyEmail": null
|
||||
}
|
||||
}
|
||||
```
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Create Survey {{ tag: 'POST', label: '/api/v1/management/surveys' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Create a survey
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Body
|
||||
|
||||
<CodeGroup title="Request Body">
|
||||
```json {{ title: 'cURL' }}
|
||||
{
|
||||
"environmentId": "clmlmwdqq0003196ufewo6ibg",
|
||||
"type": "link",
|
||||
"name": "My new Survey"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/api/v1/management/surveys">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST \
|
||||
'https://app.formbricks.com/api/v1/management/surveys' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST https://app.formbricks.com/api/v1/management/surveys/ \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'x-api-key: <your-api-key>' \
|
||||
-d '{"environmentId": "cln8k0t47000fz87njmmu2bck", "name": "My Survey from API", "type": "link"}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "clna6bqnz000az8zubq3e757t",
|
||||
"createdAt": "2023-10-03T10:25:26.975Z",
|
||||
"updatedAt": "2023-10-03T10:25:26.975Z",
|
||||
"name": "My new Survey",
|
||||
"redirectUrl": null,
|
||||
"type": "link",
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck",
|
||||
"status": "draft",
|
||||
"questions": [],
|
||||
"thankYouCard": {
|
||||
"enabled": false
|
||||
},
|
||||
"displayOption": "displayOnce",
|
||||
"recontactDays": null,
|
||||
"autoClose": null,
|
||||
"delay": 0,
|
||||
"autoComplete": null,
|
||||
"closeOnDate": null,
|
||||
"surveyClosedMessage": null,
|
||||
"verifyEmail": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Update Survey by ID {{ tag: 'PUT', label: '/api/v1/management/surveys/<survey-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Update a survey by its ID
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Body
|
||||
|
||||
<CodeGroup title="Request Body">
|
||||
```json {{ title: 'cURL' }}
|
||||
{
|
||||
"name": "My renamed Survey",
|
||||
"redirectUrl":"https://formbricks.com",
|
||||
"type":"web"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="PUT" label="/api/v1/management/surveys/<survey-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST https://app.formbricks.com/api/v1/management/surveys/<survey-id> \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'x-api-key: <your-api-key>' \
|
||||
-d '{"name": "My renamed Survey"}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "cloqzeuu70000z8khcirufo60",
|
||||
"createdAt": "2023-11-09T09:23:42.367Z",
|
||||
"updatedAt": "2023-11-09T09:23:42.367Z",
|
||||
"name": "My renamed Survey",
|
||||
"redirectUrl": null,
|
||||
"type": "link",
|
||||
"environmentId": "clonzr6vc0009z8md7y06hipl",
|
||||
"status": "inProgress",
|
||||
"welcomeCard": {
|
||||
"html": "Thanks for providing your feedback - let's go!",
|
||||
"enabled": false,
|
||||
"headline": "Welcome!",
|
||||
"timeToFinish": false
|
||||
},
|
||||
"questions": [
|
||||
{
|
||||
"id": "l9rwn5nbk48y44tvnyyjcvca",
|
||||
"type": "openText",
|
||||
"headline": "Why did you leave the platform?",
|
||||
"required": true,
|
||||
"inputType": "text"
|
||||
}
|
||||
],
|
||||
"thankYouCard": {
|
||||
"enabled": true,
|
||||
"headline": "Thank you!",
|
||||
"subheader": "We appreciate your feedback."
|
||||
},
|
||||
"hiddenFields": {
|
||||
"enabled": true,
|
||||
"fieldIds": []
|
||||
},
|
||||
"displayOption": "displayOnce",
|
||||
"recontactDays": null,
|
||||
"autoClose": null,
|
||||
"delay": 0,
|
||||
"autoComplete": 50,
|
||||
"closeOnDate": null,
|
||||
"surveyClosedMessage": null,
|
||||
"productOverwrites": null,
|
||||
"singleUse": {
|
||||
"enabled": false,
|
||||
"isEncrypted": true
|
||||
},
|
||||
"verifyEmail": null,
|
||||
"pin": null,
|
||||
"triggers": [],
|
||||
"attributeFilters": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Delete Survey by ID {{ tag: 'DELETE', label: '/api/v1/management/surveys/<survey-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Delete a survey by its ID.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="DELETE" label="/api/v1/management/surveys/<survey-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X DELETE \
|
||||
'https://app.formbricks.com/api/v1/management/surveys/<survey-id>' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{title:'200 Success'}}
|
||||
{
|
||||
"data": {
|
||||
"id": "cln8k0tjz00n5z87nwq527h3z",
|
||||
"createdAt": "2023-10-02T07:13:19.775Z",
|
||||
"updatedAt": "2023-10-02T07:13:19.775Z",
|
||||
"name": "Churn Survey",
|
||||
"type": "link",
|
||||
"environmentId": "cln8k0t47000fz87njmmu2bck",
|
||||
"status": "inProgress",
|
||||
"attributeFilters": [],
|
||||
"displayOption": "displayOnce",
|
||||
"autoClose": null,
|
||||
"triggers": [],
|
||||
"redirectUrl": null,
|
||||
"recontactDays": null,
|
||||
"questions": [
|
||||
{
|
||||
"id": "churn-reason",
|
||||
"type": "multipleChoiceSingle",
|
||||
"headline": "Why did you cancel your subscription?",
|
||||
"subheader": "We're sorry to see you leave. Help us do better:",
|
||||
"required": true,
|
||||
"logic": [
|
||||
{
|
||||
"condition": "equals",
|
||||
"value": "Difficult to use",
|
||||
"destination": "easier-to-use"
|
||||
},
|
||||
{
|
||||
"condition": "equals",
|
||||
"value": "It's too expensive",
|
||||
"destination": "30-off"
|
||||
},
|
||||
{
|
||||
"condition": "equals",
|
||||
"value": "I am missing features",
|
||||
"destination": "missing-features"
|
||||
},
|
||||
{
|
||||
"condition": "equals",
|
||||
"value": "Poor customer service",
|
||||
"destination": "poor-service"
|
||||
},
|
||||
{
|
||||
"condition": "equals",
|
||||
"value": "I just didn't need it anymore",
|
||||
"destination": "end"
|
||||
}
|
||||
],
|
||||
"choices": [
|
||||
{
|
||||
"id": "isud2xethsw63dlwl89kr4kj",
|
||||
"label": "Difficult to use"
|
||||
},
|
||||
{
|
||||
"id": "opuu4ba3dlele3n0gjkuh27c",
|
||||
"label": "It's too expensive"
|
||||
},
|
||||
{
|
||||
"id": "gnypapo0rhvkt8pwosrphvbl",
|
||||
"label": "I am missing features"
|
||||
},
|
||||
{
|
||||
"id": "wkgsrsrazd9kfunqhzjezx6t",
|
||||
"label": "Poor customer service"
|
||||
},
|
||||
{
|
||||
"id": "pykmgyyw74vg0gaeryj6bo4c",
|
||||
"label": "I just didn't need it anymore"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "easier-to-use",
|
||||
"type": "openText",
|
||||
"headline": "What would have made {{productName}} easier to use?",
|
||||
"subheader": "",
|
||||
"required": true,
|
||||
"buttonLabel": "Send",
|
||||
"logic": [
|
||||
{
|
||||
"condition": "submitted",
|
||||
"destination": "end"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "30-off",
|
||||
"type": "cta",
|
||||
"headline": "Get 30% off for the next year!",
|
||||
"required": true,
|
||||
"buttonLabel": "Get 30% off",
|
||||
"logic": [
|
||||
{
|
||||
"condition": "clicked",
|
||||
"destination": "end"
|
||||
}
|
||||
],
|
||||
"html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We'd love to keep you as a customer. Happy to offer a 30% discount for the next year.</span></p>",
|
||||
"buttonUrl": "https://formbricks.com",
|
||||
"buttonExternal": true,
|
||||
"dismissButtonLabel": "Skip"
|
||||
},
|
||||
{
|
||||
"id": "missing-features",
|
||||
"type": "openText",
|
||||
"headline": "What features are you missing?",
|
||||
"subheader": "",
|
||||
"required": true,
|
||||
"logic": [
|
||||
{
|
||||
"condition": "submitted",
|
||||
"destination": "end"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "poor-service",
|
||||
"type": "cta",
|
||||
"headline": "So sorry to hear 😔 Talk to our CEO directly!",
|
||||
"required": true,
|
||||
"buttonLabel": "Send email to CEO",
|
||||
"logic": [
|
||||
{
|
||||
"condition": "clicked",
|
||||
"destination": "end"
|
||||
}
|
||||
],
|
||||
"html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We aim to provide the best possible customer service. Please email our CEO and she will personally handle your issue.</span></p>",
|
||||
"buttonUrl": "mailto:ceo@company.com",
|
||||
"buttonExternal": true,
|
||||
"dismissButtonLabel": "Skip"
|
||||
}
|
||||
],
|
||||
"thankYouCard": {
|
||||
"enabled": false
|
||||
},
|
||||
"delay": 0,
|
||||
"autoComplete": null,
|
||||
"closeOnDate": null,
|
||||
"surveyClosedMessage": null,
|
||||
"verifyEmail": null
|
||||
}
|
||||
}
|
||||
```
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
@@ -1,398 +0,0 @@
|
||||
import {generateManagementApiMetadata} from "@/lib/utils"
|
||||
|
||||
export const metadata = generateManagementApiMetadata("Webhook",["Fetch","Create","Delete"])
|
||||
|
||||
#### Management API
|
||||
|
||||
# Webhook API
|
||||
|
||||
Formbricks' Webhook API offers a powerful interface for interacting with webhooks. Webhooks allow you to receive real-time HTTP notifications of changes to specific objects in the Formbricks environment.
|
||||
|
||||
The behavior of the webhooks is determined by their trigger settings. The trigger determines which updates the webhook sends. Current available triggers include "responseCreated", "responseUpdated", and "responseFinished". This allows you to customize your webhooks to only send notifications for the events that are relevant to your application.
|
||||
|
||||
Webhooks are tied to a specific Formbricks environment. Once set, a webhook will receive updates from all surveys within this environment. This makes it easy to manage your data flow and ensure that all relevant updates are caught by the webhook.
|
||||
|
||||
This set of API can be used to
|
||||
- [List All Webhooks](#list-webhooks)
|
||||
- [Get Webhook](#retrieve-webhook-by-id)
|
||||
- [Create Webhook](#create-webhook)
|
||||
- [Delete Webhook](#delete-webhook-by-id)
|
||||
|
||||
And the detailed Webhook Payload is elaborated [here](#webhook-payload).
|
||||
|
||||
These APIs are designed to facilitate seamless integration of Formbricks with third-party systems. By making use of our webhook API, you can automate the process of sending data to these systems whenever significant events occur within your Formbricks environment.
|
||||
|
||||
<Note>You will need an API Key to interact with these APIs.</Note>
|
||||
|
||||
---
|
||||
|
||||
## List Webhooks {{ tag: 'GET', label: '/api/v1/webhooks' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
Learn how to retrieve a list of all webhooks via API.
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/webhooks">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/webhooks' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{ title: '200 Success' }}
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "cliu1kdza000219zftad4ip6c",
|
||||
"createdAt": "2023-06-13T08:49:04.198Z",
|
||||
"updatedAt": "2023-06-13T08:49:04.198Z",
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"environmentId": "clisypjy4000319t4imm289uo",
|
||||
"triggers": [
|
||||
"responseFinished"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Retrieve Webhook by ID {{ tag: 'GET', label: '/api/v1/webhooks/<webhook-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/api/v1/webhooks/<webhook-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location \
|
||||
'https://app.formbricks.com/api/v1/webhooks/<webhook-id>' \
|
||||
--header \
|
||||
'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{ title: '200 Success' }}
|
||||
{
|
||||
"data": {
|
||||
"id": "cliu167rk000019zfhbo68bar",
|
||||
"createdAt": "2023-06-13T08:38:02.960Z",
|
||||
"updatedAt": "2023-06-13T08:38:02.960Z",
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"environmentId": "clisypjy4000319t4imm289uo",
|
||||
"triggers": [
|
||||
"responseFinished"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Create Webhook {{ tag: 'POST', label: '/api/v1/webhooks' }}
|
||||
|
||||
Add a webhook to your product.
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Request Body Parameters
|
||||
|
||||
<Properties>
|
||||
<Property name="url" type="string" required>
|
||||
The URL where the webhook will send data to.
|
||||
</Property>
|
||||
<Property name="triggers" type="string[]" required>
|
||||
List of events that will trigger the webhook.
|
||||
</Property>
|
||||
<Property name="surveyIds" type="string[]">
|
||||
List of survey IDs that will trigger the webhook. If not provided, the webhook will be triggered for all surveys.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
| field name | required | default | description |
|
||||
| ---------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| url | yes | - | The endpoint that the webhook will send data to |
|
||||
| trigger | yes | - | The event that will trigger the webhook ("responseCreated" or "responseUpdated" or "responseFinished") |
|
||||
| surveyIds | no | - | List of survey IDs that will trigger the webhook. If not provided, the webhook will be triggered for all surveys. |
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/api/v1/webhooks">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location --request POST 'https://app.formbricks.com/api/v1/webhooks' \
|
||||
--header 'x-api-key: <your-api-key>' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"triggers": ["responseFinished"]
|
||||
}'
|
||||
```
|
||||
|
||||
```json {{ title: 'Example Request Body' }}
|
||||
{
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"triggers": ["responseFinished"]
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{ title: '200 Success' }}
|
||||
{
|
||||
"data": {
|
||||
"id": "cliu1kdza000219zftad4ip6c",
|
||||
"createdAt": "2023-06-13T08:49:04.198Z",
|
||||
"updatedAt": "2023-06-13T08:49:04.198Z",
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"environmentId": "clisypjy4000319t4imm289uo",
|
||||
"triggers": ["responseFinished"],
|
||||
"surveyIds": ["clisypjy4000319t4imm289uo"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '400 Bad Request' }}
|
||||
{
|
||||
"code": "bad_request",
|
||||
"message": "Missing trigger",
|
||||
"details": {
|
||||
"missing_field": "trigger"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Delete Webhook by ID {{ tag: 'DELETE', label: '/api/v1/webhooks/<webhook-id>' }}
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
|
||||
### Mandatory Headers
|
||||
|
||||
<Properties>
|
||||
<Property name="x-Api-Key" type="string">
|
||||
Your Formbricks API key.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="DELETE" label="/api/v1/webhooks/<webhook-id>">
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl --location --request DELETE 'https://app.formbricks.com/api/v1/webhooks/<webhook-id>' \
|
||||
--header 'x-api-key: <your-api-key>'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
|
||||
```json {{ title: '200 Success' }}
|
||||
{
|
||||
"data": {
|
||||
"id": "cliu167rk000019zfhbo68bar",
|
||||
"createdAt": "2023-06-13T08:38:02.960Z",
|
||||
"updatedAt": "2023-06-13T08:38:02.960Z",
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"environmentId": "clisypjy4000319t4imm289uo",
|
||||
"triggers": ["responseFinished"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '401 Not Authenticated' }}
|
||||
{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json {{ title: '404 Not Found' }}
|
||||
{
|
||||
"code": "not_found",
|
||||
"message": "Webhook not found.",
|
||||
"details": {
|
||||
"webhookId": "The requested webhook does not exist."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
## Webhook Payload
|
||||
|
||||
This documentation helps understand the payload structure that will be received when the webhook is triggered in Formbricks.
|
||||
|
||||
<Row>
|
||||
<Col sticky>
|
||||
|
||||
| Variable | Type | Description |
|
||||
| --------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| webhookId | String | Webhook's Id |
|
||||
| event | String | The name of the trigger event [responseCreated, responseUpdated, responseFinished] |
|
||||
| data | Object | Contains the details of the newly created response. |
|
||||
| data.id | String | Formbricks Response ID. |
|
||||
| data.createdAt | String | The timestamp when the response was created. |
|
||||
| data.updatedAt | String | The timestamp when the response was last updated. |
|
||||
| data.surveyId | String | The identifier of the survey associated with this response. |
|
||||
| data.finished | Boolean | A boolean value indicating whether the survey response is marked as finished. |
|
||||
| data.data | Object | An object containing the response data, where keys are question identifiers, and values are the corresponding answers given by the respondent. |
|
||||
| data.meta | Object | Additional metadata related to the response, such as the user's operating system and browser information. |
|
||||
| data.personAttributes | Object | An object with attributes related to the respondent, such as their email and a user ID (if available). |
|
||||
| data.person | Object | Information about the respondent, including their unique id, attributes, and creation/update timestamps. |
|
||||
| data.notes | Array | An array of notes associated with the response (if any). |
|
||||
| data.tags | Array | An array of tags assigned to the response (if any). |
|
||||
|
||||
</Col>
|
||||
<Col>
|
||||
|
||||
### An example webhook payload
|
||||
|
||||
<CodeGroup title="Payload">
|
||||
|
||||
```json
|
||||
{
|
||||
"webhookId": "cljwxvjos0003qhnvj2jg4k5i",
|
||||
"event": "responseCreated",
|
||||
"data": {
|
||||
"id": "cljwy2m8r0001qhclco1godnu",
|
||||
"createdAt": "2023-07-10T14:14:17.115Z",
|
||||
"updatedAt": "2023-07-10T14:14:17.115Z",
|
||||
"surveyId": "cljsf3d7a000019cv9apt2t27",
|
||||
"finished": false,
|
||||
"data": {
|
||||
"qumbk3fkr6cky8850bvvq5z1": "Executive"
|
||||
},
|
||||
"meta": {
|
||||
"userAgent": {
|
||||
"os": "Mac OS",
|
||||
"browser": "Chrome"
|
||||
}
|
||||
},
|
||||
"personAttributes": {
|
||||
"email": "test@web.com",
|
||||
"userId": "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING"
|
||||
},
|
||||
"person": {
|
||||
"id": "cljold01t0000qh8ewzigzmjk",
|
||||
"attributes": {
|
||||
"email": "test@web.com",
|
||||
"userId": "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING"
|
||||
},
|
||||
"createdAt": "2023-07-04T17:56:17.154Z",
|
||||
"updatedAt": "2023-07-04T17:56:17.154Z"
|
||||
},
|
||||
"notes": [],
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
@@ -1,57 +0,0 @@
|
||||
export const metadata = {
|
||||
title: "Guide for Setting Custom Attributes | Formbricks Documentation",
|
||||
description:
|
||||
"Learn how to set attributes in code using setAttribute function. Enhance user segmentation, target surveys effectively, and gather valuable insights for better decisions. Easily send user-specific details for better survey segmentation and gain deeper insights.",
|
||||
};
|
||||
|
||||
#### Attributes
|
||||
|
||||
# Setting attributes with code
|
||||
|
||||
One way to send attributes to Formbricks is in your code. In Formbricks, there are two special attributes for [user identification](/docs/attributes/identify-users)(user ID & email) and custom attributes. An example:
|
||||
|
||||
## Setting during Initialization
|
||||
|
||||
It's recommended to set custom user attributes directly during the initialization of Formbricks for better user identification.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Set custom attributes during initialization">
|
||||
|
||||
```javascript
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
userId: "<user_id>",
|
||||
attributes: {
|
||||
plan: "free",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
## Setting independently
|
||||
|
||||
You can use the setAttribute function to set any custom attribute for the user (e.g. name, plan, etc.) anywhere in the user journey. Formbricks maintains a state of the current user inside the browser and makes sure attributes aren't sent to the backend twice.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Setting Plan to Pro">
|
||||
|
||||
```javascript
|
||||
formbricks.setAttribute("Plan", "Pro");
|
||||
```
|
||||
|
||||
</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.
|
||||
@@ -1,23 +0,0 @@
|
||||
export const metadata = {
|
||||
title: "Understanding User Attributes in Formbricks Surveys",
|
||||
description:
|
||||
"Dive into the importance of attributes in surveys. Learn how key-value pairs can significantly improve survey targeting, enhance feedback quality, and guide data-driven decisions with Formbricks.",
|
||||
};
|
||||
|
||||
#### Attributes
|
||||
|
||||
# What are attributes and why are they useful?
|
||||
|
||||
Surveying your user base without segmentation leads to weak results and survey fatigue. Attributes help you segment your users into groups.
|
||||
|
||||
## What are attributes?
|
||||
|
||||
Attributes are key-value pairs that you can set for each person individually. For example, the attribute "Plan" can be set to "Free" or "Paid".
|
||||
|
||||
## How do attributes work?
|
||||
|
||||
Attributes are sent from your application to Formbricks and are associated with the current user. We store it in our database and allow you to use it the next time you create a survey.
|
||||
|
||||
## Why are attributes useful?
|
||||
|
||||
Attributes help show surveys to the right group of people. For example, you can show a survey to all users who have a "Plan" attribute set to "Paid".
|
||||
@@ -1,5 +1,5 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import ChangeText from "./change-text.webp";
|
||||
import CreateChurnFlow from "./create-cancel-flow.webp";
|
||||
@@ -57,7 +57,7 @@ If you don't have an account yet, create one at [app.formbricks.com](https://app
|
||||
|
||||
Click on "Create Survey" and choose the template “Churn Survey”:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={CreateChurnFlow}
|
||||
alt="Create churn survey by template"
|
||||
quality="100"
|
||||
@@ -68,7 +68,7 @@ Click on "Create Survey" and choose the template “Churn Survey”:
|
||||
|
||||
You’re free to update the question and answer options. However, based on our experience, we suggest giving the provided template a go 😊
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ChangeText}
|
||||
alt="Change text content"
|
||||
quality="100"
|
||||
@@ -89,7 +89,7 @@ To create the trigger for your Churn Survey, you have two options to choose from
|
||||
|
||||
1. **Trigger by innerText:** You likely have a “Cancel Subscription” button in your app. You can setup a user Action with the according `innerText` to trigger the survey, like so:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={TriggerInnerText}
|
||||
alt="Set the trigger by inner Text"
|
||||
quality="100"
|
||||
@@ -98,7 +98,7 @@ To create the trigger for your Churn Survey, you have two options to choose from
|
||||
|
||||
2. **Trigger by CSS Selector:** In case you have more than one button saying “Cancel Subscription” in your app and only want to display the survey when one of them is clicked, you want to be more specific. The best way to do that is to give this button the HTML `id=“cancel-subscription”` and set your user action up like so:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={TriggerCSS}
|
||||
alt="Set the trigger by CSS Selector"
|
||||
quality="100"
|
||||
@@ -107,7 +107,7 @@ To create the trigger for your Churn Survey, you have two options to choose from
|
||||
|
||||
3. **Trigger by pageURL:** Lastly, you could also display your survey on a subpage “/subscription-cancelled” where you forward users once they cancelled the trial subscription. You can then create a user Action with the type `pageURL` with the following settings:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={TriggerPageUrl}
|
||||
alt="Set the trigger by page URL"
|
||||
quality="100"
|
||||
@@ -126,7 +126,7 @@ Here is our complete [Actions manual](/docs/actions/why) covering [Code](/docs/a
|
||||
|
||||
### 5. Select Action in the “When to ask” card
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={SelectAction}
|
||||
alt="Select feedback button action"
|
||||
quality="100"
|
||||
@@ -137,7 +137,7 @@ Here is our complete [Actions manual](/docs/actions/why) covering [Code](/docs/a
|
||||
|
||||
Lastly, scroll down to “Recontact Options”. Here you have to choose the correct settings to make sure you milk these super valuable insights. You want to make sure that this survey is always displayed, no matter if the user has already seen a survey in the past days:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={RecontactOptions}
|
||||
alt="Set recontact options"
|
||||
quality="100"
|
||||
@@ -148,7 +148,7 @@ These settings make sure the survey is always displayed, when a user wants to Ca
|
||||
|
||||
### 7. Congrats! You’re ready to publish your survey 💃
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={PublishSurvey}
|
||||
alt="Publish survey"
|
||||
quality="100"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import DocsFeedback from "@/components/docs/DocsFeedback";
|
||||
import AddAction from "./add-action.webp";
|
||||
@@ -46,7 +46,7 @@ To get this running, you'll need a bit of time. Here are the steps we're going t
|
||||
|
||||
2. In the Menu (top right) you see that you can switch between a “Development” and a “Production” environment. These are two separate environments so your test data doesn’t mess up the insights from prod. Switch to “Development”:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={SwitchToDev}
|
||||
alt="switch to dev environment"
|
||||
quality="100"
|
||||
@@ -55,7 +55,7 @@ To get this running, you'll need a bit of time. Here are the steps we're going t
|
||||
|
||||
3. Then, create a survey using the template “Docs Feedback”:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={DocsTemplate}
|
||||
alt="select docs template"
|
||||
quality="100"
|
||||
@@ -64,7 +64,7 @@ To get this running, you'll need a bit of time. Here are the steps we're going t
|
||||
|
||||
4. Change the Internal Question ID of the first question to **“isHelpful”** to make your life easier 😉
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ChangeId}
|
||||
alt="switch to dev environment"
|
||||
quality="100"
|
||||
@@ -80,7 +80,7 @@ To get this running, you'll need a bit of time. Here are the steps we're going t
|
||||
|
||||
6. Click on “Continue to Settings or select the audience tab manually. Scroll down to “When to ask” and create a new Action:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={WhenToAsk}
|
||||
alt="set up when to ask card"
|
||||
quality="100"
|
||||
@@ -89,7 +89,7 @@ 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:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={AddAction}
|
||||
alt="add action"
|
||||
quality="100"
|
||||
@@ -99,7 +99,7 @@ To get this running, you'll need a bit of time. Here are the steps we're going t
|
||||
|
||||
8. Select the Non-Event in the dropdown. Now you see that the “Publish survey” button is active. Publish your survey 🤝
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={SelectNonevent}
|
||||
alt="select nonevent"
|
||||
quality="100"
|
||||
@@ -128,7 +128,7 @@ 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:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={DocsNavi}
|
||||
alt="doc navigation"
|
||||
quality="100"
|
||||
@@ -412,7 +412,7 @@ Before you roll it out in production, you want to test it. To do so, you need tw
|
||||
|
||||
When you are on the survey detail page, you’ll find both of them in the URL:
|
||||
|
||||
<Image src={CopyIds} alt="copy IDs" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
<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>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import ActionCSS from "./action-css.webp";
|
||||
import ActionText from "./action-text.webp";
|
||||
@@ -54,7 +54,7 @@ If you don't have an account yet, create one at [app.formbricks.com](https://app
|
||||
|
||||
Click on "Create Survey" and choose the template “Feature Chaser”:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={CreateSurvey}
|
||||
alt="Create survey by template"
|
||||
quality="100"
|
||||
@@ -65,7 +65,7 @@ Click on "Create Survey" and choose the template “Feature Chaser”:
|
||||
|
||||
The questions you want to ask are dependent on your feature and can be very specific. In the template, we suggest a high-level check on how easy it was for the user to achieve their goal. We also add an opportunity to provide context:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ChangeText}
|
||||
alt="Change text content"
|
||||
quality="100"
|
||||
@@ -84,7 +84,7 @@ There are two ways to track a button:
|
||||
|
||||
1. **Trigger by innerText:** You might have a button with a unique text at the end of your feature e.g. "Export Report". You can setup a user Action with the according `innerText` to trigger the survey, like so:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ActionText}
|
||||
alt="Set the trigger by inner Text"
|
||||
quality="100"
|
||||
@@ -93,7 +93,7 @@ There are two ways to track a button:
|
||||
|
||||
2. **Trigger by CSS Selector:** In case you have more than one button saying “Export Report” in your app and only want to display the survey when one of them is clicked, you want to be more specific. The best way to do that is to give this button the HTML `id=“export-report-featurename”` and set your user action up like so:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ActionCSS}
|
||||
alt="Set the trigger by CSS Selector"
|
||||
quality="100"
|
||||
@@ -104,7 +104,7 @@ Please follow our [Actions manual](/docs/actions/why) for an in-depth descriptio
|
||||
|
||||
### 4. Select Action in the “When to ask” card
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={SelectAction}
|
||||
alt="Select PMF trigger button action"
|
||||
quality="100"
|
||||
@@ -115,7 +115,7 @@ Please follow our [Actions manual](/docs/actions/why) for an in-depth descriptio
|
||||
|
||||
Lastly, scroll down to “Recontact Options”. Here you have full freedom to decide who you want to ask. Generally, you only want to ask every user once and prevent survey fatigue. It's up to you to decide if you want to ask again, when the user did not yet reply:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={RecontactOptions}
|
||||
alt="Set recontact options"
|
||||
quality="100"
|
||||
@@ -124,7 +124,7 @@ Lastly, scroll down to “Recontact Options”. Here you have full freedom to de
|
||||
|
||||
### 7. Congrats! You’re ready to publish your survey 💃
|
||||
|
||||
<Image src={Publish} alt="Publish survey" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
<MdxImage src={Publish} alt="Publish survey" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? You need to have the Formbricks Widget installed to display the Feature Chaser
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
import Link from "next/link";
|
||||
|
||||
import AddAction from "./add-action.webp";
|
||||
import AddCSSAction from "./add-css-action.webp";
|
||||
@@ -13,7 +13,8 @@ import RecontactOptions from "./set-recontact-options.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Implementing the Feedback Box with Formbricks: A Step-by-Step Tutorial",
|
||||
description: "Unlock user insights effortlessly! Discover how to set up the Feedback Box in your app using Formbricks, allowing your users to provide real-time feedback. Follow our comprehensive guide to enhance user experience and respond rapidly to feedback",
|
||||
description:
|
||||
"Unlock user insights effortlessly! Discover how to set up the Feedback Box in your app using Formbricks, allowing your users to provide real-time feedback. Follow our comprehensive guide to enhance user experience and respond rapidly to feedback",
|
||||
};
|
||||
|
||||
#### Best Practices
|
||||
@@ -49,34 +50,34 @@ If you don't have an account yet, create one at [app.formbricks.com](https://app
|
||||
|
||||
Then, create a new survey and look for the "Feedback Box" template:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={CreateFeedbackBox}
|
||||
alt="Create feedback box by template"
|
||||
quality="100"
|
||||
className="rounded-lg max-w-full sm:max-w-3xl"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### 2. Update question content
|
||||
|
||||
Change the questions and answer options according to your preference:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ChangeTextContent}
|
||||
alt="Change text content"
|
||||
quality="100"
|
||||
className="rounded-lg max-w-full sm:max-w-3xl"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### 3. Create user action to trigger Feedback Box:
|
||||
|
||||
Go to the “Audience” tab, find the “When to send” card and choose “Add Action”. We will now use our super cool No-Code User Action Tracker:
|
||||
|
||||
<Image src={AddAction} alt="Add action" quality="100" className="rounded-lg max-w-full sm:max-w-3xl" />
|
||||
<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.
|
||||
## 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:
|
||||
@@ -84,46 +85,46 @@ We have two options to track the Feedback Button in your application: innerText
|
||||
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 grid-cols-2 space-x-2 max-w-full sm:max-w-3xl">
|
||||
<Image src={AddHTMLAction} alt="Add HTML action" quality="100" className="rounded-lg" />
|
||||
<Image src={AddCSSAction} alt="Add CSS action" quality="100" className="rounded-lg" />
|
||||
<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" />
|
||||
</div>
|
||||
|
||||
### 4. Select action in the “When to ask” card
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={SelectAction}
|
||||
alt="Select feedback button action"
|
||||
quality="100"
|
||||
className="rounded-lg max-w-full sm:max-w-3xl"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### 5. Set Recontact Options correctly
|
||||
|
||||
Scroll down to “Recontact Options”. Here you have to choose the right settings so that the Feedback Box pops up every time the user action is performed. (Our default is that every user sees every survey only once):
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={RecontactOptions}
|
||||
alt="Set recontact options"
|
||||
quality="100"
|
||||
className="rounded-lg max-w-full sm:max-w-3xl"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### 6. You’re ready publish your survey!
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={PublishSurvey}
|
||||
alt="Publish survey"
|
||||
quality="100"
|
||||
className="rounded-lg max-w-full sm:max-w-3xl"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Setting up the Widget
|
||||
|
||||
<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.
|
||||
## 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.
|
||||
</Note>
|
||||
|
||||
###
|
||||
|
||||
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,115 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import NewsletterSurveyType from "./choose-survey-type.webp";
|
||||
import NewsletterSurveyEmbedCode from "./embed-survey-code-in-your-email.webp";
|
||||
import NewsletterSurveyEmbedPrompt from "./embed-survey-prompt.webp";
|
||||
import NewsletterSurveyEditor from "./improve-newsletter-content-editor-formbricks.webp";
|
||||
import NewsletterSurvey from "./improve-newsletter-content-survey-location.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Measure email content quality with Formbricks",
|
||||
description:
|
||||
"Measuring the content quality of both transactional and marketing email is a key element for improving customer communication.",
|
||||
};
|
||||
|
||||
#### Best Practices
|
||||
|
||||
# Improve Email Content
|
||||
|
||||
Email remains the predominant way to communicate with your customers. Measure the effectiveness to improve your offering.
|
||||
|
||||
## Purpose
|
||||
|
||||
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.
|
||||
- Use link prefilling to store the answer users clicked on in the email.
|
||||
- Dynamic user identification to append reader's email for personalized profiles and follow ups.
|
||||
|
||||
## Installation
|
||||
|
||||
To embed the newsletter survey into your email, follow these steps:
|
||||
|
||||
1. Create new 'Improve Newsletter Content' survey at [app.formbricks.com](https://app.formbricks.com/)
|
||||
2. Select how you where you want to display the survey.
|
||||
3. Copy the embed code anywhere you want in your newsletter.
|
||||
|
||||
### 1. Create new 'Improve Newsletter Content' Survey
|
||||
|
||||
If you don't have an account yet, create one at [app.formbricks.com](https://app.formbricks.com/auth/signup)
|
||||
|
||||
Then, create a new survey and look for the "Improve Newsletter Content" template:
|
||||
|
||||
<MdxImage
|
||||
src={NewsletterSurvey}
|
||||
alt="Create Improve Newsletter Content by template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### 2. Customize Survey questions
|
||||
|
||||
Customize survey questions, emojis or stars however you like:
|
||||
|
||||
<MdxImage
|
||||
src={NewsletterSurveyEditor}
|
||||
alt="Edit Improve Newsletter Content template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### 3. Configure Survey Settings
|
||||
|
||||
When you are done customizing your survey questions, navigate to the Settings tab and choose the type of survey you want. You need to choose Link Survey:
|
||||
|
||||
<MdxImage
|
||||
src={NewsletterSurveyType}
|
||||
alt="Choose survey type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### 4. Choose how you want to embed your survey
|
||||
|
||||
After publishing your survey, a modal that prompts you to embed your survey will pop up.
|
||||
|
||||
<MdxImage
|
||||
src={NewsletterSurveyEmbedPrompt}
|
||||
alt="Embed newsletter survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Select the Embed Survey card and you will be directed to another modal, where the first embed option displayed will be to embed the survey in an email.
|
||||
|
||||
### 5. Copy code to embed the survey in your newsletter
|
||||
|
||||
Click the button with the “View Embed Code” text at the top right corner of the modal and simply paste the HTML code for your survey anywhere you want it in your newsletter. You can see the preview in the below image:
|
||||
|
||||
<MdxImage
|
||||
src={NewsletterSurveyEmbedCode}
|
||||
alt="Embed survey code"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
And you're done! Send a test email to yourself and try it out 🤓
|
||||
|
||||
## Learn about data prefilling
|
||||
|
||||
<Note>
|
||||
## How does data prefilling work? Learn about how link prefilling and user identification maximize your
|
||||
insights in [this detailed
|
||||
guide](/blog/how-smart-writers-use-formbricks-open-source-tool-to-measure-the-quality-of-their-newsletter-content).
|
||||
</Note>
|
||||
|
||||
###
|
||||
|
||||
# That’s it! 🎉
|
||||
@@ -1,5 +1,5 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import ActionText from "./action-innertext.webp";
|
||||
import ActionPageurl from "./action-pageurl.webp";
|
||||
@@ -54,7 +54,7 @@ If you don't have an account yet, create one at [app.formbricks.com](https://app
|
||||
|
||||
Click on "Create Survey" and choose the template “Improve Trial Conversion”:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={CreateSurvey}
|
||||
alt="Create survey by template"
|
||||
quality="100"
|
||||
@@ -65,7 +65,7 @@ Click on "Create Survey" and choose the template “Improve Trial Conversion”:
|
||||
|
||||
You’re free to update the questions and answer options. However, based on our experience, we suggest giving the provided template a go 😊
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ChangeText}
|
||||
alt="Change text content"
|
||||
quality="100"
|
||||
@@ -91,7 +91,7 @@ How you trigger your survey depends on your product. There are two options:
|
||||
|
||||
1. **Trigger by pageURL:** Let’s say you have a page under “/trial-cancelled” where you forward users once they cancelled the trial subscription. You can then create an user Action with the type `pageURL` with the following settings:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ActionPageurl}
|
||||
alt="Change text content"
|
||||
quality="100"
|
||||
@@ -102,7 +102,7 @@ Whenever a user visits this page, the survey will be displayed ✅
|
||||
|
||||
2. **Trigger by Button Click:** In a different case, you have a “Cancel Trial button in your app. You can setup a user Action with the according `innerText` like so:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ActionText}
|
||||
alt="Change text content"
|
||||
quality="100"
|
||||
@@ -113,7 +113,7 @@ Please have a look at our complete [Actions manual](/docs/actions/why) if you ha
|
||||
|
||||
### 5. Select Action in the “When to ask” card
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={SelectAction}
|
||||
alt="Select feedback button action"
|
||||
quality="100"
|
||||
@@ -124,7 +124,7 @@ Please have a look at our complete [Actions manual](/docs/actions/why) if you ha
|
||||
|
||||
Lastly, scroll down to “Recontact Options”. Here you have to choose the correct settings to make sure you gather as many insights as possible. You want to make sure that this survey is always displayed, no matter if the user has already seen a survey in the past days:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={RecontactOptions}
|
||||
alt="Set recontact options"
|
||||
quality="100"
|
||||
@@ -133,7 +133,7 @@ Lastly, scroll down to “Recontact Options”. Here you have to choose the corr
|
||||
|
||||
### 7. Congrats! You’re ready to publish your survey 💃
|
||||
|
||||
<Image src={Publish} alt="Publish survey" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
<MdxImage src={Publish} alt="Publish survey" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? You need to have the Formbricks Widget installed to display the Feedback Box
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import ActionCSS from "./action-css.webp";
|
||||
import ActionInner from "./action-innertext.webp";
|
||||
@@ -59,7 +59,7 @@ If you don't have an account yet, create one at [app.formbricks.com](https://app
|
||||
|
||||
Click on "Create Survey" and choose the template “Interview Prompt”:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={CreatePrompt}
|
||||
alt="Create interview prompt by template"
|
||||
quality="100"
|
||||
@@ -70,7 +70,7 @@ Click on "Create Survey" and choose the template “Interview Prompt”:
|
||||
|
||||
Update the prompt, description and button text to match your products tonality. You can also update the button color in the Product Settings.
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ChangeText}
|
||||
alt="Change text content"
|
||||
quality="100"
|
||||
@@ -79,7 +79,7 @@ Update the prompt, description and button text to match your products tonality.
|
||||
|
||||
In the button settings you have to make sure it is set to “External URL”. In the URL field, copy your booking link (e.g. https://cal.com/company/user-interview). If you don’t have a booking link yet, head over to [cal.com](http://cal.com) and get one - they have the best free plan out there!
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={InterviewExample}
|
||||
alt="Add CSS action"
|
||||
quality="100"
|
||||
@@ -105,7 +105,7 @@ Great, now only the “Power User” segment will see our Interview Prompt. But
|
||||
|
||||
To create the trigger to show your Interview Prompt, go to the “Audience” tab, find the “When to send” card and choose “Add Action”. We will now use our super cool No-Code User Action Tracker:
|
||||
|
||||
<Image src={AddAction} alt="Add action" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
<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
|
||||
@@ -117,7 +117,7 @@ Generally, we have two types of user actions: Page views and clicks. The Intervi
|
||||
|
||||
1. **pageURL:** Whenever a user visits a page the survey will be displayed, as long as the other conditions match. Other conditions are pre-segmentation, if this user has seen a survey in the past 2 weeks, etc.
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ActionPageurl}
|
||||
alt="Add page URL action"
|
||||
quality="100"
|
||||
@@ -127,8 +127,13 @@ Generally, we have two types of user actions: Page views and clicks. The Intervi
|
||||
2. **innerText & CSS-Selector:** When a user clicks an element (like a button) with a specific text content or CSS selector, the prompt will be displayed as long as the other conditions also match.
|
||||
|
||||
<div className="flex max-w-full flex-col sm:max-w-3xl lg:gap-1">
|
||||
<Image src={ActionCSS} alt="Add CSS action" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ActionCSS}
|
||||
alt="Add CSS action"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
<MdxImage
|
||||
src={ActionInner}
|
||||
alt="Add inner text action"
|
||||
quality="100"
|
||||
@@ -138,7 +143,7 @@ Generally, we have two types of user actions: Page views and clicks. The Intervi
|
||||
|
||||
### 5. Select action in the “When to ask” card
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={SelectAction}
|
||||
alt="Select feedback button action"
|
||||
quality="100"
|
||||
@@ -149,7 +154,7 @@ Generally, we have two types of user actions: Page views and clicks. The Intervi
|
||||
|
||||
Scroll down to “Recontact Options”. Here you have to choose the correct settings to strike the right balance between asking for user feedback and preventing survey fatigue. Your settings also depend on the size of your user base or segment. If you e.g. have thousands of “Power Users” you can easily afford to only display the prompt once. If you have a smaller user base you might want to ask twice to get a sufficient amount of bookings:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={RecontactOptions}
|
||||
alt="Set recontact options"
|
||||
quality="100"
|
||||
@@ -158,7 +163,7 @@ Scroll down to “Recontact Options”. Here you have to choose the correct sett
|
||||
|
||||
### 7. Congrats! You’re ready to publish your survey 💃 🤸
|
||||
|
||||
<Image src={Publish} alt="Publish survey" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
<MdxImage src={Publish} alt="Publish survey" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? You need to have the Formbricks Widget installed to display the Feedback Box
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import DemoPreview from "@/components/dummyUI/DemoPreview";
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import ActionCSS from "./action-css.webp";
|
||||
import ActionPageurl from "./action-pageurl.webp";
|
||||
@@ -53,7 +53,7 @@ If you don't have an account yet, create one at [app.formbricks.com](https://app
|
||||
|
||||
Click on "Create Survey" and choose one of the PMF survey templates. The first one is rather short, the latter builds on the ["Product-Market Fit Engine"](https://review.firstround.com/how-superhuman-built-an-engine-to-find-product-market-fit) developed by Superhuman:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={CreateSurvey}
|
||||
alt="Create survey by template"
|
||||
quality="100"
|
||||
@@ -64,7 +64,7 @@ Click on "Create Survey" and choose one of the PMF survey templates. The first o
|
||||
|
||||
You’re free to update the question and answer options. However, based on our experience, we suggest giving the provided template a go 😊 Here is a very [detailed description](https://coda.io/@rahulvohra/superhuman-product-market-fit-engine) of what to do with the data you’re collecting.
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ChangeText}
|
||||
alt="Change text content"
|
||||
quality="100"
|
||||
@@ -100,13 +100,13 @@ You need a trigger to display the survey but in this case, the filtering does al
|
||||
|
||||
<Col>
|
||||
<div>
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ActionCSS}
|
||||
alt="Add CSS action"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ActionPageurl}
|
||||
alt="Add inner text action"
|
||||
quality="100"
|
||||
@@ -116,7 +116,7 @@ You need a trigger to display the survey but in this case, the filtering does al
|
||||
</Col>
|
||||
### 5. Select Action in the “When to ask” card
|
||||
<Col>
|
||||
<Image
|
||||
<MdxImage
|
||||
src={SelectAction}
|
||||
alt="Select PMF trigger button action"
|
||||
quality="100"
|
||||
@@ -127,7 +127,7 @@ You need a trigger to display the survey but in this case, the filtering does al
|
||||
|
||||
Lastly, scroll down to “Recontact Options”. Here you have to choose the correct settings to make sure your data remains of high quality. You want to make sure that this survey is only responded to once per user. It is up to you to decide if you want to display it several times until the user responds:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={RecontactOptions}
|
||||
alt="Set recontact options"
|
||||
quality="100"
|
||||
@@ -136,7 +136,7 @@ Lastly, scroll down to “Recontact Options”. Here you have to choose the corr
|
||||
|
||||
### 7. Congrats! You’re ready to publish your survey 💃
|
||||
|
||||
<Image src={Publish} alt="Publish survey" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
<MdxImage src={Publish} alt="Publish survey" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
<Note>
|
||||
## Formbricks Widget running? You need to have the Formbricks Widget installed to display the Feedback Box
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import UnstableCache from "./unstable-cache-documentation.webp";
|
||||
|
||||
export const metadata = {
|
||||
@@ -209,6 +210,7 @@ We will rewrite the function `getApiKey` we created in the `service.ts` file to
|
||||
|
||||
```ts
|
||||
import { unstable_cache } from "next/cache";
|
||||
|
||||
import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { apiKeyCache } from "./cache";
|
||||
|
||||
@@ -252,7 +254,7 @@ _Breakdown of the above code._
|
||||
|
||||
In the above code we only introduce something new called `unstable_cache`, read more about it [here](https://nextjs.org/docs/app/api-reference/functions/unstable_cache#parameters). In a nutshell these are its parameters:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={UnstableCache}
|
||||
alt="Unstable Cache Parameters"
|
||||
quality="100"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import DemoApp from "./demoapp.webp";
|
||||
|
||||
@@ -14,7 +14,7 @@ export const metadata = {
|
||||
|
||||
To play around with the in-app [User Actions](/docs/actions/why), you can use the Demo App. It's a simple React app that you can run locally and use to trigger actions and set [Attributes](/docs/attributes/why).
|
||||
|
||||
<Image src={DemoApp} alt="Demo App Preview" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
<MdxImage src={DemoApp} alt="Demo App Preview" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
## Functionality
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import CorsHandling from "./cors-handling-in-api.webp";
|
||||
|
||||
export const metadata = {
|
||||
@@ -25,7 +26,7 @@ Thank you for choosing to contribute to Formbricks. Before you start, please fam
|
||||
- Constants should be in the packages folder
|
||||
- Types should be in the packages folder
|
||||
- How we handle Pull Requests
|
||||
- Read environment variables from `.env.mjs`
|
||||
- Read server-side environment variables from `constants.ts`
|
||||
|
||||
---
|
||||
|
||||
@@ -64,7 +65,7 @@ Please keep the following in mind:
|
||||
- When dealing with Management APIs always make sure to require authentication via API keys and a sufficient authorization check.
|
||||
- Make sure to handle CORS requests in any new Client API endpoint you create as these are called from the browser in link surveys or `formbricks-js`. Example below:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={CorsHandling}
|
||||
alt="Cors handling within an API"
|
||||
quality="100"
|
||||
@@ -83,9 +84,9 @@ You should store constants in `packages/lib/constants`
|
||||
|
||||
You should store type in `packages/types`
|
||||
|
||||
## Read environment variables from `.env.mjs`
|
||||
## Read server-side environment variables from `constants.ts`
|
||||
|
||||
Environment variables (`process.env`) shouldn’t be accessed directly but be added in the `.env.mjs` and should be accessed from here. This practice helps us ensure that the variables are typesafe.
|
||||
Server-side environment variables (`process.env`) shouldn’t be accessed directly but included into the `constants.ts` file and read from there. This way we can assure they are used only on the server side and are also type-safe.
|
||||
|
||||
## How we handle Pull Requests
|
||||
|
||||
|
||||
@@ -42,6 +42,4 @@ If you are at all unsure, just raise it as an enhancement issue first and tell u
|
||||
|
||||
To be able to keep working on Formbricks over the coming years, we need to collect a CLA from all relevant contributors.
|
||||
|
||||
Please note that we can only get your contribution merged when we have a CLA signed by you.
|
||||
|
||||
To access the CLA form, please click [here](https://formbricks.com/clmyhzfrymr4ko00hycsg1tvx)
|
||||
Once you open a PR, you will get a message from the CLA bot to fill out the form. Please note that we can only get your contribution merged when we have a CLA signed by you.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import GitpodAuth from "./gitpod/auth.webp";
|
||||
import GitpodNewWorkspace from "./gitpod/new-workspace.webp";
|
||||
@@ -63,7 +63,7 @@ This will install the Formbricks codebase and all the dependencies on your local
|
||||
1. Wait for the web and demo apps to launch on Gitpod. This automatically opens the `apps/demo/.env` file. Utilize dynamic localhost URLs (e.g., `localhost:3000` for signup and `localhost:8025` for email confirmation) to configure `NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID`. After creating your account and finding the `ID` in the URL at `localhost:3000`, replace `YOUR_ENVIRONMENT_ID` in the `.env` file located in `app/demo`.
|
||||
|
||||
**Web Component Initialization:**
|
||||
- we initialize the @formbricks/web component during prebuilds. This involves:
|
||||
- We initialize the @formbricks/web component during prebuilds. This involves:
|
||||
1. Installing build dependencies for the `@formbricks/web#go` task from turbo.json in prebuilds to save time.
|
||||
2. Starting PostgreSQL and Mailhog containers for running migrations in prebuilds.
|
||||
3. To prevent the "Init" task from running indefinitely due to prebuild rules, a cleanup `docker compose down` step i.e. `db:down` is added to `turbo.json`. This step is designed to halt the execution of containers that are currently running.
|
||||
@@ -93,13 +93,18 @@ After clicking the one-click setup button, Gitpod will open a new tab or window.
|
||||
|
||||
### 2. Authorizing in Gitpod
|
||||
|
||||
<Image src={GitpodAuth} alt="Gitpod Auth Page" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />-
|
||||
This is the Gitpod Authentication Page. It appears when you click the "Open in GitPod" button and Gitpod needs
|
||||
<MdxImage
|
||||
src={GitpodAuth}
|
||||
alt="Gitpod Auth Page"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
- This is the Gitpod Authentication Page. It appears when you click the "Open in GitPod" button and Gitpod needs
|
||||
to authenticate your access to the workspace. Click on 'Continue With Github' to authorize your GitPod session.
|
||||
|
||||
### 3. Creating a New Workspace
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={GitpodNewWorkspace}
|
||||
alt="Gitpod New workspace Page"
|
||||
quality="100"
|
||||
@@ -113,7 +118,7 @@ and follow the prompts to authorize the integration. 2. Change the `WEBAPP_URL`
|
||||
|
||||
### 4. Gitpod preparing the created Workspace
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={GitpodPreparing}
|
||||
alt="Gitpod Preparing workspace Page"
|
||||
quality="100"
|
||||
@@ -124,7 +129,7 @@ page while Gitpod sets up your development environment.
|
||||
|
||||
### 5. Gitpod running the Workspace
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={GitpodRunning}
|
||||
alt="Gitpod Running Workspace Page"
|
||||
quality="100"
|
||||
@@ -159,7 +164,7 @@ Here are the ports and corresponding URLs for the services within your Gitpod en
|
||||
|
||||
- **Port 1025**:
|
||||
|
||||
- **Service**: SMPT server
|
||||
- **Service**: SMTP server
|
||||
- **Description**: SMTP Server for sending and receiving email messages. This server is responsible for handling email communication.
|
||||
|
||||
- **Port 8025**:
|
||||
@@ -189,7 +194,7 @@ Here are the ports and corresponding URLs for the services within your Gitpod en
|
||||
|
||||
{" "}
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={GitpodPorts}
|
||||
alt="Gitpod Ports tab"
|
||||
quality="100"
|
||||
@@ -204,7 +209,7 @@ These URLs and port numbers represent various services and endpoints within your
|
||||
|
||||
1. After clicking the one-click setup button, you will be redirected to the Github Codespaces page. Review the configuration and click on the 'Create Codespace' button to create a new Codespace.
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={GithubCodespaceNew}
|
||||
alt="New Github Codespace"
|
||||
quality="100"
|
||||
@@ -213,7 +218,7 @@ These URLs and port numbers represent various services and endpoints within your
|
||||
|
||||
2. This will start loading the Codespace. Keep in mind this might take a few minutes to complete depending on your internet connection and the instance availability.
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={GithubCodespaceLoading}
|
||||
alt="Loading Github Codespace"
|
||||
quality="100"
|
||||
@@ -242,7 +247,7 @@ These URLs and port numbers represent various services and endpoints within your
|
||||
|
||||
5. Right next to the Terminal, you will see a **Ports** tab, click on it to see the ports and their respective URLs. Now access the Forwarded Address for port 3000 and you should be able to visit your Formbricks App!
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={GithubCodespacePorts}
|
||||
alt="Github Codespace Ports"
|
||||
quality="100"
|
||||
@@ -304,7 +309,7 @@ cp .env.example .env
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
4. Generate & set some secret values mandatory for the ENCRYPTION_KEY & NEXTAUTH_SECRET in the .env file. You can use the following command to generate the random string of required length:
|
||||
4. Generate & set some secret values mandatory for the `ENCRYPTION_KEY` & `NEXTAUTH_SECRET` in the .env file. You can use the following command to generate the random string of required length:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Set value of ENCRYPTION_KEY">
|
||||
@@ -330,11 +335,17 @@ pnpm go
|
||||
</Col>
|
||||
This starts the Formbricks main app (plus all its dependencies) as well as the following services using Docker:
|
||||
|
||||
- a `postgres` container for hosting your database,
|
||||
- a `mailhog` container that acts as a mock SMTP server and shows received mails in a web UI (forwarded to your host's `localhost:8025`)
|
||||
- A `postgres` container for hosting your database,
|
||||
- A `mailhog` container that acts as a mock SMTP server and shows received mails in a web UI (forwarded to your host's `localhost:8025`)
|
||||
- Demo App at [http://localhost:3002](http://localhost:3002)
|
||||
- Landing Page at [http://localhost:3001](http://localhost:3001)
|
||||
|
||||
<Note>
|
||||
**WSL2 users**: If you encounter connection issues with Prisma, ensure your WSL2 instance's PostgreSQL
|
||||
service is stopped before running `pnpm go`. Use the command `sudo systemctl stop postgresql` to stop the
|
||||
service.
|
||||
</Note>
|
||||
|
||||
**You can now access the Formbricks app on [http://localhost:3000](http://localhost:3000)**. You will be automatically redirected to the login. To use your local installation of formbricks, create a new account.
|
||||
|
||||
{" "}
|
||||
@@ -361,4 +372,4 @@ pnpm build
|
||||
|
||||
---
|
||||
|
||||
Still can’t figure it out? Join our [Discord](https://discord.com/invite/3YFcABF2Ts)!
|
||||
Can’t figure it out? Join our [Discord](https://discord.com/invite/3YFcABF2Ts)!
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import ClearAppData from "./clear-app-data.webp";
|
||||
import UncaughtPromise from "./uncaught-promise.webp";
|
||||
import Logout from "./logout.webp";
|
||||
import UncaughtPromise from "./uncaught-promise.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks Troubleshooting Guide: How to Solve & Debug Common Issues",
|
||||
@@ -20,7 +20,7 @@ Here you'll find help with frequently recurring problems
|
||||
|
||||
This can happen but fear not, the fix is easy: Delete the application storage of your browser and reload the page. This will force the app to re-fetch the data from the server:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ClearAppData}
|
||||
alt="Demo App Preview"
|
||||
quality="100"
|
||||
@@ -34,6 +34,7 @@ If nothing helps, run `pnpm clean` and then `pnpm i` again. This solves a lot.
|
||||
## "I get a full-screen error with cryptic strings"
|
||||
|
||||
This usually happens when the Formbricks Widget wasn't correctly or completely built.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Build js library first and then run again">
|
||||
|
||||
@@ -49,6 +50,7 @@ pnpm dev
|
||||
## My machine struggles with the repository
|
||||
|
||||
Since we're working with a monorepo structure, the repository can get quite big. If you're having trouble working with the repository, try the following:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Only run the required project">
|
||||
|
||||
@@ -70,7 +72,7 @@ However, in our experience it's better to run `pnpm dev` than having two termina
|
||||
|
||||
## Uncaught (in promise) SyntaxError: Unexpected token !DOCTYPE ... is not valid JSON
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={UncaughtPromise}
|
||||
alt="Uncaught promise"
|
||||
quality="100"
|
||||
@@ -79,4 +81,4 @@ However, in our experience it's better to run `pnpm dev` than having two termina
|
||||
|
||||
This happens when you're using the Demo App and delete the Person within the Formbricks app which the widget is currently connected with. We're fixing it, but you can also just logout your test person and reload the page to get rid of it.
|
||||
|
||||
<Image src={Logout} alt="Logout Person" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
<MdxImage src={Logout} alt="Logout Person" quality="100" className="max-w-full rounded-lg sm:max-w-3xl" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Libraries } from "@/components/docs/Libraries";
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import SetupChecklist from "./env-id.webp";
|
||||
import ReactApp from "./react-in-app-survey-app-popup-form.webp";
|
||||
@@ -28,7 +28,7 @@ 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:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={SetupChecklist}
|
||||
alt="Step 2 - Setup Checklist"
|
||||
quality="100"
|
||||
@@ -46,13 +46,13 @@ 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.4.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)}();
|
||||
</script>
|
||||
!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)}();
|
||||
</script>
|
||||
<!-- END Formbricks Surveys -->
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
### Required Customizations to be Made
|
||||
### Required customizations to be made
|
||||
|
||||
<Properties>
|
||||
<Property name="environment-id" type="string">
|
||||
@@ -76,7 +76,7 @@ Install the Formbricks SDK using one of the package managers ie `npm`,`pnpm`,`ya
|
||||
<Col>
|
||||
<CodeGroup title="Install Formbricks JS library">
|
||||
```shell {{ title: 'npm' }}
|
||||
npm install --save @formbricks/js
|
||||
npm install @formbricks/js
|
||||
```
|
||||
```shell {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/js
|
||||
@@ -99,7 +99,6 @@ if (typeof window !== "undefined") {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
debug: true, // remove when in production
|
||||
});
|
||||
}
|
||||
|
||||
@@ -112,7 +111,7 @@ export default App;
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
### Required Customizations to be Made
|
||||
### Required customizations to be made
|
||||
|
||||
<Properties>
|
||||
<Property name="environment-id" type="string">
|
||||
@@ -129,9 +128,9 @@ export default App;
|
||||
|
||||
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.
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ReactApp}
|
||||
alt="In app survey in React app for micro surveys"
|
||||
alt="In-app survey in React app for micro surveys"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
@@ -154,7 +153,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 --save @formbricks/js
|
||||
npm install @formbricks/js
|
||||
```
|
||||
```shell {{ title: 'pnpm' }}
|
||||
pnpm add @formbricks/js
|
||||
@@ -182,7 +181,6 @@ useEffect(() => {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
debug: true, // remove when in production
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -232,7 +230,6 @@ if (typeof window !== "undefined") {
|
||||
formbricks.init({
|
||||
environmentId: "<environment-id>",
|
||||
apiHost: "<api-host>",
|
||||
debug: true, // remove when in production
|
||||
});
|
||||
}
|
||||
|
||||
@@ -256,7 +253,7 @@ export default function App({ Component, pageProps }: AppProps) {
|
||||
</Col>
|
||||
Refer to our [Example NextJS Pages Directory project](https://github.com/formbricks/examples/tree/main/nextjs-pages) for more help!
|
||||
|
||||
### Required Customizations to be Made
|
||||
### Required customizations to be made
|
||||
|
||||
<Properties>
|
||||
<Property name="environment-id" type="string">
|
||||
@@ -269,14 +266,6 @@ Refer to our [Example NextJS Pages Directory project](https://github.com/formbri
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Optional Customizations to be Made
|
||||
|
||||
<Properties>
|
||||
<Property name="debug" type="boolean">
|
||||
Whether you want to see debug messages from Formbricks on your client-side console.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### What are we doing here?
|
||||
|
||||
First we need to initialize the Formbricks SDK, making sure it only runs on the client side.
|
||||
@@ -294,7 +283,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 --save @formbricks/js
|
||||
npm install @formbricks/js
|
||||
````
|
||||
|
||||
```shell {{ title: 'pnpm' }}
|
||||
@@ -345,7 +334,7 @@ router.afterEach((to, from) => {
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
### Required Customizations to be Made
|
||||
### Required customizations to be made
|
||||
|
||||
<Properties>
|
||||
<Property name="environment-id" type="string">
|
||||
@@ -358,21 +347,13 @@ router.afterEach((to, from) => {
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Optional Customizations to be Made
|
||||
|
||||
<Properties>
|
||||
<Property name="debug" type="boolean">
|
||||
Whether you want to see debug messages from Formbricks on your client-side console.
|
||||
</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!
|
||||
|
||||
## Validate your setup
|
||||
|
||||
Once you have completed the steps above, you can validate your setup by checking the **Setup Checklist** in the Settings. Your widget status indicator should go from this:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={WidgetNotConnected}
|
||||
alt="Widget isnt connected"
|
||||
quality="100"
|
||||
@@ -381,13 +362,53 @@ Once you have completed the steps above, you can validate your setup by checking
|
||||
|
||||
To this:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={WidgetConnected}
|
||||
alt="Widget is connected"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## Debugging Formbricks Integration
|
||||
|
||||
Enabling Formbricks debug mode in your browser is a useful troubleshooting step for identifying and resolving complex issues. This section outlines how to activate debug mode, covers common use cases, and provides insights into specific debug log messages.
|
||||
|
||||
### Activate Debug Mode
|
||||
|
||||
To activate Formbricks debug mode:
|
||||
|
||||
1. **Via URL Parameter:**
|
||||
|
||||
- Enable debug mode mode by adding `?formbricksDebug=true` to your application's URL (e.g. `https://example.com?formbricksDebug=true` or `https://example.com?page=123&formbricksDebug=true`). This parameter will enable debugging for the current page.
|
||||
|
||||
2. **View Debug Logs:**
|
||||
|
||||
- Open your browser's developer tools by pressing `F12` or right-clicking and selecting "Inspect."
|
||||
- Navigate to the "Console" tab to view Formbricks debugging information.
|
||||
|
||||
**How to Open Browser Console:**
|
||||
|
||||
- **Google Chrome:** Press `F12` or right-click, select "Inspect," and go to the "Console" tab.
|
||||
- **Firefox:** Press `F12` or right-click, select "Inspect Element," and go to the "Console" tab.
|
||||
- **Safari:** Press `Option + Command + C` to open the developer tools and navigate to the "Console" tab.
|
||||
- **Edge:** Press `F12` or right-click, select "Inspect Element," and go to the "Console" tab.
|
||||
|
||||
### Common Use Cases
|
||||
|
||||
Debug mode is beneficial for scenarios such as:
|
||||
|
||||
- Verifying Formbricks initialization.
|
||||
- Identifying survey trigger issues.
|
||||
- Troubleshooting unexpected behavior.
|
||||
|
||||
### Debug Log Messages
|
||||
|
||||
Debug log messages provide insights into:
|
||||
|
||||
- API calls and responses.
|
||||
- Event tracking, survey triggers and form interactions.
|
||||
- Initialization errors.
|
||||
|
||||
## 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`):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import ReactApp from "../framework-guides/react-in-app-survey-app-popup-form.webp";
|
||||
import I1 from "./1-in-app-survey-or-popup-survey-setup.webp";
|
||||
import I2 from "./2-settings-for-survey-popup-in-app-for-feedback.webp";
|
||||
import I3 from "./3-web-app-survey-settings-for-in-app-survey-popup.webp";
|
||||
@@ -8,7 +9,6 @@ import I5 from "./5-options-survey-popup-in-app-for-feedback.webp";
|
||||
import I6 from "./6-setup-in-app-survey-popup-feedback-box.webp";
|
||||
import I7 from "./7-in-app-survey-popup-for-feedback.webp";
|
||||
import I8 from "./8-pop-up-form-in-web-app-survey.webp";
|
||||
import ReactApp from "../framework-guides/react-in-app-survey-app-popup-form.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Formbricks Quickstart Guide: In-App Surveys Made Simple",
|
||||
@@ -20,15 +20,15 @@ export const metadata = {
|
||||
|
||||
# Quickstart
|
||||
|
||||
In app surveys have 6-10x better conversion rates than emailed out surveys. This tutorial explains how to run an in app survey in your web app in 10 to 15 minutes. Let’s go!
|
||||
In-app surveys have 6-10x better conversion rates than emailed out surveys. This tutorial explains how to run an in-app survey in your web app in 10 to 15 minutes. Let’s go!
|
||||
|
||||
## Create a free Formbricks Cloud account
|
||||
|
||||
While you can [self-host](/docs/self-hosting/deployment) Formbricks, 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 click through the onboarding, until you’re here:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I1}
|
||||
alt="Choose in app survey template"
|
||||
alt="Choose in-app survey template"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl "
|
||||
/>
|
||||
@@ -37,7 +37,7 @@ While you can [self-host](/docs/self-hosting/deployment) Formbricks, the quickes
|
||||
|
||||
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:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I2}
|
||||
alt="Settings for popup survey inside web app"
|
||||
quality="100"
|
||||
@@ -48,7 +48,7 @@ As you can see in the orange note here, we have not yet connected Formbricks Clo
|
||||
|
||||
Select “Web App” in the How to ask settings:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I3}
|
||||
alt="Survey settings for popup micro surve"
|
||||
quality="100"
|
||||
@@ -57,25 +57,25 @@ Select “Web App” in the How to ask settings:
|
||||
|
||||
Scroll down to Survey Trigger and choose “New Session”. This will cause this survey to appear when the Formbricks Widget tracks a new user session:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I4}
|
||||
alt="In app survey trigger for feedback popup micro survey"
|
||||
alt="In-app survey trigger for feedback popup micro survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
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:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I5}
|
||||
alt="Options for survey popup in app micro survey"
|
||||
alt="Options for survey popup in-app micro survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Now hit **Publish** and you’ll be forwarded to the Summary Page. This is where you’ll find the responses to this survey. On the Summary Page click through to the Setup Checklist:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I6}
|
||||
alt="pop up survey settings for inapp web survey"
|
||||
quality="100"
|
||||
@@ -86,9 +86,9 @@ Now hit **Publish** and you’ll be forwarded to the Summary Page. This is where
|
||||
|
||||
On the Setup Checklist you have two elements. At the top you find the Widget Status Indicator. Once your app is connected to Formbricks Cloud successfully, this will turn green:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I7}
|
||||
alt="feedback popup in app survey"
|
||||
alt="feedback popup in-app survey"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
@@ -98,9 +98,9 @@ In the manual below, this code snippet contains all the information you need:
|
||||
- The **Environment ID** of your current Formbricks workspace
|
||||
- The **API Host** which is ‘https://app.formbricks.com’ for Cloud users
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I8}
|
||||
alt="settings for in app survey popping up"
|
||||
alt="settings for in-app survey popping up"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
@@ -120,9 +120,9 @@ In a local instance of your app, you'll embed the Formbricks Widget. Dependent o
|
||||
|
||||
Now, restart your app in your terminal to make sure the widget is loaded. Once its loaded, open the browser console to see the Formbricks debug logs. If you did everything right, you should now see your survey in the lower right corner:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={ReactApp}
|
||||
alt="In app survey in React app for micro surveys"
|
||||
alt="In-app survey in React app for micro surveys"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Image from "next/image";
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import I1 from "./1-set-up-in-app-micro-survey-popup.webp";
|
||||
import I2 from "./2-micro-survey-pop-up-in-app.webp";
|
||||
@@ -20,9 +20,9 @@ In case you don’t see your survey right away, here's what you can do. Go throu
|
||||
|
||||
Go back to [app.formbricks.com](http://app.formbricks.com) or your self-hosted instance's URL and go to the Setup Checklist in the Settings. If the status is still indicated as “Not connected” your app hasn't yet pinged the Formbricks Cloud:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I1}
|
||||
alt="setup checklist ui of survey popup for in app surveys"
|
||||
alt="setup checklist ui of survey popup for in-app surveys"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
@@ -37,9 +37,9 @@ Go back to [app.formbricks.com](http://app.formbricks.com) or your self-hosted i
|
||||
|
||||
If your app is connected with Formbricks Cloud, the survey might have not been loaded properly. Check the debug logs and search for the list of surveys loaded. It should look like so:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I3}
|
||||
alt="survey logs for in app survey pop up micro"
|
||||
alt="survey logs for in-app survey pop up micro"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
@@ -48,9 +48,9 @@ If your app is connected with Formbricks Cloud, the survey might have not been l
|
||||
|
||||
The widget only loads surveys which are **public** and **in progress**. Go to Formbricks Cloud and to the Survey Summary page. Check if your survey is live:
|
||||
|
||||
<Image
|
||||
<MdxImage
|
||||
src={I2}
|
||||
alt="ui of survey popup for in app micro surveys"
|
||||
alt="ui of survey popup for in-app micro surveys"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
73
apps/formbricks-com/app/docs/in-app-surveys/actions/page.mdx
Normal file
@@ -0,0 +1,73 @@
|
||||
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.",
|
||||
};
|
||||
|
||||
#### In-App Surveys
|
||||
|
||||
# Actions
|
||||
|
||||
You want to understand what your users think and feel during specific moments in the user journey. To be able to ask at exactly the right point in time, you need actions.
|
||||
|
||||
## How do Actions work?
|
||||
|
||||
Actions are a little notification sent from your application to Formbricks. When a predefined action happens in your app, the Formbricks widget notices. This action can then trigger a survey to be shown to the user and is stored in the database.
|
||||
You decide which actions are sent either in your [Code](#code-actions) or by setting up a [No-Code](#no-code-actions) action within Formbricks.
|
||||
|
||||
### Why are actions useful?
|
||||
|
||||
Actions help you to display your surveys at the right time. Later on, you will be able to segment your users based on the actions they have triggered in the past. This way, you can create much more granular user segments, e.g. only target users that already have used a specific feature.
|
||||
|
||||
## No-Code Actions
|
||||
|
||||
No-Code actions can be set up within Formbricks with just a few clicks. There are three types of No-Code actions:
|
||||
|
||||
1. **Page URL Action**
|
||||
|
||||
The page URL action is triggered, when a user visits a specific page in your application. There are several match conditions:
|
||||
|
||||
- `exactMatch`: The URL should exactly match the provided string.
|
||||
- `contains`: The URL should contain the specified string as a substring.
|
||||
- `startsWith`: The URL should start with the specified string.
|
||||
- `endsWith`: The URL should end with the specified string.
|
||||
- `notMatch`: The URL should not match the specified condition.
|
||||
- `notContains`: The URL should not contain the specified string as a substring.
|
||||
|
||||
2. **innerText Action**
|
||||
|
||||
The innerText action checks if the `innerText` of a clicked HTML element matches a specific text, e.g. the label of a button. Display a survey on any button click!
|
||||
|
||||
3. **CSS Selector Action**
|
||||
|
||||
The CSS Selector action checks if the provided CSS selector matches the selector of a clicked HTML element. The CSS selector can be a class, id or any other CSS selector within your website. Display a survey on any element click!
|
||||
|
||||
## Code Actions
|
||||
|
||||
Actions can also be set in the codebase to trigger surveys. Please add the code action first in the Formbricks web interface to be able to configure your surveys to use this action.
|
||||
|
||||
After that you can fire an action using `formbricks.track()`
|
||||
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,97 @@
|
||||
import { MdxImage } from "@/components/shared/MdxImage";
|
||||
|
||||
import GermansGpt from "./germans-gpt.webp";
|
||||
import Hni from "./hni.webp";
|
||||
import PowerUsers from "./power-users.webp";
|
||||
import RideHailing from "./ride-hailing.webp";
|
||||
import UpsellMiro from "./upsell-miro.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Advanced Targeting in Surveys | Formbricks",
|
||||
description:
|
||||
"Advanced Targeting allows you to show surveys to just the right group of people. You can target surveys based on user attributes, user events, metadata , literally anything! This helps you get more relevant feedback and make data-driven decisions. All of this without writing a single line of code.",
|
||||
};
|
||||
|
||||
#### In-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>
|
||||
|
||||
## How to setup Advanced Targeting
|
||||
|
||||
<Note>
|
||||
Advanced Targeting is available on the Pro plan! Don't worry, you just need to enter your credit card
|
||||
details to start the freemium plan.
|
||||
</Note>
|
||||
|
||||
1. On the Formbricks dashboard, click on **People & Segments** tab from the top navigation bar.
|
||||
|
||||
2. Switch to the **Segments** tab & click on **Create Segment**.
|
||||
|
||||
3. Give your segment a title & a description to help you remember what this segment is about.
|
||||
|
||||
4. Now click on the **Add Filter** button to add a filter. You can filter based on actions, user attributes, other segments, devices, and more.
|
||||
|
||||
5. To group a set of filters together, click on the Three Dots icon on the right side of the filter and click on **Create Group**.
|
||||
|
||||
6. Try playing around with different filters & conditions that we have provided to see how the segment size changes.
|
||||
|
||||
7. Once you are happy with the segment, click on **Save Segment**.
|
||||
|
||||
8. Now, when you create a survey, you can select this segment to target your survey to.
|
||||
|
||||
## Examples:
|
||||
|
||||
1. Let's say you want to upsell to: Miro, Loom, Figma, Slack and Asana.
|
||||
|
||||
<MdxImage
|
||||
src={UpsellMiro}
|
||||
alt="Upselling Opportunity"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
2. Post-experience surveying for a ride hailing app where users who have taken more than 1 ride are shown a survey.
|
||||
|
||||
<MdxImage
|
||||
src={RideHailing}
|
||||
alt="Ride Hailing Targeting"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
3. Target High Value users who have $100k+ in their bank account, own 20+ stocks, and have are an active user.
|
||||
|
||||
<MdxImage
|
||||
src={Hni}
|
||||
alt="Target Active High Net Worth Individuals"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
4. Target Germans on mobile phones who have regenerated chatGPT answers frequently in the last quarter and did so today.
|
||||
|
||||
<MdxImage
|
||||
src={GermansGpt}
|
||||
alt="Target Germans on Mobile Phones who have regenerated chatGPT answers frequently in the last quarter and did so today"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
5. Sneak Peak: How we at Formbricks automate inviting power users to chat with us
|
||||
|
||||
<MdxImage
|
||||
src={PowerUsers}
|
||||
alt="Automate inviting power users to chat with us at Formbricks"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
After Width: | Height: | Size: 20 KiB |