COQL vs Search Records in Zoho CRM — Limits, Speed, and When to Use Each
Sat Jan 18 2025
Zoho CRM · Query Design
COQL vs Search Records in Zoho CRM — Limits, Speed, and When to Use Each
Developers often ask whether to use COQL or the CRM Search Records API. This guide compares limits, performance, pagination, and real-world patterns so you can pick the right tool.
Choose COQL when…
- You need precise filters (AND/OR, ranges) and select only specific fields.
- You want fewer, denser network calls (select only what you need).
- You can work within row and field caps per query.
Choose Search Records when…
- You’re doing keyword/criteria searches supported by the endpoint.
- You need straightforward pagination (page/per_page) over large sets.
- You want to avoid COQL’s field cap and fetch many fields/schema defaults.
Key differences at a glance
- API shape: COQL executes a SQL-like
select_query
. Search Records takes query params/criteria and returns records with default field sets unless you specify fields. - Limits: COQL typically returns up to 200 rows and supports
limit <offset>, <count>
. Search Records uses page/per_page(often up to 200 per page). - Performance: For complex filters where you only need a handful of columns, COQL can be effectively faster because you transfer less JSON. For wide objects or fuzzy searches, Search Records is often simpler and comparable.
- Deluge vs REST: Use Deluge CRM tasks if they cover your use case; otherwise call REST via
invokeurl
for COQL or advanced search.
COQL examples (REST via invokeurl
)
Fetch only the fields you care about from Leads
, up to 200 rows:
// COQL (REST) via invokeurl in Deluge — single page body = { "select_query": "select Last_Name, Email, City from Leads where City = 'Dubai' limit 200" }; resp = invokeurl [ url : "https://www.zohoapis.com/crm/v8/coql" type : POST parameters : body connection : "zoho_crm_all" ]; // Null-safe reads rows = ifNull(resp.get("data"), list()); for each r in rows { email = ifNull(r.get("Email"), ""); // ... }
COQL pagination:
// Fetch up to 10,000 rows (50 × 200). Adjust repeats for more/less pages. // Uses "limit <offset>, 200" and stops when info.more_records == false. repeats = repeat(",", 49); // 49 commas => 50 iterations in toList() offset = 0; iteration = 0; all_rows = list(); for each r in repeats.toList() { q = "select id, Last_Name, Email from Leads where City = 'Dubai' limit " + offset + ", 200"; body = {"select_query": q}; resp = invokeurl [ url : "https://www.zohoapis.com/crm/v8/coql" type : POST parameters : body.toString() connection : "zoho_crm_all" ]; data = ifNull(resp.get("data"), list()); all_rows.addAll(data); // Early stop when server indicates no more pages if (response.getJSON("info").getJSON("more_records") == false) { break; } iteration = iteration + 1; offset = iteration * 200; // next page offset } info "Total fetched via COQL: " + all_rows.size();
Tips: COQL strings require single quotes around values. Keep field lists reasonable to avoid errors and reduce payload size.
Search Records examples (REST via invokeurl
)
Keyword/criteria search with simple pagination:
// Make sure of scope=ZohoSearch.securesearch.READ // Search Records (page/per_page) per_page = 200; page = 1; params = { "criteria": "(City:equals:Dubai)", "page" : page, "per_page": per_page }; resp = invokeurl [ url : "https://www.zohoapis.com/crm/v8/Leads/search" type : GET parameters : params connection : "zoho_crm_all" ]; rows = ifNull(resp.get("data"), list());
Search pagination (bounded loop + early break):
// Up to 10,000 rows (50 × 200). Increase repeats for more. repeats = repeat(",", 49); per_page = 200; page = 1; all_rows = list(); for each _ in repeats.toList() { urlStr = "https://www.zohoapis.com/crm/v8/Leads/search?page=" + page.toString() + "&per_page=" + per_page.toString() + "&criteria=(City:equals:Dubai)"; resp = invokeurl [ url : urlStr type : GET connection : "zoho_crm_all" ]; data = ifNull(resp.get("data"), list()); all_rows.addAll(data); infoMap = ifNull(resp.get("info"), Map()); more = infoMap.get("more_records"); // Stop when server says no more, or last page shorter than per_page if ((more != null && more == false) || data.size() < per_page) { break; } page = page + 1; } info "Total fetched via Search: " + all_rows.size();
Choosing by use case
- Dashboards/light reads: need a few columns with precise filters → COQL.
- Bulk/wide records: want many fields, okay with multiple pages → Search.
- Hybrid: COQL to get IDs + key columns, then fetch full details in chunks.
Common limits & guardrails
- Rows per call: COQL ≈ 200; Search
per_page
≈ 200. - COQL fields: keep field list reasonable (commonly ~50).
- Rate limits (429): add retries/backoff in your calling layer if you hit quotas.
- Null-safety: wrap reads with
ifNull
in Deluge.
Hybrid pattern: COQL + detail fetch
// 1) COQL to narrow set (IDs + a few columns) body = {"select_query":"select id from Deals where Stage = 'Closed Won' limit 200"}; coql = invokeurl [ url : "https://www.zohoapis.com/crm/v8/coql" type : POST parameters : body.toString() connection : "zoho_crm_all" ]; ids = List(); for each id in coql.get("data").toList() { ids.add(id.get("id)); } // 2) Fetch details one-by-one details = list(); for each rid in ids_list { resp = invokeurl [ url : "https://www.zohoapis.com/crm/v8/Deals/" + rid type : GET connection : "zoho_crm_all" ]; if(resp.get("data") != null) { details.add(resp.get("data") } }
SEO mini-FAQ
- “Is COQL faster than Search?” Often, if you select fewer fields and return less JSON.
- “Max records per COQL call?” Typically 200 rows. Paginate with offset/count.
- “When to avoid COQL?” When you need many fields from wide layouts or fuzzy search.