JavaScript SDK Specification

    JavaScript SDK Specification

    Examples on this page match desearch-js@1.5.1. extract() is the extract call. webCrawl() remains a deprecated alias on this version. New code should call extract().

    First AI Search call: Search API. Page fetch: Extract API. Keys: Auth and API keys.

    Install

    Requires Node.js 20.18.1 or later. Node 18 is not supported. npm still installs the package on Node 18 with an EBADENGINE warning, but that setup is not tested.

    Pin the version used in these examples:

    bash
    npm install desearch-js@1.5.1

    Use 1.5.1 or later. On 1.5.0, importing the package could crash with TypeError: webidl.util.markAsUncloneable is not a function when the package manager installed undici 8 at the top level of the project. 1.5.1 limits its undici dependency to versions 6 and 7 and loads correctly even when undici 8 is present.

    Construct the client

    Desearch is both the default export and a named export. Pass the raw API key. Do not expose production keys in browser bundles.

    ES modules:

    javascript
    import Desearch from "desearch-js"; // or: import { Desearch } from "desearch-js"; const desearch = new Desearch(process.env.DESEARCH_API_KEY);

    CommonJS:

    javascript
    const { Desearch } = require("desearch-js"); async function main() { const desearch = new Desearch(process.env.DESEARCH_API_KEY); const result = await desearch.aiSearch({ prompt: "latest AI search API notes", tools: ["web"], count: 10, }); console.log(result); } main();

    Do not pass streaming into aiSearch. The method always sends a non-stream request. For "streaming": true, call REST. See Streaming AI Search.

    Extract

    javascript
    const content = await desearch.extract({ url: "https://en.wikipedia.org/wiki/Artificial_intelligence", format: "text", });

    Billing metadata

    Read request cost from response headers. JSON object bodies may also include cost_usd, usage_count, service, and currency.

    HeaderMeaning
    X-Desearch-Cost-UsdRequest cost in USD
    X-Desearch-Usage-CountBillable usage units
    X-Desearch-ServicePricing service key
    X-Desearch-CurrencyCurrency code

    Arrays, text responses, and streaming responses keep their body shape. Use headers for those. This page does not list dollar rates.

    Errors

    • Missing or invalid key: 401.
    • Validation failure: 4xx with the API message.
    • 429 or 5xx: retry with backoff.

    Do not invent error JSON schemas beyond the API Reference.

    Parity with Python

    CapabilityPython 1.2.1JavaScript 1.5.1
    AI Searchai_search(...)aiSearch({...})
    Extract page contentREST /web/extract or web_crawlextract({...})
    Streaming helpersNot on this package. Use REST (streaming guide)Same
    Billing fields on a JSON objectRead body and headersSame
    Billing on a streamHeaders onlyHeaders only
    People Search (Python 1.4.0, JavaScript 1.6.0)x_profile_search(...), youtube_creator_search(...), linkedin_profile_search(...), tiktok_creator_search(...)xProfileSearch({...}), youtubeCreatorSearch({...}), linkedinProfileSearch({...}), tiktokCreatorSearch({...})
    Wait for a People Search taskwait_for_people_task(task_id)waitForPeopleTask(task)
    Read every People Search resultiter_people_results(task_id)iterPeopleResultPages({ task_id })
    People Search metadata labels (Python 1.5.0, JavaScript 1.7.0)metadata={...} on the search methods and list_people_tasksmetadata: {...} in the search request and in listPeopleTasks

    Python extract() is not on PyPI desearch-py 1.2.1. See the Python SDK.

    Other methods already on this package

    Web search:

    javascript
    const result = await desearch.webSearch({ query: "latest AI search news", num: 10, start: 0, }); console.log(result);

    X search:

    javascript
    const result = await desearch.xSearch({ query: "Bittensor", sort: "Top", count: 20, }); console.log(result);

    People Search (1.6.0 and later)

    People Search methods ship in desearch-js 1.6.0. The examples above match 1.5.1.

    bash
    npm install desearch-js@^1.6.0

    A search runs in the background. Start it, wait for it, then read or export the people it found:

    javascript
    import { randomUUID } from "node:crypto"; import Desearch from "desearch-js"; const desearch = new Desearch(process.env.DESEARCH_API_KEY); // The only billed call. It returns a queued task at once. const task = await desearch.xProfileSearch( { query: "Indie hackers building in public who share their MRR", count: 10 }, { idempotencyKey: randomUUID() }, ); // Polls until the task ends. Free. await desearch.waitForPeopleTask(task, { intervalMs: 5000, timeoutMs: 10 * 60 * 1000 }); for await (const page of desearch.iterPeopleResultPages({ task_id: task.task_id, limit: 100 })) { for (const person of page.results) { console.log(person.handle, person.score?.value); } } const csv = await desearch.exportPeopleResults({ task_id: task.task_id, format: "csv" }); console.log(csv.length);
    MethodRoute
    xProfileSearch, youtubeCreatorSearch, linkedinProfileSearch, tiktokCreatorSearchPOST /desearch/people/search/{x,youtube,linkedin,tiktok} (billed)
    listPeopleTasksGET /desearch/people/tasks
    getPeopleTaskGET /desearch/people/tasks/{task_id}
    getPeopleResultsGET /desearch/people/tasks/{task_id}/results
    pausePeopleTask, resumePeopleTask, cancelPeopleTaskPOST /desearch/people/tasks/{task_id}/pause, /resume, /cancel
    exportPeopleResultsGET /desearch/people/tasks/{task_id}/export
    listPeopleProfilesGET /desearch/people/profiles
    exportPeopleProfilesGET /desearch/people/profiles/export
    waitForPeopleTaskPolls getPeopleTask until the task ends
    iterPeopleResultPagesFollows next_cursor on getPeopleResults

    Each search request takes query, count, min_score, exclude, and that platform's filters, plus metadata from 1.7.0 (below). idempotencyKey in the second argument is sent as the Idempotency-Key header. Pause, resume, and cancel throw PeopleTaskConflictError on HTTP 409. waitForPeopleTask throws when timeoutMs passes; the search keeps running. Flow, filters, and billing: People Search.

    Label searches with metadata (1.7.0 and later)

    desearch-js 1.7.0 adds metadata to the four search methods and a metadata option to listPeopleTasks. Use it to tag each search with your own labels, such as the campaign, workspace, or customer it belongs to, and to list those searches later. The search itself never uses the labels.

    bash
    npm install desearch-js@^1.7.0
    javascript
    import { randomUUID } from "node:crypto"; import Desearch from "desearch-js"; const desearch = new Desearch(process.env.DESEARCH_API_KEY); const task = await desearch.xProfileSearch( { query: "Indie hackers building in public who share their MRR", count: 10, metadata: { campaign: "q4-outbound", workspace_id: "ws_42" }, }, { idempotencyKey: randomUUID() }, ); console.log(task.metadata); // { campaign: 'q4-outbound', workspace_id: 'ws_42' } // Later: every search of that campaign, newest first. const { tasks } = await desearch.listPeopleTasks({ metadata: { campaign: "q4-outbound" }, }); for (const t of tasks) { console.log(t.task_id, t.status, t.metadata.workspace_id); }
    • task.metadata is {} for a search without labels.
    • A search takes up to 10 keys. Keys are 1 to 40 characters of a-z, 0-9, _, ., or -, and values are strings of up to 200 characters. The SDK does not check them; the API answers 422 otherwise.
    • listPeopleTasks sends each pair as a metadata.<key>=<value> query parameter, and a task must match all of them exactly. Pass up to 3 pairs (the API answers 400 otherwise), and pass the same metadata with each cursor when you page.
    • This metadata is the task's labels. It is not the cost metadata that { includeMetadata: true } returns.

    Next