Overview
This guide shows how to track property changes in HubSpot—specifically how to store and view both the current and previous email address on a contact record. It covers three approaches depending on your HubSpot subscription and tools.
Option 1: Native HubSpot Property Change Tracking (Pro+)
If you have HubSpot Pro or Enterprise, you can track property changes using custom events.
Steps
- Go to Data Management → Events.
- Create a Custom Event.
- Select Track Object Changes.
- Choose the object (e.g., Contact).
- Select the property (e.g., Email).
- Set the trigger (e.g., when Email is known).
Limitation
- Only works if the property is visible to all users.
- If property visibility is restricted, it will not appear as an option.
Option 2: HubSpot Workflow + Custom Code (Recommended for Pro+)
This method stores the previous value in a separate property.
Step 1: Create a “Previous Email” Property
- Type: Email
- Recommendation: Restrict editing or keep hidden to prevent overwrites
Step 2: Build a Workflow
- Go to Automation → Workflows.
- Trigger:
- Property value changed → Email
- Enable re-enrollment
Step 3: Add Custom Code Action
- Requires Operations Hub Pro
- Use Node.js
- Purpose: Retrieve property history via API and extract the previous value
- Here's the code I used:
const axios = require('axios');
exports.main = async (event, callback) => {
const contactId = event.object.objectId;
const token = process.env.accessToken;
try {
const response = await axios.get(
`https://api.hubapi.com/crm/v3/objects/contacts/${contactId}?propertiesWithHistory=email`,
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
}
);
const history =
response.data?.propertiesWithHistory?.email || [];
history.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
const previousValue =
history.length > 1 ? String(history[1].value ?? '') : '';
callback({
outputFields: {
previous_email: previousValue
}
});
} catch (err) {
console.error('Error fetching property history:', err?.message || err);
callback({
outputFields: {
previous_email: ''
}
});
}
};
Key requirements:
- Private access token (via HubSpot service key)
- Scope:
contacts.read
- Pass contact ID into the script
- Output: previous email value
Step 4: Update Contact Record
- Action: Edit Record
- Set:
- Property: Previous Email
- Value: Output from custom code step
Result
- Current email = Email property
- Previous email = stored in custom property
- Can be used in lists, segments, and reporting
Option 3: Zapier (If You Don’t Have Ops Hub Pro)
This replicates the same logic using Zapier.
Zap Structure
Step 1: Trigger
- App: HubSpot
- Event: Contact Property Change
- Property: Email
Step 2: API Request
- Use HubSpot API via Zapier
- Endpoint: Contact with
propertiesWithHistory
- Include internal property name (e.g.,
email)
Step 3: Extract Previous Value
- Use Formatter → Utilities → Pick from List
- Select index:
0 = current value
1 = previous value
Step 4: Update Contact
- Action: Update Contact
- Set:
- Previous Email = extracted value
Result
- Same outcome as workflow method without custom code
Creating a Segment or List
To view changes:
- Create a list or segment
- Filters:
- Email has been updated in last X days
- Email is known
- (Optional) Previous Email is known to exclude first-time entries
This allows side-by-side comparison of current vs. previous values.
Option 4: Export Property History
If you only need periodic visibility:
- Go to Settings → Properties
- Find the property (e.g., Email)
- Click More → Export Property History
Output
- CSV or Excel file
- Includes all historical values across records
Key Takeaways
- Best native option: Custom events (Pro+)
- Most flexible: Workflow + custom code
- No Ops Hub Pro: Use Zapier
- Quick audit: Export property history
When to Use Each Method
| Scenario |
Best Option |
| Simple tracking (no restrictions) |
Custom Events |
| Need stored previous value |
Workflow + Custom Code |
| No Ops Hub Pro |
Zapier |
| One-time analysis |
Export |
Final Notes
- Property visibility affects tracking capabilities
- Always store historical values in a separate property
- Use lists or segments to make data actionable
Bye for now.