Skip to main content
Embedded Data is data about this response. A page type, a plan, a campaign, a quiz score, the device the survey was answered on. It rides along with the answers, shows up in the response table and in exports, and can be used in recall, logic and redirect URLs. That makes it the counterpart to contact attributes, which are data about this person and persist across every response they ever give.
The API payloads keep their shape and no survey needs editing; only hiddenFields.enabled is now derived (true whenever a passed-in field exists) and ignored on write. What did change is the editor: the Hidden Fields and Variables cards are now one Embedded Data card, where a field’s source is Passed in or Calculated. See Hidden Fields and Variables if you already use them.

The Three Sources

Every Embedded Data field has exactly one source, and the source decides who is allowed to write it. Ingested fields are the only ones anything outside the survey can write. Computed fields are set by logic while the respondent answers, and reserved fields are read-only auto-capture, so a URL param or an SDK call naming one of them is dropped and logged rather than stored.

Where Values Come From

Which capture channel is available depends on the survey type, and this is the part worth reading twice, because a URL param does nothing for an app survey and setEmbeddedData() does nothing for a link survey.
Mobile SDKs render the survey inside a WebView that has no host page, so location and document.referrer describe nothing real there. The page and campaign fields are left absent on mobile responses rather than filled with a meaningless value. The device fields are honest measurements of the device and are captured. If you want the equivalent of a page name on mobile, pass it yourself: setEmbeddedData({ screen: "checkout" }).
A field does not care which channel filled it. plan is declared the same way, filled by ?plan=pro on a link survey and by setEmbeddedData({ plan: "pro" }) on an app survey, and reads back identically in recall, logic, filters and exports.

Declaring a Field

An ingested or computed field has to exist before anything can fill it, and there are two places to declare one:
  • In the survey editor, for a field only that survey uses: the Embedded Data card, where one dialog creates either source.
  • In Settings → Workspace → Embedded Data, for a field the whole workspace shares. A field declared there can be linked from any survey, and editing it once changes it for every survey using it. The same page lists which surveys use each field, and refuses to delete one that is still in use. See Field library.
Reserved fields are never declared, they are always available. A passed-in field carries two things you type, and they do different jobs. Its name is what you call it — what the response table, the summary and your exports show, renameable at any time. Its key is the address the value lives under: the URL parameter, the SDK key, and what recall and logic resolve. The key fills itself in from the name, and cannot change once the field exists, because responses are already stored under it. A calculated field added on a survey has a name only; one in the library also takes a key, because that is how other surveys find it. Either way its storage address is generated. Keys follow one rule everywhere, and reserved names are refused for new fields in any casing. The full rule and the refused list live on the Hidden Fields page. A field also carries a type that decides how its value is read back and compared. In this release:
  • Passed-in fields can be string, number, boolean or date, wherever they are declared, and incoming values are coerced to the declared type.
  • Calculated fields are text or number — the types survey logic can produce — and the initial value you set is the default the field falls back to.
  • Reserved fields are typed by Formbricks, and several of them are genuinely numeric: viewportWidth < 768 is a numeric comparison in logic, not a comparison of digit strings.
A field’s type and default are set in its own dialog, on a survey field and a library field alike. A passed-in field also has a lock there: a locked field ignores whatever a URL param or the SDK sends and uses its default instead, which is how you fix a value nobody outside can change. A calculated field has no lock: only the survey’s own logic writes it.

What Happens to an Incoming Value

The same contract runs in the browser when the survey is displayed, and again on the server when the response is saved, so what the client accepts is never taken on trust.
1

Allow-list

Only names the survey declares as ingested fields are stored. An unknown key, a computed field, a reserved field or a locked field is dropped and logged, never stored, and never an error.
2

Case-insensitive matching

A field declared customerRef is filled by ?customerref=x as well as ?customerRef=x. The value is always stored under the declared spelling, so exports and recall see one key.
3

Coercion to the declared type

Values are coerced rather than rejected. "42" into a number field becomes 42; true, 1, yes and on (and their negatives) become the strings "true" and "false" — that canonical pair is what a response stores, what an export column shows, and what a filter compares against; a date field accepts 2026-08-06 and full ISO 8601 datetimes, stores ISO 8601, and reads a datetime with no zone as UTC rather than as the respondent’s local time. A value that cannot be coerced is stored verbatim and flagged, so a bad parameter never blocks a response. A field left as string — every field declared in the survey editor — passes through this step unchanged, since every scalar has a lossless text form; it does visible work on a shared field that declares a narrower type.
4

Size limit

One value is capped at 16 KB of UTF-8. Anything longer is truncated on a character boundary and flagged, not rejected.
5

Collision with a question

A question’s answer always wins its own key. A field whose name collides with a question id can never hold a value, and the collision is reported.
A field nothing arrived for keeps its key absent rather than empty, and reads back as its default value if it has one. That is what makes #recall:plan/fallback:unknown# show the fallback instead of a blank.

Precedence

When two sources offer the same field on the same response, the more explicit one wins:
  1. a question’s answer, always, for its own key;
  2. an explicit formbricks.track("action", { hiddenFields: { plan: "pro" } }) value;
  3. the ambient bag set with setEmbeddedData(), or the URL parameter on a link survey;
  4. the field’s default value;
  5. otherwise the field is unset.
Reserved fields sit outside this list because they are never written from outside. The one interaction is shadowing: if a survey declares its own field named url or country, that name resolves to the declared field everywhere, and the reserved field of the same name is not offered, listed or exported for that survey.

Reading the Values Back

Once a value is on a response it behaves like any other response data:
  • Recall it into question copy, ending cards and redirect URLs with #recall:<name>/fallback:<text>#.
  • Use it as a logic operand to branch the survey.
  • Filter and group responses by it.
  • Export it as a stable, typed column in CSV and Excel.
Mid-survey surfaces (recall inside a running survey, logic conditions) can only use values that exist while the respondent is still answering. Server-derived reserved fields such as country or durationSeconds are only known once the response reaches Formbricks, so they are available on the response but not offered to a running survey. The Reserved Fields page marks which is which.

Next Steps

Reserved Fields

The full catalog of auto-captured fields, their types, and what the Anonymize toggle suppresses.

setEmbeddedData

The JavaScript SDK reference: merge semantics, SPA route changes, GTM and the debug trace.

Mobile SDKs

setEmbeddedData on React Native, iOS, Android and Flutter, with each language’s value types.

Hidden Fields & Variables

What changes for surveys you already run, and what does not.