# Prefill

Last updated: 2026-07-07

Canonical human page: https://fillo.so/docs/prefill
Quickstart: https://fillo.so/docs/embed.md
Code-defined forms: https://fillo.so/docs/authoring.md
Styling: https://fillo.so/docs/styling.md
Webhooks: https://fillo.so/docs/webhooks.md
Custom UI: https://fillo.so/docs/custom-ui.md
API reference: https://fillo.so/docs/reference.md
Troubleshooting: https://fillo.so/docs/troubleshooting.md

Three ways to get answers into a form before the visitor types anything: automatic URL prefill, an explicit `initialData` prop, and hidden-field defaults — plus the parser itself for manual control.

## URL prefill

URL prefill works in embeds automatically (SDK 0.6+), not just on the hosted /f page. After hydration the SDK reads the page's query string: any field can be prefilled as `?fieldId=value`, and hidden fields read their configured `paramName` (falling back to the field id). Values are coerced and validated per field kind — options must exist, numbers respect min/max, `multi_select` takes comma-separated option ids — so a crafted URL can't inject invalid answers. `file_upload`, `ranking`, `matrix`, `signature`, and `custom` fields are never prefilled from a URL.

## initialData

Precedence: an explicit `initialData` prop and anything the visitor already typed always win over URL parameters.

```tsx
"use client";

import { FilloForm } from "@usefillo/react";

export function Onboarding({ userEmail }: { userEmail: string }) {
  // initialData wins over URL parameters; visitors can still edit the values.
  return <FilloForm formId="onboarding" initialData={{ email: userEmail, plan: "team" }} />;
}
```

## Manual parsing

Defaults: **hidden fields** may carry a `defaultValue`, applied when no matching parameter is present. Other field kinds do not take `defaultValue` — schema normalization strips it — so use `initialData` for visible fields.

For manual control, `@usefillo/core` exports the parser itself:

```ts
import { defineForm, prefillFromParams } from "@usefillo/core";

const form = defineForm({
  id: "waitlist",
  pages: [{ id: "p1", blocks: [
    { id: "email", kind: "email", label: "Email", required: true },
    { id: "src", kind: "hidden", label: "Source", paramName: "src", defaultValue: "direct" },
  ]}],
});

// The exact parser the SDK runs after hydration — call it yourself when you
// want the values earlier, or somewhere without a URL:
const params = Object.fromEntries(new URLSearchParams("?email=ada@example.com&src=newsletter"));
const initialData = prefillFromParams(form.schema, params);
// → { email: "ada@example.com", src: "newsletter" } — coerced + validated per kind
```
