Building a long form one question at a time works, but it's slow. Importing skips that: paste a JSON document describing every page, question, choice, and follow-up rule, and the whole form is built at once. Copy this article with the button above or below, paste it into an LLM along with a description of the form you want, and it can write that document for you.

Find importing from Create form, under Paste JSON, or from Import JSON in the form editor's page bar.

  • On Create form, importing builds a brand-new draft form, the same as choosing a starting point does.
  • In the editor, Import JSON replaces the current draft's pages and questions entirely with what's in the pasted document — anything in the draft that isn't in the JSON is gone. A form you've already published is unaffected until you publish again; respondents keep seeing the last published version until then.

Either way, the document is checked in full before anything is saved. If any part of it doesn't fit the format below, nothing is created or changed, and the specific problem is reported.

The document

{
  "title": "Volunteer sign-up",
  "schema": { "description": "...", "pages": [] }
}

title is optional, up to 150 characters. Leave it out and the title typed into the page's own title field is used instead; replacing a form in the editor keeps its current title.

schema holds the form itself. description is optional intro text under the title (1000 characters). completion is optional — { "heading": "...", "message": "..." } — shown after a response is submitted. payment is optional too; leave it out unless the form should charge for a response, which still needs Stripe connected before the form can be published (see Require payment for a Form response). pages is required, and needs at least one page: { "title": "...", "blocks": [] }.

A page's blocks run in order, and are one of four kinds: { "type": "heading", "text": "..." }, { "type": "paragraph", "text": "..." }, { "type": "divider" }, or a question: { "type": "field", "field": { ... } }.

Questions

{
  "key": "attending",
  "type": "yes_no",
  "label": "Will you attend?",
  "required": true
}

label is the question text, required, up to 500 characters. description is optional help text shown underneath it. required is true or false, defaulting to false. key is a short made-up name for this question — it isn't part of the finished form, and only matters if a later question follows up on this one, covered below.

options lists the choices offered, and is required — at least one — for radio, checkboxes, and select; leave it out for every other type.

Type Answer
text one line
textarea multiple lines
email an email address checked as valid
phone one line not checked
url a web address checked as valid
number one line not range-checked
radio one of several choices needs options
checkboxes any of several choices needs options
select one choice, as a dropdown needs options
yes_no Yes or No built in — don't set options
date a date
time a time
rating 1 to 5 built in — don't set options
file one uploaded file

Follow-up questions

Give an earlier question a key, then point a later question's visibility at it with fieldKey:

{
  "key": "has_guests",
  "type": "yes_no",
  "label": "Bringing any guests?",
  "required": true
},
{
  "key": "guest_names",
  "type": "textarea",
  "label": "Guest names",
  "visibility": [
    { "fieldKey": "has_guests", "operator": "equals", "value": "Yes" }
  ]
}

This is the same conditional visibility the editor's own Conditional visibility panel offers — see Build, publish, and share a form. Every fieldKey must match a key used elsewhere in the document, or the import is rejected. operator is equals, not_equals, contains, answered, or not_answered. A question can list more than one rule; add "visibilityMode": "any" alongside visibility when matching just one of them should be enough, instead of requiring all of them.

A complete example

{
  "title": "Team retreat RSVP",
  "schema": {
    "description": "Let us know if you're joining this year's retreat.",
    "completion": { "heading": "Thanks!", "message": "We'll follow up with details closer to the date." },
    "pages": [{
      "title": "",
      "blocks": [
        { "type": "field", "field": { "key": "name", "type": "text", "label": "Full name", "required": true } },
        { "type": "field", "field": { "key": "email", "type": "email", "label": "Email", "required": true } },
        { "type": "field", "field": { "key": "attending", "type": "yes_no", "label": "Will you attend?", "required": true } },
        { "type": "field", "field": {
            "key": "diet",
            "type": "select",
            "label": "Dietary preference",
            "required": true,
            "options": ["No restrictions", "Vegetarian", "Vegan", "Other"],
            "visibility": [{ "fieldKey": "attending", "operator": "equals", "value": "Yes" }]
        } }
      ]
    }]
  }
}

If an import is rejected for a reason you can't work out, Contact support.