Connect HubSpot to Salesforce
Keep marketing's system and sales's system in step: qualified contacts and companies flow from HubSpot into Salesforce, pipeline and owner changes flow back, and each field has a defined source of truth so neither side overwrites the other. Every record change is an ordered run you can inspect and replay.
Why teams connect HubSpot and Salesforce
Marketing runs in HubSpot, sales runs in Salesforce, and the two need the same picture of a contact, a company, and a deal. HubSpot's own Salesforce sync covers the basics, but many teams outgrow it: they need field-level control over who wins, dedup logic that matches their data, custom object coverage, and a record of what the sync did.
- Each field has a defined source of truth, so a rep editing a title in Salesforce is not overwritten by a stale HubSpot value, and vice versa
- New contacts are matched, not duplicated: email first, then the stored cross-system IDs, then an optional name-and-company check
- Custom objects and custom fields on both sides are in scope, not just the standard object set
- Every record sync is an ordered run log, so a contact that looks wrong can be traced to the exact sync and field that wrote it
Worked example
The lead handoff flow most teams turn on first.
HubSpot SQL to a Salesforce Lead, and Salesforce status back to HubSpot
Triggered when a HubSpot contact reaches Sales Qualified Lead, with dedup against existing Salesforce records and a field-level merge on the way back.
- Trigger: HubSpot
Deal stage changedis not used here; insteadContact property changedwherelifecyclestage = salesqualifiedlead. - Fetch: the change trigger carries the changed property only, so
Get recordpulls the full contact and its associated company. - Dedup: search Salesforce for a
ContactbyEmail, then aLeadbyEmail, then aLeadmatchingLastNameplusCompany. Use the first match. - Resolve owner: a data table maps the HubSpot owner's email to a Salesforce
User.Id. If the contact has no owner, assign by territory rules. - Write: upsert the Salesforce
Lead, keyed on the storedHubspot_Contact_Id__c, mapping the fields below. Company defaults to[Self-sourced]if the HubSpot company is blank, because Lead requires it. - Stamp both sides: write the Salesforce
Lead.Idto the HubSpot propertysalesforce_lead_id, and the HubSpoths_object_idtoLead.Hubspot_Contact_Id__c. - Reverse: a second flow listens for Salesforce
LeadandContactchanges and updates HubSpot, but only the fields where Salesforce is the source of truth (lead status, owner, opportunity stage).
Field mapping
The starting map for the HubSpot contact to Salesforce Lead step. The source-of-truth column is the rule the reverse flow reads.
| HubSpot property | Salesforce field | Source of truth / notes |
|---|---|---|
email | Email | Primary match key. Lowercased on write. Not unique in HubSpot, so cross-IDs back it up. |
hs_object_id | Hubspot_Contact_Id__c | Reverse match key. Custom field on Lead and Contact. |
salesforce_lead_id | Id | Idempotency key. Written back to HubSpot after the first create. |
firstname, lastname | FirstName, LastName | HubSpot source. Reverse only if blank in HubSpot. |
company | Company | Override. Lead requires a value; default to [Self-sourced] when blank. |
jobtitle | Title | Salesforce source once a rep owns the lead. HubSpot source before that. |
hubspot_owner_id | OwnerId | Resolved through an owner-map table. IDs do not match across systems. |
hs_analytics_source | LeadSource | Enum, mapped through a lookup. HubSpot source, never overwritten. |
lifecyclestage | Status (derived) | Drives the object choice and the initial status, not a direct field copy. |
createdate | , | Epoch milliseconds in HubSpot. Not written to Salesforce, which sets its own CreatedDate. |
What syncs, each direction
- Qualified people and companies. Contacts at a chosen lifecycle stage become Leads or Contacts. Associated companies become Accounts, matched on domain. (HubSpot to Salesforce)
- Marketing context. Original source, first and last touch campaign, and email engagement land as fields or campaign members for attribution in Salesforce. (HubSpot to Salesforce)
- Pipeline and ownership. Lead status, opportunity stage and amount, owner changes, and closed-won flow back and set the HubSpot lifecycle stage and deal. (Salesforce to HubSpot)
- Consent and do-not-contact. An email opt-out or a do-not-contact flag set on either side propagates to the other immediately, whichever system it originated in. (Either direction)
Governance and audit
The same controls apply to this sync as to every other Neblex workload.
- Ordered run log. Every record sync is an event log with the before and after of each field. Replay a run without re-firing the create in the other system.
- Approval steps. Pause for review on a bulk change, a mapping change's first run, or a merge that would collapse two Salesforce records into one.
- Scoped access. HubSpot uses a private app token with only the needed scopes. Salesforce uses a connected app and a permission set limited to the synced objects.
- Environments. Build against a HubSpot test account and a Salesforce sandbox, then promote the same flow and mapping to production.
Frequently asked questions
Is this prompt or batched?
Close to it. Changes on either side are picked up by the polled change triggers on the schedule you set, from every minute upward, and a scheduled reconcile catches anything a poll missed.
How are conflicts resolved when both sides change a field?
By a source-of-truth rule per field, which you set in the mapping. Where both sides can legitimately edit a field, the rule is last-write-wins with the run log showing which side wrote it.
How are duplicates prevented?
Matching runs email first, then the stored cross-system IDs on both records, then an optional name-and-company check. The write is keyed on the stored ID, so a retry updates rather than creates.
Does this replace HubSpot's native Salesforce sync?
It can. HubSpot's native sync is a reasonable choice for a simple standard-object sync. Teams move to this for field-level control, custom objects, dedup they define, and one run log across every integration, not just this one.
Are custom objects supported?
Yes. Salesforce custom objects, and HubSpot custom objects on Enterprise tiers, are mapped the same way as standard objects.
Does anything get installed in Salesforce?
No. The connector uses the Salesforce REST and Bulk APIs through a connected app. No managed package or Apex is deployed.
Connectors on this page
HubSpot
CRM
- Operations
- 336
- Typed outputs
- 81.5%
- Change triggers
- 48 (poll)
- Authentication
- Bearer
Salesforce
CRM
- Operations
- 1,296
- Typed outputs
- 57.9%
- Change triggers
- 95 (poll)
- Authentication
- OAuth2
Bring one real integration
We will build it with you against your own systems, with the run log open.