/ Example — Gravity Forms

Gravity Forms Webhooks: Send Gravity Forms Submissions to n8n (Step-by-Step)

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.

/ Basic Method

Basic Gravity Forms Webhook Using wp_remote_post

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:

functions.php — gravity forms webhook (basic)
add_action('gform_after_submission', function ($entry, $form) { $name = rgar($entry, '1'); // Full Name (field ID 1) $email = rgar($entry, '2'); // Email Address (field ID 2) $phone = rgar($entry, '3'); // Phone Number (field ID 3) $subject = rgar($entry, '4'); // Subject (field ID 4) $message = rgar($entry, '5'); // Message (field ID 5) wp_remote_post('https://your-n8n-url/webhook/test', [ 'headers' => ['Content-Type' => 'application/json'], 'body' => json_encode([ 'name' => $name, 'email' => $email, 'phone' => $phone, 'subject' => $subject, 'message' => $message, ]), ]); }, 10, 2);

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.

/ Production Reality

Why the Basic Gravity Forms Webhook Setup Breaks 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.

/ Better Approach

Reliable Method: Queue-Based Webhooks with Retry and Logging

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.

/ Setup

Step-by-Step: Gravity Forms Webhook Setup
with Retry and Logging

  1. 1
    Install the plugin

    Search for this exact description in Plugins → Add Plugin — it narrows the WordPress.org search to exactly one result:

    search text — paste into WordPress plugin search
    Reliable Webhooks Queue Smart Retry Replay
    Search plugin by Reliable Webhooks Queue Smart Retry Replay
  2. 2
    Create a new webhook

    Go to Webhooks → Add Webhook in the WordPress admin. Give it a name (e.g., "Gravity Forms → n8n").

    Create a new Gravity Forms webhook
  3. 3
    Select the trigger

    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.

    action hook — paste into the trigger field
    gform_after_submission
  4. 4
    Set the webhook URL

    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.

  5. 5
    Save and test

    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.

    Gravity Forms webhooks in action — form submission, Event Log delivery status, and raw payload in log details
  6. 6
    Optional: customize the payload with field mapping

    Use the Payload tab in the webhook settings to pick exactly which Gravity Forms fields are sent and rename keys — no code required.

    Gravity Forms webhooks payload mapping — selecting and renaming fields via the plugin UI
/ n8n

Setting Up the n8n Webhook

On the n8n side, you need a Webhook node configured to receive POST requests:

  1. 1
    Add a Webhook node

    In your n8n workflow, add a new node and search for "Webhook".

  2. 2
    Set HTTP Method to POST

    The plugin sends a JSON POST request, so make sure the Webhook node is set to accept POST.

  3. 3
    Copy the webhook URL

    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).

    n8n Webhook node configuration — HTTP Method POST, Header Auth, Respond Immediately, showing the production webhook URL to copy
    n8n Webhook node — copy the Production URL and paste it into the plugin's webhook URL field
  4. 4
    Activate and test

    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.

    Full walkthrough — Gravity Forms submission triggers a webhook payload delivered to n8n via Flow Systems Webhook Actions
/ Payload

Example Payload

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.

POST body — application/json (args[1] form definition omitted)
{ "event": { "id": "efab972c-09bc-460b-9ec3-ad63484b3b14", "timestamp": "2026-04-01T15:30:47Z", "version": "1.0" }, "hook": "gform_after_submission", "args": [ { "id": "3", "status": "active", "form_id": "1", "ip": "172.22.0.1", "source_url": "https://your-wordpress-site.com/gravity-forms-example/", "currency": "USD", "date_created": "2026-04-01 15:30:47", "created_by": "1", "1": "Mateusz", "2": "mateusz@flowsystems.pl", "3": "(150) 010-0900", "4": "general", "5": "Hey, this is example test form message!" } ], "timestamp": 1775057447, "site": { "url": "https://your-wordpress-site.com" } }

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.

/ REST API

Field Mapping via REST API

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.

  1. A
    List all webhooks — find the Gravity Forms one

    Start by listing all configured webhooks to get the webhook ID:

    curl — GET /webhooks
    curl -s https://your-wordpress-site.com/wp-json/fswa/v1/webhooks \ -H "Authorization: Bearer <your-token>" | jq .
    response
    [ { "id": "22", "name": "Gravity Forms to n8n example", "endpoint_url": "https://n8n.your-site.com/webhook/126cc22b-ba78-4d37-b3b9-2e72eb2edc7e", "auth_header": "Bearer webhook", "is_enabled": true, "triggers": ["gform_after_submission"] } ]

    The webhook ID is 22. Use this in the next steps.

  2. B
    Get webhook config

    Fetch the full config for webhook ID 22 to confirm trigger and endpoint:

    curl — GET /webhooks/22
    curl -s https://your-wordpress-site.com/wp-json/fswa/v1/webhooks/22 \ -H "Authorization: Bearer <your-token>" | jq .
    response
    { "id": "22", "name": "Gravity Forms to n8n example", "endpoint_url": "https://n8n.your-site.com/webhook/126cc22b-ba78-4d37-b3b9-2e72eb2edc7e", "auth_header": "Bearer webhook", "is_enabled": true, "created_at": "2026-03-30 20:20:58", "triggers": ["gform_after_submission"] }
  3. C
    Fetch the captured payload

    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:

    curl — GET /schemas/webhook/22/trigger/gform_after_submission
    curl -s "https://your-wordpress-site.com/wp-json/fswa/v1/schemas/webhook/22/trigger/gform_after_submission" \ -H "Authorization: Bearer <your-token>" | jq .example_payload
    response (example_payload — trimmed)
    { "hook": "gform_after_submission", "args": [ { "id": "3", "form_id": "1", "1": "Mateusz", "2": "mateusz@flowsystems.pl", "3": "(150) 010-0900", "4": "general", "5": "Hey, this is example test form message!" } ] }

    The path to the name field is args.0.1 (array index 0, key "1").

  4. D
    Apply field mapping

    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.

    curl — PUT /schemas/webhook/22/trigger/gform_after_submission
    curl -s -X PUT \ "https://your-wordpress-site.com/wp-json/fswa/v1/schemas/webhook/22/trigger/gform_after_submission" \ -H "Authorization: Bearer <your-token>" \ -H "Content-Type: application/json" \ -d '{ "include_user_data": false, "field_mapping": { "mappings": [ {"source": "args.0.1", "target": "name"}, {"source": "args.0.2", "target": "email"}, {"source": "args.0.3", "target": "phone"}, {"source": "args.0.4", "target": "subject"}, {"source": "args.0.5", "target": "message"}, {"source": "args.0.form_id", "target": "form_id"} ], "excluded": ["args"], "includeUnmapped": true } }' | jq .field_mapping
    response — confirmed mapping
    { "mappings": [ { "source": "args.0.1", "target": "name" }, { "source": "args.0.2", "target": "email" }, { "source": "args.0.3", "target": "phone" }, { "source": "args.0.4", "target": "subject" }, { "source": "args.0.5", "target": "message" }, { "source": "args.0.form_id", "target": "form_id" } ], "excluded": ["args"], "includeUnmapped": true }

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.

/ Real-World Reliability

Why Your Gravity Forms Webhook
Needs Retry Support

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.

/ FAQ

Common questions

Gravity Forms has a Webhooks Add-On (paid, requires an Elite license) but no built-in webhook support in the base plugin. The free approach is to hook into the 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.
Hook into the 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.
Every field in a Gravity Forms form has a numeric ID assigned in the form builder. In the 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').
With a bare 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.
Yes, if you use a plugin with retry support. Flow Systems Webhook Actions retries failed deliveries automatically and also exposes a REST API endpoint (POST /wp-json/fswa/v1/logs/{id}/retry) that lets you replay any past submission — including successful ones.
Yes. 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.