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
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 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.
Connect your Zoho CRM account.
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.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)
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 Zoho CRM β Create a Record module, connect your Zoho CRM account, select your module (e.g. Leads), and map your fields.
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
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 Zoho CRM's field format.
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:
Go to the Zoho API Console and click Add Client.
Select Self Client as the client type (simplest for server-to-server integrations).
Note your Client ID and Client Secret.
Under the Self Client tab, generate a grant token with the scope
ZohoCRM.modules.ALL(or a more specific scope likeZohoCRM.modules.leads.CREATE).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:
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 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/LeadsContacts:
/crm/v2/ContactsAccounts:
/crm/v2/AccountsDeals:
/crm/v2/DealsCustom 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 |
|
| Required for Leads and Contacts |
|
| |
|
| Required for Leads |
|
| Used for deduplication |
|
| |
|
| |
|
| Zoho uses "Designation" for job title |
|
| |
|
| |
(origin URL) |
| Available as |
π‘ 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.
