Integrating n8n with HubSpot: Complete CRM Automation Setup
HubSpot’s robust CRM capabilities combined with n8n’s flexible automation power create endless possibilities for streamlining your sales and marketing processes. This comprehensive guide will walk you through setting up key HubSpot integrations that can transform how you manage leads, contacts, and customer relationships.
Why Integrate n8n with HubSpot?
HubSpot excels at contact management and sales pipeline tracking, but it has limitations when it comes to complex multi-system workflows. n8n bridges this gap by connecting HubSpot to your other business tools and enabling sophisticated automation that goes beyond HubSpot’s native workflow capabilities.
Common integration scenarios include:
- Syncing leads from multiple sources into HubSpot
- Triggering external actions when deals move through pipeline stages
- Enriching contact data from external APIs
- Creating complex lead scoring based on multiple data sources
- Automating follow-up sequences across multiple platforms
Setting Up Your HubSpot Connection
Prerequisites
- Active HubSpot account (free tier works for basic integrations)
- n8n instance with internet access
- HubSpot API key or OAuth app credentials
Connecting n8n to HubSpot
Method 1: Using API Key (Simpler)
- In HubSpot, navigate to Settings → Integrations → API Key
- Generate your API key if you don’t have one
- In n8n, add a HubSpot node
- Select “API Key” as authentication method
- Paste your API key
Method 2: Using OAuth (More Secure)
- In HubSpot, go to Settings → Integrations → Connected Apps
- Create a new app with required scopes
- In n8n, select “OAuth2” authentication
- Enter your app credentials and authorize
Required HubSpot Scopes
For comprehensive automation, ensure your connection includes these scopes:
contacts
– Read and write contact datadeals
– Manage deals and pipeline informationcompanies
– Access company recordstickets
– Handle support ticketstimeline
– Create timeline eventsfiles
– Upload and manage files
Essential HubSpot Automation Workflows
Workflow 1: Lead Capture and Enrichment
This workflow captures leads from multiple sources and enriches them before adding to HubSpot.
Trigger: Webhook (for form submissions, landing pages, etc.)
{
"email": "prospect@company.com",
"firstName": "Sarah",
"lastName": "Johnson",
"company": "Tech Solutions Inc",
"source": "website_form"
}
Step 1: Data Enrichment Add an HTTP Request node to enrich the lead with company data:
- URL:
https://api.clearbit.com/v2/enrichment/find
- Parameters:
email={{$json.email}}
- Headers:
Authorization: Bearer YOUR_CLEARBIT_KEY
Step 2: Lead Scoring Use a Code node to calculate lead score:
const lead = $input.first().json;
let score = 0;
// Email domain scoring
const domain = lead.email.split('@')[1];
if (!['gmail.com', 'yahoo.com', 'hotmail.com'].includes(domain)) {
score += 20; // Business email
}
// Company size scoring (from enrichment data)
if (lead.company_size > 100) score += 30;
else if (lead.company_size > 50) score += 20;
else if (lead.company_size > 10) score += 10;
// Industry scoring
const highValueIndustries = ['technology', 'healthcare', 'finance'];
if (highValueIndustries.includes(lead.industry)) {
score += 25;
}
return [{
json: {
...lead,
leadScore: score,
priority: score >= 50 ? 'high' : score >= 25 ? 'medium' : 'low'
}
}];
Step 3: Create HubSpot Contact Add HubSpot node with “Create Contact” operation:
- Email:
{{$json.email}}
- First Name:
{{$json.firstName}}
- Last Name:
{{$json.lastName}}
- Company:
{{$json.company}}
- Lead Score:
{{$json.leadScore}}
- Lead Source:
{{$json.source}}
Step 4: Conditional Assignment Use IF node to assign high-priority leads to senior sales reps:
- Condition:
{{$json.priority}}
equalshigh
- True: Assign to senior sales rep and send immediate notification
- False: Add to standard nurturing sequence
Workflow 2: Deal Stage Automation
Automate actions when deals move through your sales pipeline.
Trigger: HubSpot Trigger – Deal Updated Configure to trigger when deal stage changes.
Step 1: Stage Identification Use Switch node to handle different stages:
- Case 1: “Qualified Lead” → Send welcome packet
- Case 2: “Proposal Sent” → Set follow-up reminder
- Case 3: “Closed Won” → Trigger onboarding workflow
- Case 4: “Closed Lost” → Add to nurturing campaign
Step 2: Closed Won Actions For won deals, create a comprehensive onboarding sequence:
// Extract deal and contact information
const deal = $json;
const dealValue = deal.amount;
const contactId = deal.associations.contacts[0];
// Determine onboarding tier based on deal size
let onboardingTier = 'standard';
if (dealValue > 50000) onboardingTier = 'enterprise';
else if (dealValue > 10000) onboardingTier = 'professional';
// Set implementation timeline
const implementationWeeks = onboardingTier === 'enterprise' ? 8 :
onboardingTier === 'professional' ? 4 : 2;
return [{
json: {
dealId: deal.id,
contactId: contactId,
dealValue: dealValue,
onboardingTier: onboardingTier,
implementationWeeks: implementationWeeks,
kickoffDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
}
}];
Step 3: Create Implementation Tasks Use HubSpot node to create tasks for the customer success team:
- Task 1: Schedule kickoff call
- Task 2: Prepare onboarding materials
- Task 3: Set up customer accounts
Workflow 3: Contact Lifecycle Automation
Automatically move contacts through lifecycle stages based on their behavior and engagement.
Trigger: HubSpot Trigger – Contact Property Changed Monitor changes to key properties like email opens, website visits, or form submissions.
Step 1: Engagement Scoring
const contact = $json;
let engagementScore = 0;
// Email engagement
if (contact.hs_email_open_count > 10) engagementScore += 20;
if (contact.hs_email_click_count > 5) engagementScore += 15;
// Website activity
if (contact.num_pageviews > 20) engagementScore += 25;
if (contact.recent_conversion_date) engagementScore += 30;
// Determine lifecycle stage
let newStage = contact.lifecyclestage;
if (engagementScore >= 60 && contact.lifecyclestage === 'lead') {
newStage = 'marketingqualifiedlead';
} else if (engagementScore >= 80 && contact.lifecyclestage === 'marketingqualifiedlead') {
newStage = 'salesqualifiedlead';
}
return [{
json: {
contactId: contact.id,
currentStage: contact.lifecyclestage,
newStage: newStage,
engagementScore: engagementScore,
shouldUpdate: newStage !== contact.lifecyclestage
}
}];
Step 2: Update Contact and Notify Team If lifecycle stage should change:
- Update contact in HubSpot with new lifecycle stage
- Create task for sales team if contact becomes SQL
- Send notification to appropriate team members
Advanced Integration Patterns
Pattern 1: Bi-Directional Sync
Keep HubSpot in sync with external systems by creating workflows that work in both directions.
Example: Syncing with Customer Support System
- When support ticket is created → Create HubSpot ticket
- When HubSpot deal closes → Create customer account in support system
- When contact updates in either system → Sync changes to the other
Pattern 2: Data Validation and Cleanup
Automatically clean and validate data as it enters HubSpot:
// Email validation and formatting
function validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
// Phone number formatting
function formatPhone(phone) {
const cleaned = phone.replace(/\D/g, '');
if (cleaned.length === 10) {
return `(${cleaned.slice(0,3)}) ${cleaned.slice(3,6)}-${cleaned.slice(6)}`;
}
return phone;
}
// Company name standardization
function standardizeCompany(company) {
return company
.replace(/\b(inc|llc|corp|ltd)\b\.?/gi, match => match.toUpperCase())
.trim();
}
const contact = $input.first().json;
const cleanedContact = {
...contact,
email: contact.email ? contact.email.toLowerCase().trim() : '',
phone: contact.phone ? formatPhone(contact.phone) : '',
company: contact.company ? standardizeCompany(contact.company) : '',
isValidEmail: validateEmail(contact.email || '')
};
return [{ json: cleanedContact }];
Pattern 3: Multi-Touch Attribution
Track lead sources across multiple touchpoints:
// Attribution tracking
const contact = $json;
const newSource = $json.latest_source;
const existingSources = contact.all_lead_sources ?
contact.all_lead_sources.split(';') : [];
// Add new source if not already tracked
if (newSource && !existingSources.includes(newSource)) {
existingSources.push(newSource);
}
// Calculate source weights for attribution
const sourceWeights = {
'organic_search': 0.4,
'paid_search': 0.3,
'social_media': 0.2,
'email': 0.1,
'direct': 0.1
};
let attributionScore = 0;
existingSources.forEach(source => {
attributionScore += sourceWeights[source] || 0.1;
});
return [{
json: {
contactId: contact.id,
allLeadSources: existingSources.join(';'),
attributionScore: Math.round(attributionScore * 100),
primarySource: existingSources[0],
latestSource: newSource
}
}];
Error Handling and Best Practices
Handling API Rate Limits
HubSpot has API rate limits that you need to respect:
// Add delay between API calls for bulk operations
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// For bulk contact creation
const contacts = $input.all();
const results = [];
for (let i = 0; i < contacts.length; i++) {
try {
// Process contact
const result = await processContact(contacts[i]);
results.push(result);
// Rate limiting - HubSpot allows 100 requests per 10 seconds
if (i % 10 === 0 && i > 0) {
await delay(1000); // Wait 1 second every 10 requests
}
} catch (error) {
console.log(`Error processing contact ${i}:`, error.message);
results.push({ error: error.message, contact: contacts[i] });
}
}
return results.map(result => ({ json: result }));
Data Validation
Always validate data before sending to HubSpot:
function validateHubSpotContact(contact) {
const errors = [];
// Required fields
if (!contact.email) errors.push('Email is required');
if (!contact.firstname) errors.push('First name is required');
// Data format validation
if (contact.email && !validateEmail(contact.email)) {
errors.push('Invalid email format');
}
// HubSpot-specific validation
if (contact.phone && contact.phone.length > 20) {
errors.push('Phone number too long for HubSpot');
}
return {
isValid: errors.length === 0,
errors: errors,
contact: contact
};
}
Monitoring and Logging
Add logging to track workflow performance:
// Comprehensive logging for HubSpot operations
const operation = 'create_contact';
const startTime = Date.now();
try {
// Your HubSpot operation here
const result = await hubspotOperation();
const logData = {
operation: operation,
success: true,
duration: Date.now() - startTime,
recordsProcessed: 1,
timestamp: new Date().toISOString()
};
console.log('HubSpot Operation Success:', JSON.stringify(logData));
return [{ json: { ...result, log: logData } }];
} catch (error) {
const errorLog = {
operation: operation,
success: false,
error: error.message,
duration: Date.now() - startTime,
timestamp: new Date().toISOString()
};
console.error('HubSpot Operation Failed:', JSON.stringify(errorLog));
throw error;
}
Testing Your HubSpot Integration
Test Data Strategy
Create test contacts and deals in HubSpot for safe testing:
// Test contact data generator
function generateTestContact() {
const testDomains = ['test-company.com', 'example-corp.com'];
const firstNames = ['Test', 'Demo', 'Sample'];
const lastNames = ['Contact', 'Lead', 'Prospect'];
return {
email: `test+${Date.now()}@${testDomains[Math.floor(Math.random() * testDomains.length)]}`,
firstname: firstNames[Math.floor(Math.random() * firstNames.length)],
lastname: lastNames[Math.floor(Math.random() * lastNames.length)],
company: 'Test Company Inc',
phone: '555-0123',
lead_source: 'API_TEST'
};
}
Cleanup Procedures
Always clean up test data:
// Clean up test contacts after testing
const testContacts = await hubspot.contacts.search({
filterGroups: [{
filters: [{
propertyName: 'lead_source',
operator: 'EQ',
value: 'API_TEST'
}]
}]
});
for (const contact of testContacts.results) {
await hubspot.contacts.basicApi.archive(contact.id);
console.log(`Cleaned up test contact: ${contact.id}`);
}
Scaling Your HubSpot Integration
As your automation grows, consider these optimization strategies:
Batch Processing: Group multiple operations together to reduce API calls and improve performance.
Caching: Store frequently accessed HubSpot data in n8n to avoid repeated API calls.
Queue Management: For high-volume operations, implement queuing to handle rate limits gracefully.
Monitoring: Set up alerts for failed operations and performance degradation.
The combination of HubSpot’s CRM capabilities and n8n’s automation flexibility creates powerful opportunities for streamlining your sales and marketing operations. Start with simple integrations and gradually build more sophisticated workflows as you identify opportunities for automation in your business processes.