The dynamic, headless form builder for Strapi v5.
FormFlow lets you build configurable forms visually in the Strapi admin panel and consume them over a clean REST API from any frontend. Forms, fields, validation, spam protection, notifications, and submissions all live in Strapi — your frontend just fetches the schema and posts the values. Truly headless: bring your own framework, your own styling, your own UX.
Your submissions stay in your own database. Not in a third-party form service. No per-submission pricing, no separate data-processing agreement, nobody else holding your leads.
Genuinely headless — not an embedded widget. Fetch a JSON schema, post the values back. Works with React, Vue, Next.js, Nuxt, Astro, SvelteKit, or plain fetch. Official React and Vue SDKs ship alongside it — use them or ignore them. You own every pixel.
The free core is a real product, not a trial. MIT-licensed, with unlimited forms and unlimited submissions. No time limit, no watermark, no "upgrade to export your own data" — CSV and JSON export are built in.
Your editors build the forms, not you. Drag-and-drop builder, 20+ field types, per-field validation, and live preview, all inside the Strapi admin your team already uses. One fewer thing routed through a developer.
Spam is handled on day one. Honeypot, per-form rate limiting, and reCAPTCHA v2 are included and free.
Submissions don't just sit there. An inbox with statuses and bulk actions, email notifications on submit, and a REST API — plus webhooks and integrations when you outgrow that.
A drag-and-drop form builder with a rich field registry:
- Basic inputs — text, textarea, email, number, phone, url, password
- Choice — select (dropdown), radio, checkbox, boolean (yes/no toggle)
- Date & time — date, time, datetime
- Advanced — file upload, hidden, signature, rating / NPS, address + map, rich text, calculated, payment, consent
- Layout elements — heading, paragraph, divider
- Per-field options: label, placeholder, description, default value, required flag, half/full width, and custom HTML attributes
- Live field preview and duplicate-form support
- Per-field validation rules with custom error messages
- Conditional visibility based on another field's value
- Multi-step / wizard forms with per-step grouping and validation
- Submission inbox with list and detail views
- Status management (new, read, processed, archived, spam) and bulk actions
- Export to CSV, JSON, Excel (XLSX), and PDF, with optional scheduled exports
- Approval workflow (pending / approved / rejected) for forms that require manual review
- Submission count tracking per form
- Honeypot field (configurable field name)
- Google reCAPTCHA v2 and v3 (with score threshold)
- Cloudflare Turnstile
- hCaptcha
- IP blocklist
- Per-form rate limiting
- Email notifications on submission (configurable recipients, subject, reply-to, and templates)
- Customer-owned Telegram rich-message notifications, with tokens managed from the Strapi admin; outbound-only, with no deployment or webhook required (setup guide)
- Outgoing webhooks (POST/PUT, custom headers,
submission.created/submission.updatedevents) - Pre-built integrations: Slack, Google Sheets, Mailchimp, HubSpot, Notion, Zapier, and Make
- Per-form locale content overrides (localized labels, placeholders, descriptions, option labels, and success messages) served through the public API by locale
- Persist partial submissions and return a resume token so users can continue a long form later
- Per-form metrics: views, starts, completions, and drop-off
- Consent capture field
- Configurable data retention
- IP anonymization
- Per-subject data export and deletion with an audit log
- Role-based access control (RBAC) integrated with Strapi's Settings → Roles → Plugins, with granular actions for reading, creating, updating, deleting, and exporting forms and submissions
- Public, configurable REST API under
/api/formflowfor fetching schemas and submitting values - Sanitized public schema (server-only secrets such as the reCAPTCHA secret key are never exposed)
- Official headless frontend renderers for React and Vue (see below)
# npm
npm install @formflowjs/strapi-plugin-formflow
# yarn
yarn add @formflowjs/strapi-plugin-formflowEnable the plugin in config/plugins.ts (or config/plugins.js):
export default {
formflow: {
enabled: true,
},
};Requires Strapi v5. FormFlow creates its own content types automatically on startup — no manual migration is needed.
Rebuild the admin panel so the FormFlow UI is bundled in:
npm run build
npm run developTesting a locally linked build: after
yalc push, stop the consuming Strapi app, remove its generated.strapi/,node_modules/.strapi/,.cache/,.vite/,build/, anddist/directories, then rebuild and restart. Otherwise Strapi or Vite may continue serving a stale admin bundle.
-
Create a form. In the Strapi admin, open FormFlow from the main left sidebar (the FormFlow icon), create a form, add fields in the builder, configure validation and settings, and activate it. Note the form's slug.
-
Fetch the schema from your frontend:
curl https://your-strapi.example.com/api/formflow/forms/contact
Returns the sanitized schema —
title,description,slug,fields, and publicsettings. -
Submit values. The request body is a flat map of field names to values:
curl -X POST https://your-strapi.example.com/api/formflow/forms/contact/submit \ -H "Content-Type: application/json" \ -d '{ "name": "Ada Lovelace", "email": "ada@example.com", "message": "Hello from FormFlow!" }'
On success you receive
{ "data": { "success": true, "message": "...", "redirectUrl": null } }. Validation failures return HTTP400with a per-field error map.
For
filefields, send the request asmultipart/form-datainstead of JSON.
You don't have to wire up fetch calls and rendering by hand. The official headless SDKs fetch the schema, render the fields, run validation, and submit for you — framework-agnostic and bring-your-own-styling (no CSS shipped, works with Next.js, Astro, Vite, Nuxt, and more). They're built on the shared @formflowjs/core engine.
# React
npm i @formflowjs/react
# Vue
npm i @formflowjs/vueRepository and docs: https://github.com/Digidinc/formflow-sdk
All public endpoints are mounted under /api/formflow and are unauthenticated by default (configurable via Strapi route policies).
| Method | Path | Description |
|---|---|---|
GET |
/api/formflow |
Plugin index / health check |
GET |
/api/formflow/forms/:slug |
Get a form's sanitized public schema (optionally per locale) |
POST |
/api/formflow/forms/:slug/submit |
Submit values for the form |
POST |
/api/formflow/forms/:slug/partial |
Save a partial submission and receive a resume token |
GET |
/api/formflow/forms/:slug/partial/:resumeToken |
Resume a saved partial submission by token |
POST |
/api/formflow/forms/:slug/analytics/start |
Record a form-start analytics event (the headless SDKs call this) |
FormFlow works out of the box with no configuration. Optional plugin options can be set in config/plugins.js (or .ts) under the formflow key:
// config/plugins.js
module.exports = () => ({
formflow: {
enabled: true,
config: {
// Mask submitter IP addresses before storage (IPv4 last octet zeroed,
// IPv6 truncated to the /64 prefix), in both the stored `ipAddress`
// column and `metadata.ipAddress`. Requires a Business license to take
// effect. Default: false (raw IP stored).
anonymizeIp: false,
// When > 0, a daily cron deletes submissions older than this many days.
// Requires a Business license to take effect. Default: 0 (disabled;
// submissions are kept indefinitely and no cron is registered).
dataRetentionDays: 0,
// Optional instance-wide reCAPTCHA defaults. Per-form spam settings take
// precedence; secrets here are server-only and never returned publicly.
recaptcha: {
enabled: false,
siteKey: '',
secretKey: '',
version: 'v3', // 'v2' | 'v3'
threshold: 0.5, // v3 score threshold
},
},
},
});| Option | Type | Default | Description |
|---|---|---|---|
anonymizeIp |
boolean |
false |
Mask submitter IPs before storage. Requires a Business license. |
dataRetentionDays |
number |
0 |
Daily-purge submissions older than N days; 0 disables. Requires Business. |
recaptcha |
object |
— | Instance-wide reCAPTCHA defaults (per-form settings take precedence). |
The license key is provided via the FORMFLOW_LICENSE_KEY environment variable (server-only; never returned in public responses). Without it, FormFlow runs as the fully-functional free tier.
Both privacy options are OFF by default, so existing installs are unaffected until an administrator opts in and holds the required license entitlement.
Your license activates each installation against an activation slot. Your plan includes a fixed number of slots, and each distinct installation consumes one. Most problems below come from a slot still being held by an installation you no longer use.
| Symptom | Cause | Fix |
|---|---|---|
| Premium features stay off and the logs show a license-quota message | Every activation slot is in use — often by an old installation | Deactivate the stale site from your account dashboard, then restart Strapi |
| Features were working, then stopped after a database reset or restore | A reset clears the stored installation identity, so the plugin registers as a new installation while the old one still holds the slot | Deactivate the old site from your account dashboard, then restart Strapi |
Features stopped after changing FORMFLOW_LICENSE_KEY and changing it back |
Each key change re-registers the installation; the previous registration keeps its slot | Deactivate the old site from your account dashboard, then restart Strapi |
| Features stopped after moving to a new server or container | The new host registers as a separate installation | Deactivate the old site from your account dashboard, then restart Strapi |
| Everything works locally but not in production | The license key is missing from the production environment | Confirm FORMFLOW_LICENSE_KEY is set in the production .env and restart |
Avoiding it: the plugin stores a stable installation identity in the Strapi database, so ordinary restarts, redeploys, and code updates reuse the same slot and never consume a new one. Only a database reset, a license-key change, or a move to a different host creates a new registration. If you routinely rebuild environments (ephemeral CI, preview deployments), contact support to raise your activation quota.
If your license lapses: a revoked, cancelled, or expired key removes premium features at the next license check — within 24 hours, or immediately if an administrator refreshes the license from the FormFlow settings page. The 14-day grace period covers network outages only: if the license service is unreachable, premium features keep working from the cached entitlement. Your forms, submissions, and data are never affected — only premium features are gated, and the free tier stays fully functional.
Everything above is free unless this table says otherwise. The free tier is MIT-licensed and production-ready — unlimited forms, unlimited submissions, no expiry — so you can ship on it and never pay us anything.
| Free | Pro | Business | |
|---|---|---|---|
| Forms & submissions | Unlimited | Unlimited | Unlimited |
| Field types | All standard, layout, and file upload | + signature, rating/NPS, address + map, rich text, calculated, payment | Everything in Pro |
| Validation rules | ✓ | ✓ | ✓ |
| Conditional logic & multi-step forms | ✓ | ✓ | |
| Submission inbox, statuses, bulk actions | ✓ | ✓ | ✓ |
| Export | CSV, JSON | + Excel, PDF, scheduled exports | Everything in Pro |
| Email notifications | ✓ | + autoresponders, custom templates, white-label | Everything in Pro |
| Anti-spam | Honeypot, rate limiting, reCAPTCHA v2 | + reCAPTCHA v3, Turnstile, hCaptcha, IP blocklist | Everything in Pro |
| Webhooks & integrations (Slack, Sheets, Mailchimp, HubSpot, Notion, Zapier, Make) | ✓ | ✓ | |
| Save & resume, analytics | ✓ | ✓ | |
| Telegram notifications | 1 connection | 2 connections | 4 connections |
| GDPR retention, IP anonymization, consent field, audit log | ✓ | ||
| Approval workflow, multi-language forms | ✓ | ||
| RBAC, headless REST API, React & Vue SDKs | ✓ | ✓ | ✓ |
Paid plans are annual and priced per project. See pricing for current rates, or install and use the free tier for as long as you like — no account and no credit card required.
- Website: https://digidinc.github.io/formflow
- Pricing & plans: https://digidinc.github.io/formflow/#pricing
- Commercial support: info@digid.ca
- Repository & issues: https://github.com/Digidinc/strapi-plugin-formflow
- Frontend SDKs: https://github.com/Digidinc/formflow-sdk (
@formflowjs/react,@formflowjs/vue)
FormFlow sends anonymous, opt-out usage telemetry so we can see how many installs are active and prioritize what to build. We never collect personal data, form content, submissions, or environment secrets.
Each install sends a one-time install event plus a daily heartbeat containing only:
- An anonymous install id (a SHA-256 hash of your Strapi project UUID — not reversible to your project)
- Plugin version, Strapi version, and Node.js version
- License tier (
free/pro/business) and total number of forms - Approximate country (derived at the edge, never your IP)
Opt out at any time by setting:
FORMFLOW_TELEMETRY_DISABLED=trueTelemetry is also disabled automatically if you've disabled Strapi's own telemetry (via STRAPI_TELEMETRY_DISABLED, npx strapi telemetry:disable, or removing the project uuid).
FormFlow is open-core:
FormFlow is developed and maintained by Bardiya Rahimi and commercially published by Digid Inc., which is authorized to distribute and commercially license the software.
- The free core — every file except those under an
ee/directory — is licensed under the MIT License. - The premium Enterprise Edition code (under
server/src/ee/andadmin/src/ee/, powering the Pro and Business features) is source-available under the FormFlow EE License. You may view and evaluate it, but production use requires a valid license key.
Pro/Business features are gated at runtime by a license key (FORMFLOW_LICENSE_KEY). Without one, FormFlow runs as the fully-functional free tier — your forms and submissions always work.
