diff --git a/apps/docs/app/best-practices/contact-form/images/embed.png b/apps/docs/app/best-practices/contact-form/images/embed.png
deleted file mode 100644
index 1be2dae3e1..0000000000
Binary files a/apps/docs/app/best-practices/contact-form/images/embed.png and /dev/null differ
diff --git a/apps/docs/app/global/variables/images/created-variables.webp b/apps/docs/app/global/variables/images/created-variables.webp
new file mode 100644
index 0000000000..4567d91598
Binary files /dev/null and b/apps/docs/app/global/variables/images/created-variables.webp differ
diff --git a/apps/docs/app/global/variables/images/input-variables.webp b/apps/docs/app/global/variables/images/input-variables.webp
new file mode 100644
index 0000000000..6273bfe5fc
Binary files /dev/null and b/apps/docs/app/global/variables/images/input-variables.webp differ
diff --git a/apps/docs/app/global/variables/images/logic-with-variables.webp b/apps/docs/app/global/variables/images/logic-with-variables.webp
new file mode 100644
index 0000000000..24db41a7e3
Binary files /dev/null and b/apps/docs/app/global/variables/images/logic-with-variables.webp differ
diff --git a/apps/docs/app/global/variables/images/variables-card.webp b/apps/docs/app/global/variables/images/variables-card.webp
new file mode 100644
index 0000000000..c9f6c781d6
Binary files /dev/null and b/apps/docs/app/global/variables/images/variables-card.webp differ
diff --git a/apps/docs/app/global/variables/images/variables-usage.webp b/apps/docs/app/global/variables/images/variables-usage.webp
new file mode 100644
index 0000000000..2ff22da6ad
Binary files /dev/null and b/apps/docs/app/global/variables/images/variables-usage.webp differ
diff --git a/apps/docs/app/global/variables/page.mdx b/apps/docs/app/global/variables/page.mdx
new file mode 100644
index 0000000000..686ad37b2a
--- /dev/null
+++ b/apps/docs/app/global/variables/page.mdx
@@ -0,0 +1,89 @@
+import { MdxImage } from "@/components/MdxImage";
+
+import CreatedVariables from "./images/created-variables.webp";
+import InputVariables from "./images/input-variables.webp";
+import LogicWithVariables from "./images/logic-with-variables.webp";
+import VariablesCard from "./images/variables-card.webp";
+import VariablesUsage from "./images/variables-usage.webp";
+
+export const metadata = {
+ title: "Variables",
+ description: "Add variabeles to your surveys to transform your survey into a quiz",
+};
+
+# Hidden Fields
+
+Variables are a powerful feature in Formbricks that allows you to keep track of data variables when user fills a form. This feature is especially useful when you want to use your survey as a quiz.
+
+## Types of Variables
+
+There are two types of variables you can add to your survey:
+
+1. **Text**: You can add text variables to your survey to capture text data.
+2. **Number**: You can add number variables to your survey to capture number data.
+
+## How to Add Variables
+
+1. Edit the survey you want to add variables to & switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Variables**.
+
+
+
+2. Now click on it to add a new variable ID. You can add as many variables as you want. You can also choose the type of variable you want to add along with the default value.
+
+
+
+
+
+## Use case:
+
+- **Quiz**: You can use variables to create a quiz. For example, you can add a variable `score` and update it every time a user answers a question. You can also use the variable for recall to show the final score to the user.
+
+- **Personalisation**: You can use variables to store user data and personalise the survey experience. For example, you can add a variable `full_name` and update it every time a user fills in their first name and last name. You can use the variable to personalise the survey experience by addressing the user with their full name.
+
+## How is it different from Hidden Fields?
+
+Variables are different from hidden fields in the following ways:
+
+1. **Setting**: Hidden fields can be set through query parameters or `formbricks.init`, but the variables can only be set either during creation or dynamically by using logic actions.
+2. **Updating**: Hidden fields cannot be set again, but the value of variables can be updated while the user fills the survey.
+3. **Type**: Hidden fields can only store text data, but variables can store both text and number data.
+
+## How to use Variables
+
+1. Once you have added the variables to your survey, you'll be able to access them in the logic editor. You can use the variables to create logic actions and conditions.
+
+
+
+2. You can create logic based on the variables and questions in your survey and can update the variables based on the user's response.
+
+
+
+
+ To know more about how to use logic in Formbricks, check out the [Conditional
+ Logic](/global/conditional-logic).
+
diff --git a/apps/docs/lib/navigation.ts b/apps/docs/lib/navigation.ts
index 066a12c9ce..516b26c48b 100644
--- a/apps/docs/lib/navigation.ts
+++ b/apps/docs/lib/navigation.ts
@@ -54,6 +54,7 @@ export const navigation: Array = [
title: "Add Image/Video to Question",
href: "/global/add-image-or-video-question",
},
+ { title: "Variables", href: "/global/variables" },
],
},
],
@@ -85,6 +86,7 @@ export const navigation: Array = [
title: "Add Image/Video to Question",
href: "/global/add-image-or-video-question",
},
+ { title: "Variables", href: "/global/variables" },
],
},
],
diff --git a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx
index 639d4cb349..09db904fef 100644
--- a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx
+++ b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx
@@ -608,8 +608,10 @@ export const getMatchValueProps = (
options: groupedOptions,
};
} else if (selectedVariable?.type === "number") {
- const allowedQuestions = questions.filter((question) =>
- [TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS].includes(question.type)
+ const allowedQuestions = questions.filter(
+ (question) =>
+ [TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS].includes(question.type) ||
+ (question.type === TSurveyQuestionTypeEnum.OpenText && question.inputType === "number")
);
const questionOptions = allowedQuestions.map((question) => {
@@ -945,8 +947,10 @@ export const getActionValueOptions = (
return groupedOptions;
} else if (selectedVariable.type === "number") {
- const allowedQuestions = questions.filter((question) =>
- [TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS].includes(question.type)
+ const allowedQuestions = questions.filter(
+ (question) =>
+ [TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS].includes(question.type) ||
+ (question.type === TSurveyQuestionTypeEnum.OpenText && question.inputType === "number")
);
const questionOptions = allowedQuestions.map((question) => {
diff --git a/packages/types/surveys/types.ts b/packages/types/surveys/types.ts
index bec8f0c2cf..f48a1f310e 100644
--- a/packages/types/surveys/types.ts
+++ b/packages/types/surveys/types.ts
@@ -1748,7 +1748,11 @@ const validateConditions = (
});
} else if (variable.type === "number") {
const validQuestionTypes = [TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS];
- if (!validQuestionTypes.includes(question.type)) {
+ if (
+ !validQuestionTypes.includes(question.type) &&
+ question.type === TSurveyQuestionTypeEnum.OpenText &&
+ question.inputType !== "number"
+ ) {
issues.push({
code: z.ZodIssueCode.custom,
message: `Conditional Logic: Invalid question type "${question.type}" for right operand in logic no: ${String(logicIndex + 1)} of question ${String(questionIndex + 1)}`,
@@ -1985,7 +1989,13 @@ const validateActions = (
const allowedQuestions = [TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS];
const selectedQuestion = survey.questions.find((q) => q.id === action.value.value);
- if (!selectedQuestion || !allowedQuestions.includes(selectedQuestion.type)) {
+
+ if (
+ !selectedQuestion ||
+ (!allowedQuestions.includes(selectedQuestion.type) &&
+ selectedQuestion.type === TSurveyQuestionTypeEnum.OpenText &&
+ selectedQuestion.inputType !== "number")
+ ) {
return {
code: z.ZodIssueCode.custom,
message: `Conditional Logic: Invalid question type for number variable in logic no: ${String(logicIndex + 1)} of question ${String(questionIndex + 1)}`,