How a Drupal and Salesforce integration works and what it needs first
A Drupal and Salesforce integration is usually a contributed-module-based sync rather than a custom build, and the method this topic covers is the Salesforce Suite, a set of contributed Drupal modules that map Drupal data to Salesforce records. Your Drupal site collects user registrations, content and form submissions that sales and service teams need inside Salesforce, so the first decision is which of three data directions you need: users, content or submissions. User sync typically maps Drupal accounts to Salesforce contacts, content sync may relate pages or nodes to accounts or opportunities, and submission sync usually creates or updates contacts and opportunities from a form. Each direction has different identifiers, duplicate rules and owners, so treat them as separate mapping exercises rather than one generic sync.
Before scoping, confirm the exact Salesforce Suite module, its branch and its compatibility with your Drupal version on its Drupal.org project page only if your sign-in design also uses OpenID Connect; for the Salesforce modules themselves, check their Drupal.org project pages directly, because branches and supported Drupal versions change. Record which Salesforce objects, custom fields and API version each module expects, and which Drupal major version you run. Drupal 11 is the current major version, and the PHP requirement for your Drupal version should be checked against the hosting plan. Ask your Salesforce administrator for the org type, sandbox availability and whether a connected app for JWT authentication already exists, since those choices determine the first build steps.
Plan the ownership questions early: who owns the Salesforce field definitions, who approves changes to duplicate rules, and who receives alerts when a sync fails. Confirm whether the integration needs to run in both directions, because a one-way push is simpler to test and support than a two-way sync that can overwrite edits on either side. Identify the personal data that moves between systems, the consent basis for each field and whether any of it falls under your privacy obligations. Finally, ask for a written scope that lists the modules, objects, fields and environments, because that list is what a fixed-scope quote can price, and it is what your own team will use to judge whether a partner or internal staff should carry the work.
What you need in place before the Salesforce connection is configured
The Salesforce connection depends on decisions made before any module is installed. Confirm the Drupal version, the Salesforce org and its integration identity, the signing credentials, the network path and the people who own the data, because each one blocks the next step.
A supported Drupal core major
Confirm that your site runs a Drupal core major version that still receives security coverage. Check the Drupal core release schedule for the current dates, since Drupal 10 reaches end of life on December 9, 2026 and Drupal 12 is scheduled for the week of December 7, 2026. If you are still on Drupal 7, the Salesforce module work becomes part of a migration first, because Drupal 7 security support ended on January 5, 2025.
Salesforce org and integration user
Decide which Salesforce org receives the data and create a dedicated integration user with a profile limited to the objects and fields the sync needs. Avoid reusing a personal administrator account, because its permissions and password changes will break the sync without warning. Ask Salesforce which edition you hold and what API call limits apply to that org, since these vary by edition and license.
Connected App configured for JWT
Register a Connected App in the Salesforce org that accepts JWT bearer authentication, and assign the integration user to it through a permission set or profile. The app needs the consumer key it issues and the certificate you upload. Document who can change this app, because altering its OAuth scopes or policies silently changes what Drupal can read and write.
Certificate and private key under your control
Generate the key pair on infrastructure your team controls, store the private key where only the Drupal runtime can read it, and upload only the public certificate to Salesforce. Set a rotation date at the start, because an expired certificate stops authentication for every sync at once. Keep the key out of the Git repository and the Drupal database.
Outbound HTTPS to Salesforce
Confirm that the Drupal host can make outbound HTTPS calls to your Salesforce login and API hostnames, and that any egress proxy, firewall or allowlist permits them. Test from the same runtime that runs cron or queue workers, not only from an administrator's workstation. Blocked egress usually appears as intermittent timeouts, so verify it before troubleshooting field mappings.
A named data governance owner
Name one person who approves which Drupal fields map to Salesforce contacts, accounts and opportunities, and who answers for consent and retention of form submissions. This owner signs off on changes to the mapping and on any new object sync. Without this role, field drift between the two systems tends to surface only when a sales or service team reports wrong data.
Mapping Drupal users, content and submissions to Salesforce objects
This table lists the common Drupal sources, their Salesforce targets, the sync direction, the match key and the person who should own each rule. Read it as a starting point for the mapping workbook, not a finished design, because several rows depend on the module and Salesforce org you choose.
| Drupal source | Salesforce target | Direction | Match key and owner of the rule |
|---|---|---|---|
| User account (email, name, status) | Contact, linked to an Account | Both, with a defined winner per field | Email or an external ID agreed before go-live; identity owner decides |
| Profile field (job title, country, consent flags) | Contact fields and consent or preference fields | Push from Drupal, pull only for approved fields | Same key as the user account; marketing or privacy owner sets consent rules |
| Organization or company reference on a profile | Account | Push, with pull for account ownership | Account external ID or a normalized name; sales operations owns deduplication |
| Content type (for example, a partner or event page) | Custom object | Push, usually one way | Drupal node ID stored as an external ID; content owner defines which fields sync |
| Webform submission (lead or contact request) | Lead, Contact or Opportunity | Push at submission time | Email plus a submission ID; sales operations decides create versus update rules |
| Picklist-style values (industry, lead source, stage) | Picklist fields in Salesforce | Mapped in both directions | Explicit value table maintained by the business owner; unmapped values must fail visibly |
| Opportunity-related form data | Opportunity | Push, with stage changes pulled only if approved | Opportunity external ID or CRM record ID; sales owner approves stage rules |
| Module-specific objects or fields (confirm) | Standard or custom objects | Confirm per module | Confirm with the chosen contributed module's supported mappings before finalizing the rule |
Choosing push, pull and scheduled sync timing
Real-time push sends a record to Salesforce as soon as a user saves content or submits a form. It fits work where a delay causes real business harm, such as a lead from a contact form that a sales representative must see within minutes. The cost is one API call per event at peak traffic, plus the work of handling failures inline, because a user is waiting on the response.
- API consumption: each save or submission can trigger one or more calls, so bursts of traffic (a campaign launch, for example) scale API usage directly with visitor activity.
- User-facing latency: a synchronous call slows the save or submission unless it is moved to a queue after the user's request completes.
- Retry handling: Drupal must decide whether a failed push is retried, logged for review or shown to the user, and this decision needs an owner.
- Salesforce outage behavior: without a queue, submissions can fail or be lost during downtime, so queue-based push is the safer default for most forms.
- Duplicate risk: repeated saves can create duplicate records unless the integration uses an external ID or upsert logic.
Check with your Salesforce administrator which objects and fields your org's API usage reporting covers, and confirm the current API limits for your edition in Salesforce documentation before you size the push volume.
Scheduled batch sync collects changed Drupal records and sends them to Salesforce on a timer, either through Drupal cron or a queue worker run by the operating system scheduler. It suits data that does not need to be current to the minute, such as account hierarchies, content summaries or periodic donor and member reporting. Batching reduces the number of calls and lets you control the load on both systems.
- Change tracking: the sync needs a reliable way to find records changed since the last run, usually a changed timestamp or a dedicated queue table.
- Batch size and window: larger batches reduce calls but lengthen runs and increase the impact of a single failure, so the window should be agreed with both teams.
- Cron dependency: Drupal cron runs on page requests or on a schedule, so a long job can block other tasks unless it is moved to a dedicated worker.
- Partial failure handling: a batch should record which records succeeded so that a rerun does not resend everything.
- Recovery after outage: a batch that fails during a Salesforce outage should resume from its checkpoint rather than restart from the beginning.
Confirm the schedule and maximum batch size with your Salesforce administrator, and test a full run against a sandbox before enabling it on production data.
Pulling brings data from Salesforce into Drupal, for example to display account status, populate a directory or refresh a list of opportunities for an internal portal. The timing is set by how often Drupal requests the data, so it can be on demand, on a schedule or driven by notifications where Salesforce supports them for your configuration. Pull traffic is easy to overlook because read calls still count against API usage.
- Caching strategy: caching results in Drupal reduces repeated calls, but stale cached data must be acceptable to the people reading it.
- Query scope: pulling whole objects on every run is costly, so queries should filter by modified date and selected fields.
- Conflict with push: if the same field is written by both systems, pull can overwrite recent Drupal edits, so each field needs one owner.
- Behavior during outage: Drupal should show the last known data with a clear age indicator rather than an empty page.
- Access control: pulled records must respect Drupal roles, since Salesforce field-level security does not automatically apply inside Drupal.
Verify with your Salesforce administrator which user and permission set the integration uses for reads, and document the freshness the business expects for each pulled field.
Configuring the Salesforce connection in the right order
This sequence moves from Salesforce access and authentication to a tested, scheduled sync, so each layer is verified before the next one depends on it. Teams that follow it can isolate a failure to one object, one credential or one mapping.
Create the least-privilege integration user
In Salesforce, create a dedicated integration user with a profile or permission set that grants read and write access only to the objects and fields the sync needs, such as Contact, Account and Opportunity, and nothing else. Your Salesforce administrator should confirm field-level security for each field before any mapping is planned, and the user should not be a personal account. You know this step is done when the user can log in to the sandbox and view the chosen objects, and when a test query shows that fields outside the agreed list are not returned.
Create the Connected App and upload the certificate
Create a Connected App in Salesforce, enable OAuth settings, and select the JWT bearer flow with the integration user pre-authorized. Generate a private key and certificate pair on a server you control, store the private key in your secrets manager, and upload only the certificate to the Connected App. The check is that the Connected App saves with the certificate attached and that the consumer key is recorded in your configuration inventory, not in source control.
Install the Salesforce Suite module with Composer
Add the Salesforce Suite module and its dependencies to the Drupal codebase with Composer, commit the updated composer.json and composer.lock, and deploy through the same pipeline used for other code. Enable the module and its required submodules in a non-production environment with Drush. Confirm the installation by checking that the module status reports enabled without missing dependency errors and that the Salesforce configuration pages load for an administrator account.
Configure JWT credentials and test the token exchange
In the Drupal Salesforce configuration, enter the consumer key, the integration username, the Salesforce login URL for the sandbox, and the path to the private key file or the secret reference your environment provides. Save the configuration and run the authentication test from the admin interface. The step is complete when Salesforce returns a valid access token and the connection status shows the sandbox org identity. If the request fails, check the certificate fingerprint, the pre-authorization of the user and the login host before changing anything else.
Map fields for one object at a time
Start with a single object, usually Contact, and define each Drupal field to Salesforce field pair in a written mapping sheet agreed with the business owner. Record the data type, required status, the source of truth for each field and the handling of blank values. Add the mappings in Drupal, then add the next object only after the first one has passed testing. The check is a mapping review where each Salesforce field has one owner and one Drupal field, with no unmapped required fields.
Configure push or pull timing per object
For each object, decide whether Drupal pushes records to Salesforce, pulls records from Salesforce, or uses both directions, and document which system wins when both change. Configure the push or pull behavior on that object's mapping, and choose whether the sync runs on form submission, on cron or through a queue. The check is a written direction and timing table that the business owner has signed off, plus a test edit in each system that confirms the expected direction and nothing in the opposite direction.
Run a sandbox sync of a small test set
Create a small set of test records in the Salesforce sandbox, including edge cases such as missing email addresses, duplicate contacts and records with restricted fields, and run the sync manually for those records only. Review the Drupal logs and the Salesforce records for each case, and confirm that errors are reported with the record identifier and the Salesforce error code. The step is complete when every test record lands in the expected state and each failure produces a readable log entry that a support engineer can act on.
Enable scheduled processing after review
Only after the sandbox results are reviewed, enable the scheduled sync and queue processing in the target environment, starting with the objects that passed testing. Set up alerting on failed authentication and on growing error queues, and confirm the integration user's password or certificate rotation process is documented. The check is that the first scheduled run completes with the expected record counts and that the monitoring alert fires when a test credential is deliberately made invalid in a non-production environment.
Securing the JWT connection and the data it carries
A JWT connection is only as safe as the key that signs it and the data that flows through it. The cards below cover the controls that protect the signing key, the integration account, the fields that leave Drupal, the logs, and the patches that reach the Salesforce module and Drupal core.
Keep the private key out of reach
Store the private key file outside the web root so no browser or misconfigured web server can request it, and keep it out of version control so it never lands in a repository, a container image or a shared build artifact. Confirm the file permissions allow only the PHP process account to read it, and that backups of the site code do not silently copy the key to places with weaker access control. Rotate the key through a planned change, and record which Salesforce connected app trusts which public certificate.
Pull credentials from your secrets process
Consumer keys, usernames and any passphrases should come from your organization's secrets handling process, not from a settings form saved in the database or from a file committed to Git. Ask who can view and change these values in each environment, and whether the process supports rotation without a code release. Test the rotation path in a non-production environment before the first production change, because a key swap that breaks sign-in stops every sync at once.
Restrict the integration user
Give the Salesforce integration user a profile and permission set that allows only the objects and fields the sync reads or writes, such as Contact, Account and Opportunity fields named in the mapping. Remove API access that the integration does not need, and check whether the user can see records outside the sync scope through sharing rules or role hierarchy. Review the permission set after each change to the mapping, since a new field added to the Drupal side often needs a matching grant in Salesforce.
Limit which fields leave Drupal
Map only the Drupal fields a Salesforce process needs, and treat each mapped field as a decision about personal data. Check consent flags and retention rules before a form submission or user record is pushed, and decide whether records of people who withdrew consent are removed, flagged or left untouched in Salesforce. Ask your privacy team to confirm the lawful basis and retention period for each object, because the field list is where the data-protection obligations become concrete.
Keep personal data out of sync logs
Sync logs help engineers diagnose failed records, but a log line that repeats an email address, phone number or full payload turns the log store into another copy of personal data. Log record identifiers, object names, timestamps, HTTP status codes and error categories instead, and confirm that Salesforce error messages returned to Drupal are truncated or scrubbed before they are written. Set a retention period for the log store that matches your data policy, and restrict who can read it.
Track advisories for the module and core
The Drupal Security Team publishes advisories with CVE identifiers and risk scores for core and contributed projects, and releases security fixes on the third Wednesday of the month. Subscribe the team to advisories for the Salesforce module, its dependencies and Drupal core, and set a rule for how quickly a critical fix moves to staging and production. Confirm that the site can receive a security release without a full redesign, because a module that is pinned to an old version becomes a standing exposure.
Testing field mapping and sync behavior before go-live
Test the integration in a Salesforce sandbox loaded with data shaped like production before any go-live decision. Production-like means the same record types, the same picklist values, the same validation rules and the same volume of duplicate-prone contacts, not a handful of hand-typed records. Ask the Salesforce administrator to confirm which sandbox type matches the org's metadata and data needs, and confirm that the connected app and JWT certificate used in testing are separate from production credentials. Each mapped field needs its own test cases. Cover blank values (a blank Drupal field should not overwrite a populated Salesforce field unless the mapping says so), duplicate email addresses across Contact and Lead records, long text that exceeds the Salesforce field length, unpublished Drupal content that should never reach Salesforce, and multilingual field labels that must map to the same API field name regardless of language.
Test failure and retry deliberately. Disconnect the network or block the Salesforce API endpoint partway through a batch sync, then confirm what the queue or sync log records, whether partially written records are left behind, and whether the retry completes the batch without losing rows. Then run the same sync a second time with no source changes and confirm that no duplicate Contacts, Accounts or Opportunities were created. The check should compare record counts and external ID values before and after the rerun. If the mapping relies on an external ID field, confirm it is populated and unique in the sandbox before this test, because duplicate prevention depends on it.
Record the evidence in a form that can be reused. Each test run should note the Drupal version, the version of the contributed Salesforce module and any sync or connector module in use, the mapping version (the spreadsheet, configuration export or code commit that defines field pairs and sync direction), and the Salesforce org ID and sandbox name. Store the test results with those identifiers so that a later module upgrade or mapping change can be rerun and compared against the same cases. Confirm with your Drupal team who owns the mapping version and where the evidence is kept, because an upgrade review without this baseline usually means repeating the whole plan.
Common Drupal to Salesforce sync failures and their fixes
This table lists the failures most often seen when Drupal pushes or pulls data with Salesforce, the likely cause of each and the first fix to try. Start with the Drupal log and the Salesforce debug logs for the integration user, because most symptoms show an error there before they show a data problem. Treat each fix as a hypothesis to confirm in a staging org before changing production mappings or credentials.
| Symptom | Likely cause | Fix |
|---|---|---|
| JWT token request rejected with an invalid grant or audience error | The audience value does not match the Salesforce login host, the connected app is not configured for the certificate, or the signing key does not match the uploaded certificate | Confirm the audience and login URL for the target org type, re-upload the matching public certificate to the connected app, and check the private key and client ID in the Drupal configuration |
| JWT authentication succeeds but API calls return insufficient privileges | The integration user is not pre-authorized for the connected app, or its profile and permission sets do not grant access to the objects being synced | Pre-authorize the integration user on the connected app, then grant object and field access through a dedicated permission set and retest with the same user |
| Token suddenly stops working after a certificate renewal | The certificate in Drupal was rotated but the connected app still holds the old public certificate, or the new key pair was not deployed to every environment | Upload the new public certificate to the connected app, update the private key in each environment's secrets store, and clear caches before retesting |
| Record saves fail with a picklist or required field error | Drupal sends a value that is not an active picklist entry, a blank value for a required Salesforce field, or a value in a different language or label | Map Drupal values to Salesforce API names in a lookup table, add defaults for required fields, and review the field mapping after every change to picklist values |
| Duplicate contacts or accounts appear after sync | The match key is weak, such as name or a non-unique email, or the sync creates records instead of searching for existing ones first | Match on a unique external ID or a normalized email, run a search before create, and clean existing duplicates with a reviewed merge plan |
| Drupal submissions look saved but Salesforce has no new records | Queue workers or cron have stopped, so queued items wait without an error on the Salesforce side | Check queue size and the last cron run, confirm workers run under a supervisor, and alert when items age beyond an agreed threshold |
| Batch runs time out or return API limit errors | Large initial loads send too many calls in one window, or several jobs compete for the same daily API allocation | Split backfills into smaller batches, use bulk or composite endpoints where the design allows, schedule runs outside peak usage, and track remaining API limits in the Salesforce org |
| Fields stop syncing or values change shape after an upgrade | A Drupal core or contributed module update changed field handling, or a module was upgraded without updating the mapping configuration | Compare exported configuration before and after the upgrade, run the sync test suite on staging, and confirm the module release notes before rolling out |
Questions buyers ask before hiring help with a Salesforce integration
What drives the cost of a Drupal and Salesforce integration?
The main drivers are the number of Salesforce objects in scope (contacts, accounts, opportunities, and any custom objects), how many fields must map and how much transformation they need, how often data must move and how fast, how much custom logic sits between the two systems, and how many Salesforce orgs are involved. Each object and each mapping rule adds design, build and test work. Timing requirements add effort because near-real-time sync needs event handling and retry design, while a nightly batch is simpler. Ask any provider to price these drivers separately so you can see which choices move the total. A quote follows from the written scope.
How long does a Salesforce integration take to build?
Duration depends mostly on the same factors as cost: object count, mapping complexity, sync timing, custom business rules and the number of orgs. Discovery work, such as agreeing match keys and reviewing duplicate data in Salesforce, often takes longer than teams expect. Testing against real-looking records, error handling for rejected writes and a controlled cutover also add time. Ask for a schedule that separates discovery, build, testing and go-live so you can see where delays would enter. The agreed timeline should appear in the written scope rather than in a verbal estimate.
What do we need to provide for a Salesforce integration project?
You need to provide Salesforce admin access sufficient to create connected app or integration user configuration, and a named person who can approve field mappings and business rules. A data owner should decide which Drupal fields map to which Salesforce fields and who wins when both systems hold different values. A sandbox Salesforce org is needed for build and testing so production records are not affected. Your team must also decide match keys, such as email address or an external ID, and how consent status is recorded and passed between systems. Missing decisions in these areas are the most common cause of rework.
Can our internal team build a Salesforce integration without a partner?
Yes, if your team has Drupal developers who can write or configure custom code and at least one engineer who understands the Salesforce API, authentication and object model. The work becomes harder when the team has not yet run a production sync, because error handling, retries and data reconciliation are where most failures occur. Check whether your developers can maintain the code after the build, since the integration will need updates when Drupal or Salesforce changes. A partner is often used for the design, the first build or a review, while your team keeps ownership of the running system.
How should we scope a Salesforce integration in a fixed-scope agreement?
Write the scope as a list of objects, fields and mappings, the sync direction and timing for each, the authentication method, the error handling rules, the test environments and the acceptance criteria. Name what is excluded, such as historic data backfill, additional orgs or custom reporting. Include who signs off each deliverable and how change requests are priced. DeployOpen works on fixed-scope engagements, with scope, deliverables and timelines agreed in writing before work starts, and a quote follows from that written scope. Compare proposals by how clearly they state these items.
Does a Salesforce integration need ongoing support after go-live?
Most integrations need some ongoing attention. Salesforce releases, changes to custom fields by admins, Drupal core and contributed module updates, and certificate or credential rotation can all break a working sync. Monitoring of failed records, a process for reviewing rejected writes and a named owner for mapping changes reduce the time to recover. You can handle this in-house or arrange a support retainer, which DeployOpen offers for ongoing support and upgrades. Decide before go-live who owns each of these tasks, because unowned integrations tend to drift.
How do we check that a Salesforce sync is working correctly?
Verify the sync with test cases that cover create, update and delete paths for each object, plus deliberately invalid records that should fail in a controlled way. Compare record counts and sample field values between Drupal and Salesforce after each run. Confirm that failed records are logged, retried according to your rules and surfaced to an owner. Check authentication behavior by testing token expiry and revoked access. Ask any provider to show the test plan and the reconciliation report format before accepting the work.
How DeployOpen scopes, builds and supports the Salesforce integration
DeployOpen plans, implements, customizes, integrates, documents and supports self-hosted open-source platforms inside your own infrastructure, so the Drupal and Salesforce integration runs in your cloud accounts or data centers. Engagements are usually fixed-scope, with the scope, deliverables and timelines agreed in writing before work starts.
How we scope
- Map which Drupal entities (users, content types, Webform submissions) correspond to which Salesforce objects in your org.
- Agree field mapping, direction of each sync and the source of truth for every shared field in writing.
- Confirm Salesforce edition, API access, sandbox availability and the connected app setup needed for JWT authentication.
How we build
- Configure JWT authentication with a dedicated integration user and least-privilege permissions in both a sandbox and production.
- Build and test push and pull timing, including queue handling, retries and duplicate detection, against sandbox data.
- Test error paths such as expired certificates, locked records and validation rule failures, with logging that a support team can read.
How we hand over
- Deliver a written field mapping, sync schedule, credential rotation procedure and error runbook for your operations team.
- Provide configuration exported from Drupal and the Salesforce setup notes so changes can be reviewed and reproduced.
- Walk your administrators through monitoring, reprocessing failed records and the steps for adding a new mapped field.
How we support
- Ongoing support, Drupal and contributed module upgrades and continuous testing are available as retainers.
- Re-test the integration when Drupal core, the Salesforce API version or the contributed modules change.
- Confirm with your Salesforce administrator which API and licensing limits apply to your org before setting sync volumes.

