Form Submissions

Every fill of a published form is stored, and the store is a tab on the form itself. Open Design → Forms, pick a form, and switch to Submissions: one row per submission, oldest first, with no filtering and no configuration. The table is a direct view of what was captured, not a report built on top of it — which is why it is the right place to go when you want to know whether something arrived at all.

The Submissions tab of the Contact Us form, showing the date column, one column per field including Email, a long free-text answer wrapping inside its cell, and the page column linking to the page each fill came from

Reading the table

The columns are built from the form as it exists right now:

  • date — the day the fill arrived, formatted MM/DD/YYYY. There is no time of day in this column.
  • one column per field currently on the form, headed by the field’s submitted name — firstname, email, explain — not by the label your visitors see.
  • page — a link to the page the form was submitted from, showing that page’s title and opening it in the CMS.

Two consequences follow from “the form as it exists right now”, and both surprise people:

Adding a field has the mirror effect: the new column appears immediately and every submission made before you added it shows blank in that column, because those visitors were never asked.

There is also no page size. The tab asks for every fill this form has ever received, in the order they were stored, and renders all of them. On a form with heavy traffic that is a large page and a slow one, and the newest submission is at the bottom rather than the top. That is a known rough edge rather than a setting you have missed.

What a submission records

A row carries more than the visitor typed. Some of it comes from the form, some from the browser, some from Leed’s own session tracking.

ValueWhere it comes fromShown in the table?
The answers to the form’s standard fieldsthe visitorYes — one column each
Answers under a name Leed does not recognize, stored together as JSON in otherFieldsthe visitorYes, under that name
emailthe visitorYes
emailDomain, derived from the addressLeed, on writeNo
timezone — the browser’s IANA zone, e.g. Europe/Berlinthe browserNo
knownUser — whether Leed recognized this visitor when the page loadedthe page’s autofill checkNo
verifiedUser — Turnstile’s verdictthe challenge, server-verifiedNo
pageId and pageTypeId — the page the form was onthe host pageAs the page link
The tracking session the fill belongs tothe visitor’s sessionNo
timethe server clock, on arrivalYes, as date
purpose and productName — real columns with no standard field behind thema field you name purpose or productname, or a hand-built payloadNo — see below
The full column list, for anyone querying the data directly

A formFillEvents row is: id, companyId, sessionStateId, time, pageId, pageTypeId, formId, verifiedUser, knownUser, firstName, lastName, email, emailDomain, phone, company, title, address, city, state, postalCode, country, terms, timezone, purpose, productName, and otherFields.

Note the casing: the columns are camelCase, while the names submitted from a rendered form are lower case (firstname, postalcode). Leed maps between the two on the way in, which is why nothing you do in the builder needs to know about it.

Answers Leed did not expect

Anything submitted under a name that is not one of the values above lands in otherFields, a JSON object on the row, and appears in the table under its own name. A custom field you added in the builder is exactly this case: the builder drops in a text field, you rename it, the visitor’s answer arrives under that name, and the table reads it back out of otherFields.

The table’s lookup is what makes this work — and what makes one narrow case fail. A column is read from a real database field only for the twelve standard field names; every other field is read out of otherFields. A handful of names are neither: purpose, productname and timezone are recognized on the way in and written to their own columns, so they never reach otherFields — and the table, finding nothing there, renders them blank on every row. Avoid those three as field names, or accept that their column will always look empty even though the data is stored.

What a submission sets in motion

Storing the row is the first step and the only one that always happens. When the submission carries an email address, or Leed already recognizes the visitor, four more things follow: the contact it creates or updates, a marketing opt-in recorded against that contact, an internal notification to whichever addresses the form lists, and — if the form has an email template — a response email. The whole chain, in order is worth reading once if a submission ever looks like it went missing, because the last two steps run on a queue and land a moment after the row does.

Two things about that contact are worth knowing here. Its full history — every page this person read before and after they filled the form — is on their lead profile, and that activity view needs a Starter plan or better. And contacts count: past your plan’s quota they are hidden rather than deleted, so a submission can be sitting in this table while the contact it created is not visible in Engage.

When a submission does not create a contact

The other half of that condition is worth stating too: if Leed does recognize the visitor, an email address is not required. A returning contact who submits a form with nothing but a message still gets a contact update and still triggers the notifications, because the identity came from the session rather than from the form. Recognition is only attempted when the form has Leed Autofill switched on — that setting is what runs the check whose answer travels with the submission — so a form with autofill off treats every visitor as new, however often they have filled your other forms.

Preview sites never record a fill

Documentation MCP signups land here too

If your documentation offers AI access to readers, the profile a reader submits to get it is captured as a form fill on a protected system form named Documentation MCP, and those captures appear on that form’s Submissions tab exactly like on-site fills. Their rows are stored with verifiedUser set, and the page column is empty for every one of them — the capture happens on the sign-in screen, not on a page of your site.

Two of the columns on that form render blank. Its fields are named firstName and lastName in camelCase, and the service writes those values straight onto the row’s own columns rather than into otherFields — so the table, which recognizes only the lower-case firstname and lastname, has nowhere to read them from. The values are stored and come back through the API; they are invisible here and nowhere else. Email, phone, title and company all display normally. Configuring the Docs MCP covers the form’s role in the flow, and the reader sign-in flow covers what the reader actually sees.

Getting submissions out

There is no export button on this tab. Three honest options:

  • Read them here. For a form with a few dozen submissions this is the fastest thing available.
  • Work with the contacts instead. Almost everything you want to do with a submission — segment it, email it, hand it to sales — is a thing you do to the contact it created, in Engage. The submission is the event; the contact is the record.
  • Fetch them from an AI client. The Operator MCP exposes get_form_fills, which takes a formId plus limit (1–100) and offset and returns the complete rows — including the columns this table does not show. The forms and assets tools covers connecting a client and the rest of what it can reach.

If a form’s numbers matter more than its individual rows, form performance aggregates the same submissions into submissions, submitters and a conversion rate.

ESC