Discover is intent-ranked semantic web search. You give it a query plus an
intent, and it returns results scored by AI relevance — optionally with the full
parsed page content. It is the right primitive when result quality/relevance
matters more than raw keyword rank, and the building block for retrieval (RAG),
research, and knowledge-base pipelines.
Discover vs. the neighbors:
Keyword "what ranks for X" SERP → use the search skill (bdata search).
Structured data from a known platform (Amazon/LinkedIn/…) → use data-feeds.
A whole research brief or a RAG/search pipeline on top of Discover → use
live-research or rag-pipeline (both call this API).
How it works (async: trigger → poll)
Trigger a job → you get a task_id.
Poll with the task_id until status is "done" (intermediate: "processing").
Read results[].
The CLI and SDKs do the trigger+poll for you; the raw REST flow is shown below for
when you need parameters the wrappers don't expose (notably mode).
Pick your surface
You are…
Use
In a terminal, one-off or scripted
CLI: bdata discover
Writing Node/TS code
JS SDK: client.discover() — see js-sdk-best-practices
Writing Python code
Python SDK: client.discover() — see python-sdk-best-practices
Need mode (deep/fast/zeroRanking) or include_images
# Intent-ranked discovery, JSONbdata discover "enterprise LLM platforms" \ --intent "vendor pages with pricing" \ --num-results 15 --json --pretty# With parsed page content in one pass (for RAG / research)bdata discover "webhook retry best practices" \ --include-content --num-results 10 -o results.json# Date-boundedbdata discover "react server components" \ --start-date 2025-01-01 --end-date 2025-12-31 --num-results 20 --json
Results live at .results[]; each has title, link, description,
relevance_score, and content when --include-content. Full CLI flag list:
search skill → references/flags.md.
SDK (one line each)
javascript
// JS — see js-sdk-best-practices for all options.// VERIFIED v1.1.0: discover() returns a WRAPPER { success, data:[...], totalResults, cost, taskId, ... }const res = await client.discover('Tesla battery tech', { intent: 'EV battery breakthroughs', numResults: 10, includeContent: true });const rows = res.data; // ← rows are in .data (NOT a bare array, NOT .results)
python
# Python — see python-sdk-best-practices (confirm whether rows come back directly, under .data, or .results)out = client.discover(query="Tesla battery tech", intent="EV battery breakthroughs")
no AI ranking, max raw volume; ignores num_results, no include_content
bulk corpus collection for rag-pipeline
mode is currently REST-only — the CLI and SDKs don't expose it. For deep
coverage via the CLI/SDK, approximate with a high num_results + a sharp
intent; for true deep/zeroRanking, use the raw REST flow above.
⚠️ Cross-surface gotcha: REST/CLI return rows under .results; the JS SDK
returns them under .data (and wraps everything in {success, ...} — check
success before reading data). Don't assume one shape across surfaces.
relevance_score is a float (snake_case). Higher = more relevant to intent.
content is plain text by default (Markdown when REST format=md). A high
relevance_score does not guarantee good content — pages can be 404 stubs or
nav-only; gate on content length + "not found"/block-page signatures before use.
Verification gate
Trigger returned a task_id (REST: status:"ok"). No id → check auth / that Discover is enabled on the account (403 if disabled).
Polled to status:"done" before reading — never read results while processing.
results[] non-empty — if empty, the query/intent is too narrow; loosen and retry. Don't claim success on empty.
include_content bodies aren't block pages — grep content for captcha, Just a moment, Access Denied, cf-browser-verification (same list as scrape). Drop poisoned rows.
Relevance sanity — if top relevance_scores are low or off-topic, sharpen intent (not just query).
Red flags
Passing only query with no intent — you lose the whole point (intent ranking). Always give an intent.
Treating Discover as keyword SERP — for "what ranks for X", use search.
Setting num_results > 20 — capped at 20; for more, run multiple targeted queries and dedup (see live-research).
Using zeroRanking then expecting include_content or num_results to apply — they don't.
Reading results before status:"done".
Treating an intermittent success:false (SDK) / empty results (REST/CLI) as a hard error — it's often transient; retry once with backoff first (see references/api-reference.md → Transient failures).
Fabricating relevance_score or content when a call fails — report the failure instead.
References
references/api-reference.md [blocked] — full REST endpoint spec, the exact param matrix per surface (REST vs CLI vs JS SDK vs Python SDK), error codes, and limits.