GraphQLLitePro
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.
Demos
Have a look at our headless demos to get a feel for what's possible with GraphQL:
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
- Query
- Response
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
requiredMessage
}
}
}
}
}
}
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,
"requiredMessage": null,
},
{
"type": "text",
"label": "Last Name",
"handle": "lastName",
"required": true,
"requiredMessage": "Last Name is required."
}
]
}
]
}
]
}
]
}
}
}
Querying a single Form
- Query
- Response
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
- Query
- Response
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"
}
]
}
}
]
}
}
Form Query Arguments
The following arguments are available when querying single or multiple forms:
| Argument | Type | Description |
|---|---|---|
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 |
limit | Int | Limit the amount of returned form results |
offset | Int | Offset the returned form results |
orderBy | String | Order the forms by a specific property |
sort | String | Sort 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:
| Argument | Type | Description |
|---|---|---|
id | [Int] | Narrow the queried fields by one or more field's ID'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"]) {
id
handle
}
}
}
}
Mutations
GraphQL mutations provide a way to modify data. The actual mutations will vary depending on the schema and what it allows. There are common mutations per GraphQL object type and additional type-specific mutations.
Creating a new Submission
To create a new submission we use form-specific mutations in the form of save_<formHandle>_Submission.
Mutations take the data as arguments. We pass the values we want to use in the query as query variables.
In this example, we're using a form with the handle of contact which contains form fields for first name, last name and email. Our form also has Honeypot and ReCaptcha V3 enabled. We also pass some form property overrides, setting dynamic notification recipients.
You can grab these values using form-specific GraphQL queries or by creating an custom endpoint on your site.
See How to Render a Form.
// Query
mutation SaveContactSubmission(
$formProperties: FreeformFormPropertiesInputType,
$honeypot: FreeformHoneypotInputType,
$javascriptTest: FreeformJavascriptInputType,
$captcha: FreeformCaptchaInputType,
$csrfToken: FreeformCsrfTokenInputType,
$firstName: String,
$lastName: String,
$email: String,
) {
save_contact_Submission(
formProperties: $formProperties
honeypot: $honeypot
javascriptTest: $javascriptTest
captcha: $captcha
csrfToken: $csrfToken
firstName: $firstName
lastName: $lastName
email: $email
) {
submissionId
success
}
}
// Query Variables
{
"formProperties": {
"dynamicNotification": {
"recipients": ["support@solspace.com", "user@solspace.com"],
"template": "new_template_1.twig"
}
}
"honeypot": {
"name": "freeform_form_handle",
"value": ""
}
"captcha": {
"name": "g-recaptcha-response",
"value": "INSERT RECAPCTHA RESPONSE",
},
"csrfToken": {
"name": "INSERT CSRF TOKEN NAME",
"value": "INSERT CSRF TOKEN VALUE",
},
"javascriptTest": {
"name": "freeform_form_handle",
"value": "",
},
"firstName": "Solspace",
"lastName": "Freeform",
"email": "support@solspace.com"
}
Example response data:
{
"data": {
"save_contact_Submission": {
"submissionId": 1982,
"success": true
}
}
}
Submission Mutation Arguments
| Argument | Type | Description |
|---|---|---|
... | Arguments depending on the field layout for the form |
Interfaces
Form InterfaceImproved in 5.9.6+
These are the fields available for the FreeformFormInterface:
| Field | Type | Description |
|---|---|---|
id | Int | ID |
uid | String | UID |
name | String | Name |
handle | String | Handle |
type | String | Type |
hash | String | The form's hash needed to submit forms |
color | String | Color |
description | String | Description |
returnUrl | String | The specified return URL |
storeData | Boolean | Are submissions being stored for this form |
submissionTitleFormat | String | Title format used for new submission titles |
submissionMutationName | String | The forms GraphQL mutation name for submissions |
ipCollectingEnabled | Boolean | Are the IP addresses being stored |
ajaxRenamed in 5.0+ | Boolean | Is the ajax enabled for this form |
showProcessingSpinner | Boolean | Should the submit button show a spinner when submitting |
showProcessingText | Boolean | Should the submit button change the button label while submitting |
processingText | String | The submit button loading label text |
defaultStatus | Int | The assigned default status ID of new submissions |
formTemplate | String | The assigned default formatting template |
honeypot | FreeformHoneypotInterface | A fresh honeypot instance |
csrfToken | FreeformCsrfTokenInterface | A fresh csrf token |
captchaDeprecated in 5.9.7+ | FreeformCaptchaInterface | The captcha for this form |
captchasRenamed in 5.9.7+ | [FreeformCaptchaInterface] | The captchas for this form |
fields | [FreeformFieldInterface] | A list of Form's Field |
pages | [FreeformPageInterface] | A list of Form's Page entities |
successBehaviorNew in 5.9.6+ | String | The form's success behavior |
successTemplateNew in 5.9.6+ | String | The form's success template |
successMessage | String | The specified success message |
errorMessage | String | The specified error message |
disableSubmit | Boolean | Should the form’s submit button be disabled when the form is submitted |
disableReset | Boolean | Should the form’s submit button be disabled state be reset |
duplicateCheckNew in 5.9.6+ | String | The form’s duplicate check rule |
stopSubmissionsAfterNew in 5.9.6+ | String | The form’s stop submissions after date |
enctype | String | The form’s enctype |
rules | FreeformRulesInterface | The form’s rules |
postForwardingNew in 5.9.5+ | FreeformPostForwardingInterface | The Post Forwarding integration for this form |
gtmNew in 5.9.5+ | FreeformGoogleTagManagerInterface | The Google Tag Manager integration for this form |
javascriptTestNew in 5.9.6+ | FreeformJavascriptTestInterface | The Javascript Test integration for this form |
Field Interface
Use FreeformFieldInterface.
The base FreeformFieldInterface implemented by all field types. You can see specific Field Type fields here.
| Field | Type | Description |
|---|---|---|
id | Int | ID |
type | String | Type |
label | String | Label |
handle | String | Handle |
instruction | String | Instructions |
required | Boolean | Is the field required |
requiredMessageNew in 5.10.8+ | String | The custom required message for the field |
pageIndex | Int | The page index this field is assigned to |
attributesNew in 5.0+ | [FreeformAttributesInterface] | Field's attributes |
Page Interface
Use FreeformPageInterface.
Each page contains a list of FreeformRowInterface objects:
| Field | Type | Description |
|---|---|---|
index | Int | Index of the page |
label | String | Page's label |
rows | [FreeformRowInterface] | A list of FreeformRowInterface objects |
Row Interface
Use FreeformRowInterface.
Each row contains a list of fields:
| Field | Type | Description |
|---|---|---|
id | String | A unique hash generated for each row |
fields | [FreeformFieldInterface] | A list of FreeformFieldInterface objects |
Submission Interface
These are the fields available for the FreeformSubmissionInterface:
| Field | Type | Description |
|---|---|---|
id | Int | The ID of the submission |
finished | Boolean | Whether the submission is finished or not |
freeformPayload | String | The payload of the submission |
hash | String | The generated hash for the submission |
captchaDeprecated in 5.9.7+ | FreeformCaptchaInterface | The captcha for this form. |
captchasRenamed in 5.9.7+ | [FreeformCaptchaInterface] | The captchas for this form |
csrfToken | FreeformCsrfTokenInterface | The CSRF token (name and value) of the submission |
honeypot | FreeformHoneypotInterface | The Honeypot (name and value) of the submission |
html | String | The generated HTML for the submission |
multiPage | Boolean | Whether the submission has multiple pages or not |
onSuccess | String | The success behavior of the submission |
returnUrl | String | The return URL of the submission |
submissionId | Int | The ID of the submission |
duplicateRenamed in 5.0+ | Boolean | Whether the form submission is a duplicate or not |
submissionToken | String | The generated token for the submission |
success | Boolean | Whether the submission is a success or not |
dateCreated | DateTime | The created date for the submission |
dateUpdated | DateTime | The updated date for the submission |
isSpam | Boolean | Whether the submission is a spam or not |
spamReasons | String | Spam reasons for the submission |
user | User | The author of the submission |
assets | [Asset] | The assets of the submission |
postForwardingNew in 5.9.5+ | FreeformPostForwardingInterface | The Post Forwarding integration of the submission |
gtmNew in 5.9.5+ | FreeformGoogleTagManagerInterface | The Google Tag Manager integration of the submission |
javascriptTestNew in 5.9.6+ | FreeformJavascriptTestInterface | The Javascript Test integration of the submission |
Option Interface
Use FreeformOptionInterface.
| Field | Type | Description |
|---|---|---|
value | String | Option's value |
label | String | Option's label |
checked | Boolean | Is the option checked |
Opinion Scale Interface
Use FreeformOpinionScaleInterface.
| Field | Type | Description |
|---|---|---|
value | String | Value |
label | String | Label |
Attributes InterfaceNew in 5.0+
Use FreeformAttributesInterface.
| Field | Type | Description |
|---|---|---|
input | FreeformAttributeInterface | Input attributes |
label | FreeformAttributeInterface | Label attributes |
instructions | FreeformAttributeInterface | Instructions attributes |
container | FreeformAttributeInterface | Container attributes |
error | FreeformAttributeInterface | Error attributes |
Attribute Interface
Use FreeformAttributeInterface.
| Field | Type | Description |
|---|---|---|
attribute | String | Name of the Attribute |
value | String | Value of the Attribute |
Honeypot Interface
Use FreeformHoneypotInterface.
| Field | Type | Description |
|---|---|---|
errorMessageNew in 5.9.6+ | String | Error message for Honeypot |
name | String | Name of Honeypot |
valueDeprecated in 5.9.7+ | String | Value of Honeypot. |
CSRF Token Interface
Use FreeformCsrfTokenInterface.
| Field | Type | Description |
|---|---|---|
name | String | Name of the CSRF token |
value | String | Value of the CSRF token |
Captcha InterfaceRenamed in 5.0+, Improved in 5.9.6+
Use FreeformCaptchaInterface.
In Freeform 5.9.6+, FreeformSubmissionCaptchaInputType was renamed to FreeformCaptchaInputType. If using FreeformSubmissionCaptchaInputType, be sure to change it to FreeformCaptchaInputType.
| Field | Type | Description |
|---|---|---|
name | String | The forms GraphQL mutation name for submissions |
handleDeprecated in 5.9.7+ | String | The forms GraphQL mutation handle for submissions. |
enabledDeprecated in 5.9.7+ | Boolean | Is Captcha enabled for this form. |
actionNew in 5.9.6+ | String | The Captcha action |
errorMessageNew in 5.9.6+ | String | The Captcha custom error message |
failureBehaviorNew in 5.9.6+ | String | The Captcha failure behaviour |
fieldHandleNew in 5.9.6+ | String | The Captcha field handle |
localeNew in 5.9.6+ | String | The Captcha locale |
scoreThresholdNew in 5.9.6+ | String | The Captcha score threshold |
sizeNew in 5.9.6+ | String | The Captcha size |
themeNew in 5.9.6+ | String | The Captcha theme |
triggerOnInteractNew in 5.9.6+ | Boolean | Will the Captcha trigger on interaction |
versionNew in 5.9.6+ | String | The Captcha version |
Buttons InterfaceNew in 5.0+
Use FreeformButtonsInterface.
| Field | Type | Description |
|---|---|---|
layout | String | The button layout |
submitLabel | String | The button submit label |
back | Boolean | Whether the button has back button or not |
backLabel | String | The button back label |
save | Boolean | Whether the button has save button or not |
saveLabel | String | The button save label |
saveRedirectUrl | String | The button save redirect URL |
emailField | FreeformFieldInterface | The button email notification recipient |
notificationTemplate | FreeformNotificationTemplateInterface | |
attributes | FreeformButtonsAttributesInterface | The button attributes |
Buttons Attributes InterfaceNew in 5.0+
Use FreeformButtonsAttributesInterface.
| Field | Type | Description |
|---|---|---|
container | FreeformAttributeInterface | Container attributes |
column | FreeformAttributeInterface | Column attributes |
buttonWrapper | FreeformAttributeInterface | Button Wrapper attributes |
submit | FreeformAttributeInterface | Submit button attributes |
back | FreeformAttributeInterface | Back button attributes |
save | FreeformAttributeInterface | Save button attributes |
Notification Template InterfaceNew in 5.0+
Use FreeformNotificationTemplateInterface.
| Field | Type | Description |
|---|---|---|
id | Int | The ID of the notification template |
name | String | The name of the notification template |
handle | String | The file name of the notification template |
description | String | The description of the notification template |
fromEmail | String | The from email that will appear in the notification template |
fromName | String | The from name that will appear in the notification template |
replyToName | String | The reply to name that will appear in the notification template |
replyToEmail | String | The reply to email that will appear in the notification template |
cc | String | The email address(es) you would like to be CC'd in the notification template |
bcc | String | The email address(es) you would like to be BCC'd in the notification template |
includeAttachments | Boolean | Whether to include attachments in the notification template or not |
presetAssets | [String] | Assets included as attachments in the notification template |
subject | String | The subject of the notification template |
body | String | The HTML content of the notification template |
textBody | String | The text content of the notification template |
autoText | Boolean | Whether Freeform will automatically provide a Text-only version of the notification based on the HTML version |
Rules InterfaceNew in 5.0+
Use FreeformRulesInterface.
| Field | Type | Description |
|---|---|---|
pages | [FreeformPageRuleInterface] | The page rules |
fields | [FreeformFieldRuleInterface] | The field rules |
Page Rule InterfaceNew in 5.0+
Use FreeformPageRuleInterface.
| Field | Type | Description |
|---|---|---|
id | Int | The ID for the page rule |
uid | String | The UID for the page rule |
page | FreeformPageInterface | The page for the rule |
combinator | String | The combinator for the page rule |
conditions | [FreeformRuleConditionInterface] | The conditions for the page rule |
Field Rule InterfaceNew in 5.0+
Use FreeformFieldRuleInterface.
| Field | Type | Description |
|---|---|---|
id | Int | The ID for the field rule |
uid | String | The UID for the field rule |
field | FreeformFieldInterface | The field for the field rule |
combinator | String | The combinator for the field rule |
conditions | [FreeformRuleConditionInterface] | The conditions for the field rule |
Rule Condition InterfaceNew in 5.0+
Use FreeformRuleConditionInterface.
| Field | Type | Description |
|---|---|---|
uid | String | The UID for the rule condition |
field | FreeformFieldInterface | The field for the rule condition |
operator | String | The operator for the rule condition |
value | String | The value for the rule condition |
Form Properties InterfaceNew in 5.0+
Use FreeformFormPropertiesInterface.
| Field | Type | Description |
|---|---|---|
dynamicNotification | FreeformDynamicNotificationInterface` | Allows using a dynamic template level notification for a more fine-grained control. |
Dynamic Notification InterfaceNew in 5.0+
Use FreeformDynamicNotificationInterface.
| Field | Type | Description |
|---|---|---|
recipients | [String] | The recipients of the notification |
template | String | The name of the notification template |
Post Forwarding InterfaceNew in 5.9.5+
Use FreeformPostForwardingInterface.
| Field | Type | Description |
|---|---|---|
url | String | The Post Forwarding URL |
eventTrigger | String | The Post Forwarding error trigger |
sendFiles | Boolean | Will Post Forwarding send files |
Google Tag Manager (GTM) InterfaceNew in 5.9.5+
Use FreeformGoogleTagManagerInterface.
| Field | Type | Description |
|---|---|---|
containerId | String | The container ID |
eventName | String | The event name |
Javascript Test InterfaceNew in 5.9.6+
Use FreeformJavascriptTestInterface.
| Field | Type | Description |
|---|---|---|
errorMessage | String | Custom error message of Javascript Test |
name | String | Input Name of Javascript Test |
Field Types
Text
| Field | Type | Description |
|---|---|---|
value | String | The default value |
placeholder | String | Input's placeholder attribute |
fields {
... on FreeformField_Text {
value
placeholder
}
}
Textarea
| Field | Type | Description |
|---|---|---|
value | String | The default value |
rows | Int | Number of rows shown for this textarea |
placeholder | String | Input's placeholder attribute |
fields {
... on FreeformField_Textarea {
value
rows
placeholder
}
}
Dropdown
| Field | Type | Description |
|---|---|---|
value | String | The default value |
options | [FreeformOptionInterface] | The assigned options |
fields {
... on FreeformField_Dropdown {
value
options {
value
label
checked
}
}
}
Checkbox
| Field | Type | Description |
|---|---|---|
value | String | The default value |
checkedByDefaultNew in 5.10.7+ | Boolean | Should the checkbox be checked by default |
checkedDeprecated in 5.10.7+ | Boolean | This attribute does not work. Please use checkedByDefault instead. |
fields {
... on FreeformField_Checkbox {
value
checkedByDefault
}
}
Multi-Select
| Field | Type | Description |
|---|---|---|
values | [String] | The default values |
options | [FreeformOptionInterface] | The assigned options |
fields {
... on FreeformField_MultipleSelect {
values
options {
value
label
checked
}
}
}
Checkboxes
| Field | Type | Description |
|---|---|---|
values | [String] | The default values |
oneLine | Boolean | Should this be shown in a single line |
options | [FreeformOptionInterface] | The assigned options |
fields {
... on FreeformField_Checkboxes {
values
oneLine
options {
value
label
checked
}
}
}
Radios
| Field | Type | Description |
|---|---|---|
value | String | The default value |
options | [FreeformOptionInterface] | The assigned options |
fields {
... on FreeformField_Radios {
value
options {
value
label
checked
}
}
}
| Field | Type | Description |
|---|---|---|
placeholder | String | Input's placeholder attribute |
fields {
... on FreeformField_Email {
placeholder
}
}
Number
| Field | Type | Description |
|---|---|---|
value | String | The default value |
minLength | Int | Minimum length of the number |
minValue | Int | Minimum value of the number |
maxValue | Int | Maximum length of the number |
decimalCount | Int | Number of decimals |
decimalSeparator | String | The decimal separator |
thousandsSeparator | String | The thousands separator |
allowNegative | Bool | Allow negative numbers |
placeholder | String | Input's placeholder attribute |
fields {
... on FreeformField_Number {
value
minLength
minValue
maxValue
decimalCount
decimalSeparator
thousandsSeparator
allowNegative
placeholder
}
}
File
| Field | Type | Description |
|---|---|---|
fileKinds | [String] | Allowed file kinds |
maxFileSizeKB | Int | Maximum allowed filesize in KB |
fileCount | Int | Number of allowed simultaneous file uploads |
fields {
... on FreeformField_File {
fileKinds
maxFileSizeKB
fileCount
}
}
Confirmation
| Field | Type | Description |
|---|---|---|
targetFieldHash | String | Hash of the field that has to be confirmed |
fields {
... on FreeformField_Confirmation {
targetFieldHash
}
}
Date & Time
| Field | Type | Description |
|---|---|---|
value | String | The default value |
dateTimeType | String | Type of the date field. ("date", "time", "both") |
generatePlaceholder | Boolean | Should a placeholder be auto-generated for this field |
dateOrder | String | Order of the date chunks. |
date4DigitYear | Boolean | Determines if the year should be displayed with 4 digits or two |
dateLeadingZero | Boolean | Determines if the dates should use a leading zero |
dateSeparator | String | Date separator |
clock24h | Boolean | Should the clock use a 24h format |
clockSeparator | String | Clock separator |
clockAMPMSeparate | Boolean | Should the AM/PM be separated from the time by a space |
useDatepicker | Boolean | Should the built-in datepicker be used |
minDate | String | Specifies the minimum allowed date that can be picked |
maxDate | String | Specifies 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
| Field | Type | Description |
|---|---|---|
value | String | The 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
| Field | Type | Description |
|---|---|---|
value | String | The default value |
pattern | String | Phone number pattern |
useJsMask | Boolean | Should the built-in pattern matcher javascript be enabled |
fields {
... on FreeformField_Phone {
value
pattern
useJsMask
}
}
Rating
| Field | Type | Description |
|---|---|---|
value | String | The default value |
maxValue | Int | Phone number pattern |
colorIdle | String | Color of the unselected, unhovered rating star |
colorHover | String | Color of the hovered rating star |
colorSelected | String | Color of the selected rating star |
fields {
... on FreeformField_Rating {
value
maxValue
colorIdle
colorHover
colorSelected
}
}
Regex
| Field | Type | Description |
|---|---|---|
value | String | The default value |
pattern | String | Regex pattern |
message | String | The error message to be displayed |
fields {
... on FreeformField_Regex {
value
pattern
message
}
}
Signature
| Field | Type | Description |
|---|---|---|
width | Int | Width in pixels |
height | Int | Height in pixels |
showClearButton | Boolean | Determines if the "clear" button should be displayed |
borderColor | String | Signature field border color |
backgroundColor | String | Signature field background color |
penColor | String | Signature field pen color |
penDotSize | Float | The size of the pen dot |
fields {
... on FreeformField_Signature {
width
height
showClearButton
borderColor
backgroundColor
penColor
penDotSize
}
}
Table
| Field | Type | Description |
|---|---|---|
useScript | Boolean | Should the built-in javascript for handling table rows be used |
maxRows | Int | Number of maximum allowed rows this table can have |
addButtonLabel | Boolean | The label for the "add row" button |
addButtonMarkup | String | Custom html for the "add row" button |
removeButtonLabel | String | The label for the "delete row" button |
removeButtonMarkup | String | Custom html for the "delete row" button |
tableLayout | String | JSON of the table layout |
fields {
... on FreeformField_Table {
useScript
maxRows
addButtonLabel
addButtonMarkup
removeButtonLabel
removeButtonMarkup
tableLayout
}
}
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
actionentry in the POST payload that points tofreeform/submit. - A
formHashentry which you will have to retrieve from an endpoint you create. - A
honeypotentry if you're using the Honeypot. - A
captchaentry if you're using the Freeform Captchas. - A
csrfTokenentry if you're using Craft's CSRF tokens. - A
freeform_payloadentry if you're usingEncrypted Payloadas the session storage type.
To get a valid formHash, honeypot, captcha, csrfToken and freeform_payload, you will have to create an endpoint on your site.
Twig
If you're using Twig, here's how to return the form properties data:
{# You can attach custom form properties #}
{# https://docs.solspace.com/craft/freeform/v5/templates/queries/form/#parameters #}
{% set formProperties = {} %}
{% set form = freeform.form('your_form_handle', formProperties) %}
PHP
If you're making your own endpoint via PHP, then we've outlined some simple steps to follow in order to set up a custom Freeform Module.
Make sure to read How to Build a Module if you are new to extending Craft with custom modules.
Create a Module
Below is an example of what your /modules/FreeformModule.php file should look like:
<?php
namespace modules;
use Craft;
use yii\base\Module;
class FreeformModule extends Module
{
public function init()
{
Craft::setAlias('@modules', __DIR__);
if (Craft::$app->getRequest()->getIsConsoleRequest()) {
$this->controllerNamespace = 'modules\\console\\controllers';
} else {
$this->controllerNamespace = 'modules\\controllers';
}
parent::init();
}
}
Update the Application Config
Add your module to your project's application configuration by listing it in the /config/app.php file:
<?php
use modules\FreeformModule;
return [
'modules' => [
'freeform-module' => FreeformModule::class,
],
'bootstrap' => ['freeform-module'],
];
Add Controller
Create a new controller for Freeform located at /modules/controllers/FormController.php:
<?php
namespace modules\controllers;
use craft\web\Controller;
use Solspace\Freeform\Freeform;
use yii\web\Response;
class FormController extends Controller
{
protected array|bool|int $allowAnonymous = true;
public function actionIndex(): string
{
return 'Welcome to the Craft Freeform Form Controller';
}
public function actionProperties(int $formId): Response
{
$form = Freeform::getInstance()->forms->getFormById($formId);
if ($form) {
return $this->asJson($form->toArray());
}
return $this->asJson(['message' => 'Form was not found']);
}
}
Update the Routes
Update the /config/routes.php with your new module controller actions:
<?php
return [
'graphql/api' => 'graphql/api',
'freeform/form' => 'freeform-module/form/index',
'freeform/form/properties/<formId:\d+>' => 'freeform-module/form/properties',
];
Example JSON Response
The JSON response looks like this:
{
"id": 1,
"hash": "xxxxxxxx-xxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"name": "My Form Handle",
"handle": "my-form-handle",
"class": "Solspace\\Freeform\\Form\\Types\\Regular",
"enctype": "application\/x-www-form-urlencoded",
"properties": {
"hash": "YNkW4Jzye-O2Gd90zeo-tY6a9U8ihSaw0zdJ9yUKne7P7OiLNVnuMVi9Nf5v",
"init-time": 1694603762,
"secret": "F2okR1p8To6y1nAZaY5n"
},
"attributes": {
"row": {},
"success": {},
"errors": {}
},
"settings": {
"behavior": {
"ajax": true,
"showProcessingSpinner": true,
"showProcessingText": true,
"processingText": "Its Processing...",
"successBehavior": "reload",
"successTemplate": "successsample.twig",
"returnUrl": "/",
"successMessage": "Form has been submitted successfully!",
"errorMessage": "Sorry, there was an error submitting the form. Please try again.",
"duplicateCheck": "limit_once_per_email",
"stopSubmissionsAfter": "2023-09-15T23:00:00.000000Z"
},
"general": {
"name": "My Form Handle",
"handle": "my-form-handle",
"type": "Solspace\\Freeform\\Form\\Types\\Regular",
"submissionTitle": "{{ dateCreated|date(\"Y-m-d H:i:s\") }}",
"formattingTemplate": "basic-dark/index.twig",
"description": "Test Form",
"color": "#d0021b",
"storeData": true,
"defaultStatus": 3,
"collectIpAddresses": true,
"allowUsersToOptIn": true,
"optInCheckbox": null
}
},
"csrfToken": {
"name": "CRAFT_CSRF_TOKEN",
"token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
"honeypot": {
"errorMessage": "Form honeypot is invalid",
"name": "freeform_form_handle"
},
"gtm": {
"containerId": "GTM-xxxxxxxxxxxx",
"eventName": "demo-form-submitted"
},
"postForwarding": {
"url": "xxxxxxxxxxxxxx",
"errorTrigger": "An error occurred",
"sendFiles": true
},
"javascriptTest": {
"errorMessage": "Javascript must be enabled to submit this form",
"name": "freeform_javascript_test"
},
"javascriptTest": {
"errorMessage": "Javascript must be enabled to submit this form",
"inputName": "freeform_javascript_test",
},
// If using encrypted payloads:
"freeform_payload": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"anchor": "xxxxxx-form-xxxxxxxx-xxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"action": "freeform\/submit",
// If using Captchas:
"captchas": [{
"size": "normal",
"theme": "light",
"locale": "en",
"errorMessage": "Please verify that you are not a robot.",
"failureBehavior": "display-error",
"triggerOnInteract": false,
"enabled": true,
"handle": "captcha",
"action": "submit",
"version": "v2-checkbox",
"scoreThreshold": "0.5",
"name": "g-recaptcha-response" // or h-captcha-response or cf-turnstile-response
}]
}
Have a look at our headless demos to get a feel for what's possible with GraphQL: