Skip to main content

Form Prefill: Cascade, Pinning Values & Hidden Fields

Four sources, one cascade — how defaults, persistence, URL params and embed options prefill fields, plus how to pin values that visitors can't override

M
Written by Maxim Tan

RocketLead form fields can be prefilled from four different sources. This article explains the precedence between them, what each source can and cannot do, and how to pin values that visitors cannot override.

The cascade

When the widget mounts, it walks four prefill sources. Each layer can fill empty slots; higher-priority layers blindly overwrite lower-priority ones. Final priority, from highest to lowest:

#

Source

Wins over

Authored by

1

Embed prefill option

URL params, persistence, defaults

The page that hosts the embed (developer JS)

2

URL query params

Persistence, defaults

The visitor's URL bar / inbound link

3

localStorage persistence

Defaults

The visitor (return-visit autofill)

4

Field defaultValue

(bottom)

The form editor (config)

Mental model: most-explicit-context wins. Code beats URL bar beats local storage beats static config. A field that no source provides a value for stays empty.

Source 1 — Embed prefill (highest priority)

Set when calling window.rocketlead.forms.create() from your page's JavaScript:

<div id="rl-form"></div> <script src="https://cdn.rocketlead.io/static/forms/widget.js" defer></script> <script>   window.rocketlead.forms.create({     target:     '#rl-form',     formId:     'shared-form-id',     prefill:    { location: 'studio-uuid-for-this-page' },     hideFields: ['location']   }); </script>

Keys are matched first against fieldId, then against the field's stable name (set in the editor). Unknown keys are dropped silently.

Because embed prefill is the highest-priority source, this is how you pin a value that visitors cannot override — even with a crafted URL. See Hidden fields below.

Source 2 — URL query params

The visitor's URL automatically prefills matching fields. Two key conventions:

https://your-site.com/contact?fieldId=value https://your-site.com/contact?yourFieldName=value

fieldId wins on collision with another field's name.

Multi-value (checkbox) fields: repeat the key.

?days=mon&days=wed

Booking-calendar fields are special — a URL value is interpreted as an appointment-type id to preselect inside the calendar, not a slot. Slots are always picked interactively against live availability.

Privacy and captcha fields can never be prefilled from URL params — consent must be explicit, captcha tokens come from the third-party provider at submit time.

Source 3 — localStorage persistence

If the form has persistence enabled in the editor, listed shared fields are read from localStorage on mount and written on every change. This is the "return visitor autofill" mechanism — surveys, multi-step funnels, abandoned-and-returned flows.

The persistence bucket is keyed by form id, so two embeds of the same form on the same domain share their bucket.

Source 4 — Field defaultValue (lowest priority)

A static fallback authored in the form editor. Only fills slots no other source filled.

Field type

defaultValue shape

Validation

text / email / tel

string

respects maxLength; truncated silently at runtime, rejected at publish

select / location

string

must match one of the field's option values

checkbox

string[] (non-empty)

every entry must match an option

booking-calendar

not supported

appointment-type

not supported yet (per-calendar default planned)

captcha / privacy

not supported

Defaults run in the editor's preview, so the editor reflects what visitors will see.

Hidden fields

The embed-level hideFields option removes a field from the rendered form while keeping its value in the submission payload. Combined with prefill, this is the multi-instance pattern — one published form, N embeds, each pinning a different value.

window.rocketlead.forms.create({   target:     '#rl-form',   formId:     'lead-form',   prefill:    { location: 'studio-uuid', utm_source: 'google' },   hideFields: ['location', 'utm_source'] });

Behaviour:

  • The renderer skips hidden fields — they never appear in step bodies or in the review/summary step.

  • Their values stay in the form's internal state, so studio routing (location), validation, and submission all still see them.

  • URL params targeting a hidden field are silently dropped. A crafted ?location=other-studio link cannot override what the embedder pinned. The embed prefill itself is allowed because the embedder is the source of authority.

  • Validation is unchanged. A hidden required field without a matching prefill will fail at submit. The widget logs console.warn on mount when this is the case.

Validation & sanitisation

Every prefill source applies the same defensive rules; mismatches are dropped silently rather than crashing the form.

  • Sanitisation — text inputs (text/email/tel) and option keys are stripped of <, >, and ASCII control characters before further processing. Values that become empty after stripping are dropped.

  • Option matchselect, location, and checkbox values must match one of the field's published option values. Stale or unknown values are dropped.

  • maxLength — text values exceeding the field's maxLength are truncated silently at the widget; the publish step rejects them outright.

  • Type shape — non-string passed to a string field, or non-array to a checkbox, is dropped.

Quick reference — what each field type accepts

Field type

Embed prefill

URL params

Persistence

defaultValue

text / email / tel

select / location

checkbox

booking-calendar

✓ (appt type)

appointment-type

captcha

privacy

Examples

One form, many locations

A franchise with five WordPress sites embeds the same form on every site, pinning a different studio per page:

<!-- studio1.example.com/contact --> <div id="rl-form"></div> <script>   window.rocketlead.forms.create({     target:     '#rl-form',     formId:     'shared-lead-form',     prefill:    { location: 'studio-1-uuid' },     hideFields: ['location']   }); </script>
<!-- studio2.example.com/contact — same form, different studio --> <script>   window.rocketlead.forms.create({     target:     '#rl-form',     formId:     'shared-lead-form',     prefill:    { location: 'studio-2-uuid' },     hideFields: ['location']   }); </script>

Submissions land on each studio's correct calendar / lead-pool table automatically — the location field drives studio resolution under the hood, even when hidden.

Campaign tracking from the URL

A tracking field carries the utm_source from inbound campaign links:

https://your-site.com/contact?utm_source=google&utm_campaign=spring2026

Pass it through as a hidden field at the embed level:

const params = new URLSearchParams(window.location.search); window.rocketlead.forms.create({   target:  '#rl-form',   formId:  'lead-form',   prefill: {     utm_source:   params.get('utm_source')   ?? 'direct',     utm_campaign: params.get('utm_campaign') ?? ''   },   hideFields: ['utm_source', 'utm_campaign'] });

Default with override

The email_subject field has a defaultValue of "Trial lesson inquiry" set in the editor. A campaign page links visitors with a custom subject:

https://your-site.com/landing?email_subject=Summer-Promo

Result: "Summer-Promo" (URL beats default). If the visitor returns later without the URL parameter, persistence — if enabled — shows their last-typed value, otherwise the editor default reappears.

Common pitfalls

  • "My default isn't showing in the published form" — make sure no other source is filling the slot. URL params and persistence both override defaults. Test in an incognito window without query strings to confirm.

  • "My embed prefill isn't applying" — the key didn't resolve. The widget matches fieldId first, then the field's stable name. Check the field's name in the editor under Field settings → Name.

  • "Validation says my form is incomplete but I can't see why" — a hidden required field has no matching prefill. Open devtools — the widget logs a console.warn at mount listing each affected field.

  • "My select/location prefill is ignored" — the value isn't in the field's options. Check the editor's option list against what your embed/URL is sending.

Related articles

Did this answer your question?