Pass values into a form
Hand a form values from the page, link or app that opens it, save them with each response and use them to steer the form.
A hidden field is a value the form receives without asking for it. It is not a question. The page that opens the form supplies it: a plan name from a pricing page, a customer id from your app, a campaign from a link.
What a hidden field does:
- It is saved with the response, next to the answers, and appears in
exports, webhooks and the
responses API as
hiddenFields. - It can steer the form. A question's visibility, a branch, an ending and a rule that sets a variable can all test it.
- It can choose a price, through a variable. See Charge an amount that depends on a value.
It does not appear in the conversation. A question cannot quote it with
{{ref}} recall, which only reads answers.
Declare the field
Only declared names are accepted by the hosted page and the embed. Anything else in the link is ignored.
In the builder, open Settings, then Hidden fields & variables, type a name and press Enter. Over the API or MCP, add it to the form document:
{ "hiddenFields": [{ "name": "plan" }, { "name": "customer_id" }] }A name starts with a letter or underscore, then letters, digits, _, . or -,
up to 61 characters. Names are case sensitive: plan and Plan are different
fields.
Pass it in the link
Add the name as a query parameter to the form's link:
https://chatform.in/f/your-form-slug?plan=pro&customer_id=8271Encode anything that is not plain text, as you would any URL
(?note=two%20seats). A value is at most 500 characters. Repeat a name and the
link is ambiguous, so it is ignored. A form takes at most 25 hidden fields.
Pass it through the embed
On the script tag, one data-hidden- attribute per field:
<script
src="https://chatform.in/embed.js"
data-form="your-form-slug"
data-hidden-plan="pro"
data-hidden-customer_id="8271"
defer
></script>HTML lowercases attribute names, so data-hidden-customerId arrives as
customerid. Use lowercase field names if you pass them this way, or set them
from script, which keeps your casing:
window.Chatform.prefill({ plan: "pro", customerId: "8271" });Call prefill before the form opens. Values set after the conversation has
started are not picked up, because a session reads its hidden fields once, when
it begins.
An iframe takes the same query parameters as the link. In React, pass hidden:
<ChatformEmbed slug="your-form-slug" hidden={{ plan: "pro", customerId: "8271" }} />Pass it from your server
A session opened through the API, and a response submitted through it, take a
hiddenFields object:
curl -X POST https://api.chatform.in/v1/forms/$FORM_ID/sessions \
-H "x-api-key: $CHATFORM_SECRET_KEY" \
-H "content-type: application/json" \
-d '{"hiddenFields": {"plan": "pro"}}'The API does not check names against the form, so declare every field you send.
The MCP tool submit_response takes the same object as hidden_fields.
Steer the form with it
A condition can read a hidden field wherever it reads an answer: a question's visibility, a branch, an ending rule, a rule that sets a variable. A condition may only name a declared field. Publishing fails otherwise.
{
"left": { "kind": "hidden", "name": "plan" },
"op": "eq",
"value": "pro"
}Test for the field being absent as well. A link that was copied without its parameters opens the form with nothing set.
Charge an amount that depends on a value
A payment question in Variable mode charges the value of a form variable. Rules set that variable, and a rule can test a hidden field. So a link can pick between amounts you wrote into the form.
Say the pricing page links to ?plan=pro or ?plan=team. Declare plan, add a
number variable price, and add one rule per plan:
{
"variables": [{ "name": "price", "type": "number", "initial": 0 }],
"hiddenFields": [{ "name": "plan" }],
"logic": [
{
"id": "r_price_pro",
"action_kind": "set_variable",
"when": {
"op": "and",
"groups": [],
"conditions": [{ "left": { "kind": "hidden", "name": "plan" }, "op": "eq", "value": "pro" }]
},
"variable": "price",
"expr": 99
},
{
"id": "r_price_team",
"action_kind": "set_variable",
"when": {
"op": "and",
"groups": [],
"conditions": [{ "left": { "kind": "hidden", "name": "plan" }, "op": "eq", "value": "team" }]
},
"variable": "price",
"expr": 299
}
]
}Then set the payment question to Variable and choose price, with a minimum
and maximum as a guard. The amount is worked out on the server, so the
respondent sees and pays what your rules say. Rules run after each answer, so
the payment question needs at least one question before it.
A link can choose between prices you have written down. It cannot carry a price
of its own. A rule can test a hidden field but cannot copy its value into a
variable, so a cart total such as ?total=4999 is saved with the response and
never charged. That is deliberate: anyone can edit a link, and an amount taken
from one would let a visitor set their own price. Charge a total your server
computes by creating the payment on your own gateway and sending the respondent
there, or give each product a rule as above.
Verified checkout is described in Verified payments.