Google Sheets to HubSpot, cleaner ICP profiles
You start with a simple list of domains in a spreadsheet. Then the mess begins: tabs everywhere, half-finished notes, “we’ll research this later,” and HubSpot records that never quite match how your team actually qualifies accounts.
Demand gen managers feel it when targeting gets fuzzy. Agency owners feel it when client lists need proof, fast. And sales ops gets stuck cleaning fields instead of improving the process. This ICP profile automation turns a Google Sheet of domains into consistent, decision-ready company profiles in HubSpot.
Below, you’ll see what the workflow does, what it replaces, and what changes once your “research” stops living in scattered tabs and starts living in your CRM.
How This Automation Works
See how this solves the problem:
n8n Workflow Template: Google Sheets to HubSpot, cleaner ICP profiles
flowchart LR
subgraph sg0["Start Flow"]
direction LR
n0@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model", pos: "b", h: 48 }
n1@{ icon: "mdi:robot", form: "rounded", label: "Structured Output Parser", pos: "b", h: 48 }
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Sona Enrich"]
n3@{ icon: "mdi:cog", form: "rounded", label: "End", pos: "b", h: 48 }
n4@{ icon: "mdi:play-circle", form: "rounded", label: "Start", pos: "b", h: 48 }
n5@{ icon: "mdi:database", form: "rounded", label: "Get Company List from Sheet", pos: "b", h: 48 }
n6["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Scrape Website Content"]
n7["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/html.dark.svg' width='40' height='40' /></div><br/>Extract HTML Content"]
n8["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Clean & Format Text"]
n9@{ icon: "mdi:robot", form: "rounded", label: "Analyze with AI", pos: "b", h: 48 }
n10@{ icon: "mdi:cog", form: "rounded", label: "Collect AI Results", pos: "b", h: 48 }
n11["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Create Custom HubSpot Fields"]
n12@{ icon: "mdi:swap-vertical", form: "rounded", label: "Prepare Data for Loop", pos: "b", h: 48 }
n13@{ icon: "mdi:swap-vertical", form: "rounded", label: "Split Companies and AI Outpu..", pos: "b", h: 48 }
n14@{ icon: "mdi:swap-vertical", form: "rounded", label: "Loop Through Companies", pos: "b", h: 48 }
n15["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/hubspot.svg' width='40' height='40' /></div><br/>Create HubSpot Company"]
n16["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Format Custom Properties"]
n17["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Update Company with AI Data"]
n4 --> n5
n2 --> n15
n9 --> n10
n0 -.-> n9
n10 --> n11
n8 --> n9
n7 --> n8
n12 --> n13
n15 --> n16
n14 --> n3
n14 --> n2
n6 --> n7
n16 --> n17
n1 -.-> n9
n5 --> n6
n17 --> n14
n11 --> n12
n13 --> n14
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n4 trigger
class n1,n9 ai
class n0 aiModel
class n5 database
class n2,n6,n11,n17 api
class n8,n16 code
classDef customIcon fill:none,stroke:none
class n2,n6,n7,n8,n11,n15,n16,n17 customIcon
The Challenge: Turning “a domain list” into real ICP decisions
Most teams don’t struggle to find prospects. They struggle to qualify them consistently. Someone pastes a domain into a Sheet, someone else opens the website, skims pricing, guesses an industry, and drops a few notes that only make sense to the person who wrote them. Two days later, you’re in HubSpot trying to segment “B2B SaaS with mid-market pricing,” and you realize half the records don’t even have employee count, location, or a clean description. It’s not just slow. It’s unreliable, and it quietly wrecks targeting.
The friction compounds. Here’s where it usually breaks down.
- Every prospect requires a manual mini-research project, so lists stall out after the first dozen companies.
- Notes end up unstructured, which makes segmentation feel like guesswork instead of filtering.
- Different people interpret the same site differently, so “ICP fit” changes depending on who looked that day.
- HubSpot records get created without the fields you actually need, which means more cleanup before outreach can even start.
The Fix: Enrich, analyze, and sync each domain into HubSpot
This workflow starts with a Google Sheet column called “Website Domain,” then turns each domain into a complete HubSpot company profile. It pulls website content via HTTP requests, strips out the junk (navigation, footers, repeated boilerplate), and sends the cleaned text into an AI agent powered by an OpenAI chat model. The AI extracts structured signals you actually care about: positioning, features, target personas, pricing model hints, and value propositions. Next, the workflow enriches the same company via Sona Enrich to capture firmographics and growth signals like employee count, revenue estimates, headquarters location, funding, and technographic clues. Finally, it creates the company in HubSpot, generates the custom properties you need, and patches the record with a properly mapped payload so the data lands where your team will use it.
The workflow kicks off from a manual trigger (or you can schedule it later). It reads your rows, processes domains in batches, then loops through each company to enrich, create, and update in HubSpot. You end up with standardized profiles that are built for filtering and scoring, not just “saving notes for later.”
What Changes: Before vs. After
| What This Eliminates | Impact You’ll See |
|---|---|
|
|
Real-World Impact
Say you qualify 40 companies a week from a spreadsheet. Manually, you might spend about 20 minutes per company between scanning the site, guessing ICP fit, grabbing employee count, and then cleaning up HubSpot fields later. That’s roughly 13 hours of research work. With this workflow, you drop domains into Google Sheets, launch the run, and let the scraping + AI + Sona enrichment do the heavy lifting; your “work” becomes review and segmentation, which is often closer to 1–2 minutes per company.
Requirements
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets to store domains in a “Website Domain” column.
- HubSpot to create and update company records.
- OpenAI API key (get it from your OpenAI account dashboard).
- Sona Enrich API credentials (get access from Sona, then copy your API key).
Skill level: Intermediate. You’ll connect accounts, paste API keys, and map a few HubSpot properties, but you won’t be writing an app.
Need help implementing this? Talk to an automation expert (free 15-minute consultation).
The Workflow Flow
A run starts from n8n and pulls your domain list. The workflow uses Google Sheets to retrieve rows from your spreadsheet, expecting a “Website Domain” column so it knows what to process.
Website content gets collected and cleaned. HTTP requests fetch the company’s website pages, then the HTML is turned into readable text. A normalization step removes repetitive sections so the AI isn’t basing decisions on cookie banners and footer links.
AI turns messy text into structured ICP signals. An AI agent (OpenAI chat model) extracts consistent fields like industry, positioning, personas, value proposition, and pricing cues. Those results are aggregated into a standardized format so every company is comparable.
Firmographics are enriched and everything lands in HubSpot. Inside a batch loop, the workflow calls Sona Enrich for employee count, revenue estimates, location, funding, and technographics, then creates the company in HubSpot and patches in a mapped property payload.
You can easily modify which AI fields get generated and which HubSpot properties they map to based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Manual Trigger
This workflow starts manually so you can validate data and outputs before running in production.
- Add the Manual Launch Trigger node as the workflow trigger.
- Leave all parameters at their defaults in Manual Launch Trigger.
- Confirm the connection from Manual Launch Trigger to Retrieve Company Sheet to match the execution flow.
Step 2: Connect Google Sheets
Pull the list of company domains from Google Sheets for downstream scraping and enrichment.
- Open Retrieve Company Sheet and set Document to
[YOUR_ID]. - Set Sheet to
gid=0(Sheet1). - Credential Required: Connect your googleSheetsOAuth2Api credentials in Retrieve Company Sheet.
Step 3: Set Up Website Fetching and Text Normalization
Fetch each website, extract readable content, and normalize the text before AI processing.
- In Fetch Website Pages, set URL to
{{ ($json['Website Domain'].match(/^https?:\/\/) ? $json['Website Domain'] : 'https://' + $json['Website Domain']).toLowerCase() }}. - Keep the batching settings in Fetch Website Pages to avoid rate limits (batch size 1, interval 2000ms).
- In Extract Page Text, set Operation to extractHtmlContent and keep the extraction selectors for
main, body, article, .main-content, #content, pwith skips forscript, img, style, nav, footer, header. - In Normalize Content Text, keep the provided JavaScript to clean noise, and confirm it references Retrieve Company Sheet for the
website_domainmapping.
Website Domain column in your sheet contains URLs without a protocol or TLD, the expression in Fetch Website Pages may resolve incorrectly. Ensure domains are valid or adjust the expression.
Step 4: Set Up AI Content Analysis
Analyze cleaned website content with an LLM, parse structured JSON, and aggregate outputs for downstream CRM updates.
- In AI Content Analysis, keep Prompt Type set to define and ensure the Text prompt includes
{{ $json.main_content }}and{{ $json.website_domain }}. - Connect OpenAI Chat Engine as the language model for AI Content Analysis.
- Credential Required: Connect your openAiApi credentials in OpenAI Chat Engine.
- Attach Structured JSON Parser to AI Content Analysis and keep the JSON schema example as provided.
- In Aggregate AI Outputs, keep Fields to Aggregate set to
outputfor batching AI results.
Step 5: Configure HubSpot Enrichment and CRM Sync
Create missing HubSpot fields, enrich company data from Sona, create companies, and patch enriched details back to HubSpot.
- In Generate HubSpot Fields, set URL to
https://api.hubapi.com/[CONFIGURE_YOUR_API_KEY]and keep the JSON body that defines all custom properties. - Credential Required: Connect your hubspotAppToken credentials in Generate HubSpot Fields, Create CRM Company, and Patch Company Details.
- In Assemble Loop Payload, set the output assignment to
{{ $('Aggregate AI Outputs').first().json.output }}. - In Split Records to Items, set Field to Split Out to
outputand connect it to Iterate Company Batch. - In Sona Firmographic Enrich, keep the URL and query parameter
websiteas configured; ensure the headerx-api-keyis set in the node. - In Create CRM Company, keep the Name expression
{{ $json.data.name || $('Iterate Company Batch').first().json.website_name }}and the additional fields as configured to map Sona data. - In Build Property Payload, keep the JavaScript that maps Sona and AI fields to HubSpot properties.
- In Patch Company Details, set URL to
https://api.hubapi.com/crm/v3/objects/companies/{{ $('Create CRM Company').first().json.companyId }}and JSON Body to{{ $json }}. - Confirm Iterate Company Batch feeds Finish Step after each patch to complete the loop.
[CONFIGURE_YOUR_API_KEY] or use a correct HubSpot endpoint for property creation.
Step 6: Test and Activate Your Workflow
Run a manual test to confirm enrichment, AI parsing, and HubSpot updates are working end-to-end.
- Click Execute Workflow starting from Manual Launch Trigger.
- Verify that Retrieve Company Sheet returns rows and Fetch Website Pages produces HTML content.
- Check AI Content Analysis output for valid JSON parsed by Structured JSON Parser, then confirm Aggregate AI Outputs aggregates the
outputfield. - Confirm HubSpot updates: Create CRM Company returns a
companyIdand Patch Company Details succeeds with enriched properties. - When results look correct, toggle the workflow to Active for production use.
Watch Out For
- HubSpot legacy app tokens can be created with the wrong scopes. If company creation or field generation fails, check your HubSpot app permissions (crm.schemas.companies.read/write and crm.objects.companies.write) first.
- If you’re scraping sites that block bots or heavily rely on JavaScript, the HTTP Request node may return thin content. In that case, swap the scraping method or adjust the fetch target so the AI has enough real text to work with.
- Default AI prompts are generic. Add your ICP definitions and “what good looks like” early, or you’ll spend your time second-guessing outputs instead of trusting the properties in HubSpot.
Common Questions
About an hour if your accounts and API keys are ready.
Yes, but you’ll want someone comfortable with HubSpot properties and API keys. No coding is required, though mapping fields takes a little care.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in OpenAI API usage and your Sona Enrich plan.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
You can change what gets extracted by editing the prompt inside the AI Content Analysis node, then adjust how it lands in HubSpot in the Build Property Payload step. Common customizations include adding “ICP fit reason,” scoring rules, extra persona fields, or a stricter industry taxonomy. If you already have your own enrichment provider, you can also replace the Sona Firmographic Enrich HTTP request with another API call and keep the rest of the flow the same.
Usually it’s an expired or under-scoped token from the HubSpot legacy app setup. Regenerate the token, confirm the company object and schema scopes are enabled, then reselect the credential in the Create CRM Company node. If it fails only on updates, the Patch Company Details request may be referencing a property that doesn’t exist yet, so check that the Generate HubSpot Fields step actually ran successfully.
If you self-host, capacity mostly depends on your server and your API rate limits.
Often, yes, because this flow benefits from batching, looping, structured parsing, and multi-step CRM updates, which gets awkward and expensive in simpler tools. n8n also gives you more control over how scraped text is cleaned before it hits the model, and that quality difference shows up in your fields. Zapier or Make can still work if you only need “Sheet row → create HubSpot company” with a couple of fields. Once you want AI extraction, enrichment calls, property creation, and a patch/update cycle, n8n is usually the calmer choice. If you’re unsure, Talk to an automation expert and describe your volume and field requirements.
Once this is running, your spreadsheet stops being a research to-do list and becomes a clean input queue. HubSpot gets the context, your team gets the filters, and you get your week back.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.