Setting up a CF7 to webhook integration isn't built into Contact Form 7. To send form submissions to tools like n8n you need custom code or an additional plugin. This guide covers both approaches — the quick way and the reliable way.
TL;DR
wpcf7_mail_sent + wp_remote_post — works for low-volume forms but has no retry, no logging, and silently drops failures$submission->get_posted_data()['field-name'] from the WPCF7_ContactForm submission object
The most common approach to a CF7 to webhook integration uses the wpcf7_mail_sent action hook. Contact Form 7 fires this hook after a successful submission — you hook into it, grab the submitted data, and POST it to your webhook endpoint.
Here's the minimal working code. Add it to your theme's functions.php or a custom plugin:
This works. It's simple and widely used. For a hobby project or an internal form with low submission volume, it does the job.
The problem is what happens in production.
The wp_remote_post() approach works in development. The problem shows up once your CF7 to webhook integration is handling real traffic: the call is synchronous, so PHP blocks and waits for the remote server to respond before the form submission completes.
Contact Form 7 has over 10 million active installations on WordPress.org — making it one of the most-deployed plugins in the ecosystem. At that scale, silent webhook failure is not an edge case; it accumulates across every site relying on synchronous wp_remote_post() without retry logic.
Form submissions can fail silently if the receiving service is down. Without retries, that means lost leads — and no way to know it happened until someone complains.
This example uses Webhook Actions by Flow Systems — a free WordPress plugin that provides reliable webhook delivery with automatic retry and replay support.
It works by queuing webhook dispatch as a background job, so your form submissions are never blocked by a slow or unavailable endpoint.
A reliable CF7 to webhook setup separates two things the basic approach conflates: recording that a submission happened and delivering it to the endpoint.
When a CF7 form is submitted, a background job is queued immediately. The user gets an instant response — the form submission is complete from their perspective. A cron worker then picks up the job and attempts delivery in the background.
If the delivery fails — because n8n returned a 5xx, hit a rate limit (429), or simply timed out — the job is scheduled for retry with exponential backoff: 1 min, 2 min, 4 min, 8 min, 16 min. Each attempt is logged with the HTTP status code and response body. You can see every success and failure in the WordPress admin.
If all retry attempts are exhausted, the job enters a failed state — visible in the event log, and replayable via the REST API or the admin UI. No data is lost.
Search for this exact description in Plugins → Add Plugin — it narrows the WordPress.org search to exactly one result:
Go to Webhooks → Add Webhook in the WordPress admin. Give it a name (e.g., "CF7 → n8n").
Paste your n8n webhook URL (e.g., https://your-n8n-url/webhook/test). The plugin will POST form data to this endpoint on every submission.
On the n8n side, you need a Webhook node configured to receive POST requests:
In your n8n workflow, add a new node and search for "Webhook".
The plugin sends a JSON POST request, so make sure the Webhook node is set to accept POST.
Click "Listen for test event" in n8n, then submit your CF7 form. n8n will display the incoming payload so you can map the fields to subsequent nodes.
Here's what a typical CF7 submission looks like when it arrives at your n8n webhook. The field names match the name attributes you set in your CF7 form tags.
The payload wraps the full WPCF7_ContactForm object including submitted fields, page url, remote_ip, and user_agent. Use args[0].submission.fields in n8n to access form values directly.
Every webhook delivery attempt is stored in the event log — success or failure. If a CF7 submission didn't reach n8n, you can replay it without asking the user to resubmit.
The plugin exposes a REST API for this:
Replace {id} with the log entry ID visible in the Event Log. This re-queues the exact payload that was originally sent — no need to reconstruct it.
You can also trigger retries from the WordPress admin UI. Both options are covered in the REST API documentation.
A contact form submission is often a high-intent signal — someone typing their email and pressing send is more committed than a page view. Losing that data silently is costly.
With a bare wp_remote_post() call, any of these common scenarios causes permanent data loss:
n8n restarts during deployment. Your instance hits a memory limit and returns 500. The incoming webhook URL changes and the old one starts returning 404. A rate limit is hit during a campaign burst.
None of these are edge cases in real production environments. A queue with retries means these scenarios become recoverable failures instead of silent data loss. The event log means you can diagnose and replay — instead of guessing.
Exponential backoff is the industry-standard approach for retryable HTTP operations. AWS documentation on error retries and exponential backoff explains that spacing retries progressively further apart — rather than at fixed intervals — reduces load on a recovering service and improves overall delivery success rates for transient failures.
Without retries, a single n8n restart during business hours can mean lost leads. With retry and replay support, the same event becomes a recoverable blip — automatically resolved within minutes.
wpcf7_mail_sent action and use wp_remote_post() to send submitted data to your endpoint. For production use, a queue-based plugin like Webhook Actions by Flow Systems gives you automatic retries, delivery logging, and replay — so no form submission is ever lost silently. See the full code and step-by-step setup above.
wpcf7_mail_sent action hook, or a plugin that handles webhook dispatch for you.
wpcf7_mail_sent action, retrieve submitted data via WPCF7_Submission::get_instance(), and post it to your n8n webhook URL using wp_remote_post(). For reliable delivery with retries, use a queue-based plugin like Webhook Actions by Flow Systems that handles failures automatically.
wp_remote_post() call, the data is lost silently — there's no retry and no log entry. With a queue-based system, the failed delivery is stored and retried automatically with exponential backoff (1 min → 2 min → 4 min → 8 min → 16 min). You can also replay any failed submission manually from the WordPress admin.
POST /wp-json/fswa/v1/logs/{id}/retry) that lets you replay any past submission — including successful ones.
wp_remote_post() is synchronous — PHP blocks and waits for the remote server to respond before the form submission completes. If your n8n instance is slow or unavailable, users experience a delayed or failed form submission. A queue-based approach dispatches the webhook in the background so the user sees an instant response regardless of endpoint latency.