Skip to main content

GraphQL3.10+

Freeform supports querying form layouts and form submission mutations via GraphQL. This guide assumes you have some GraphQL experience. To learn more about GraphQL and Craft, please check out the Fetch content with GraphQL guide and Craft's GraphQL API.

Queries

Querying Freeform data

Freeform has a root freeform query, which contains all the possible queries nested inside it to avoid conflicts with other plugins.

Querying multiple Forms

To query all or some forms, you have to use the forms query:

query {
freeform {
forms {
name
handle
pages {
label
rows {
fields {
id
type
label
handle
required
}
}
}
}
}
}

Example response data:

{
"data": {
"freeform": {
"forms": [
{
"name": "My Form",
"handle": "myForm",
"pages": [
{
"label": "First Page",
"rows": [
{
"fields": [
{
"type": "text",
"label": "First Name",
"handle": "firstName",
"required": false
},
{
"type": "text",
"label": "Last Name",
"handle": "lastName",
"required": true
}
]
},
{
"fields": [
{
"type": "submit",
"label": "Submit",
"handle": null,
"required": false
}
]
}
]
}
]
}
]
}
}
}

Querying a single Form

You can query a single form directly by using the form query:

query {
freeform {
form (handle: "my-form") {
name
handle
pages {
# ...
}
}
}
}

Example response data:

{
"data": {
"freeform": {
"form": {
"name": "My Form",
"handle": "myForm",
"pages": [
{
"label": "First Page",
"rows": [
{
"fields": [
{
"type": "text",
"label": "First name",
"handle": "firstName",
"required": false
}
]
}
]
}
]
}
}
}
}

Querying a form field on a Craft Entry

You can query an Entry form field by using the form field name in the query: Assuming the form field's handle is myFormFieldHandle and the section is called Blog

query {
entries {
id
title
... on blog_blog_Entry {
myFormFieldHandle {
id
name
fields {
handle
label
type
}
}
}
}
}

Example response data:

{
"data": {
"entries": [
{
"id": "226",
"title": "Some Entry title",
"myFormFieldHandle": {
"id": 1,
"name": "Simple Form",
"fields": [
{
"handle": "firstName",
"label": "First Name",
"type": "text"
},
{
"handle": null,
"label": "Submit",
"type": "submit"
}
]
}
}
]
}
}

Form Query Arguments

The following arguments are available when querying single or multiple forms:

ArgumentTypeDescription
id[Int]Narrow the queried forms by one or more form ID's
uid[String]Narrow the queried forms by one or more form UID's
handle[String]Narrow the queried forms by one or more form handles
limitIntLimit the amount of returned form results
offsetIntOffset the returned form results
orderByStringOrder the forms by a specific property
sortStringSort by asc or desc order
query {
freeform {
# This is just an example
# For `id`, `uid` and `handle` - you can either pass a single value
# or an array of values for each argument
form(
id: 1
handle: "test"
limit: 1
offset: 2
orderBy: "name"
sort: "desc"
) {
id
}
}
}

Field Query Arguments

You can query fields by the following arguments:

ArgumentTypeDescription
id[Int]Narrow the queried fields by one or more field's ID's
hash[String]Narrow the queried fields by one or more field's UID's
handle[String]Narrow the queried fields by one or more field's handles
query {
freeform {
forms {
# This is just an example
# You can either pass a single value or an array of values for each argument
fields(
id: [1, 2, 3]
handle: ["firstName", "lastName"]
hash: "some-hash"
) {
id
handle
hash
}
}
}
}

Interfaces

Form Interface

These are the fields available for the FreeformFormInterface:

FieldTypeDescription
idIntID
uidStringUID
nameStringName
handleStringHandle
hashStringThe form's hash needed to submit forms
colorStringColor
descriptionStringDescription
returnUrlStringThe specified return URL
storeDataBooleanAre submissions being stored for this form
submissionTitleFormatStringTitle format used for new submission titles
submissionMutationNameStringThe forms GraphQL mutation name for submissions
extraPostUrlStringAn URL that will get a POST call with the submitted data
extraPostTriggerPhraseStringA keyword or phrase Freeform should check for in the output of the POST URL to know if and when there’s an error to log, e.g. ‘error’ or ‘an error occurred’.
ipCollectingEnabledBooleanAre the IP addresses being stored
ajaxEnabledBooleanIs the ajax enabled for this form
showSpinnerBooleanShould the submit button show a spinner when submitting
showLoadingTextBooleanShould the submit button change the button label while submitting
loadingTextStringThe submit button loading label text
defaultStatusIntThe assigned default status ID of new submissions
formTemplateStringThe assigned default formatting template
gtmEnabledBooleanIs the Google Tag Manager enabled for this form?
gtmIdStringThe Google Tag Manager ID
gtmEventNameStringThe name of the Event that will be added to Google Tag Manager's data layer
honeypotFreeformHoneypotInterfaceA fresh honeypot instance
csrfTokenFreeformCsrfTokenInterfaceA fresh csrf token
reCaptchaFreeformFormReCaptchaInterfaceThe ReCaptcha for this form
fields[FreeformFieldInterface]A list of Form's Field
pages[FreeformPageInterface]A list of Form's Page entities

Field Interface

The base FreeformFieldInterface implemented by all field types. You can see specific Field Type fields here.

FieldTypeDescription
idIntID
typeStringType
labelStringLabel
hashStringGenerated unique field hash
handleStringHandle
instructionStringInstructions
requiredBooleanIs the field required
pageIndexIntThe page index this field is assigned to
inputAttributes[FreeformAttributeInterface]Field's input attributes
labelAttributes[FreeformAttributeInterface]Field's label attributes
errorAttributes[FreeformAttributeInterface]Field's error attributes
instructionAttributes[FreeformAttributeInterface]Field's instruction attributes

Page Interface

Each page contains a list of FreeformRowInterface objects:

FieldTypeDescription
indexIntIndex of the page
labelStringPage's label
rows[FreeformRowInterface]A list of FreeformRowInterface objects

Row Interface

Each row contains a list of fields:

FieldTypeDescription
idStringA unique hash generated for each row
fields[FreeformFieldInterface]A list of FreeformFieldInterface objects

Field Types

Text

FieldTypeDescription
valueStringThe default value
maxLengthIntMaximum length of chars allowed for this field
placeholderStringInput's placeholder attribute
fields {
... on FreeformField_Text {
value
maxLength
placeholder
}
}

Textarea

FieldTypeDescription
valueStringThe default value
maxLengthIntMaximum length of chars allowed for this field
rowsIntNumber of rows shown for this textarea
placeholderStringInput's placeholder attribute
fields {
... on FreeformField_Textarea {
value
maxLength
rows
placeholder
}
}

Select

FieldTypeDescription
valueStringThe default value
options[FreeformOptionInterface]The assigned options
fields {
... on FreeformField_Select {
value
options {
value
label
checked
}
}
}

Checkbox

FieldTypeDescription
valueStringThe default value
checkedBooleanShould the checkbox be checked by default
fields {
... on FreeformField_Checkbox {
value
checked
}
}

Multi-Select

FieldTypeDescription
values[String]The default values
options[FreeformOptionInterface]The assigned options
fields {
... on FreeformField_MultipleSelect {
values
options {
value
label
checked
}
}
}

Checkbox Group

FieldTypeDescription
values[String]The default values
oneLineBooleanShould this be shown in a single line
options[FreeformOptionInterface]The assigned options
fields {
... on FreeformField_CheckboxGroup {
values
oneLine
options {
value
label
checked
}
}
}

Radio Group

FieldTypeDescription
valueStringThe default value
options[FreeformOptionInterface]The assigned options
fields {
... on FreeformField_RadioGroup {
value
options {
value
label
checked
}
}
}

Email

FieldTypeDescription
notificationIdStringThe ID or the filename of the email template
placeholderStringInput's placeholder attribute
fields {
... on FreeformField_Email {
notificationId
placeholder
}
}

Dynamic Recipients

FieldTypeDescription
values[String]The default values
notificationIdStringThe ID or the filename of the email template
showAsRadioBooleanShould the field be shown as a list of radio inputs
showAsCheckboxesBooleanShould the field be shown as a list of checkbox inputs
oneLineBooleanShould radios or checkboxes be displayed in a single line
options[FreeformOptionInterface]The assigned options
fields {
... on FreeformField_DynamicRecipients {
values
notificationId
showAsRadio
showAsCheckboxes
oneLine
options {
valuel
label
checked
}
}
}

Number

FieldTypeDescription
valueStringThe default value
minLengthIntMinimum length of the number
minValueIntMinimum value of the number
maxValueIntMaximum length of the number
decimalCountIntNumber of decimals
decimalSeparatorStringThe decimal separator
thousandsSeparatorStringThe thousands separator
allowNegativeBoolAllow negative numbers
placeholderStringInput's placeholder attribute
fields {
... on FreeformField_Number {
value
minLength
minValue
maxValue
decimalCount
decimalSeparator
thousandsSeparator
allowNegative
placeholder
}
}

File

FieldTypeDescription
fileKinds[String]Allowed file kinds
maxFileSizeKBIntMaximum allowed filesize in KB
fileCountIntNumber of allowed simultaneous file uploads
fields {
... on FreeformField_File {
fileKinds
maxFileSizeKB
fileCount
}
}

Confirmation

FieldTypeDescription
targetFieldHashStringHash of the field that has to be confirmed
fields {
... on FreeformField_Confirmation {
targetFieldHash
}
}

Date & Time

FieldTypeDescription
valueStringThe default value
dateTimeTypeStringType of the date field. ("date", "time", "both")
generatePlaceholderBooleanShould a placeholder be auto-generated for this field
dateOrderStringOrder of the date chunks.
date4DigitYearBooleanDetermines if the year should be displayed with 4 digits or two
dateLeadingZeroBooleanDetermines if the dates should use a leading zero
dateSeparatorStringDate separator
clock24hBooleanShould the clock use a 24h format
clockSeparatorStringClock separator
clockAMPMSeparateBooleanShould the AM/PM be separated from the time by a space
useDatepickerBooleanShould the built-in datepicker be used
minDateStringSpecifies the minimum allowed date that can be picked
maxDateStringSpecifies the maximum allowed date that can be picked
fields {
... on FreeformField_Datetime {
value
dateTimeType
generatePlaceholder
dateOrder
date4DigitYear
dateLeadingZero
dateSeparator
clock24h
clockSeparator
clockAMPMSeparate
useDatepicker
minDate
maxDate
}
}

Opinion Scale

FieldTypeDescription
valueStringThe default value
legends[String]A list of all the assigned Legends
scales[FreeformOpinionScaleInterface]The assigned FreeformOpinionScaleInterface
fields {
... on FreeformField_OpinionScale {
value
legends
scales {
value
label
}
}
}

Phone

FieldTypeDescription
valueStringThe default value
patternStringPhone number pattern
useJsMaskBooleanShould the built-in pattern matcher javascript be enabled
fields {
... on FreeformField_Phone {
value
pattern
useJsMask
}
}

Rating

FieldTypeDescription
valueStringThe default value
maxValueIntPhone number pattern
colorIdleStringColor of the unselected, unhovered rating star
colorHoverStringColor of the hovered rating star
colorSelectedStringColor of the selected rating star
fields {
... on FreeformField_Rating {
value
maxValue
colorIdle
colorHover
colorSelected
}
}

Regex

FieldTypeDescription
valueStringThe default value
patternStringRegex pattern
messageStringThe error message to be displayed
fields {
... on FreeformField_Regex {
value
pattern
message
}
}

Signature

FieldTypeDescription
widthIntWidth in pixels
heightIntHeight in pixels
showClearButtonBooleanDetermines if the "clear" button should be displayed
borderColorStringSignature field border color
backgroundColorStringSignature field background color
penColorStringSignature field pen color
penDotSizeFloatThe size of the pen dot
fields {
... on FreeformField_Signature {
width
height
showClearButton
borderColor
backgroundColor
penColor
penDotSize
}
}

Table

FieldTypeDescription
useScriptBooleanShould the built-in javascript for handling table rows be used
maxRowsIntNumber of maximum allowed rows this table can have
addButtonLabelBooleanThe label for the "add row" button
addButtonMarkupStringCustom html for the "add row" button
removeButtonLabelStringThe label for the "delete row" button
removeButtonMarkupStringCustom html for the "delete row" button
tableLayoutStringJSON of the table layout
fields {
... on FreeformField_Table {
useScript
maxRows
addButtonLabel
addButtonMarkup
removeButtonLabel
removeButtonMarkup
tableLayout
}
}

Email Marketing

FieldTypeDescription
hiddenBooleanShould this field be a hidden field or a checkbox
fields {
... on FreeformField_MailingList {
hidden
}
}

Submit

FieldTypeDescription
labelNextStringLabel for the "next" button
labelPrevStringLabel for the "previous" button
disablePrevBooleanIs the "previous" button disabled
positionStringPosition of the buttons
fields {
... on FreeformField_Submit {
labelNext
labelPrev
disablePrev
position
}
}

Additional Interfaces

Option Interface

FieldTypeDescription
valuestringOption's value
labelstringOption's label
checkedbooleanIs the option checked

KeyValueMap Interface

FieldTypeDescription
keystringKey name
valuestringValue

Scales Interface

FieldTypeDescription
valuestringValue
labelstringLabel

Honeypot Interface

FieldTypeDescription
namestringValue
hashstringHash
timestampintTimestamp of the creation date

CSRF Token Interface

FieldTypeDescription
namestringName of the CSRF token
valuestringValue of the CSRF token

How to Render a Form

Below are the steps for being able to render your own form in the front-end using GraphQL data and another headless solution such as (but not limited to) Vue.js, Next.js, or React JS.

Overview

To be able to make a form submittable you will need several things:

  • An action entry in the POST payload that points to freeform/submit.
  • A formHash entry which you will have to retrieve from an endpoint you create.
  • A honeypot entry if you're using the Freeform Honeypot.
  • A reCaptcha entry if you're using the Freeform Captchas.
  • A csrfToken entry if you're using Craft's CSRF tokens.
  • A freeform_payload entry if you're using Encrypted Payload as the session storage type.

To get a valid formHash, honeypot, reCaptcha, csrfToken and freeform_payload, you will have to create an endpoint on your site.

If you're using Twig, here's how to return the data as JSON:

{# You can attach custom form properties #}
{# https://docs.solspace.com/craft/freeform/v3/template-functions/freeform.form.html#parameters #}
{% set formProperties = {} %}
{% set form = craft.freeform.form('your_form_handle') %}
{{ form.json(formProperties) }}

If you're making your own endpoint via PHP, then you could do this in your controller action:

// You can attach whatever form properties you would normally via twig
// https://docs.solspace.com/craft/freeform/v3/template-functions/freeform.form.html#parameters
$formProperties = [];

$formModel = Freeform::getInstance()->forms->getFormById(123);
$form = $formModel->getForm();

return $form->json($formProperties);

The JSON response looks like this:

{
"hash": "xxxxxxxx-xxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"handle": "my-form-handle",
"ajax": true,
"disableSubmit": true,
"disableReset": false,
"showSpinner": false,
"showLoadingText": false,
"loadingText": "Loading...",
"class": "",
"method": "post",
"enctype": "application/x-www-form-urlencoded",
"successMessage": "Form has been submitted successfully!",
"errorMessage": "Sorry, there was an error submitting the form. Please try again.",
"honeypot": {
"name": "freeform_form_handle",
"value": ""
},
// If using encrypted payloads:
"freeform_payload": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"anchor": "xxxxxx-form-xxxxxxxx-xxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"csrf": {
"name": "CRAFT_CSRF_TOKEN",
"token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
"action": "freeform/submit"
}

Then in your form building javascript code you would add the hidden inputs or attach this data to the POST payload. Below is a simple example just to give you an idea of what would have to happen:

// Get the form in whatever way your framework allows you to
const form = document.getElementById('your-form-id');

// Retreive a fresh session data for a form
const formDataResponse = await axios.get('/your/endpoint');
const data = formDataResponse.data;

// Attach the inputs or add this data directly to FormData, depending on your flow
const action = document.createElement('input');
action.name = 'action';
action.value = data.action;
form.appendChild(action);

const hashInput = document.createElement('input');
hashInput.name = 'formHash';
hashInput.value = data.hash;
form.appendChild(hashInput);

const honeypot = document.createElement('input');
honeypot.name = data.honeypot.name;
honeypot.value = data.honeypot.value;
form.appendChild(honeypot);

const csrf = document.createElement('input');
csrf.name = data.csrf.name;
csrf.value = data.csrf.token;
form.appendChild(csrf);

// Then submit the form with this data to any front-end endpoint and Craft will take care
// of passing the form data to freeform via the `action` specified