TypeScript SDK

typesearch-js — the official client for TypeScript and JavaScript.

npm install typesearch-js

Works in Node 18+, Bun, Deno, Cloudflare Workers and other edge runtimes. No dependencies. ESM and CommonJS, fully typed.

Create a client

import Typesearch from 'typesearch-js';

const ts = new Typesearch(); // reads TYPESEARCH_API_KEY
OptionDefault
apiKeyTYPESEARCH_API_KEYYour key. new Typesearch('ts_live_…') works too.
baseURLhttps://api.typesearch.aiOr TYPESEARCH_BASE_URL.
timeout70000Milliseconds before a request is aborted. A deep search can take about a minute.
maxRetries2Retries on connection errors, timeouts, 429 rate_limited and 5xx.
defaultHeaders—Headers sent with every request.
fetchglobal fetchA custom implementation, for proxies or tests.
const res = await ts.search('el dólar', {
  mode: 'normal',
  max_results: 10,
  include_domains: ['reddiaria.example', 'diarioejemplo.example'],
  published_after: '2026-09-20',
  highlights: true,
});

for (const r of res.results) {
  console.log(r.score.toFixed(2), r.title, r.highlights[0]);
}

Options and response fields have the same names as the HTTP API and are typed: SearchOptions, SearchResponse, Result and the rest are exported.

Several queries at once:

const res = await ts.search(['el dólar', 'el FMI'], { mode: 'fast' });
res.groups?.forEach((g) => console.log(g.query, g.total));

Stream

for await (const event of ts.searchStream('el dólar', { mode: 'deep' })) {
  switch (event.type) {
    case 'step':
      console.log('·', event.step.text);
      break;
    case 'partial':
      render(event.response.results);
      break;
    case 'result':
      render(event.response.results);
  }
}

// Or only the final result
const final = await ts.searchStream('el dólar').finalResponse();

An error event is thrown as an APIError from the loop.

Similar and contents

const similar = await ts.similar('https://diarioejemplo.example/economia/…', { exclude_domains: ['diarioejemplo.example'] });

const pages = await ts.contents(['https://reddiaria.example/economia/…'], { query: 'el dólar' });
// Create the job and wait for it
const res = await ts.siteSearchAndWait('diarioejemplo.example', 'el dólar', { mode: 'normal' });

// Or handle the job yourself
const job = await ts.siteSearch('diarioejemplo.example', 'el dólar');
const done = await ts.jobs.wait(job.id, { pollInterval: 2000, waitTimeout: 120_000 });

// Or stream it
for await (const event of ts.siteSearchStream('diarioejemplo.example', 'el dólar')) {
  // …
}

jobs.wait() throws JobFailedError if the job fails.

Usage

// Your key’s usage and limits
const usage = await ts.usage();

Every result shows its source and links to the original. Missing an outlet? Suggest it from the dashboard (Suggest a source) or write to support@typesearch.ai.

Errors

Every error extends TypesearchError. API errors are APIError subclasses with status, code, requestId and, for invalid requests, errors per field.

ClassWhen
BadRequestError400
AuthenticationError401
BudgetError402 — budget_too_small, insufficient_credits or spend_limit_reached
PermissionDeniedError403
NotFoundError404
RateLimitError429 — with retryAfter
InternalServerError5xx
APIConnectionError · APITimeoutErrorNo response, or too slow
JobFailedErrorA live site search job failed
import { BadRequestError, RateLimitError, APIError } from 'typesearch-js';

try {
  await ts.search('x');
} catch (e) {
  if (e instanceof BadRequestError) console.log(e.code, e.errors);
  else if (e instanceof RateLimitError) console.log(e.code, e.retryAfter);
  else if (e instanceof APIError) console.log(e.status, e.code, e.requestId);
  else throw e;
}

Retries, timeouts and cancelling

Connection errors, timeouts, 429 rate_limited and 5xx are retried twice with exponential backoff and jitter, honouring Retry-After; quota_exceeded never is. Every method takes a last argument to override the client’s settings per request — { timeout, maxRetries, signal, headers }:

const controller = new AbortController();

const res = await ts.search('el dólar', { mode: 'deep' }, {
  timeout: 90_000,
  maxRetries: 0,
  signal: controller.signal,
  headers: { 'X-Trace-Id': 'abc' },
});

For a stream, timeout covers the wait until the response starts; aborting the signal also stops reading it.

On this page