Skip to main content

How to send Browse AI data to Zoho CRM

M
Written by Melissa Shires

This guide covers three ways to send your Browse AI scraped data into Zoho CRM, 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 Zoho CRM account. For API-based methods, you'll also need a Browse AI API key and Zoho OAuth credentials.

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 Zoho CRM. No coding required. Just map your scraped fields to Zoho CRM modules.

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 Zoho CRM as the action app, then select the action that matches your use case, for example, Create/Update Module Entry for Leads, Contacts, Accounts, or Deals.

  5. Connect your Zoho CRM account.

  6. Select the module (e.g. Leads) and map each Browse AI captured field to the corresponding Zoho field. For example, map email β†’ Email, company_name β†’ Company, last_name β†’ Last Name.

  7. Test the Zap, then turn it on.

πŸ’‘ Tip: Use the Create/Update Module Entry action rather than just Create Module Entry. This checks for an existing record (by email or another unique field) and updates it if found, preventing duplicates.

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 Zoho CRM β†’ Create a Record module, connect your Zoho CRM account, select your module (e.g. Leads), and map your fields.

  5. Activate the scenario.

Method 2: Webhooks (real-time, custom code)

Use Browse AI webhooks to push data directly into Zoho CRM 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 Zoho CRM's field format.

  3. Your server authenticates with Zoho's OAuth 2.0 API and creates or updates records.

Step 1: Set up Zoho OAuth credentials

Zoho CRM uses OAuth 2.0 for API authentication. You'll need to register a "Self Client" application:

  1. Go to the Zoho API Console and click Add Client.

  2. Select Self Client as the client type (simplest for server-to-server integrations).

  3. Note your Client ID and Client Secret.

  4. Under the Self Client tab, generate a grant token with the scope ZohoCRM.modules.ALL (or a more specific scope like ZohoCRM.modules.leads.CREATE).

  5. Exchange the grant token for access and refresh tokens (see the code example below).

⚠️ Zoho data centers: Your API domain depends on where your Zoho account is hosted. Use https://accounts.zoho.com for US, https://accounts.zoho.eu for EU, https://accounts.zoho.in for India, https://accounts.zoho.com.au for Australia, or https://accounts.zoho.jp for Japan. The same applies to API endpoints (e.g. zohoapis.com vs zohoapis.eu).

Step 2: Build your webhook endpoint

This example receives Browse AI webhook data and creates a Lead in Zoho CRM:

import requests
from flask import Flask, request, jsonifyapp = Flask(__name__)# Zoho OAuth credentials
ZOHO_CLIENT_ID = "your_client_id"
ZOHO_CLIENT_SECRET = "your_client_secret"
ZOHO_REFRESH_TOKEN = "your_refresh_token"
ZOHO_ACCOUNTS_URL = "https://accounts.zoho.com"  # Change for your data center
ZOHO_API_URL = "https://www.zohoapis.com/crm/v2"  # Change for your data centerdef get_zoho_access_token():
    """Get a fresh access token using the refresh token."""
    resp = requests.post(f"{ZOHO_ACCOUNTS_URL}/oauth/v2/token", params={
        "refresh_token": ZOHO_REFRESH_TOKEN,
        "client_id": ZOHO_CLIENT_ID,
        "client_secret": ZOHO_CLIENT_SECRET,
        "grant_type": "refresh_token"
    })
    return resp.json()["access_token"]def create_zoho_record(module, data, access_token):
    """Create a record in a Zoho CRM module."""
    resp = requests.post(
        f"{ZOHO_API_URL}/{module}",
        headers={
            "Authorization": f"Zoho-oauthtoken {access_token}",
            "Content-Type": "application/json"
        },
        json={"data": [data]}
    )
    return resp.json()def upsert_zoho_record(module, data, duplicate_check_fields, access_token):
    """Create or update a record using duplicate check fields."""
    resp = requests.post(
        f"{ZOHO_API_URL}/{module}/upsert",
        headers={
            "Authorization": f"Zoho-oauthtoken {access_token}",
            "Content-Type": "application/json"
        },
        json={
            "data": [data],
            "duplicate_check_fields": duplicate_check_fields
        }
    )
    return resp.json()@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 Zoho CRM Lead fields
    lead_data = {
        "First_Name": captured.get("first_name", ""),
        "Last_Name": captured.get("last_name", "") or "Unknown",
        "Company": captured.get("company_name", "") or "Unknown",
        "Email": captured.get("email", ""),
        "Phone": captured.get("phone", ""),
        "Website": captured.get("website", ""),
        "Designation": captured.get("job_title", ""),
        "Lead_Source": "Browse AI",
        "Description": f"Auto-imported from Browse AI robot {task.get('robotId')}"
    }    # Remove empty values
    lead_data = {k: v for k, v in lead_data.items() if v}    # Get access token and upsert the lead (deduplicating by email)
    access_token = get_zoho_access_token()
    result = upsert_zoho_record("Leads", lead_data, ["Email"], access_token)    return jsonify({"status": "success", "result": result}), 200if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

Getting your initial refresh token

Before the above code works, you need to exchange a one-time grant token for a refresh token. Run this once:

# Exchange grant token for access + refresh tokens (run once)
import requestsresp = requests.post("https://accounts.zoho.com/oauth/v2/token", params={
    "code": "YOUR_GRANT_TOKEN",  # From Zoho API Console Self Client
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "grant_type": "authorization_code"
})tokens = resp.json()
print(f"Access Token: {tokens['access_token']}")
print(f"Refresh Token: {tokens['refresh_token']}")
# Save the refresh token securely. It does not expire.

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 Zoho CRM in batches.

Example: Poll and sync to Zoho CRM

import requests
from datetime import datetime, timedeltaBROWSE_AI_API_KEY = "your_browse_ai_api_key"
ROBOT_ID = "your_robot_id"
ZOHO_REFRESH_TOKEN = "your_refresh_token"
ZOHO_CLIENT_ID = "your_client_id"
ZOHO_CLIENT_SECRET = "your_client_secret"def get_zoho_access_token():
    resp = requests.post("https://accounts.zoho.com/oauth/v2/token", params={
        "refresh_token": ZOHO_REFRESH_TOKEN,
        "client_id": ZOHO_CLIENT_ID,
        "client_secret": ZOHO_CLIENT_SECRET,
        "grant_type": "refresh_token"
    })
    return resp.json()["access_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_zoho(tasks):
    """Upsert Zoho CRM leads from Browse AI task results."""
    access_token = get_zoho_access_token()
    records = []    for task in tasks:
        captured = task.get("capturedTexts", {})
        records.append({
            "Last_Name": captured.get("last_name", "") or "Unknown",
            "Company": captured.get("company_name", "") or "Unknown",
            "Email": captured.get("email", ""),
            "Phone": captured.get("phone", ""),
            "Lead_Source": "Browse AI"
        })    # Zoho supports batch upsert of up to 100 records per request
    if records:
        requests.post(
            "https://www.zohoapis.com/crm/v2/Leads/upsert",
            headers={
                "Authorization": f"Zoho-oauthtoken {access_token}",
                "Content-Type": "application/json"
            },
            json={
                "data": records,
                "duplicate_check_fields": ["Email"]
            }
        )# 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.

Zoho CRM-specific tips

Preventing duplicate records

Zoho CRM's /upsert endpoint is the best way to prevent duplicates. It accepts a duplicate_check_fields parameter that specifies which fields to match on. If a record with matching values exists, it updates that record instead of creating a new one:

# Upsert: create if new, update if Email matches an existing lead
requests.post(
    "https://www.zohoapis.com/crm/v2/Leads/upsert",
    headers={
        "Authorization": f"Zoho-oauthtoken {access_token}",
        "Content-Type": "application/json"
    },
    json={
        "data": [lead_data],
        "duplicate_check_fields": ["Email"]
    }
)

You can check against multiple fields (e.g. ["Email", "Phone"]) depending on your deduplication needs.

Working with different modules

The examples above use the Leads module, but Zoho CRM uses the same API pattern for all standard and custom modules. Just change the module name in the URL:

  • Leads: /crm/v2/Leads

  • Contacts: /crm/v2/Contacts

  • Accounts: /crm/v2/Accounts

  • Deals: /crm/v2/Deals

  • Custom modules: /crm/v2/Your_Custom_Module

Batch operations

Zoho CRM supports creating or upserting up to 100 records in a single API call. If you're syncing large volumes of Browse AI data, batch your records to reduce the number of API calls and stay within rate limits.

Common field mappings

Here are typical mappings between Browse AI captured fields and standard Zoho CRM Lead fields:

Browse AI field

Zoho CRM field

Notes

last_name

Last_Name

Required for Leads and Contacts

first_name

First_Name

company_name

Company

Required for Leads

email

Email

Used for deduplication

phone

Phone

website

Website

job_title

Designation

Zoho uses "Designation" for job title

address

Street

city

City

(origin URL)

Description or custom field

Available as task.inputParameters.originUrl

πŸ’‘ Custom fields: Zoho CRM supports custom fields on all modules. Create them in Setup β†’ Customization β†’ Modules and Fields. The API name of custom fields typically follows the format Custom_Field_Name (with underscores). You can list all available fields via GET /crm/v2/settings/fields?module=Leads.

Sending monitoring data to Zoho CRM

If you're using Browse AI monitors to track changes on websites, you can push change events into Zoho CRM. Use the taskCapturedDataChanged webhook event to trigger updates. For example, you could update a Contact's fields when their LinkedIn profile changes, or create a Zoho CRM 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

Zoho returns "INVALID_TOKEN" or 401 Unauthorized

Your access token has expired (they last about 1 hour). Use the refresh token to get a new access token before each batch of API calls, as shown in the code examples above.

Zoho returns "MANDATORY_NOT_FOUND" error

A required field is missing. For Leads, Last_Name and Company are always required. If your Browse AI data doesn't include these, provide a fallback value like "Unknown".

Zoho returns "DUPLICATE_DATA" error

You're using the standard create endpoint (POST /crm/v2/Leads) and a record with that email already exists with a duplicate check rule enabled. Switch to the /upsert endpoint instead (see "Preventing duplicate records" above).

Wrong data center

If you get connection errors or unexpected 404s, make sure your API URL matches your account's data center. US accounts use zohoapis.com, EU accounts use zohoapis.eu, and so on. Check your Zoho login URL to determine your data center.

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.

Did this answer your question?