Gravity Forms doesn't include built-in webhook output in its base plugin. To send form entries to tools like n8n you need custom code or an additional plugin. This guide covers both approaches — plus how to map numeric field IDs to clean names using the REST API.
The most direct approach to Gravity Forms webhooks uses the gform_after_submission action hook. Gravity Forms fires this hook after a successful submission — you hook into it, read the entry data using the rgar() helper, and POST it to your webhook endpoint.
Field values are stored under their numeric field ID in the $entry array. Field 1 is rgar($entry, '1'), field 2 is rgar($entry, '2'), and so on. Checkbox sub-fields use dot notation: rgar($entry, '6.1'). (rgar() docs)
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 Gravity Forms webhook is handling real traffic: the call is synchronous, so PHP blocks and waits for the remote server to respond before the form submission completes.
Gravity Forms submissions can fail silently if the receiving service is down. Without retries, that means lost leads — no way to know it happened until someone complains.
This example uses Flow Systems Webhook Actions — 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 Gravity Forms submissions are never blocked by a slow or unavailable endpoint. See the step-by-step setup or jump to the REST API field mapping section.
A reliable Gravity Forms webhook setup separates two things the basic approach conflates: recording that a submission happened and delivering it to the endpoint.
When a Gravity Forms entry is created, 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., "Gravity Forms → n8n").
Set the WordPress action hook to gform_after_submission. This fires once per successful Gravity Forms entry — after validation passes and the entry is stored in the database.
Paste your n8n webhook URL (e.g., https://your-n8n-url/webhook/test). The plugin will POST the full Gravity Forms entry to this endpoint on every submission.
Submit your Gravity Forms form. Check the Event Log in the plugin admin to see the delivery status and the raw payload that was sent.
Use the Payload tab in the webhook settings to pick exactly which Gravity Forms fields are sent and rename keys — no code required.
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.
n8n will generate a URL like https://your-n8n-url/webhook/126cc22b-ba78-4d37-b3b9-2e72eb2edc7e. Copy this and paste it into the plugin's webhook URL field (step 4 above).
Click "Listen for test event" in n8n, then submit your Gravity Forms form. n8n will display the incoming payload so you can inspect the field structure before mapping fields.
Here's what a typical Gravity Forms submission looks like when it arrives at your n8n webhook. The args property is an array — args[0] is the entry, args[1] is the full form definition (fields, confirmations, notifications) and is omitted here for brevity.
Field values are stored under their numeric field ID as string keys: "1" is Full Name, "2" is Email, and so on.
In n8n, use {{ $json.args[0]["1"] }} to access the name field, {{ $json.args[0]["2"] }} for email, and so on. The numeric key names are unwieldy in workflows — the REST API section below shows how to apply field mapping so your n8n nodes receive name, email, etc. instead.
The plugin captures the raw payload from the first real form submission and lets you define a field mapping — translating dot-notation paths in the payload (like args.0.1) to clean output keys (like data.name). After mapping, every future delivery arrives at n8n with readable field names instead of numeric IDs.
All requests use your API token in the Authorization header. Replace <your-token> below with your actual token from Webhooks → API Keys in the WordPress admin.
Start by listing all configured webhooks to get the webhook ID:
The webhook ID is 22. Use this in the next steps.
Fetch the full config for webhook ID 22 to confirm trigger and endpoint:
After the first real form submission fires, the plugin captures the raw payload. Fetch it to see the exact dot-notation paths to use in your field mapping:
The path to the name field is args.0.1 (array index 0, key "1").
PUT the schema with your field mapping. Use a mappings array of source/target pairs. The excluded array removes entire top-level keys from the output — here we exclude args to drop the raw Gravity Forms entry and form definition, keeping only the mapped fields and other top-level envelope keys.
After the PUT, every future delivery arrives at n8n with name, email, phone, subject, message, and form_id — the raw args array (including the full form definition and trailing nulls) is excluded. Your n8n expressions are readable and the payload is clean.
See the full PUT /schemas API reference for all available options.
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.
Without retries, a single n8n restart during business hours can mean lost Gravity Forms leads. With retry and replay support, the same event becomes a recoverable blip — automatically resolved within minutes.
gform_after_submission action and use wp_remote_post() to forward submission data. For production reliability with automatic retries and delivery logging, use a queue-based plugin like Flow Systems Webhook Actions.
gform_after_submission action (2 args: $entry, $form) and post the entry data to your n8n webhook URL using wp_remote_post(). Use rgar($entry, '1') to read field values by their numeric field ID. For reliable delivery with retries, use a queue-based plugin like Flow Systems Webhook Actions that handles failures automatically.
gform_after_submission hook, field values are stored in the $entry array under their field ID as a string key: $entry['1'] for field 1, $entry['2'] for field 2, and so on. Use the rgar() helper to safely read these values: rgar($entry, '1'). Checkbox sub-fields use dot notation: rgar($entry, '6.1').
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.