Enrich HubSpot companies with technographic data from BuiltWith using n8n
Install this workflow
Download the n8n workflow JSON and import it into your n8n instance.
tech-enrich.n8n.jsonPrerequisites
- n8n instance — n8n cloud or self-hosted
- HubSpot private app token with
crm.objects.companies.readandcrm.objects.companies.writescopes - BuiltWith API key (Pro plan or above — API access is not available on free or Basic plans)
- Custom HubSpot company properties created for tech stack data (e.g.,
tech_stack_crm,tech_stack_marketing,tech_stack_analytics) - n8n credential configured for HubSpot
Why n8n?
n8n's Code node is the cleanest way to handle BuiltWith's deeply nested JSON response (Results[0].Result.Paths[0].Technologies[]). You write the categorization logic once in JavaScript, and the visual canvas shows exactly which companies were enriched, which had no tech data, and which failed. Self-hosted n8n means unlimited executions — the only variable cost is BuiltWith credits.
The trade-off is setup complexity. You'll configure 6-7 nodes with HTTP requests, a Code node for parsing, and error handling for domains BuiltWith doesn't recognize. If you want a single file you can read top-to-bottom, the Code approach is simpler.
Step 1: Create the trigger
You have two options for triggering technographic enrichment:
Option A — Trigger on new companies: Add a HubSpot Trigger node → Watch Companies (new companies only).
Option B — Scheduled batch (recommended): Add a Schedule Trigger → Weekly, Sunday at 22:00. This enriches all companies that haven't been looked up yet, in a single batch.
Tech stacks change slowly (quarterly at most). A weekly batch is more efficient than enriching every new company immediately. It also helps you stay within BuiltWith's monthly API call limits.
Step 2: Fetch companies from HubSpot
Add an HTTP Request node to search for companies missing tech stack data:
- Method: POST
- URL:
https://api.hubapi.com/crm/v3/objects/companies/search - Authentication: HubSpot credential
- Body:
{
"filterGroups": [{
"filters": [{
"propertyName": "tech_stack_crm",
"operator": "NOT_HAS_PROPERTY"
}]
}],
"properties": ["domain", "name", "tech_stack_crm"],
"limit": 50
}Step 3: Loop through companies and call BuiltWith
Add a Split In Batches node (batch size: 1) to iterate over the search results.
Add an HTTP Request node for BuiltWith:
- Method: GET
- URL:
https://api.builtwith.com/v21/api.json - Query Parameters:
KEY: Your BuiltWith API keyLOOKUP:{{ $json.properties.domain }}
The BuiltWith response contains a Results[0].Result.Paths[0].Technologies[] array. Each technology object has:
Name— e.g., "Salesforce", "Google Analytics"Tag— category tag like "analytics", "crm", "marketing-automation"Categories[]— array of category strings
The technology data is buried several levels deep: Results[0].Result.Paths[0].Technologies[]. If a domain isn't found, Results may be empty or the Paths array may not contain technologies. Always add null checks.
Step 4: Parse the tech stack with a Code node
Add a Code node to extract and categorize the technologies:
const response = $input.first().json;
const technologies = response?.Results?.[0]?.Result?.Paths?.[0]?.Technologies || [];
const categories = {
crm: [],
marketing: [],
analytics: [],
ecommerce: [],
hosting: [],
};
const categoryMap = {
"crm": "crm",
"marketing-automation": "marketing",
"email": "marketing",
"analytics": "analytics",
"web-analytics": "analytics",
"ecommerce": "ecommerce",
"shopping-cart": "ecommerce",
"hosting": "hosting",
"cdn": "hosting",
};
for (const tech of technologies) {
const tag = tech.Tag?.toLowerCase() || "";
for (const [pattern, category] of Object.entries(categoryMap)) {
if (tag.includes(pattern) || (tech.Categories || []).some(c => c.toLowerCase().includes(pattern))) {
categories[category].push(tech.Name);
break;
}
}
}
return [{
json: {
tech_stack_crm: categories.crm.join(", ") || "None detected",
tech_stack_marketing: categories.marketing.join(", ") || "None detected",
tech_stack_analytics: categories.analytics.join(", ") || "None detected",
tech_stack_all: technologies.map(t => t.Name).join(", "),
tech_count: technologies.length,
}
}];Step 5: Update the HubSpot company
Add an HTTP Request node:
- Method: PATCH
- URL:
https://api.hubapi.com/crm/v3/objects/companies/{{ $('Split In Batches').item.json.id }} - Authentication: HubSpot credential
- Body:
{
"properties": {
"tech_stack_crm": "{{ $json.tech_stack_crm }}",
"tech_stack_marketing": "{{ $json.tech_stack_marketing }}",
"tech_stack_analytics": "{{ $json.tech_stack_analytics }}",
"tech_stack_all": "{{ $json.tech_stack_all }}",
"tech_enrichment_date": "{{ new Date().toISOString().split('T')[0] }}"
}
}Before running this workflow, create the custom company properties in HubSpot: tech_stack_crm, tech_stack_marketing, tech_stack_analytics, tech_stack_all, and tech_enrichment_date. Set them as single-line text fields (or multi-line for tech_stack_all).
Step 6: Add a Wait node and error handling
Add a Wait node (2 seconds) after the BuiltWith HTTP Request to stay within API rate limits.
Add error handling:
- Retry on Fail on the BuiltWith HTTP node (2 retries, 5-second wait) — handles temporary API errors
- A separate Error Workflow to alert on failures
Step 7: Test and activate
- Click Execute Workflow with a small batch (set limit to 5)
- Check the BuiltWith response — verify the
Technologiesarray contains expected tools - Check the Code node output — verify categorization is correct
- Open a company in HubSpot to confirm tech stack properties were written
- Toggle the workflow to Active
Troubleshooting
Cost
- n8n cloud: Starts at $24/mo. Each company lookup uses ~5 executions.
- BuiltWith Pro plan: $295/mo with 500 API calls. Enterprise: $495/mo with 2,000 calls.
- Per company: 1 BuiltWith API call. At $295/mo for 500 calls, that's ~$0.59 per company lookup.
- HubSpot: Free within API rate limits.
At $0.59+ per lookup on the Pro plan, BuiltWith is one of the more expensive enrichment APIs. Be selective about which companies you enrich — filter for high-value prospects, target accounts, or companies above a certain size threshold. Don't enrich your entire database.
Common questions
How many companies can I enrich per week on BuiltWith Pro?
BuiltWith Pro includes 500 API calls/month. A weekly batch of 50 companies uses 200 calls/month, leaving 300 for re-enrichment or ad-hoc lookups. Don't run batches larger than 125/week on Pro — you'll hit the monthly limit.
Why is the 2-second Wait node necessary?
BuiltWith's rate limits vary by plan, but the Pro plan typically allows 1-2 requests per second. The 2-second delay is conservative. On the Enterprise plan, you can likely reduce this to 1 second. Without the delay, BuiltWith returns 429 errors and n8n's Retry on Fail handler kicks in, slowing things down more than the proactive delay would.
Can I detect whether a company uses a specific competitor product?
Yes. Add an IF node after the Code node that checks if tech_stack_crm contains your competitor's name (e.g., "Salesforce"). Route matches to an additional HubSpot update that sets a boolean uses_competitor_crm property for easy segmentation.
Next steps
- Add lead scoring — use the tech stack data in HubSpot workflows to score companies. Competitor CRM users get +20 points, complementary tool users get +10.
- Detect competitors — add specific checks for competitor products and set a
uses_competitor_crmboolean property for easy segmentation - Re-enrich quarterly — modify the search filter to also include companies where
tech_enrichment_dateis older than 90 days
Looking to scale your AI operations?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.