WP Webhooks / Blog / Integrations

Sending Gravity Forms Entries to Salesforce as Leads

Gravity Forms Salesforce integration explained: what the official Elite add-on does, and how gform_after_submission sends leads on any licence.

8 min 2026-08-30
#gravityforms#salesforce#integrations

TL;DR: Gravity Forms has an official Salesforce add-on. It is good, and it is Elite-only — which is the whole reason this question gets asked.

  • The Salesforce Add-On ships with the Elite licence ($259/year). Basic ($59) and Pro ($159) do not include it.
  • The Webhooks Add-On is also Elite-only, so "just use a webhook feed" is not the cheaper answer people assume.
  • gform_after_submission is part of Gravity Forms core and works on every licence, Basic included.
  • Send a Lead unless you have a reason not to — it is the object Salesforce designed for inbound strangers.
  • Whatever route you take, the entry must reach Salesforce after the visitor gets their confirmation, not during it.

/ Licence

Does Gravity Forms have an official Salesforce integration?

Yes, and it is worth taking seriously before reaching for code. Gravity Forms released a Salesforce Add-On in April 2026. It creates and updates leads, contacts, accounts and other Salesforce objects from a form feed, supports conditional logic so entries only sync when criteria are met, and — the part that matters most in practice — it detects duplicates and updates existing records instead of creating new ones.

That is a genuinely well-scoped integration, and if you hold an Elite licence there is no argument for writing this yourself. Configuring a feed takes minutes; the equivalent code takes a week and then needs maintaining.

The catch is the licence tier. Both add-ons people reach for here sit at the top of the range:

LicencePrice / yearSalesforce Add-OnWebhooks Add-Ongform_after_submission
Basic$59NoNoYes
Pro$159NoNoYes
Elite$259YesYesYes

The last column is the one that changes the decision. gform_after_submission is not an add-on — it is a hook inside Gravity Forms itself, available on every licence including the $59 Basic tier. So the real choice is not "pay for Elite or go without", it is "pay $200 more per year for a configuration UI, or spend an afternoon on the hook".

Worth being honest about which way that decision usually goes. If you run one site and value your afternoons, Elite is the better buy. If you run twenty client sites on Basic licences, or you already have delivery infrastructure, paying twenty times for a feed UI you would use once per site is harder to justify.

FIG 03 — The three routes from a form entry to a Salesforce lead

/ Object

Should a form entry become a Lead or a Contact?

A Lead, in almost every case. Salesforce's object model draws a deliberate line: a Lead is an unqualified person who has expressed interest and has not yet been vetted, while a Contact is a person attached to an Account you already do business with. A website form produces the former by definition — you have a name and an email address from someone you have never spoken to.

Writing form submissions straight into Contacts skips the qualification step the CRM exists to manage, and it tends to annoy the people who own the Salesforce org rather more than it helps them. Leads can be converted into a Contact, an Account and an Opportunity in one operation once someone qualifies them, and that conversion is a workflow the sales team already has.

The Lead object requires LastName and Company. That second one bites on consumer-facing forms that never ask for a company — the create fails with a validation error until you either add the field to the form or supply a documented placeholder. Decide which before you ship, because discovering it through failed deliveries is a poor use of a Friday.

Cyberpunk illustration: an augmented courier crouched at an open service hatch in the plinth of a huge sealed toll arch, reaching into a plain lit maintenance corridor that runs on past the shutter the arch will not lift.

/ Auth

How does the entry authenticate against Salesforce?

Through the OAuth 2.0 client credentials flow — the server-to-server flow, where your site exchanges a consumer key and secret for a short-lived access token, and the token response also tells you the instance_url every later call must use. The full setup, including the External Client App configuration and the version-discovery endpoint, is covered in the WordPress to Salesforce integration guide; the short version is that there is no per-user login involved and no refresh token to manage.

What is specific to forms is idempotency. A form can be submitted twice by an impatient visitor, and a queued delivery can be retried after a timeout that actually succeeded. Both produce a duplicate Lead unless the write is an upsert keyed on something you control:

PHP — upserting a Lead keyed on an external ID

// Entry ID is a natural external key: unique, stable, already yours.
$external_id = 'gf-' . $entry['id'];

$url = trailingslashit( $instance_url )
     . 'services/data/v64.0/sobjects/Lead/GF_Entry_Id__c/'
     . rawurlencode( $external_id );

$res = wp_remote_request( $url, [
    'method'  => 'PATCH',
    'timeout' => 15,
    'headers' => [
        'Authorization' => 'Bearer ' . $token,
        'Content-Type'  => 'application/json',
    ],
    'body' => wp_json_encode( [
        'LastName' => rgar( $entry, '1.6' ),
        'FirstName' => rgar( $entry, '1.3' ),
        'Email'    => rgar( $entry, '3' ),
        // Required on Lead. Supply a placeholder if the form has no company field.
        'Company'  => rgar( $entry, '5' ) ?: '[not provided]',
        'LeadSource' => 'Web',
    ] ),
] );

$code = wp_remote_retrieve_response_code( $res );
// 201 = Lead created. 204 = existing Lead updated, EMPTY BODY.
if ( 204 === $code ) {
    return true; // do not json_decode this — there is nothing to decode
}

The GF_Entry_Id__c field is a custom field on Lead, marked External ID and Unique in Salesforce Setup. Creating it is a two-minute job and it converts every retry in the system from a risk into a no-op. Note the 204 handling: a successful update returns an empty body, so any code that decodes JSON unconditionally will throw on the path where everything worked.

The visitor's confirmation page must not depend on Salesforce being awake. Once you accept that, every other decision — queue, retry, external ID — follows. — the design rule for form-to-CRM delivery

/ Timing

Why should the Salesforce call not run during the submission?

Because gform_after_submission runs inside the request the visitor is still waiting on. The entry is already saved by that point, so the data is safe — but the confirmation page does not render until your callback returns, and a callback that calls Salesforce inherits Salesforce's latency and its outages.

With a 15-second timeout on the token call and another on the upsert, a bad afternoon at Salesforce turns into a 30-second wait on a contact form, and PHP-FPM workers stack up behind every submission. Visitors who assume the form is broken submit again, which doubles the load at exactly the wrong moment — and produces the duplicate Leads the external ID above is there to absorb.

Queue it. Record what needs sending, return immediately, and let a background worker own the delivery. A Salesforce outage should delay data by minutes, not break the form.

The retry policy follows the same distinction as any API integration, and the failure modes are worth naming precisely:

  • 5xx, 429, connection timeout → retry with backoff. The request was fine; the moment was not.
  • 400 validation error (missing Company, bad picklist value) → do not retry. It will fail identically forever.
  • 401 → fetch a fresh token, replay once, then stop.
  • 403 REQUEST_LIMIT_EXCEEDED → the org's shared daily allowance is gone. Back off hard; this is not your integration's budget alone.
ConcernOfficial Salesforce Add-On (Elite)Webhook Actions
Field mapping UIPurpose-built feed with a picker for Salesforce objects and fields — clearly better hereGeneric field mapping; you supply the endpoint and the JSON shape yourself
Licence requiredGravity Forms Elite, $259/yearWorks on any Gravity Forms licence, Basic included
ScopeGravity Forms entries onlyAny WordPress or WooCommerce hook, not just forms
Retry on 5xx / 429Handled by the add-onExponential backoff, 5 attempts by default
Per-attempt delivery logFeed processing is logged by Gravity FormsRequest, response and status per attempt, with replay
Credential storageManaged by the add-onEncrypted vault for static secrets; the OAuth exchange that mints the token stays yours

Read that table honestly and the split is clear. On a single Elite site, the official add-on wins on the thing you will touch most — mapping fields without writing JSON. The webhook route wins on licence cost across many sites, and on scope, because the same delivery layer also carries WooCommerce orders, user registrations and anything else that fires a hook. Neither removes the need to understand the Lead object or the API limits.

If your destination is HubSpot instead, the Gravity Forms to HubSpot walkthrough covers the equivalent path with a very different rate-limit model. And if entries are reaching neither CRM with no visible error, why webhooks fail silently in production is the place to start.

try_it

Seeing it run beats reading about it. The live preview boots a throwaway WordPress with Webhook Actions already installed and demo deliveries sitting in the log — no signup, nothing left on your machine afterwards.

/Footnotes
¹ Salesforce Add-On features and licence requirement, Gravity Forms.
² Licence tiers and add-on availability, Gravity Forms pricing.
³ gform_after_submission signature, Gravity Forms documentation.
sObject Rows by External ID upsert semantics, Salesforce REST API Developer Guide.
FAQ

Things engineers always ask.

Don't see yours? Open an issue on GitHub or check the full reference in the API docs.

Does Gravity Forms have an official Salesforce add-on? +
Yes. Gravity Forms released a Salesforce Add-On in April 2026 that creates and updates leads, contacts, accounts and other objects from a form feed, with conditional logic and duplicate detection. It is bundled with the Elite licence at $259 per year and is not included in the Basic or Pro tiers.
Can I send Gravity Forms entries to Salesforce without the Elite licence? +
Yes. The gform_after_submission hook is part of Gravity Forms itself rather than an add-on, so it is available on every licence including Basic. You supply the Salesforce authentication, the field mapping and the delivery, either in code or through a plugin that already owns the queue and retry logic.
Should a Gravity Forms entry create a Lead or a Contact in Salesforce? +
A Lead in almost every case. Salesforce treats a Lead as an unqualified person who has expressed interest and a Contact as someone attached to an existing Account. A website form produces the former by definition. Leads can be converted to a Contact, Account and Opportunity once qualified.
How do I stop duplicate leads when a form is submitted twice? +
Upsert on an external ID rather than creating. Add a custom field on Lead marked External ID and Unique, populate it with the Gravity Forms entry ID, and PATCH to the sObject Rows by External ID resource. Salesforce returns 201 when it inserted and 204 when it updated, so a repeated delivery is harmless.
Why should the Salesforce call not run inside gform_after_submission? +
Because that hook runs inside the request the visitor is still waiting on. Calling Salesforce inline makes the confirmation page wait for the API, so a slow or unavailable Salesforce becomes a slow or broken form. Queue the delivery and let a background worker send it.
Ready

Your next automation is
one sentence away.

$ wp plugin install flowsystems-webhook-actions --activate