---
title: "Gravity Forms to Salesforce Without an Elite Licence"
description: "Gravity Forms Salesforce integration explained: what the official Elite add-on does, and how gform_after_submission sends leads on any licence."
url: "https://wpwebhooks.org/blog/gravity-forms-salesforce-integration/"
date: "2026-08-30"
---

# Gravity Forms to Salesforce Without an Elite Licence

**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](https://www.gravityforms.com/integrations/salesforce/) 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:

| Licence | Price / year | Salesforce Add-On | Webhooks Add-On | gform\_after\_submission |
| --- | --- | --- | --- | --- |
| Basic | $59 | No | No | Yes |
| Pro | $159 | No | No | Yes |
| Elite | $259 | Yes | Yes | Yes |

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.](https://wpwebhooks.org/blog/gravity-forms-salesforce-integration/og_image.jpg)

/ 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](https://wpwebhooks.org/blog/wordpress-salesforce-integration/); 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.

| Concern | Official Salesforce Add-On (Elite) | Webhook Actions |
| --- | --- | --- |
| Field mapping UI | Purpose-built feed with a picker for Salesforce objects and fields — clearly better here | Generic field mapping; you supply the endpoint and the JSON shape yourself |
| Licence required | Gravity Forms Elite, $259/year | Works on any Gravity Forms licence, Basic included |
| Scope | Gravity Forms entries only | Any WordPress or WooCommerce hook, not just forms |
| Retry on 5xx / 429 | Handled by the add-on | Exponential backoff, 5 attempts by default |
| Per-attempt delivery log | Feed processing is logged by Gravity Forms | Request, response and status per attempt, with replay |
| Credential storage | Managed by the add-on | Encrypted 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](https://wpwebhooks.org/blog/gravity-forms-hubspot-integration/) 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](https://wpwebhooks.org/blog/why-wordpress-webhooks-silently-fail-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.

[Try the live preview →](https://playground.wordpress.net/?blueprint-url=https://wpwebhooks.org/blueprint.json) [Install plugin](https://downloads.wordpress.org/plugin/flowsystems-webhook-actions.zip)

/Footnotes

¹ Salesforce Add-On features and licence requirement, [Gravity Forms](https://www.gravityforms.com/integrations/salesforce/).

² Licence tiers and add-on availability, [Gravity Forms pricing](https://www.gravityforms.com/pricing/).

³ gform\_after\_submission signature, [Gravity Forms documentation](https://docs.gravityforms.com/gform_after_submission/).

⁴ sObject Rows by External ID upsert semantics, [Salesforce REST API Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_sobject_upsert.htm).

## Structured data

```json
{"@context":"https://schema.org","@type":"Article","headline":"Gravity Forms to Salesforce Without an Elite Licence","description":"Gravity Forms Salesforce integration explained: what the official Elite add-on does, and how gform_after_submission sends leads on any licence.","datePublished":"2026-08-30","dateModified":"2026-08-30","author":{"@type":"Person","name":"Mateusz Skorupa","url":"https://wpwebhooks.org/about/"},"publisher":{"@type":"Organization","name":"WP Webhooks","url":"https://wpwebhooks.org"},"url":"https://wpwebhooks.org/blog/gravity-forms-salesforce-integration/","image":{"@type":"ImageObject","url":"https://wpwebhooks.org/blog/gravity-forms-salesforce-integration/og_image.jpg","width":1200,"height":630,"caption":"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."},"keywords":["gravity forms salesforce","gravity forms salesforce integration","gravity forms to salesforce","gravity forms salesforce lead","gravity forms crm integration"]}

{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"WP Webhooks","item":"https://wpwebhooks.org/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://wpwebhooks.org/blog/"},{"@type":"ListItem","position":3,"name":"Gravity Forms to Salesforce Without an Elite Licence","item":"https://wpwebhooks.org/blog/gravity-forms-salesforce-integration/"}]}

{"@context":"https://schema.org","@type":"FAQPage","mainEntity":[{"@type":"Question","name":"Does Gravity Forms have an official Salesforce add-on?","acceptedAnswer":{"@type":"Answer","text":"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."}},{"@type":"Question","name":"Can I send Gravity Forms entries to Salesforce without the Elite licence?","acceptedAnswer":{"@type":"Answer","text":"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."}},{"@type":"Question","name":"Should a Gravity Forms entry create a Lead or a Contact in Salesforce?","acceptedAnswer":{"@type":"Answer","text":"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."}},{"@type":"Question","name":"How do I stop duplicate leads when a form is submitted twice?","acceptedAnswer":{"@type":"Answer","text":"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."}},{"@type":"Question","name":"Why should the Salesforce call not run inside gform_after_submission?","acceptedAnswer":{"@type":"Answer","text":"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."}}]}

{"@context":"https://schema.org","@type":"ImageObject","contentUrl":"https://wpwebhooks.org/diagrams/gravity-forms-salesforce.png","caption":"FIG 03 — The three routes from a form entry to a Salesforce lead","description":"A Gravity Forms entry can reach Salesforce three ways, and the licence tier decides which are open. The official Salesforce add-on is the least work and is bundled only with the Elite licence, so it is unavailable on Basic and Pro. The Webhooks add-on posts the entry to any endpoint but is also an Elite add-on, which surprises people who assume webhooks are a core feature. On any licence, the gform_after_submission hook is available for free, because it is part of Gravity Forms itself rather than an add-on. That route needs an OAuth token, field mapping and a retry story built by hand, or a plugin that already owns the queue and the delivery log.","encodingFormat":"image/png","creator":{"@type":"Organization","name":"WP Webhooks","url":"https://wpwebhooks.org/"},"copyrightHolder":{"@type":"Organization","name":"Flow Systems","url":"https://flowsystems.pl/"},"copyrightNotice":"© Flow Systems","creditText":"WP Webhooks","license":"https://creativecommons.org/licenses/by/4.0/","acquireLicensePage":"https://wpwebhooks.org/image-license/"}
```
