TL;DR
gform_after_update_entryfires after an existing entry is edited in wp-admin or updated viaGFAPI::update_entry()- Three parameters:
$form,$entry_id,$original_entry(pre-update state, GF 2.4+) - Retrieve the current entry with
GFAPI::get_entry($entry_id)— the hook does not pass the updated entry directly - Webhook Actions handles update-triggered delivery natively — no custom PHP needed
/ What is gform_after_update_entry
What is gform_after_update_entry and when does it fire?
gform_after_update_entry is a Gravity Forms action hook that fires immediately after an existing form entry has been saved with new values. It covers three update paths: editing an entry in the wp-admin entry editor, updating via the GFAPI::update_entry() method from custom code, and updates triggered by Gravity Forms add-ons (such as User Registration or Feed add-ons that update entry data post-submission).
What it does not cover: new submissions. An entry created by a visitor submitting a form triggers gform_after_submission, not gform_after_update_entry. The two hooks are complementary — one fires on create, the other on update. Use both if you need to keep a downstream system fully in sync with all Gravity Forms entry state changes.
Visitor submits form
│
▼
Entry created in DB
│
▼
gform_after_submission ◄─ new-entry webhook here
│
│ (later — admin edits entry or GFAPI::update_entry)
▼
Entry saved with new values in DB
│
▼
gform_after_update_entry ◄─ update webhook here
│ params: $form, $entry_id, $original_entry
▼
Downstream system receives update payload / Submission vs update
How does gform_after_update_entry differ from gform_after_submission?
gform_after_submission fires once, when a visitor submits the form and a new entry row is created. gform_after_update_entry fires every time an existing entry is subsequently modified — which means it can fire many times for the same entry ID over its lifetime.
The distinction matters for downstream integrations. A CRM contact created from gform_after_submission might need to be updated when an entry is later edited: the order status changes, a support agent adds a note, or an admin corrects a typo in the email field. Those updates arrive via gform_after_update_entry. Without a webhook on this hook, your CRM retains the original submission data even when the Gravity Forms entry has changed.
A third hook, gform_post_update_entry, is an alias used by GFAPI internals — prefer gform_after_update_entry for external integrations, as it is the documented public hook.
/ Parameters
What parameters does gform_after_update_entry pass?
The hook passes three arguments to your callback. Register with add_action( 'gform_after_update_entry', $callback, 10, 3 ) to receive all three:
- $form — the full Gravity Forms form array, including field definitions, confirmations, notifications, and settings. Use
$form['id']for the form ID and$form['fields']to iterate over field metadata. - $entry_id — the integer ID of the entry that was just updated. The entry itself is not passed directly; retrieve it with
GFAPI::get_entry($entry_id). - $original_entry — the entry array as it existed before the update, available since Gravity Forms 2.4. Use this to build diff payloads or to skip the webhook when only irrelevant fields changed.
PHP — hook registration with all three parameters
add_action( 'gform_after_update_entry', function( $form, $entry_id, $original_entry ) { // $form — full form array // $entry_id — integer entry ID // $original_entry — entry values before the update }, 10, 3 ); // ← priority, accepted_args — must pass 3
/ Reading updated values
How do you read the original and updated entry values?
The hook gives you the pre-update state via $original_entry. To read the post-update state, call GFAPI::get_entry($entry_id). Field values are keyed by field ID as a string — $entry['1'] for field ID 1, $entry['2'] for field ID 2. Use $form['fields'] to find field IDs and labels.
PHP — reading original vs updated entry values
add_action( 'gform_after_update_entry', function( $form, $entry_id, $original_entry ) { // Retrieve the current (updated) entry $updated_entry = GFAPI::get_entry( $entry_id ); if ( is_wp_error( $updated_entry ) ) { return; } // Compare a specific field (field ID 3 = status in this example) $old_status = $original_entry['3'] ?? ''; $new_status = $updated_entry['3'] ?? ''; // Skip webhook if the status field did not change if ( $old_status === $new_status ) { return; } $payload = [ 'form_id' => $form['id'], 'entry_id' => $entry_id, 'old_status' => $old_status, 'new_status' => $new_status, 'entry' => $updated_entry, ]; wp_remote_post( 'https://your-endpoint.com/webhook', [ 'headers' => [ 'Content-Type' => 'application/json' ], 'body' => wp_json_encode( $payload ), 'timeout' => 5, 'data_format' => 'body', ] ); }, 10, 3 );
/ Use cases
What are the common use cases for entry-update webhooks?
Entry-update webhooks enable a class of integrations that new-submission webhooks cannot cover on their own. The most frequent patterns in production:
- CRM status sync. A sales team updates the entry status field (e.g. "Qualified" → "Closed") in wp-admin. The update webhook fires and pushes the new deal stage to HubSpot, Salesforce, or Pipedrive without the team needing access to the CRM directly.
- Order or ticket lifecycle tracking. Service businesses use Gravity Forms as a lightweight order management tool. Status changes to "In Progress", "Awaiting Parts", or "Completed" trigger webhooks that update job boards or send notifications to n8n workflows.
- Data correction propagation. When an admin corrects a typo — wrong email, misspelled name, incorrect address — the update webhook propagates the fix to downstream systems without a manual re-sync.
- Add-on triggered updates. Gravity Forms add-ons (User Registration, Stripe, GravityView) can update entry values programmatically via GFAPI.
gform_after_update_entryfires on these programmatic updates too, enabling event-driven automation even for machine-generated changes.
/ Webhook Actions
How does Webhook Actions handle update-triggered delivery?
The Webhook Actions plugin listens for Gravity Forms entry updates as a native trigger. Select "Gravity Forms — Entry Updated" from the trigger picker, choose the form, and configure the webhook endpoint — no PHP required. The plugin dispatches deliveries asynchronously: the update response in wp-admin returns immediately while delivery happens in a background queue cycle.
Delivery logs track every attempt: HTTP status code, response body, timestamp, and retry count. Failed deliveries retry automatically with exponential backoff (1 min → 2 min → 4 min → 8 min, capped at 1 hour, default 5 attempts). You can replay any failed delivery from the Logs screen.
Entry-update webhooks close the sync gap that new-submission webhooks leave open — they're the difference between a CRM snapshot and a CRM mirror.
| Capability | Raw gform_after_update_entry + wp_remote_post | Webhook Actions |
|---|---|---|
| Setup | Custom PHP — hook registration, payload construction | Admin UI trigger picker — no code |
| Delivery | Synchronous — blocks admin save response | Async queue — admin save returns immediately |
| Retry | None | Exponential backoff, up to 5 attempts |
| Logs | None — failures are invisible | Per-attempt log with HTTP status and response body |
| Replay | Not possible without custom tooling | One-click replay from the Logs screen |
| Deduplication | Manual — requires field-diff logic in PHP | Queue deduplication handled by the plugin |
/ Deduplication
How do you prevent duplicate webhooks on rapid successive updates?
Rapid successive updates are a real pattern: an automated workflow may update the same entry four times in a loop, or two admin users may save the same entry within seconds of each other. Without deduplication, your downstream system receives multiple payloads for a single logical change.
The field-diff approach shown in the code example above — comparing $original_entry['3'] to $updated_entry['3'] and returning early if unchanged — is the most common manual solution. Only send the webhook when a field that matters to your integration actually changed. For updates that involve multiple fields, compare a hash of the relevant subset: md5(serialize(array_intersect_key($updated_entry, $watched_fields))) against the same hash from $original_entry.
At the delivery level, include the entry ID and a hash of the payload in a transient with a short TTL (30–60 seconds). If an identical delivery arrives within the TTL, skip it. This catches duplicate hook invocations that would produce identical payloads even with field diffing. The gform_after_submission webhook guide covers additional Gravity Forms webhook patterns that complement the update flow.
get_entry, update_entry, and all public API methods.