Changelog

4.0.0-beta.12 2026-07-09

Changed

  • Improve UI feedback for third-party plugin migrations (Freeform, Sprout Forms, etc.), including clearer progress and result summaries.
  • Update the default Contact stencil to use field reference tokens in notification variables instead of legacy field handles.

Fixed

  • Require control panel access and per-form integration permissions for integrations/form-settings, filter sensitive integration attributes from request payloads, and require formId from the form builder client.
  • Reject anonymous front-end save-submission requests that attempt to create new submissions without going through submit.
  • Encode form title, handle, and notification names in the import preview summary to prevent stored XSS.
  • Fix invalid email notification handles left over from Formie 2 upgrades (for example handles containing .1), which blocked saving forms in the v4 builder.
  • Fix false unload warnings in the form builder when opening or switching forms without making changes.
  • Fix an error when duplicating a form with nested Group or Repeater fields.
  • Fix duplicating Date/Time sub-fields in the form builder creating conflicting field references.
  • Fix required rich text fields (such as Agree Description) treating empty TipTap documents as valid content.
  • Fix Date/Time field default values not rendering correctly for calendar, dropdown, number, and text display types on the front-end and in previews.
  • Fix Date/Time values displaying incorrectly when editing submissions in the control panel.
  • Fix Date/Time field sorting in submission indexes using chronological order instead of raw JSON text.
  • Fix File Upload fields allowing the temporary upload volume to be selected when it should be restricted.
  • Fix File Upload fields showing a hard error when configured with an invalid or missing volume.
  • Fix Recipients, Dropdown, and other option-based fields not round-tripping import/export data correctly, including legacy placeholder options.
  • Fix Phone field country flag preview in the form builder.
  • Fix Signature field dimensions on the submission edit screen and add a download button for the stored image.
  • Fix Signature field canvas height on the front-end preserving the stored PNG aspect ratio when restoring values or resizing.
  • Fix submission index default sort order using dateCreated instead of title, matching the default timestamp-based submission title format.
  • Fix submission field content layout in the control panel to align more closely with Craft element editing styles.
  • Fix double-encoded submission content JSON after upgrading from Formie 3, and improve date part backfill during migration.

4.0.0-beta.11 2026-07-02

Added

  • Add Cleanup service, ./craft formie/gc/run, and ./craft formie/cron/run console commands for scheduled cleanup and retention. formie/cron/run also runs due scheduled reports, with --only, --skip-gc, and --skip-reports for finer scheduling control.
  • Add formie/gc/prune-sent-notifications and formie/gc/prune-draft-storage console commands.
  • Add Checkout Mode setting to the Opayo payment integration, with Own Form (default) and Drop-in Checkout options. Drop-in Checkout renders card fields inside an Opayo-hosted iframe via sagepayCheckout, which can reduce PCI scope compared to own-form tokenisation, while reusing the existing server-side session key, transaction, and 3DS callback flow.
  • Added user guides for new areas of functionality.

Changed

  • User guides now sit alongside docs.
  • Hide PayPal buttons after successful authorization so users are not prompted to pay again before submitting the form. Buttons are restored automatically when authorization is cleared after a failed submit.

Fixed

  • Do not purge stale pending uploads when maxIncompleteSubmissionAge is disabled.
  • Fix an error with statuses when migrating from Formie 2.
  • Fix an error migrating from Formie 2 and the Recipients field.
  • Fix dispatchTiming migration issue.

4.0.0-beta.10 2026-06-26

Added

  • Add Form Statuses to label form lifecycle states in the control panel (active, draft, archived), with form builder assignment, index status menu filtering, bulk actions, and project config support. Rename existing submission workflow labels to Submission Statuses, with backward-compatible class aliases. (#1471 (opens new window))
  • Add existing and synced fields to Group fields from the form builder, so reusable field definitions can be placed inside independent group wrappers with namespaced handles. (#2069 (opens new window))
  • Show field handles in the form builder when the Craft user preference Show field handles in edit forms is enabled (admin users only), with a copy-to-clipboard control on hover. (#2279 (opens new window))
  • Show an Encrypted padlock badge on fields in the form builder when Enable Content Encryption is turned on. (#2332 (opens new window))
  • Add an optional Other choice for Radio fields, with a configurable label and free-text input on the front-end. (#1875 (opens new window))
  • Add csrfInput render option to control Craft CSRF hidden input output (true default, false to omit, or an options array such as { async: true } for statically cached pages). (#2121 (opens new window))
  • Add Enable Multi-Page Forms plugin setting to disable multi-page forms in the form builder. When disabled, authors cannot add pages and existing multi-page forms cannot be saved until reduced to a single page. (#2483 (opens new window))
  • Add password validation settings to the Password field: minimum length, and requirements for uppercase, lowercase, and special characters. (#1880 (opens new window))
  • Add a Unique User Email setting to Email Address fields, to reject email addresses already associated with a Craft user account. (#1151 (opens new window))
  • Add registered Custom Provider option sources for Dropdown, Radio, Checkboxes, and Recipients fields. Modules can register lightweight OptionSourceProviderInterface classes via OptionSources::EVENT_REGISTER_OPTION_SOURCE_PROVIDERS for local Craft data without building a full integration. See Custom option source providers. (#1421 (opens new window))
  • Add dynamic Brevo list assignment via field mapping. Map a form field to the Brevo List integration field to subscribe contacts to a submission-specific list, with fallback to the form’s configured list. (#2849 (opens new window))
  • Add Merge Multi-Option Fields setting to the Pipedrive integration. When updating an existing person (matched by email), mapped multi-option field values such as labels can be appended to existing values instead of replacing them.
  • Add global Allowed domains email rules under Settings → Spam Protection → Email Rules. Allowlisted domains or full email addresses skip global blocked-domain and free-provider checks only; other spam screening still applies. (#2335 (opens new window))
  • Add a Last Edited By column to submission sources, tracking the Craft user who last saved a submission in the control panel. (#1403 (opens new window))
  • Add craft.formie.ref() and craft.formie.refField() for building variable-picker-compatible reference tokens from Twig when overriding settings such as submitActionMessage. See Reference tokens. (#2838 (opens new window))
  • Add a persisted metadata JSON column on submissions for submit-time request context (referrer, user agent, tracking cookies) and developer-defined custom data via form.setSubmissionMetadata(). Reference tokens such as {metadata:custom.campaignId} and {metadata:request.referrer} are supported in notifications, integrations, and PDFs. (#1379 (opens new window))
  • Add formie_field_site_overrides storage for per-site field definition overrides keyed by fieldId, separate from form-level formie_form_site_overrides payloads.

Changed

  • Freeform 4/5 plugin migrations now process submissions in batches (default 100) to avoid memory exhaustion on large forms. Use php craft formie/migrate/freeform4 (or freeform5) with --batch-size, --submission-offset, --submission-limit, --submissions-only, and --skip-submissions for large migrations. (#2513 (opens new window))
  • Rework multi-site propagation and translation to use each form’s source site (where it was created) instead of Craft’s global primary site. “Same language” and “Same site group” propagation modes now filter from the source site. Forms store a persisted sourceSiteId. (#84 (opens new window))
  • Rename the submission statuses database table from formie_statuses to formie_submission_statuses, aligning with formie_form_statuses. The Table::FORMIE_STATUSES constant remains as a deprecated alias.
  • Stop routing user-authored form content (labels, placeholders, messages, options) through the formie translation category. Form copy is output from the database after site overrides are merged; formie.php is for Formie-owned UI strings only (#2907 (opens new window)).
  • Remove front-end sourceLanguage mutation in the plugin constructor that existed to work around the above behaviour.
  • Improve multi-site submission and notification handling by loading forms with site translation overrides applied for the submission’s site.
  • Store field translation overrides in formie_field_site_overrides instead of nested fields entries in form site override JSON.
  • Include multi-site translation overrides in form import/export (siteOverrides, fieldSiteOverrides, and sourceSiteHandle), keyed by site handle and field reference for portability across environments. Form exports now use export version v4.

Fixed

  • Fix form import with Update existing form not removing notifications deleted before export. Empty notifications arrays in the import payload now replace the form’s notifications instead of being ignored. (#1941 (opens new window))
  • Fix plugin uninstall via project-config/apply failing when Formie stencil project config is removed after the formie_stencils table has already been dropped. (#1710 (opens new window))
  • Fix queued integrations losing submit-time context (referrer, IP address, HubSpot/Pardot tracking cookies) by persisting request metadata on the submission at submit time and hydrating integration context from it in queue workers. (#1379 (opens new window))
  • Fix plugin migrations failing on production when allowAdminChanges is disabled because migrations attempted to write plugin settings to project config. (#2615 (opens new window))
  • Fix phone country dropdown flags not appearing on Craft Cloud. Flag sprites are inlined in the front-end bundle instead of loading from relative CSS asset paths. (#2529 (opens new window))
  • Fix date dropdown fields rejecting year-only values with “Year cannot be blank” when other date parts are disabled. Partial date parts are stored via DateFieldValue without requiring a full calendar date. (#2261 (opens new window))
  • Fix Stripe payments failing with “Invalid email address” when Payment Receipt is enabled but the mapped receipt email resolves empty (for example legacy {field.email} tokens or User Email while logged out). (#2262 (opens new window))
  • Fix Google Maps API script conflicts when Address field autocomplete and the Google Maps Craft plugin are used on the same page. Formie reuses an existing window.google instance instead of injecting a second Maps script. (#2041 (opens new window))
  • Fix captcha provider credentials saved in the control panel being wiped when project config syncs on deploy. Site-scoped captcha settings are now preserved across deployments. (#2407 (opens new window))
  • Fix notification email preview and send failing when both From Name and From Email are set. (#2698 (opens new window))
  • Fix Phone field country selector labels not respecting the field’s Country Language setting. (#2042 (opens new window))

4.0.0-beta.9 2026-06-25

Added

  • Add Lock Field Settings and Editor Note on the field editor Advanced tab to help content authors protect important field configuration. Locking dims field settings until Unlock is clicked for the session; notes appear in the field editor banner. (#1189 (opens new window))
  • Add Stripe subscription Payment Limit field settings to cancel subscriptions automatically after a fixed or dynamic number of payments using Stripe subscription schedules. (#2123 (opens new window))
  • Add Stripe subscription Setup Fee field settings to charge a one-time fee on the first subscription invoice using Stripe invoice items. (#1767 (opens new window))
  • Add headless GraphQL payment support: structured Payment field input types, payment follow-up fields on submitFormieClientForm, and BYO provider documentation. (#1375 (opens new window))
  • Migrate GoCardless payments from deprecated Redirect Flows to Billing Request Flows, including mandate fulfilment, one-off payment creation, and billing request webhooks. (#2552 (opens new window))
  • Add GoCardless recurring subscription support via Direct Debit mandate authorisation and GoCardless subscription creation after billing request fulfilment. (#2552 (opens new window))

Changed

  • Improve default theme color contrast for WCAG 2.2 AA — darker error text, muted helper text, and border-only control styling with split border tokens (#2475 (opens new window)).
  • Add Ajax-safe tab link state theme keys tabLinkCurrent and tabLinkInactive, with aliases for pageTabLinkActive, pageTabLinkInactive, and pageInactive (#1279 (opens new window)).

Fixed

  • Fix required asterisk indicator not appearing on Agree fields when the field label is hidden and consent copy is shown on the checkbox label. (#2333 (opens new window))
  • Fix rich-text links to internal pages opening in a new tab including rel="noopener noreferrer nofollow". Internal links now omit the attribute; external links keep it. (#2604 (opens new window))
  • Fix payment amount parsing for locale-formatted dynamic values (for example 1,234.56, 1.750,00, and £750.00) on both the server and in the browser payment modules. (#2334 (opens new window))
  • Fix payment follow-up states (such as 3D Secure authentication) showing as red validation errors. Action-required and pending payment responses now render as neutral form notices, and Ajax submit payloads include paymentStatus, paymentMessage, paymentAction, and paymentDecision metadata. (#2660 (opens new window))
  • Fix Stripe payment intent amounts being sent as floats; minor-unit values are now sent as integers.
  • Fix external redirect payments (for example Mollie) leaving users on the status polling page when payment fails. Failed payments now redirect back to the original form URL with a flash error message. (#2502 (opens new window))
  • Fix Stripe and other payment follow-up submits re-validating one-time captcha tokens (for example reCAPTCHA v2 checkbox and hCaptcha), which caused duplicate-token spam failures on the second Ajax POST. Incomplete continuation submits now skip captcha screening, matching replay-token behaviour. (#2465 (opens new window))
  • Fix hard-coded local-dev payment webhook proxy URL. paymentWebhookProxyUrl in config/formie.php now controls the dev-mode proxy base URL (default https://proxy.verbb.io), or can be set to an empty string to disable proxying.
  • Fix payment provider settings schema failing to load in the form builder due to a missing Payment field import in FieldsController.
  • Fix payment provider settings not pre-filling defaults when selecting a provider in the form builder.
  • Fix combobox schema fields using a literal “Select an option” empty option instead of a placeholder.

4.0.0-beta.8 2026-06-24

Added

  • Add Quiz field to forms for scored questionnaires (#605 (opens new window)). Each question supports radio buttons, checkboxes, or a dropdown; mark correct answers on static options, enable optional Weighted score for per-option points, and add Answer explanation rich text for incorrect responses. Form Behaviour → Quiz Scoring settings control pass percentage, retake restrictions (by logged-in user or IP address), and whether Ajax/client submit responses include a quizResult payload after a successful final-page submit. Scores persist in formie_submission_quiz_results for complete, non-spam submissions.
  • Add Survey field to forms with selectable presentation types: radio buttons, checkboxes, dropdown, Likert scale (#798 (opens new window)), Rating star scale (#2282 (opens new window)), and Rank drag-and-drop ordering (#605 (opens new window)). Likert supports single- and multi-row layouts, optional Weighted score on static columns, and built-in predefined scale defaults. Rank fields preserve submitted order on validation re-render.
  • Add a Results tab to the form builder when a form includes Quiz or Survey fields (#605 (opens new window)). View per-question response counts and option breakdowns, rank-weighted preference charts, Likert scoring averages when weighted scoring is enabled, and a quiz summary (attempts, average score, pass rate, pass threshold) for scored quizzes.
  • Add author documentation for Quiz and Survey fields.
  • Add multi-site support with automatic site availability via Form Group site policy and per-site content translation via sparse site overrides (#2308 (opens new window), #84 (opens new window), #2724 (opens new window)).
  • Add formie_form_site_overrides storage, FormSiteOverrides and FormSitePropagation services, CP site switcher with instant client-side switching, and translation icons on translatable builder fields.
  • Add allowedSubmitMethods plugin setting to restrict form submission methods to Ajax only, page reload only, or both (#1751 (opens new window)).
  • Add siteHandle request parameter support for headless form load and submit endpoints (#2286 (opens new window)).
  • Redesign page Client Events with a dedicated Tracking tab, support for multiple named events per page, variable picker values, and server-resolved clientEvents payloads in Ajax submit responses (#888 (opens new window)).
  • Add predefined client event templates (GTM, GA4, Meta), per-page suggestions, payload preview, optional per-event conditions, and form-level default client events with apply-to-all-pages support.
  • Add GraphQL Json siblings for stored rich-text content alongside existing Html fields (#865 (opens new window)): submitActionMessageJson, errorMessageJson, instructionsJson, descriptionJson, and contentJson.
  • Add generic saveSubmission GraphQL mutation for handle-based submission saves (#1007 (opens new window)).
  • Add submission PDF downloads from the control panel and via craft.formie.generateSubmissionPdf() / craft.formie.getSubmissionPdfDownloadUrl() (#1213 (opens new window), Discussion #1273 (opens new window)).

Changed

  • Redesign predefined/integration options UI.
  • Apply universal submission guards (global throttling, IP throttling, replay protection, and required request tokens) to client REST and GraphQL submits. Browser-only guards (honeypot, minimum submit time, form expiration) still require traditional handle + submitAction form posts.
  • Align client REST CSRF validation with enableCsrfValidationForGuests. The @verbb/formie-core REST transport now sends the CSRF token from session.tokens.csrf when present.
  • Require formie-accessForms permission for Formie CP field helper JSON actions.
  • Rate-limit anonymous payment callback requests using the same budget as payment webhooks.

Removed

  • GraphQL submission mutations no longer skip all submission guards. Browser-only guard checks still require a traditional form POST shape; headless transports must supply a bootstrap requestToken.

Fixed

  • Fix a HTML error with Signatures field.
  • Fix headless/Ajax validation error messages using the wrong locale by applying the target site language at submission time (#1545 (opens new window)).
  • Fix Summary field Ajax refreshes ignoring custom themeConfig classes by round-tripping render-time theme config through the summary HTML endpoint (#1721 (opens new window)).

4.0.0-beta.7 2026-06-18

Added

  • Add form group policies for allowed submission statuses, optional per-group field palettes, and new-form default profiles (stencil, templates, form defaults). Group policies inherit from global settings; allowed submission statuses are enforced at the group level. (#2717 (opens new window), #2209 (opens new window), #863 (opens new window))
  • Add FormGroupPolicy service as the single entry point for global → group → form policy resolution.
  • Add custom variable sources via Variables::EVENT_REGISTER_VARIABLES, exposing registered tokens in the variable picker and resolving them server-side when references are parsed. (#898 (opens new window))
  • Add group-scoped form and submission permissions using stable form group handles, with optional per-form dedicated permissions via a new Use Dedicated Permissions form setting. (#1426 (opens new window), #1356 (opens new window), #2489 (opens new window), Discussion #1696 (opens new window))
  • Add formie-importForms and formie-exportForms permissions, replacing the temporary admin-only import/export gate.
  • Add formie-accessIntegrations permission for the top-level Integrations control panel section, separate from Access settings.
  • Add nested settings page permissions under Access settings, with CP navigation and controller enforcement per page.
  • Add formie_captcha_providers table and migrate captcha provider credentials out of plugin settings, with site/project scope support and project config export for project-scoped providers.
  • Add formie_spam_settings table and migrate spam handling settings out of plugin settings, with site/project scope support and project config export for project-scoped defaults.
  • Add built-in submission guards (honeypot, minimum submit time, replay protection) via a RunSubmissionGuardsTask screen-stage workflow task and Settings → Spam Protection controls.
  • Add global email rules (blocked domains, block free providers), form submit expiration guard, and align RunSpamChecksTask with SpamHelper for documented keyword and IP matching.
  • Add suspicious text detection, maximum links screening, global submission throttling, and per-IP submission throttling under Settings → Spam Protection. (#1332 (opens new window), #1154 (opens new window), #1099 (opens new window))
  • Add a suspicious text detector focused on keyboard spam, low-quality filler text, and configurable allowed terms.
  • Add a Permissions service as the single ACL entry point for forms, submissions, sent notifications, and import/export checks.
  • Add Field Error Announcement plugin setting (Settings → Forms) to control how front-end validation and submit errors are announced to screen readers (polite, assertive, or off). Live validation while typing always uses polite announcements. (#2505 (opens new window))
  • Add optional per-form reCAPTCHA Action and Minimum Score settings for score-based modes, inheriting global Spam Protection defaults when left blank. (#2167 (opens new window), #2804 (opens new window))
  • Add scoped Submission Limits per form: cap all submissions for a form (closes the form when reached), submissions per IP address, or submissions per logged-in user, over configurable periods. Discussion #1939 (opens new window)
  • Add Reports control panel section for saved analytical views over submissions: filters, summary counts, charts, column configuration, and on-demand export (CSV, Excel, JSON, XML, text) with configurable filename tokens. (#647 (opens new window))
  • Add Scheduled Reports to email a summary and export attachment from a saved report on daily or weekly schedules, with configurable file type, optional email template, recipients, and user group delivery. (#692 (opens new window), #2184 (opens new window))
  • Add formie-accessReports, formie-manageReports, and formie-manageScheduledReports permissions.
  • Add craft formie/reports/run-scheduled console command for cron-driven scheduled report delivery.
  • Add Report Async Export Row Threshold setting (Settings → Submissions) to queue large report exports in the background (default 1000 rows). (#2259 (opens new window))
  • Add queued report exports with CP polling, email notification, and signed download links for interactive exports.
  • Add formie_report_exports table, craft formie/gc/prune-report-exports console command, and automatic expiry during Craft garbage collection.
  • Add report export download settings: interactive/scheduled link expiry (hours), and single-use download links (default on).

Changed

  • Apply single-use report export download limits to signed email links only; authenticated control panel downloads remain available until expiry.
  • Improve queued report export feedback in the control panel with a dismissible inline notice when the queue starts, instead of a delayed Craft toast about email delivery.
  • Improve report viewer load performance by skipping redundant overview refreshes on initial page load and aggregating summary counts in a single query per report instead of three counts per form.
  • Improve Submission Limits form settings UX (Apply Limit To, consolidated messaging) and clarify the distinction from global Submission Throttling abuse controls. Add Submission Limits author documentation. Discussion #1939 (opens new window)
  • Remove built-in CSV export actions from the submissions element index; use Reports for export and scheduled delivery instead.
  • Align Form element canView(), canSave(), canDuplicate(), and delete behaviour with controller permissions instead of broad allow-all checks.
  • Auto-grant creators scoped group (or dedicated per-form) manage permissions when they can create forms but lack broader access.
  • Filter CP form and submission element sources and indexes to forms the current user can view or manage.
  • Filter the settings sidebar and default settings landing page to the first settings page a user can access.
  • Unify Settings → Spam Protection as the single CP page for spam handling, keyword rules, and captcha provider credentials. Legacy spam and captchas routes redirect to the new page.
  • Deprecate captcha and spam keys in plugins.formie.settings; legacy plugin settings values are stripped on save and seeded into runtime stores via the compatibility layer.
  • Removed chart on Submissions element index in favour of dedicated Reports charting.
  • Stream CSV/text report exports row-by-row to disk for memory-safe large datasets (#2497 (opens new window)).
  • Scheduled reports attach exports when under the email attachment limit; otherwise include a signed download link in the summary email instead of silently omitting the file.
  • Store report export download tokens as SHA-256 hashes; scheduled export links default to 48-hour expiry.

Fixed

  • Fix report export email links returning “Export not found” after a control panel auto-download by serving CP polling downloads from an authenticated route that does not consume single-use signed links.
  • Fix report export downloads failing with Craft’s “Invalid token” error by using a downloadToken query param instead of token, which Craft 5.9+ reserves for route tokens.
  • Hash legacy report export download tokens in PHP during migration for MySQL/MariaDB/PostgreSQL compatibility instead of MySQL-only SHA2().
  • Kick Craft’s queue when polling queued report exports in the control panel, so large async exports progress instead of staying pending indefinitely on single-page report views.
  • Align spam keyword screening in RunSpamChecksTask with SpamHelper, restoring [match:] / [ip:] rule support and field/global reference resolution in the submission workflow.
  • Skip client-side validation for fields disabled by conditional logic, and disable conditionally hidden submit buttons so Enter no longer triggers hidden submit/next actions. (#2727 (opens new window), #1136 (opens new window), Discussion #1628 (opens new window))
  • Apply spam behaviour (success/message) without attempting to persist discarded spam submissions when Save spam submissions is disabled, avoiding failed saves under bot load. (#2818 (opens new window))
  • Bound spam keyword scanning and spam log payloads so very large field values cannot stall PHP workers during spam handling. (#2065 (opens new window))
  • Initialise captcha placeholders immediately when multipage forms change page via tabs or Ajax Next, so Friendly Captcha and other providers mount on the visible page before submit. (#1893 (opens new window))
  • Tear down Cloudflare Turnstile widgets with remove() during remounts and apply CSP nonces to dynamically loaded captcha scripts where available, reducing console noise on strict CSP hosts. (#2535 (opens new window))
  • Wait for reCAPTCHA Enterprise readiness before executing score/policy challenges on multipage navigation. (#2224 (opens new window))

4.0.0-beta.6 2026-06-14

Added

  • Add top-level Integrations control panel navigation for managing CRM, email marketing, element, and other payload integrations outside Settings.
  • Add site-scoped integrations that can be created and edited on production environments (allowAdminChanges = false). Existing integrations remain project-scoped and deploy via project config.
  • Add Display Type settings to File Upload fields: File Input (Simple) keeps the native browser input and uploads files on form submit; Upload Manager (Advanced) adds a drag-and-drop zone with async staged uploads, progress, remove, and reorder controls via Formie’s upload endpoints. Existing forms default to File Input (Simple). (#133 (opens new window), #2385 (opens new window), Discussion #1692 (opens new window))
  • Expose displayType on File Upload GraphQL field settings.
  • Add per-field Asset Data Retention settings to File Upload fields, allowing uploaded assets to be deleted after a configured duration while the submission record is kept. (#1715 (opens new window))
  • Add File Upload asset retention and stale pending upload cleanup through Craft garbage collection and dedicated console commands.
  • Add When integrations re-run settings (Integrations → Settings) with per-integration policies: once on submit (default), also when submission is edited, or custom trigger events. Integration conditions still apply. (#1429 (opens new window), #1724 (opens new window), #2591 (opens new window), #1970 (opens new window))
  • Dispatch integrations on control panel submission saves when the re-run policy includes Control panel save, including bulk status changes and other direct element saves. CP submission edit saves continue to use the submission workflow without double-triggering. (Discussion #2253 (opens new window))
  • Add IntegrationTriggers service as the single coordinator for workflow, control panel element saves, spam unmark actions, and manual integration runs.
  • Add IntegrationExecutor service to unify legacy and orchestrated integration step execution, including batched queue jobs.
  • Add NotificationTriggers service to coordinate status-change email notifications when submission statuses are updated.
  • Add Use Submission User as Author to Entry element integrations, assigning the collected submission user as the entry author when Collect User is enabled on the form. (#1363 (opens new window))
  • HubSpot Map to Form integrations now resolve custom object objectTypeId values when submitting to HubSpot forms, including portal-specific custom objects (Enterprise). Refresh HubSpot forms after creating custom objects. (#2649 (opens new window))
  • Add Enable Conditions to form integration settings, allowing integrations to be triggered only when submission field and status rules match. (#447 (opens new window))
  • Add Integration Dispatch form settings (Integrations → Settings) to run payload integrations sequentially, choose immediate vs queued execution per integration, control notification timing relative to integrations, and expose dispatch results via {dispatch:handle:property} variables (for example {dispatch:user:url}). Dispatch variables appear in variable pickers when integration dispatch is enabled. (#2635 (opens new window), #1152 (opens new window), #2810 (opens new window))
  • Add per-notification Dispatch Timing (Advanced) to override the form’s integration dispatch notification timing.
  • Add configurable Integration API Error Handling for Mailchimp and Campaign Monitor, classifying rate-limited and rejected payloads separately from operational failures. (#2172 (opens new window), #1990 (opens new window))
  • Add Integrations::EVENT_AFTER_TRIGGER_INTEGRATION_FAILED for handling integration failures outside the queue, and Send Email Alert for Failed Integration settings mirroring failed notification alerts. (Discussion #2579 (opens new window))

Changed

  • Apply control panel submission sidebar fields (title, status, spam, mark as complete) during managed CP submission saves.
  • Route all integration trigger entry points through IntegrationTriggers instead of Submission::afterSave hooks.
  • Consolidate legacy and orchestrated integration dispatch behind IntegrationExecutor, using batched TriggerIntegration queue jobs for queued steps.
  • Route status-change email notifications through NotificationTriggers instead of inline logic in Submission::afterSave.
  • Deprecate Formie 3 Submissions integration and notification dispatch helpers when compatibility mode is enabled. Use Notifications, Integrations, and IntegrationTriggers instead.
  • Remove unused Integration::shouldTriggerOnSubmissionEdit() API (superseded by re-run policies).
  • Update phone number values sent to integrations to use E164 format instead of international formatting. (Discussion #2731 (opens new window))
  • Improve integration queue job descriptions and debug output with form context (formId, formHandle, formTitle). (#2172 (opens new window))
  • Reorganise plugin settings: move integration behaviour settings to Settings → Behavior → Integrations, and move Use Queue for Notifications to Email Notifications.
  • OAuth integration redirect URIs now default to a Craft action URL instead of a site URL. Add an optional OAuth Redirect URI Override plugin setting. (#1333 (opens new window))

Fixed

  • Fix Opayo, Stripe, Paddle, and GoCardless payment integrations not resolving Billing Details field mappings from the form builder static table, so Name and Address fields are included in payment payloads again. (#2617 (opens new window))
  • Fix Salesforce integrations failing after Craft 5 / Formie 3 upgrades when OAuth tokens were migrated without instance_url, by falling back to stored integration settings and backfilling token values. (#2492 (opens new window))
  • Fix Salesforce integration refresh failing when an enabled object such as Opportunity or Case is unavailable in the connected org. (#1551 (opens new window))
  • Fix Marketo OAuth connect failing when an empty scope parameter is sent with the client-credentials grant, and normalize API domains that include a trailing /rest segment. (#2718 (opens new window))
  • Fix Mailchimp integrations not exposing or formatting Address merge fields, which prevented mapping Formie Address fields to Mailchimp audiences that require ADDRESS data. (#2387 (opens new window))
  • Improve Pardot integration errors when an account does not support API v4 (legacy Pardot Classic). (#2642 (opens new window))
  • Fix file upload assets being deleted when trashing a submission with File Uploads → Delete files enabled, so restored submissions keep their uploaded files. (#1258 (opens new window))
  • Fix new File Upload fields defaulting to an empty Email Field Summary Value setting.
  • Fix Signature fields intermittently showing a misleading “browser does not support” message on multi-page forms, conditional fields, and late layout by retrying canvas sizing, watching visibility changes, and showing accurate status copy when initialization fails. (#2708 (opens new window))

4.0.0-beta.5 2026-06-12

Added

  • Add a Template default value source for Hidden fields using sandboxed Craft object templates. Resolved server-side on render and submit; posted values are ignored. Custom Value behaviour is unchanged. (#2605 (opens new window))
  • Add rich text editing for field Instructions, including Craft entry links with target="_blank", configurable via rich-text.json under fields.instructions. Legacy plain-text and markdown instructions are normalized automatically without migration. (#724 (opens new window))
  • Add Craft-style attribute maps and merge helpers for setFieldSettings() field overrides, including mergeInputAttributes and mergeContainerAttributes. (#2510 (opens new window))
  • Add a Note builder field for form-builder guidance with Tip, Warning, Info, and Error styles. (#2498 (opens new window))
  • Add a Rich Text cosmetic field for WYSIWYG content in the form builder, configurable via rich-text.json under fields.content. (#1028 (opens new window), #1709 (opens new window), Discussion #2070 (opens new window), Discussion #772 (opens new window))
  • Add a syntax-highlighted HTML code editor for HTML cosmetic fields in the form builder, with project config via html.json. (#2181 (opens new window))
  • Add an Allow Twig setting to HTML fields, controlling whether Twig is parsed when rendering field content. Twig runs in Formie’s sandboxed template environment, not Craft’s full CP template stack.
  • Add a Custom Field form-builder field backed by opt-in Craft field adapters. (#2208 (opens new window))
  • Add a Google Maps plugin support for Custom Field field. (#625 (opens new window))
  • Add a Maps plugin field support for Custom Field field. (#626 (opens new window))
  • Add Craft Link field support for Custom Field field, covering URL, email, phone and SMS link values. (#718 (opens new window))
  • Add dynamic Option Source settings for Dropdown, Radio and Checkboxes, allowing options to be populated from predefined option sets and other structured sources. (#2684 (opens new window))
  • Add integration option sources, allowing integrations to opt in and expose selectable remote option lists to Dropdown, Radio and Checkboxes fields. (#512 (opens new window))
  • Add Mailchimp option sources for Interest Categories and Tags, using cached integration form settings and manual refresh actions from the field settings UI. (#512 (opens new window))
  • Add CRM integration option sources for HubSpot (forms and CRM properties), Salesforce, Zoho, and Microsoft Dynamics 365 picklists. (#512 (opens new window))
  • Add Template option source mode for developer-owned option lists supplied at render time without persisting or strictly validating an authoritative option list.
  • Add a Use Searchable Dropdown setting for Dropdown fields, element relation fields when Display type is Dropdown, and Recipients when shown as a dropdown. The front end loads Formie’s combobox browser module so users can filter predefined options. (#960 (opens new window))
  • Add support for changing compatible field types in the form builder, initially limited to simple string-like fields such as Single-Line Text and Email Address. Existing submissions are not rewritten. (Discussion #2110 (opens new window))
  • Add Settings → Fields → Field Builder policy settings for Allow Multi-Select Dropdowns and Allow Phone Country Selector. When disabled, the corresponding field settings are hidden in the form builder and forced off on existing fields. (Discussion #2484 (opens new window), Discussion #2485 (opens new window))
  • Expose the Allow Public Asset Volumes plugin setting in Settings → Fields, controlling whether File Upload fields can use public asset volumes and whether Public URL is available as an email summary value.
  • Add Date Range collection to Date/Time fields when Display Type is Calendar (Advanced), using Flatpickr range mode to collect a start and end date/time. (#2011 (opens new window))
  • Add an includeFlatpickrCss plugin setting to disable Formie’s bundled Flatpickr stylesheet when your project already provides its own. (#2341 (opens new window))
  • Add notification variable selectors for date ranges, including Start Date/Time, End Date/Time, Start Date, Start Time, End Date, and End Time.
  • Add GraphQL content types for date range submissions with start and end datetime values.
  • Add calendar date validation for Date/Time Text Inputs and Dropdowns, rejecting impossible dates (for example February 31), enforcing configured Min Date / Max Date settings on those display types, and surfacing validation errors on the offending sub-field. (#1458 (opens new window))
  • Add smart State / Province behaviour for Address fields, with Text or Dropdown when available input modes, country-dependent subdivision loading, dynamic labels (State, Province, Prefecture, and so on), optional hiding when unused, searchable dropdowns, and datalist suggestions for text fallback. (#1416 (opens new window))
  • Add a subdivisions endpoint (formie/address/subdivisions) and ModifyAddressSubdivisionsEvent for country-dependent state/province option data.
  • Add an address-state browser module with lazy subdivision loading, loading UX (country spinner and state skeleton), and password-manager/browser autofill reconciliation via a persistent address-level1 anchor input.
  • Add Allowed Countries and Preselect Country from IP settings to Address fields, mirroring Phone field country restrictions and using a shared formie/address/country-from-ip endpoint (CDN geo headers such as CF-IPCountry).
  • Add Preselect Country from IP to Phone fields when the country selector is enabled, wiring intl-tel-input geo lookup through the shared country-from-ip endpoint.
  • Add table column reference support for Calculations fields with explicit row scope (first, last, index, all, count, custom row expressions). Table columns now appear in the Calculations variable picker, with row targeting configured in the variable settings popover. (#1284 (opens new window))
  • Add Settings → Synced Fields as a read-only audit page listing shared field definitions and the forms they appear on, with a View usage link from synced fields in the form builder. (#2377 (opens new window))

Changed

  • Refactor predefined options to align with the new option sources system.
  • Improve HTML and Rich Text cosmetic field builder previews and control panel submission views to show rendered output instead of raw source where appropriate. (#2182 (opens new window))
  • Render HTML field builder previews inside a sandboxed iframe so control panel styles do not bleed into preview content.
  • Render HTML field Twig through Formie’s sandboxed template service instead of Craft’s unrestricted renderString(), and default Allow Twig to off for new HTML fields.
  • Respect Include in Email Field Summaries for cosmetic fields in {allFields}, {allContentFields}, and {allVisibleFields} instead of always excluding them.
  • Update @verbb/plugin-kit-react to 1.0.4 for the CodeMirror-based HTML editor, codeEditor SchemaForm field registration, and live Rich Text preview rendering via TiptapContent.
  • Normalise Address sub-field browser selectors to the data-formie-address-* namespace, with legacy short-selector fallbacks for older saved forms and address provider modules.
  • Default new Address field layouts to place Country before State / Province so dependent subdivision loading works out of the box.
  • Map Freeform Rich Text fields to Formie Rich Text rather than HTML during migration.
  • Replace the Dropdown, Radio and Checkboxes option-table Disabled column with a row-menu Visible / Hidden / Disabled availability control (#1816 (opens new window)). Hidden removes an option from the front-end form while preserving stored submission values and labels; Disabled renders the option with HTML disabled so it stays visible but cannot be selected. Legacy disabled: true option rows are treated as hidden. Non-default states are indicated in the options table with row background tints.
  • Centralise front-end option filtering in OptionsField::getFieldOptions() so hidden options are excluded consistently (including Dropdown placeholders).
  • Format Date/Time values consistently for notifications, summaries, exports, and string output using the field's Date Format and Time Format settings. Casting a normalized date value object to string now matches getFieldValueAsString().
  • Update integration field mapping to accept Date/Time reference values with text, date, and number types.
  • Move Agree field checked/unchecked display labels to the Settings tab and clarify that submissions store a boolean; use getFieldValueAsString() for Yes/No-style output. (#2288 (opens new window))
  • Normalise submission values by trimming leading and trailing whitespace during field normalization for single-line text, email, plain multi-line text, hidden, phone, number, name, address, and custom string fields. Password fields and rich text content are unchanged; existing submissions keep their stored values until resaved.

Deprecated

  • Deprecate the PredefinedOptions service, predefined option class namespace (verbb\formie\options\*), and PredefinedOptions::EVENT_REGISTER_PREDEFINED_OPTIONS event registration target. Use OptionSources, predefined option classes under verbb\formie\options\predefined\*, and OptionSources::EVENT_REGISTER_PREDEFINED_OPTIONS instead. Legacy APIs remain available through the compatibility layer with deprecation notices.

Fixed

  • Fix page-reload single-line and multi-line text limit validation rerenders so field error styling, form-level error messages, and scroll/focus behaviour match ajax submissions. (#1997 (opens new window))
  • Fix Recipients fields preserving the selected option label when multiple recipient options send to the same email address, using encrypted row identity tokens while keeping recipient emails private in front-end markup. (#2382 (opens new window))
  • Fix static Recipients option rows accepting invalid email targets by validating each comma-separated recipient address in the field settings.
  • Fix Dropdown, Radio and Checkboxes Disabled option availability not outputting HTML disabled on the front-end form. (#1816 (opens new window))
  • Fix Address and other fixed-parent sub-field settings being unavailable in the form builder by restoring on-demand field type config loading for nested sub-field types. (#1416 (opens new window))

4.0.0-beta.4 2026-06-07

Added

  • Add conditional submission status rules in the form builder Settings → Submissions tab, evaluated on the front end during submission processing. (#508 (opens new window))
  • Add repeater sub-field reference support with explicit row scope (first, last, index, all, count, custom row expressions) for variable tokens, notifications, conditions, and integrations. Repeater nested fields now appear once in the variable picker, with row targeting configured in the variable settings popover. (#1728 (opens new window), #1255 (opens new window), #2099 (opens new window), #1888 (opens new window), #2338 (opens new window))
  • Add conditional redirect rules under Behaviour → After Submit, with an optional Enable Redirect Rules toggle that overrides the default submit action when conditions match. (#830 (opens new window))
  • Add failed notification alert recipients by Craft user group and additional email addresses. (#2226 (opens new window))
  • Add per-rule validation message overrides via a Validation form builder tab and the validationMessages field setting, with legacy errorMessage values migrated to validationMessages.required. (#1269 (opens new window))
  • Add plugin-wide default validation message templates under Settings → Defaults → Field Defaults.
  • Add ValidationMessagesHelper and client data-formie-validation-{key}-message attributes for overridden validation copy on the front end.
  • Add unique-value, match-field, text-limit, number-limit, email-format, blocked-domain, options-limit, and file-upload validation message overrides on supported field types. (#1475 (opens new window))

Changed

  • Standardize validation message placeholders to {label} across PHP validators, front-end validators, and translations (legacy {name} / {attribute} aliases remain at runtime).
  • Replace text-limit counter {startTag}{num}{endTag} translation strings with Craft plural syntax and wire translated counter copy on the front end. (#2526 (opens new window))
  • Show context-aware text-limit counter copy for empty (allowed), under-limit (left), and over-limit states on the front end and in control panel submissions.
  • Add per-field validation error position on the Appearance tab, with form- and plugin-level defaults (Above Input / Below Input).
  • Resolve nested Date/Name/Address sub-field validation messages from their parent field; stop copying legacy errorMessage onto Date sub-fields.
  • Wire client-side validation message overrides for file-upload and checkbox/radio options-limit rules via data-formie-validation-*-message attributes.
  • Extend front-end t() to resolve Craft-style {param, plural, …} and {param, number} message syntax.

Fixed

  • Fix option field values appearing empty in notification “All Form Fields” summaries when options were overridden via Twig setFieldSettings(), by applying persisted submission snapshots when loading forms for email/export and falling back to stored option values when labels cannot be resolved. (#2350 (opens new window))
  • Fix submission status filters in the control panel returning no results when submissions were saved without a persisted statusId, and resolve status queries by display name as well as handle. (#2687 (opens new window))
  • Sanitize notification queue job debug data to valid UTF-8 before re-serializing failed jobs, preventing queue rows from becoming unreadable when submission content contains invalid byte sequences. (#2344 (opens new window))
  • Improve notification mailer failure logging when Craft returns no transport error message, including CLI/queue context to help diagnose cron-only send failures. (#2610 (opens new window))

4.0.0-beta.3 2026-06-06

Added

  • Add a configurable field palette for the form builder, with drag-and-drop group and field organisation, per-field enable/disable, and optional palette label overrides. Replaces the legacy Disabled Field Types settings checkboxes. (#2209 (opens new window))
  • Add a stock Form Preview slide-out in the form builder, rendering the current form with Formie’s default templates, CSS, and JavaScript. (#370 (opens new window))
  • Add synced-field support for stencils, preserving shared definition links when creating new forms from a stencil. (#1677 (opens new window), #1734 (opens new window))
  • Add stencil scopes so developers can ship starter forms in project config while content editors can create and manage their own stencils in the control panel. (#2814 (opens new window))
  • Add project stencils (stored in formie.stencils project config) alongside regular database-backed stencils, with handles unique across both scopes.
  • Add the formie-accessStencils permission for managing stencils in the control panel.
  • Add read-only viewing of project stencils when admin changes are disabled, with Save a copy to create an editable stencil.
  • Add a Type column to the stencils index, showing Project for project stencils only.
  • Add Form Groups for control panel organisation. (#1039 (opens new window), #662 (opens new window))
  • Add a dedicated Settings → Defaults control panel page for form, field, and notification defaults. (#863 (opens new window))
  • Add structured formDefaults, fieldDefaults, and notificationDefaults plugin settings, applied when new forms, fields, and notifications are created.
  • Add supportedDefaults() and schema extraction for field-type defaults, with Date, File Upload, Phone, Agree, Single-Line Text, Multi-Line Text, Email, Number, Hidden, Radio, Checkboxes, and element fields (Entries, Categories, Users, Tags, Products, Variants) as supported field types.
  • Add Field Defaults developer documentation for third-party field authors.
  • Add schema-driven form and notification defaults extracted from the form builder and notification schemas, including a PDF template default for new notifications.
  • Add captcha integration defaults for new forms and stencils via integrationDefaults.
  • Add a migration to move legacy defaultFileUploadVolume, defaultDateDisplayType, defaultDateValueOption, and defaultDateTime settings into fieldDefaults.
  • Track and display who created and last updated a form in the form builder Settings tab footer and as optional forms index columns. (Discussion #2342 (opens new window))
  • Add submission UID to the control panel submission sidebar and as an optional submissions index column. (#2404 (opens new window))
  • Add an Autocomplete setting to single-line and multi-line text fields in the form builder Settings tab, with a searchable list of HTML autocomplete tokens. (Discussion #2764 (opens new window))
  • Document using {env:FORMIE_*} environment variable tokens in notification recipient fields. (#2676 (opens new window))
  • Add an opt-in setting to disable the submit button until the current page passes validation. (#1514 (opens new window))
  • Add a page setting to place the submit button at the end of the last field row. (#2542 (opens new window))
  • Add regression tests for required File Upload fields submitted via GraphQL with base64 file data. (#1130 (opens new window))
  • Add control panel submission field condition behaviour with plugin and per-form settings to follow, collapse, or ignore front-end field and page conditions when editing submissions. (#2435 (opens new window))

Changed

  • Replace Settings → Fields disabled-field checkboxes with the new field palette editor.
  • Move stencil management from Settings to Formie → Stencils, including create, edit, and index routes under formie/stencils/*. Legacy formie/settings/stencils/* URLs redirect to the new paths.
  • Change Save as stencil from the form builder to always create an editable, database-backed stencil.

Fixed

  • Fix legacy upgrade migrations failing on fresh Craft 5 installs that never had Craft’s content or formie_tokens tables.
  • Fix form usage counts and the form builder Usage tab omitting entries on disabled Craft sites. (#2612 (opens new window))
  • Fix the form builder Usage tab not listing elements that reference a form on non-primary sites, including when Craft stores a relation without a specific sourceSiteId. (#2695 (opens new window))
  • Prompt for confirmation when closing a field settings overlay with Escape (or backdrop/header close) only when the field has unsaved changes. Untouched new fields close immediately. (#2219 (opens new window))
  • Fix dropdown field options not saving in the form builder when no default option is selected. (#2795 (opens new window))
  • Validate literal email addresses in notification recipient settings so invalid addresses are caught when saving notifications. (#2712 (opens new window))
  • Skip notification email attachments when the asset file cannot be read, instead of failing the entire send. (#2626 (opens new window))
  • Fix replacing a deleted field with a new field using the same handle requiring a two-step save in the form builder. (#1854 (opens new window))
  • Fix submit button conditions not applying on the front end. (#2568 (opens new window))
  • Fix checkbox fields saving their default option values when explicitly unchecked on submit. (#2457 (opens new window))
  • Fix missing page-list validation indicators in the form builder when a form has no pages. (#2786 (opens new window))
  • Add a default country setting for Google Places address auto-complete fields. (#2721 (opens new window))
  • Fix email notification preview failing when a recipient setting references a non-email field. (#2537 (opens new window))
  • Add a configurable maximum email attachment size, and validate notification attach assets in the form builder. (#2697 (opens new window))
  • Fix file upload validation allowing extensions such as .jfif that Craft cannot save as assets. (#2716 (opens new window))
  • Fix the Dutch translation mapping Auto to Automatisch, which incorrectly changed checkbox labels and values meaning “car”. (#2636 (opens new window))
  • Generate translatable date picker placeholders from the configured date and time formats when no custom placeholder is set. (#2464 (opens new window))
  • Fix File Upload fields failing on submit when no upload location is set, by requiring the setting in the form builder and falling back to the plugin default volume when configured. (#2597 (opens new window))
  • Fix Ajax and multi-page File Upload fields losing their uploaded-file summary after step navigation or when editing existing submissions. (#2742 (opens new window), #1856 (opens new window), #1910 (opens new window))
  • Fix File Upload fields inside Repeater or Group fields not initializing upload persistence for nested inputs. (#1448 (opens new window))

4.0.0-beta.2 2026-06-03

Fixed

  • Fix front-end JS/CSS build issues.
  • Fix ModifyFrontendJsTranslationsEvent naming.

4.0.0-beta.1 2026-06-02

Added

  • Add a Formie 3 to Formie 4 migration path for existing Craft 5 projects.
  • Add direct Formie 2 to Formie 4 migration support, allowing Craft 4 projects to move to Craft 5 without upgrading through Formie 3 first.
  • Add Formie 4 Compatibility Mode, enabled by default, to bridge selected Formie 3 class aliases, event owners, custom field schema methods, field config keys, theme config keys, and legacy front-end event listeners during upgrades.
  • Add the new React-powered form builder foundation.
  • Add schema-driven integration settings for the form builder via Integration::defineFormSettingsSchema(), Integration::getFormSettingsSchema(), Integration::EVENT_MODIFY_INTEGRATION_FORM_SETTINGS_SCHEMA, and ModifyIntegrationFormSettingsSchemaEvent.
  • Add Notifications::EVENT_MODIFY_NOTIFICATION_SCHEMA for modifying notification schemas.
  • Add a new staged submission workflow service (SubmissionWorkflow) with prepare, normalize, validate, screen, authorize, save, dispatch, and finalize stages.
  • Add submission workflow process modes for normal submits, existing-submission edits, save-draft requests, and payment replays.
  • Add submission workflow extension events: EVENT_REGISTER_WORKFLOW_STAGES, EVENT_REGISTER_STAGE_TASKS, EVENT_BEFORE_STAGE, EVENT_AFTER_STAGE, EVENT_BEFORE_TASK, and EVENT_AFTER_TASK.
  • Add SubmissionRequestEvent, SubmissionWorkflowStageEvent, SubmissionWorkflowTaskEvent, RegisterWorkflowStagesEvent, and RegisterStageTasksEvent.
  • Add workflow enums for stage and task names, including tasks such as screen.runCaptchaChecks, save.processPayments, dispatch.sendNotifications, and dispatch.triggerIntegrations.
  • Add database-backed temporary submission state, incomplete submission state, saved drafts, and resume-token handling.
  • Add save-and-resume retention settings including submissionStateRetentionDays, saveResumeTokenTtlDays, and maxSavedDraftsPerSession.
  • Add anonymous client bootstrap and refresh rate-limit settings: anonymousClientBootstrapRateLimit, anonymousClientRefreshRateLimit, and anonymousClientRateWindowSeconds.
  • Add static-cache token refresh handling with staticCacheRefreshOnLoad.
  • Add setOnlyCurrentPagePayload for limiting submitted multi-page payload handling to the current page.
  • Add plainTextHtmlSanitizationMode for controlling plain-text HTML sanitization behavior.
  • Add useCssLayers for optionally outputting Formie CSS with CSS layers.
  • Add a Formie-native submission content manager, normalizer, serializer, and accessor layer.
  • Add field definition metadata APIs and traits for Formie-owned field definitions.
  • Add Field::getDescription() description sections for field value, structure, component, behavior, references, and conditions metadata.
  • Add Field::themeConfigKey() for resolving canonical theme config field keys.
  • Add Field::defineValueForReference(), Field::getValueForReference(), Field::defineValueForReferenceBlock(), and Field::getValueForReferenceBlock() as the canonical field reference value APIs.
  • Add Field::defineValueForCondition() and Submission::getFieldValueForCondition() for condition-specific value projection.
  • Add Field::getCpEditHtml() as the canonical CP submission edit rendering contract.
  • Add Field::defineFieldSlotTag() and SlotTag for field slot tag customization.
  • Add Form::EVENT_MODIFY_SLOT_TAG, Field::EVENT_MODIFY_SLOT_TAG, and Integration::EVENT_MODIFY_SLOT_TAG.
  • Add ModifyFormSlotTagEvent, ModifyFieldSlotTagEvent, and ModifyIntegrationSlotTagEvent.
  • Add Field::EVENT_MODIFY_VALUE_FOR_REFERENCE and Field::EVENT_MODIFY_VALUE_FOR_REFERENCE_BLOCK.
  • Add ValueContext::array(), ValueContext::reference(), and ValueContext::referenceBlock().
  • Add craft.formie.parseValue() and craft.formie.parseContent() for parsing field-reference values in Twig.
  • Add craft.formie.formAssets() for form-scoped asset output.
  • Add craft.formie.frontendAssets() for shared front-end asset output.
  • Add new FormTemplate output locations: PAGE_HEADER, PAGE_FOOTER, INSIDE_FORM, and MANUAL.
  • Add initJs and useObserver rendering options for controlling Formie front-end initialization.
  • Add client/server rendering services for Formie-managed HTML and client-rendered consumers, including ClientSessionService, FormBootstrapBuilder, FormDefinitionBuilder, ClientModuleManifestBuilder, and ServerRenderPayloadBuilder.
  • Add client request/response models including FormSession, LoadContext, FormDefinition, FormBootstrap, SubmitRequest, PageTransitionRequest, SessionRefreshRequest, and SubmitResult.
  • Add client controllers for loading forms, changing pages, refreshing sessions, and submitting client-rendered forms.
  • Add FrontendAssets as the canonical shared front-end asset service.
  • Add ClientModule, ClientModuleContext, and RenderFrame models.
  • Add IntegrationInterface::getClientModule() for front-end module registration by integrations, captchas, address providers, and payments.
  • Add ClientModule manifests with render-target metadata for front-end module hydration.
  • Add hydrateFormieModules() support for hydrating individual Formie modules without mounting a full form client.
  • Add the @verbb/formie-core package for framework-agnostic form definitions, transports, field helpers, conditions, calculations, and client-rendered form state.
  • Add the @verbb/formie-browser package as Formie’s canonical browser runtime for server-rendered forms.
  • Add the @verbb/formie-react package with FormieForm, FormieClientForm, useFormieHtml(), useFormieClient(), useFormie(), useFormieField(), useFormiePage(), useFormieInstance(), and useFormieSlot().
  • Add the @verbb/formie-vue package with matching server-rendered and client-rendered Vue APIs.
  • Add the @verbb/formie-web-components package with formie-form, formie-core-form, registerFormieWebComponents(), FormieRegistry, and createFormieRegistry().
  • Add REST and GraphQL transports for client-rendered forms.
  • Add createFormieClient(), formie(), FormieValidator, ModuleRegistry, defineCaptchaModule(), definePassiveCaptchaModule(), definePaymentModule(), and defineAddressModule() to the browser package.
  • Add browser CSS exports for Formie’s base, theme, and combined CSS.
  • Add canonical formie:* browser events for mount, unmount, validation, submit, page navigation, token refresh, state reset, field modules, address modules, payment modules, and submission workflow stages.
  • Add the canonical formie:client:ready event.
  • Add page-level client analytics output via data-formie-client-event.
  • Add GraphQL formieHtmlForm for server-rendered HTML form payloads.
  • Add GraphQL formieClientForm for client-rendered form definitions and sessions.
  • Add GraphQL mutations for client-rendered form submit, page changes, and session refresh.
  • Add GraphQL runtimePayload/client payload support built from the shared front-end payload builder.
  • Add GraphQL schema scope enforcement for handle-based client form reads and lifecycle mutations.
  • Add support for nested GraphQL field builders to read stored row configs for Group, Repeater, and Table-style fields.
  • Add request-local caches for form lookups, field metadata, field config settings, client module manifests, integration lists, submission status handles, and GraphQL field metadata.
  • Add synced-field storage split between shared field definitions and per-form field placements.
  • Add migration support for synced-field definitions and placements.
  • Add blocking validation for synced-field handle collisions instead of silently renaming handles.
  • Add support for detaching synced fields.
  • Add field-reference preservation for unresolved historical submission content when fields are removed or layouts change.
  • Add support for preserving Name field multi-part layout values when field modes change.
  • Add SubmissionQuery::invalidateStaticCaches() for long-running workers after form/field mutations.
  • Add Formie::$plugin->getFactories() for programmatic form and submission builders.
  • Add security regression guard tests.
  • Add a performance harness for submission query and field-graph scenarios.
  • Add integration field-mapping regression coverage across complex and nested field values.
  • Add Formie 4 plugin docs, migration docs, developer docs, and front-end package docs.
  • Add React, Vue, Web Components, Next.js, and Nuxt starter projects for the new front-end package stack.
  • Add Craft-rendered starter examples for Barba.js, Sprig, and Datastar.
  • Add @verbb/plugin-kit and @verbb/plugin-kit-react as the shared control panel UI foundation used by Formie’s React builder.

Changed

  • Require Craft CMS 5 and PHP 8.2+.
  • Rework Formie’s form builder around React, schema-driven settings, and shared Plugin Kit React components.
  • Rework Formie’s front-end JavaScript from the old bundled theme/runtime model to package-based browser and framework runtimes.
  • Split Formie’s front-end rendering model into server-rendered forms and client-rendered forms.
  • Move Formie browser JavaScript and CSS into @verbb/formie-browser.
  • Rename @verbb/formie-dom to @verbb/formie-browser.
  • Replace old Formie JavaScript callback names and validator events with canonical formie:* DOM events.
  • Move the public ready event from formie:runtime:ready to formie:client:ready.
  • Move runtime/client PHP namespaces toward client naming, while keeping selected runtime class aliases in Compatibility Mode.
  • Rename runtime JS translation hooks to frontend JS translation hooks: Rendering::EVENT_MODIFY_FRONTEND_JS_TRANSLATIONS, ModifyFrontendJsTranslationsEvent, and Rendering::getFrontendJsTranslations().
  • Replace RuntimeModule and RuntimeModuleContext terminology with ClientModule and ClientModuleContext.
  • Replace RuntimeRenderFrame terminology with RenderFrame.
  • Rename RuntimeAssets to FrontendAssets.
  • Replace renderFormAssets(), registerFormAssets(), renderFormCss(), and renderFormJs() with formAssets().
  • Replace renderRuntimeAssets(), renderCss(), and renderJs() with frontendAssets().
  • Rename render options renderCss and renderJs to includeCss and includeJs.
  • Rename form template options outputCssLayout and outputCssTheme to outputCss.
  • Rename form template options outputJsBase and outputJsTheme to outputJs.
  • Change Formie’s default front-end CSS class prefix from fui to formie.
  • Change form submit processing from a single save-oriented path to the staged submission workflow.
  • Route controller submissions, managed client submissions, GraphQL submissions, save-draft requests, and payment replays through the same submission workflow engine.
  • Move payment processing into workflow tasks instead of calling standalone submission payment processing directly.
  • Move notification dispatch and integration dispatch into workflow dispatch tasks.
  • Move payment callbacks, webhooks, and status polls through the payment replay workflow path with idempotent handling.
  • Store temporary and incomplete submission state in the database instead of offering session/database progression storage modes.
  • Remove the old user-facing submissionStore/submissionStateMode choice from active submission progression behavior.
  • Refresh submission state tokens on each multi-page step and Ajax response.
  • Use encrypted/authenticated state tokens for multi-page progression.
  • Rework save-and-resume around tokenized database records, TTL handling, capability checks, and URL token stripping.
  • Rework pending upload handling around sidecar records, finalize-on-submit behavior, and garbage collection of stale uploads.
  • Change submit action URLs and hidden field initial values so they no longer execute Twig.
  • Separate field defaults from prefill sources.
  • Change the default submission title pipeline to use submissionTitleFormat and field references on first save.
  • Change field references to use stable field references instead of relying only on field handles in places such as notifications, calculations, conditions, and integration mapping.
  • Change field value APIs from JSON/variable/email terminology toward array/reference/reference-block terminology.
  • Change field value storage and projection to preserve unresolved historical field UIDs instead of dropping unknown values after layout changes.
  • Change CP submission editing to hydrate only required field modules rather than mounting an entire front-end form client.
  • Change condition evaluation to use explicit boolean, numeric, and string coercion.
  • Change container and repeatable field condition subjects to use handle keys while storage remains UID-keyed.
  • Change field type metadata and GraphQL metadata to read from normalized configs before materializing field objects.
  • Change Formie fields service internals to stay config-first until callers need field object traversal.
  • Change Formie form, field, integration, and GraphQL lookup hot paths to use request-local caches.
  • Change synced fields from self-referential syncId fan-out to a definition/placement storage model.
  • Lock synced-field handle edits while fields remain synced.
  • Change stencils to use the canonical React builder and snapshot semantics.
  • Change stencil form creation to remap field references when materializing forms.
  • Change integration settings in the form builder from Twig/Vue HTML to PHP-defined schemas.
  • Change custom integration front-end output from getFrontEndJsVariables() to client modules.
  • Change address providers, captchas, payments, and field modules to register browser modules via the new client module manifest.
  • Change captchas to run through the workflow screen stage.
  • Change passive captcha and spam checks to use the shared screen workflow stage.
  • Change Formie’s static-cache support to use built-in token refresh behavior instead of requiring custom refresh snippets.
  • Change headless form rendering to use explicit server-rendered and client-rendered GraphQL queries.
  • Change GraphQL formieForm { templateHtml } usage to formieHtmlForm { html }.
  • Rename GraphQL page client event settings from enableJsEvents and jsGtmEventOptions to enableClientEvents and clientEventFields.
  • Change GraphQL field metadata generation to use cached field metadata from the fields service.
  • Change GraphQL client-form access so handle-based reads and lifecycle mutations require explicit schema scopes.
  • Change custom field schema method names from defineGeneralSchema(), defineSettingsSchema(), defineAppearanceSchema(), defineAdvancedSchema(), and defineConditionsSchema() to defineFormBuilderGeneralSchema(), defineFormBuilderSettingsSchema(), defineFormBuilderAppearanceSchema(), defineFormBuilderAdvancedSchema(), and defineFormBuilderConditionsSchema().
  • Change schema node keys from $formkit to $field.
  • Change schema help text keys from help to instructions.
  • Change field builder previews from getFormBuilderPreviewHtml() to defineFormBuilderPreviewSchema().
  • Change field input template discovery from getFrontEndInputTemplatePath() to getInputTemplatePath().
  • Change field email template terminology from email templates to reference-block templates.
  • Change field slot/tag customization from HtmlTag/htmlTag terminology to SlotTag/slotTag.
  • Change form render IDs from Form::getFormId()/setFormId() terminology to Form::getRenderId()/setRenderId().
  • Move Submissions::EVENT_BEFORE_SEND_NOTIFICATION ownership to Notifications::EVENT_BEFORE_SEND_NOTIFICATION.
  • Move Submissions::EVENT_BEFORE_TRIGGER_INTEGRATION ownership to Integrations::EVENT_BEFORE_TRIGGER_INTEGRATION.
  • Keep Yii-style getElementValidationRules() as the supported submission validation surface for Formie 4.
  • Update integration field mapping to handle nested groups, repeaters, tables, element fields, and normalized field values more consistently.
  • Improve file upload validation, filename normalization, and safer CP/email summary URLs.
  • Improve payment webhook, callback, and status-poll error handling and authenticity checks.
  • Improve anonymous runtime route method constraints and abuse/rate-limit handling.
  • Improve CORS handling so arbitrary origins are not reflected when GraphQL origins are not configured.
  • Improve large-form builder drag/drop performance and validation in production builds.
  • Improve export/query performance with request-local caches and explicit invalidation hooks.

Fixed

  • Fix migration coverage for Formie 3 to Formie 4 upgrades.
  • Fix migration coverage for direct Formie 2 to Formie 4 upgrades.
  • Fix synced-field migration to preserve shared field definitions and per-form placements.
  • Fix field hydration for legacy config keys under Compatibility Mode.
  • Fix legacy webhook/automation naming compatibility during upgrades.
  • Fix Stripe and other payment replay flows to run through the canonical workflow path.
  • Fix submission workflow failure logging to include halted stage, stage metadata, payment status, payment message, and payment decision details.
  • Fix hidden condition values and container/repeatable field values to use normalized field value projections consistently.
  • Fix condition evaluator behavior for boolean, numeric, and string comparisons.
  • Fix unresolved historical submission data being lost when a form layout no longer contains the original field.
  • Fix GraphQL schema generation for nested field structures.
  • Fix GraphQL field metadata generation performance for large forms.
  • Fix form handle lookup hot paths by routing through request-local form caches.
  • Fix repeated per-form integration list resolution by memoizing enabled integrations per form per request.
  • Fix client module manifest lookup costs with request-local caches.
  • Fix long-running worker cache staleness by exposing SubmissionQuery::invalidateStaticCaches().
  • Fix file-upload security checks for MIME types, extensions, active content, and filename normalization.
  • Fix safer file upload URLs in CP and email summary contexts.
  • Fix payment webhook and callback responses to avoid exposing sensitive validation details.
  • Fix anonymous client bootstrap, refresh, page transition, and submit flows to share stricter abuse controls.
  • Fix static-cache handling for token refresh and restored form responses.
  • Fix large builder drag/drop behavior on dense multi-page forms.
  • Fix integration mapping for normalized nested field values.
  • Fix missing or inconsistent custom field compatibility for legacy schema arrays and FormKit-style nodes.
  • Fix legacy front-end event bridging for projects migrating from Formie 3 event listeners.

Deprecated

  • Deprecated Form::getFormId() and Form::setFormId(). Use Form::getRenderId() and Form::setRenderId().
  • Deprecated Form::EVENT_MODIFY_HTML_TAG. Use Form::EVENT_MODIFY_SLOT_TAG.
  • Deprecated ModifyFormHtmlTagEvent. Use ModifyFormSlotTagEvent.
  • Deprecated Field::EVENT_MODIFY_HTML_TAG. Use Field::EVENT_MODIFY_SLOT_TAG.
  • Deprecated ModifyFieldHtmlTagEvent. Use ModifyFieldSlotTagEvent.
  • Deprecated Field::EVENT_MODIFY_VALUE_AS_JSON. Use Field::EVENT_MODIFY_VALUE_AS_ARRAY.
  • Deprecated Field::EVENT_MODIFY_VALUE_FOR_EMAIL. Use Field::EVENT_MODIFY_VALUE_FOR_REFERENCE_BLOCK.
  • Deprecated field value JSON methods such as getValueAsJson() and defineValueAsJson(). Use array-based equivalents.
  • Deprecated field variable value methods such as getValueForVariable(), getValueForVariableRaw(), defineValueForVariable(), and defineValueForVariableRaw(). Use reference value methods.
  • Deprecated field email value methods such as getValueForEmail() and defineValueForEmail(). Use reference-block value methods.
  • Deprecated field email template methods such as getEmailTemplatePath(), getEmailHtml(), getEmailOptions(), hasEmailLabel(), and hasEmailPlaceholder(). Use reference-block equivalents.
  • Deprecated legacy field key helpers such as getFieldKey(), getErrorKey(), getFullHandle(), getFullNamespace(), and getReservedHandles().
  • Deprecated legacy custom field schema methods in favor of defineFormBuilder*Schema() methods.
  • Deprecated getFormBuilderPreviewHtml() in favor of defineFormBuilderPreviewSchema().
  • Deprecated getFrontEndInputTemplatePath() in favor of getInputTemplatePath().
  • Deprecated defineHtmlTag() in favor of defineFieldSlotTag().
  • Deprecated Submission::getValueAsString(), Submission::getValueAsJson(), Submission::getValueForExport(), and Submission::getValueForSummary() in favor of getFieldValue*() methods.
  • Deprecated Submission::getFieldValueAsJson() in favor of Submission::getFieldValueAsArray().
  • Deprecated Submission::getValuesAsJson() in favor of Submission::getValuesAsArray().
  • Deprecated Submission::getFieldValueForEmail() in favor of Submission::getFieldValueForReferenceBlock().
  • Deprecated Submission::getFieldValueForVariable() in favor of Submission::getFieldValueForReference().
  • Deprecated SubmissionContentManager::getValuesAsJson() in favor of getValuesAsArray().
  • Deprecated ValueContext::json() and ValueContext::TYPE_JSON. Use ValueContext::array() and ValueContext::TYPE_ARRAY.
  • Deprecated ValueContext::variable() and ValueContext::TYPE_VARIABLE. Use ValueContext::reference() and ValueContext::TYPE_REFERENCE.
  • Deprecated ValueContext::email() and ValueContext::TYPE_EMAIL. Use ValueContext::referenceBlock() and ValueContext::TYPE_REFERENCE_BLOCK.
  • Deprecated craft.formie.registerAssets(), craft.formie.registerFormAssets(), craft.formie.renderFormAssets(), craft.formie.renderFormCss(), and craft.formie.renderFormJs(). Use craft.formie.formAssets().
  • Deprecated craft.formie.renderRuntimeAssets(), craft.formie.renderCss(), and craft.formie.renderJs(). Use craft.formie.frontendAssets().
  • Deprecated render option keys renderCss, renderJs, outputCssLayout, outputCssTheme, outputJsBase, and outputJsTheme.
  • Deprecated assets() as the form-scoped asset helper name. Use formAssets().
  • Deprecated legacy theme config root keys including radio, date, email, hidden, and phone. Use radioButtons, dateTime, emailAddress, hiddenField, and phoneNumber.
  • Deprecated legacy schema config keys including limitType, limitAmount, subfieldLabelPosition, includeInEmail, and emailValue.
  • Deprecated Integration::getFormSettingsHtml() for builder settings. Use Integration::defineFormSettingsSchema().
  • Deprecated custom integration front-end variable output via getFrontEndJsVariables(). Use IntegrationInterface::getClientModule().
  • Deprecated standalone Submissions::processPayments() usage. Payments now run through workflow tasks.
  • Deprecated selected submission dispatch pass-through methods on Submissions; use the canonical workflow, notification, integration, and payment services.
  • Deprecated runtime-named PHP classes in favor of client/frontend names where aliases are provided by Compatibility Mode.
  • Deprecated Rendering::EVENT_MODIFY_RUNTIME_JS_TRANSLATIONS, ModifyRuntimeJsTranslationsEvent, and getRuntimeJsTranslations() in favor of frontend-named equivalents.
  • Deprecated GraphQL page setting names enableJsEvents and jsGtmEventOptions.
  • Deprecated the refresh-token request form query parameter. Use handle.
  • Deprecated legacy Formie DOM events such as onFormieLoaded, onFormieInit, onFormieReady, onBeforeFormieSubmit, onFormieSubmit, onAfterFormieSubmit, onFormieSubmitError, onFormiePageToggle, onFormieValidate, and onAfterFormieValidate.
  • Deprecated legacy validator events such as formieValidatorInitialized, formieValidatorDestroyed, formieValidatorShowError, and formieValidatorClearError.
  • Deprecated the global Formie.refreshForCache() helper in favor of static-cache token refresh handling.

Removed

  • Remove the legacy CustomElement inheritance model from submissions.
  • Remove the FieldLegacy bridge trait.
  • Remove legacy Formie 3 field inputHtml() fallback behavior.
  • Remove expired Formie 3 field name helper compatibility surfaces.
  • Remove old sticky JavaScript form-bus APIs.
  • Remove the built-in Duplicate captcha integration.
  • Remove the built-in JavaScript captcha integration.
  • Remove the built-in Honeypot captcha integration.
  • Remove active support for file, Redis, and Memcached draft-state backends. Formie 4 supports the database-backed adapter.
  • Remove the old submissionStateMode and submissionStore settings from active configuration.
  • Remove enableGatsbyCompatibility from active configuration.
  • Remove active session/database branching for submission progression storage.
  • Remove getFrontEndJsVariables() as the custom integration front-end API.
  • Remove old built-in front-end bundle assumptions in favor of @verbb/formie-browser and the framework packages.
  • Remove direct templateHtml usage from the primary GraphQL form rendering path.
  • Remove Algolia as a built-in address provider module.