Hidden fields let you store campaign query parameters beside a response without asking anyone to type them.
Add hidden fields
const acquisition = defineForm({
id: "demo-request",
title: "Request a demo",
pages: [{
id: "request",
blocks: [
{ id: "email", kind: "email", label: "Work email", required: true },
{ id: "utm_source", kind: "hidden", label: "UTM source", paramName: "utm_source" },
{ id: "utm_medium", kind: "hidden", label: "UTM medium", paramName: "utm_medium" },
{ id: "utm_campaign", kind: "hidden", label: "UTM campaign", paramName: "utm_campaign" },
{ id: "landing_path", kind: "hidden", label: "Landing path", paramName: "landing_path" },
],
}],
});A hosted form reads those parameters directly. For an embed later in a multi-page product flow, capture the approved values on arrival and pass them through initialData when the form mounts.
const initialData = {
utm_source: sessionStorage.getItem("utm_source") ?? "",
utm_medium: sessionStorage.getItem("utm_medium") ?? "",
utm_campaign: sessionStorage.getItem("utm_campaign") ?? "",
landing_path: sessionStorage.getItem("landing_path") ?? location.pathname,
};Decide when attribution expires and whether first-touch or last-touch wins. Don't collect arbitrary query parameters or personal data because they happen to be available.
Interpret it correctly
Visitors, link shorteners, and referrers can change or strip UTM values. They're respondent-supplied analysis context, not proof — don't base commissions, billing, access, or security decisions on them. When the source is missing, use a documented direct or unknown bucket instead of inventing one.
Try it
Start with a prompt and your coding agent builds the first form, staged for your review — or open the editor.
Related
- Beta access example: See a signup form that carries hidden campaign context.
- Hidden field: Configure
paramNameand default values. - Prefill from URL parameters: Encode and validate query values.
- Exports: Analyze campaign columns in a filtered CSV.