How to Move Salesforce Marketing Cloud Engagement History Into HubSpot
Move SFMC opens, clicks and opt-outs into HubSpot: what data views keep, how custom events backdate history, a field map, and what to keep or archive.
On this page
- The retention clock starts before the migration does
- Move contacts and their opt-outs before anything else
- Why past sends will not show as HubSpot email activity
- Custom events put SFMC engagement on the HubSpot timeline
- Field mapping from SFMC data views to HubSpot
- Keep, summarize or archive each data type
- The limits to plan around in 2026
- A worked example (hypothetical)
- Who should own the pipeline
- Sources
To migrate engagement history from Salesforce Marketing Cloud to HubSpot, you bring it in as custom event data and contact properties, because HubSpot's documented email events cover marketing emails sent through a HubSpot account. The teams that lose the most history plan the contact move first and leave engagement for the end. By the time someone asks for last spring's clicks, Marketing Cloud has aged them out.
The order that keeps the most history: pull the data before it expires, carry suppressions across before any send, rebuild the useful signals as custom events, and archive the rest where an analyst can still query it.
The retention clock starts before the migration does
Salesforce Help says "Open data is retained for six months," with the same wording for clicks, bounces and complaints. The retention limits page on Salesforce Help lists data views at "the most recent 180 days of data" and applies that policy to all data views. It also says send and engagement data (send, open, bounce, click and unsubscribe events) is retained for 730 days beginning June 16, 2025, and that anything older "is inaccessible for all customers." For longer needs, Salesforce suggests automated data extracts stored outside Marketing Cloud Engagement.
Start a nightly automation the week the migration is approved. A SQL Query activity in Automation Studio appends the previous day's rows from _Sent, _Open, _Click, _Bounce, _Unsubscribe and _Complaint into data extensions you created (the retention page lists "No limit" for user-created data extensions), and an export drops the files into your warehouse. Query by date window, since Salesforce warns that "queries returning large datasets can take longer to process and can impact system performance."
Past 180 days, these six views will not help, and other export routes depend on your account. Confirm one with Salesforce before anyone promises two years of history.
Move contacts and their opt-outs before anything else
When you migrate contacts from Salesforce Marketing Cloud to HubSpot, suppression history matters more than engagement history. A contact who unsubscribed in SFMC and gets a HubSpot newsletter in week one is a consent problem and a deliverability problem at once.
The opt-out import in the HubSpot Knowledge Base takes a CSV with an Email column, and once it processes, "the Unsubscribed from all email property of all the contacts will be set to true." Addresses that are not already contacts "will not be added to your billable contact total or created as contacts"; HubSpot marks them ineligible to receive email instead. Unsubscribes who never became HubSpot contacts come across without adding to the bill.
We build that file from _Unsubscribe, _Complaint, hard bounces from _Bounce and the unsubscribed status in your SFMC subscriber records, then run it before the first HubSpot send. If your SubscriberKey is a CRM ID, build a key-to-email crosswalk now; every later step depends on it.
Why past sends will not show as HubSpot email activity
HubSpot Developers describes the Email Events API as "used to get information about events generated by marketing emails or email campaigns sent through a HubSpot account," and its documented endpoints read events. We found no documented endpoint for writing or importing marketing email events from another platform. In practice, HubSpot's marketing email reporting starts with your first HubSpot send.
An activity import is the nearest built-in alternative. The HubSpot Knowledge Base lists Email body and Email direction as required for email activities, and says that without an Activity date the values "are automatically set to the date and time of the import." Logging every past newsletter that way buries the timeline sales reps read, so we keep activity imports for one-to-one correspondence.
Custom events put SFMC engagement on the HubSpot timeline
You can import SFMC engagement history into HubSpot as custom events, and they show on the contact timeline. The custom events article in the HubSpot Knowledge Base says "Event occurrences will appear on the contact record timeline," that event data is available "in the custom report builder and attribution reports," and that workflows can use occurrences for enrollment and delays. Its spreadsheet route notes that "Event imports can only be used for events which have already occurred," which fits history well.
For volume, the current guide on HubSpot Developers documents POST /events/2026-09/send (the legacy v3 path is /events/v3/send) and a batch endpoint that "supports batches of 500." The occurredAt field takes an ISO 8601 string or a millisecond UNIX timestamp; leave it out and the event is stamped with the request time. We found no limit in that guide on how far back occurredAt can go. Contacts match by a custom matching ID, record ID, email or usertoken.
When occurrences share an ID within a year, HubSpot accepts the first and rejects the rest. Derive each uuid from JobID, SubscriberKey and EventDate, and a failed load can be resent in full.
Field mapping from SFMC data views to HubSpot
Field sizes and the time zone note below come from the _Click reference on Salesforce Help and HubSpot's custom events article.
| SFMC source | HubSpot destination | Notes |
|---|---|---|
| SubscriberKey | Contact match by email or record ID | Use the crosswalk for internal IDs |
| EventDate (_Open, _Click) | occurredAt | _Click EventDate is stored in Central Standard Time without daylight saving time; convert to UTC |
| JobID + SubscriberKey + EventDate | uuid | A resent row is rejected as a duplicate |
| JobID | Event property such as sfmc_job_id | Join to your send records for email name |
| URL (_Click) | Event property such as clicked_url | SFMC stores up to 900 characters; HubSpot URL properties take 1024 |
| LinkName (_Click) | Event property such as link_name | SFMC allows 1024 characters; other HubSpot event properties take 256, so truncate |
| IsUnique | Filter before loading | Unique events only cuts volume |
| _Unsubscribe, _Complaint, hard bounces | Opt-out import | Sets Unsubscribed from all email to true |
| _Sent | Contact property roll-up | SFMC send count in the export window |
Keep, summarize or archive each data type
The best practice for migrating email marketing data from SFMC to HubSpot is to decide per data type, before the export runs, what HubSpot must act on and what only an analyst will query.
| Data type | Decision | Where it goes |
|---|---|---|
| Unsubscribes and complaints | Keep | Opt-out import, before the first send |
| Hard bounces | Keep | Opt-out import |
| Clicks, last 180 days | Keep | One custom event per click |
| Opens | Summarize | Last SFMC open date and open count properties |
| Sends | Summarize | Send count per contact; raw rows to the warehouse |
| Journey, SMS and forward data | Archive | Warehouse only |
Clicks earn a custom event because the URL shows which offer someone cared about. Opens are the weaker signal, and summary properties work in lists like any contact field. Note where each archived file lives and which query made it; that provenance explains why a contact's history starts in a given month.
The limits to plan around in 2026
The limitations that matter when you preserve Salesforce Marketing Cloud email engagement history in HubSpot in 2026:
- SFMC: data views hold the most recent 180 days; send and engagement data is inaccessible after 730 days.
- HubSpot custom events: the knowledge base lists Professional and Enterprise editions of HubSpot's hubs; up to 50 properties per occurrence and 50-character property names.
- HubSpot event API: batches of 500, and up to 1250 requests per second on the send endpoint.
- Webhook events: HubSpot says you cannot view timeline activity on custom events created using webhooks, so load history by API or spreadsheet.
A worked example (hypothetical)
A B2B team with 150,000 SFMC contacts approves a HubSpot move on 1 September and plans the cutover for 1 December. All figures in this example are illustrative assumptions.
- The nightly job starts 2 September. With 180 days in the data views, the first pull reaches back to early March.
- The team counts 900,000 unique click rows. At 500 per batch, that is 1,800 batch calls.
- 6,200 unsubscribes and complaints plus 2,100 hard bounces go into one opt-out CSV in late November.
- Opens roll up into two contact properties that load with the contact import.
Exporting in cutover week would have started the history in early June. Scheduling the job on approval day bought three more months of clicks.
Who should own the pipeline
A scheduled data job with a clear spec suits automation with a person signing off on each load. If an AI agent runs it, apply the rules of any autonomous marketing workflow: a named owner, a dry run on a sample and approval before anything writes to live records. Our agentic AI automation team is a further resource here, and the AI ROI calculator weighs the build against a manual export. Our guide to marketing automation in the AI era covers how the landed data feeds triggers and nurture.
Sources
- Salesforce Help: Data Views
- Salesforce Help: Data Retention Limits and Guidelines
- Salesforce Help: Data View: Click
- HubSpot Developers: Email Events API overview
- HubSpot Developers: Send custom event occurrences
- HubSpot Knowledge Base: Create custom events
- HubSpot Knowledge Base: Import opted-out contacts
- HubSpot Knowledge Base: Format import files
