Connect
Integrations
Chat, spreadsheets, email marketing, CRM, Zapier, Make, n8n and signed webhooks.
Integrations are on the Starter plan and up; Klaviyo, Mailchimp, Omnisend and HubSpot need Pro. Every delivery to an integration is logged in the Delivery Log with retries.
Open Integrations, click Connect on a destination, fill in its details, choose the forms it applies to (or all forms), and click Connect. Use Send test to send a sample submission. Pause stops deliveries without removing the connection.
Per form, the editor's Integrations tab lets you switch any destination on or off.
Chat
| Destination | What you need |
|---|---|
| Slack | An incoming webhook URL for the channel |
| Discord | A channel webhook URL |
| Microsoft Teams | A workflow or incoming webhook URL |
| Telegram | A bot token and the chat ID |
Each submission is posted as a message with the form name, reference, answers and a link to the submission.
Spreadsheets and databases
| Destination | What you need |
|---|---|
| Google Sheets | Connect your Google account and pick the spreadsheet; one row per submission |
| Airtable | A personal access token, base ID and table |
Email marketing and CRM (Pro)
| Destination | What happens |
|---|---|
| Klaviyo | The profile is created or updated and subscribed to the list you choose |
| Mailchimp | The submitter is added to an audience |
| Omnisend | The submitter is added as a contact |
| HubSpot | The contact is created or updated and the answers are logged as a note |
Zapier, Make and n8n
- In your tool, create a webhook trigger and copy its URL. Zapier: Webhooks by Zapier, Catch Hook. Make: Webhooks, Custom webhook. n8n: Webhook node, POST.
- In Form Expert, Integrations, choose the tool, paste the URL, pick the forms, Connect.
- Click Send test so the tool learns the payload and you can map fields.
Custom webhook
Webhook (custom) posts JSON to any HTTPS endpoint. Set a signing secret to verify calls.
Payload:
{
"event": "submission.created",
"version": 1,
"delivery_id": "…",
"attempt": 1,
"shop": "your-store.myshopify.com",
"form": { "id": "a8xykg4u7c", "name": "Contact us" },
"submission": {
"ref": "FX-AB12CD",
"id": "…",
"received_at": "2026-08-28T10:00:00.000Z",
"email": "[email protected]",
"customer_id": "gid://shopify/Customer/123",
"page_url": "https://your-store.com/pages/contact",
"attribution": { "utm_source": "newsletter", "utm_campaign": "spring", "referrer": "https://news.example", "landing_page": "https://your-store.com/?utm_source=newsletter" },
"data": { "name": "Ada", "email": "[email protected]", "message": "Hi" },
"fields": [{ "key": "name", "label": "Name", "type": "text", "value": "Ada" }],
"files": [{ "id": "…", "filename": "photo.jpg", "size": 12345, "mime": "image/jpeg" }]
}
}
Headers: Content-Type: application/json, X-FormEx-Event: submission.created, and with a secret, X-FormEx-Signature: t=<unix seconds>,v1=<hex>.
Verify: v1 is HMAC-SHA256 of "<t>.<raw body>" with your secret. Reject calls whose t is older than five minutes or whose signature does not match.
const [t, v1] = sig.split(",").map((p) => p.split("=")[1]);
const expected = crypto.createHmac("sha256", SECRET).update(`${t}.${rawBody}`).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1)) && Math.abs(Date.now() / 1000 - Number(t)) < 300;
Non-2xx responses are retried with backoff. Persistent failures raise an alert.
Something missing? Submit a ticket.