This guide covers three ways to send your Browse AI scraped data into HubSpot, from no-code automation to custom API integrations. Choose the method that best fits your team's technical comfort and use case.
π Prerequisites: You'll need an approved Browse AI robot with scraped data and a HubSpot account. For API-based methods, you'll also need a Browse AI API key and a HubSpot Private App access token.
Which method should I use?
Here's a quick comparison to help you decide:
Method | Best for | Technical level | Speed |
Zapier / Make | Teams without developers | No code | Near real-time |
Webhooks | Real-time pipelines with custom logic | Intermediate | Real-time |
API polling | Batch processing, scheduled syncs | Intermediate | On schedule |
Method 1: Zapier or Make (no code)
The fastest way to connect Browse AI to HubSpot. No coding required. Just map your scraped fields to HubSpot properties.
Setting up with Zapier
Go to zapier.com and create a new Zap.
Trigger: Choose Browse AI as the trigger app, then select New Successful Task Finished as the event.
Connect your Browse AI account and select the robot you want to sync data from.
Action: Choose HubSpot as the action app, then select the action that matches your use case, for example, Create Contact, Create Company, or Create Deal.
Connect your HubSpot account.
Map your fields: Match each Browse AI captured field to the corresponding HubSpot property. For example, map
emailβEmail,company_nameβCompany name,websiteβWebsite URL.Test the Zap, then turn it on.
π‘ Tip: Use Zapier's Create or Update Contact action instead of Create Contact. This automatically deduplicates by email address. If a contact already exists, it updates the record instead of creating a duplicate.
Setting up with Make (formerly Integromat)
Create a new scenario in Make.
Add a Webhooks β Custom webhook module as the trigger. Copy the webhook URL.
In Browse AI, go to your robot's Integrate tab and add the Make webhook URL under Webhooks. Select the
taskFinishedSuccessfullyevent.Add a HubSpot β Create/Update a Contact module, connect your HubSpot account, and map your fields.
Activate the scenario.
Method 2: Webhooks (real-time, custom code)
Use Browse AI webhooks to push data directly into HubSpot as soon as a task finishes. This gives you full control over data transformation and error handling.
How it works
Browse AI sends a webhook POST request to your server when a task completes.
Your server receives the scraped data and transforms it to match HubSpot property names.
Your server calls the HubSpot API to create or update records.
Step 1: Create a HubSpot Private App
You'll need a Private App to authenticate API requests to HubSpot. API keys are no longer supported.
In HubSpot, go to Settings β Integrations β Private Apps.
Click Create a private app.
Give it a name (e.g. "Browse AI Integration").
Under Scopes, grant the permissions you need:
crm.objects.contacts.writeto create/update contactscrm.objects.companies.writeto create/update companiescrm.objects.deals.writeto create/update deals
Click Create app, then copy your access token.
β οΈ Keep your access token secure. Store it in environment variables. Never hardcode it in your source code or commit it to version control.
Step 2: Build your webhook endpoint
This example receives Browse AI webhook data and creates a Contact in HubSpot:
import requests
from flask import Flask, request, jsonifyapp = Flask(__name__)HUBSPOT_ACCESS_TOKEN = "your_private_app_access_token"def create_or_update_hubspot_contact(properties):
"""Create or update a HubSpot contact using the email address."""
email = properties.get("email", "") if email:
# Try to update existing contact by email first
search_resp = requests.post(
"https://api.hubapi.com/crm/v3/objects/contacts/search",
headers={
"Authorization": f"Bearer {HUBSPOT_ACCESS_TOKEN}",
"Content-Type": "application/json"
},
json={
"filterGroups": [{
"filters": [{
"propertyName": "email",
"operator": "EQ",
"value": email
}]
}]
}
)
results = search_resp.json().get("results", []) if results:
# Update existing contact
contact_id = results[0]["id"]
resp = requests.patch(
f"https://api.hubapi.com/crm/v3/objects/contacts/{contact_id}",
headers={
"Authorization": f"Bearer {HUBSPOT_ACCESS_TOKEN}",
"Content-Type": "application/json"
},
json={"properties": properties}
)
return resp.json(), "updated" # Create new contact
resp = requests.post(
"https://api.hubapi.com/crm/v3/objects/contacts",
headers={
"Authorization": f"Bearer {HUBSPOT_ACCESS_TOKEN}",
"Content-Type": "application/json"
},
json={"properties": properties}
)
return resp.json(), "created"@app.route("/browse-ai-webhook", methods=["POST"])
def handle_webhook():
payload = request.get_json() # Only process successful task completions
if payload.get("event") != "taskFinishedSuccessfully":
return jsonify({"status": "ignored"}), 200 task = payload["task"]
captured = task.get("capturedTexts", {}) # Map Browse AI fields to HubSpot contact properties
properties = {
"email": captured.get("email", ""),
"firstname": captured.get("first_name", ""),
"lastname": captured.get("last_name", ""),
"company": captured.get("company_name", ""),
"website": captured.get("website", ""),
"jobtitle": captured.get("job_title", ""),
"phone": captured.get("phone", ""),
"hs_lead_status": "NEW",
"browseai_source": f"Robot {task.get('robotId')}"
} # Remove empty values
properties = {k: v for k, v in properties.items() if v} result, action = create_or_update_hubspot_contact(properties)
return jsonify({"status": action, "hubspot_id": result.get("id")}), 200if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
Step 3: Register the webhook in Browse AI
You can register your webhook URL through the Browse AI dashboard or the API:
Via the dashboard:
Open your robot and go to the Integrate tab.
Under Webhooks, click Add webhook.
Paste your endpoint URL (e.g.
https://yourdomain.com/browse-ai-webhook).Select the
taskFinishedSuccessfullyevent.
Via the API:
curl -X POST "https://api.browse.ai/v2/robots/YOUR_ROBOT_ID/webhooks" \
-H "Authorization: Bearer YOUR_BROWSE_AI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourdomain.com/browse-ai-webhook",
"events": ["taskFinishedSuccessfully"]
}'
π‘ IP allowlisting: Browse AI sends webhooks from IP address 3.228.254.190. If your server has a firewall, add this to your allowlist. See Webhooks: IP address for allowlisting.
Method 3: API polling (batch/scheduled)
If you prefer to pull data on a schedule rather than receive it in real time, you can poll the Browse AI API for completed tasks and push results into HubSpot in batches.
Example: Poll and sync to HubSpot
import requests
from datetime import datetime, timedeltaBROWSE_AI_API_KEY = "your_browse_ai_api_key"
ROBOT_ID = "your_robot_id"
HUBSPOT_ACCESS_TOKEN = "your_hubspot_private_app_token"def get_recent_tasks(since_hours=1):
"""Fetch tasks completed in the last N hours."""
resp = requests.get(
f"https://api.browse.ai/v2/robots/{ROBOT_ID}/tasks",
headers={"Authorization": f"Bearer {BROWSE_AI_API_KEY}"},
params={"pageSize": 100}
)
tasks = resp.json().get("result", {}).get("robotTasks", {}).get("items", []) cutoff = datetime.utcnow() - timedelta(hours=since_hours)
return [t for t in tasks if t.get("status") == "successful"
and datetime.fromisoformat(t["finishedAt"].replace("Z","")) > cutoff]def sync_to_hubspot(tasks):
"""Create HubSpot contacts from Browse AI task results."""
for task in tasks:
captured = task.get("capturedTexts", {})
properties = {
"email": captured.get("email", ""),
"lastname": captured.get("last_name", ""),
"company": captured.get("company_name", ""),
"website": captured.get("website", ""),
"hs_lead_status": "NEW"
}
properties = {k: v for k, v in properties.items() if v} requests.post(
"https://api.hubapi.com/crm/v3/objects/contacts",
headers={
"Authorization": f"Bearer {HUBSPOT_ACCESS_TOKEN}",
"Content-Type": "application/json"
},
json={"properties": properties}
)# Run this script on a schedule (e.g. cron job every hour)
π For full Browse AI API details, including pagination, bulk operations, and task filtering, see the API Guide: Getting started and API Guide: Bulk operations.
HubSpot-specific tips
Preventing duplicate contacts
HubSpot automatically deduplicates contacts by email address. If you try to create a contact with an email that already exists, HubSpot will return a 409 Conflict error. To handle this gracefully, use the search-then-update pattern shown in the webhook example above, or use HubSpot's batch upsert endpoint:
# Batch upsert: create or update contacts by email
requests.post(
"https://api.hubapi.com/crm/v3/objects/contacts/batch/upsert",
headers={
"Authorization": f"Bearer {HUBSPOT_ACCESS_TOKEN}",
"Content-Type": "application/json"
},
json={
"inputs": [
{
"idProperty": "email",
"id": "[email protected]",
"properties": {
"email": "[email protected]",
"firstname": "Jane",
"lastname": "Doe",
"company": "Acme Inc"
}
}
]
}
)
Creating Companies and Deals
The examples above focus on Contacts, but HubSpot's API uses the same pattern for all CRM objects. To create a Company or Deal instead, change the object type in the URL:
Companies:
POST /crm/v3/objects/companiesDeals:
POST /crm/v3/objects/deals
You can also associate records together. For example, linking a Contact to a Company, using HubSpot's associations API after creating both records.
Common field mappings
Here are typical mappings between Browse AI captured fields and standard HubSpot Contact properties:
Browse AI field | HubSpot property | Notes |
|
| Used for deduplication |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
(origin URL) | Custom property or | Available as |
π‘ Custom properties: You can create custom HubSpot properties (e.g. browseai_source, browseai_robot_id) to tag records imported from Browse AI. Go to Settings β Properties in HubSpot to create them, then include them in your field mapping.
Sending monitoring data to HubSpot
If you're using Browse AI monitors to track changes on websites, you can push change events into HubSpot. Use the taskCapturedDataChanged webhook event to trigger updates. For example, updating a Contact property when their LinkedIn profile changes, or creating a HubSpot Task when a competitor's pricing page is updated.
To set this up, register a webhook for the taskCapturedDataChanged event and handle the payload in your endpoint alongside taskFinishedSuccessfully.
Troubleshooting
HubSpot returns a 401 Unauthorized error
Check that your Private App access token is correct and that the app hasn't been deactivated. In HubSpot, go to Settings β Integrations β Private Apps to verify.
HubSpot returns a 409 Conflict error
A contact with that email address already exists. Use the search-then-update pattern or the batch upsert endpoint (see "Preventing duplicate contacts" above).
HubSpot returns a 429 Too Many Requests error
You've hit HubSpot's API rate limit. Private Apps allow 200 requests per 10 seconds on most plans. Add retry logic with exponential backoff, or use HubSpot's batch endpoints to reduce the number of API calls.
Webhook isn't firing
Make sure the webhook URL is publicly accessible and that your server responds with a 200 status code. See the Webhooks: Set up guide for detailed debugging steps.
Custom properties aren't showing up
Make sure you've created the custom property in HubSpot before trying to set it via the API. The property's internal name (used in API calls) may differ from its label. Check Settings β Properties for the exact internal name.
