Skip to main content

How to send Browse AI data to HubSpot

M
Written by Melissa Shires

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

  1. Go to zapier.com and create a new Zap.

  2. Trigger: Choose Browse AI as the trigger app, then select New Successful Task Finished as the event.

  3. Connect your Browse AI account and select the robot you want to sync data from.

  4. 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.

  5. Connect your HubSpot account.

  6. 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.

  7. 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)

  1. Create a new scenario in Make.

  2. Add a Webhooks β†’ Custom webhook module as the trigger. Copy the webhook URL.

  3. In Browse AI, go to your robot's Integrate tab and add the Make webhook URL under Webhooks. Select the taskFinishedSuccessfully event.

  4. Add a HubSpot β†’ Create/Update a Contact module, connect your HubSpot account, and map your fields.

  5. 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

  1. Browse AI sends a webhook POST request to your server when a task completes.

  2. Your server receives the scraped data and transforms it to match HubSpot property names.

  3. 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.

  1. In HubSpot, go to Settings β†’ Integrations β†’ Private Apps.

  2. Click Create a private app.

  3. Give it a name (e.g. "Browse AI Integration").

  4. Under Scopes, grant the permissions you need:

    • crm.objects.contacts.write to create/update contacts

    • crm.objects.companies.write to create/update companies

    • crm.objects.deals.write to create/update deals

  5. 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:

  1. Open your robot and go to the Integrate tab.

  2. Under Webhooks, click Add webhook.

  3. Paste your endpoint URL (e.g. https://yourdomain.com/browse-ai-webhook).

  4. Select the taskFinishedSuccessfully event.

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/companies

  • Deals: 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

email

email

Used for deduplication

first_name

firstname

last_name

lastname

company_name

company

job_title

jobtitle

phone

phone

website

website

address

address

city

city

(origin URL)

Custom property or notes_last_contacted

Available as task.inputParameters.originUrl

πŸ’‘ 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.

Did this answer your question?