September 10, 2026

Web Search API in JavaScript: A Practical Guide With the You.com SDK

Web Search API in JavaScript: A Practical Guide With the You.com SDK

TLDR: The official route to the You.com Web Search API from JavaScript is the youdotcom TypeScript SDK, published as @youdotcom-oss/sdk on npm with CommonJS and ESM builds. One install command, one environment variable, and a working search call is four lines. This guide covers the calls you will actually make, the typed response fields, filters, error handling, retries, and the standalone-function build for bundle-size-sensitive apps.

What is the web search api javascript pattern? Install @youdotcom-oss/sdk, put your key in an environment variable, construct a You client with apiKeyAuth, and await you.search() with a query. The SDK returns a typed SearchResponse whose results.web array carries url, title, description, snippets, and page age per result. No manual HTTP and no hand-rolled response parsing.

The SDK is generated against the published You.com API surface and maintained in the open in the youdotcom-typescript-sdk repository, with a runnable example file covering every endpoint and a benchmark script that measures SDK overhead against raw curl. It wraps four operations: search, contents, research, and agent runs. This guide focuses on search, the one most JavaScript applications call first.

How Do You Install the You.com TypeScript SDK?

Installation is one command with any of the four package managers the README documents: npm, pnpm, bun, or yarn (youdotcom-typescript-sdk README, fetched 2026-09-10).

npm add @youdotcom-oss/sdk

The package ships with both CommonJS and ES Module builds, so the same import works in a Node.js service, a bundler-based frontend, or a serverless function. Get an API key from the You.com platform and put it in an environment variable. The SDK does not read the environment on its own: you pass the value through the apiKeyAuth option, so the variable name is your choice. The SDK README uses YOU_API_KEY_AUTH, the You.com docs use YDC_API_KEY, and the examples below follow the README. That is the only configuration a first call needs.

What Does a First Search Call Look Like?

A minimal working search is the client, one await, and the typed result (SDK authentication example, fetched 2026-09-10).

import { You } from "@youdotcom-oss/sdk"

const you = new You({
  apiKeyAuth: process.env["YOU_API_KEY_AUTH"] ?? "",
})

async function run() {
  const result = await you.search({
    query: "EU AI Act enforcement timeline",
    count: 10,
  })

  for (const hit of result.results?.web ?? []) {
    console.log(hit.title, hit.url)
  }
}

run()

Two details in that snippet are doing real work. The apiKeyAuth parameter is required, and the ?? "" fallback means an unset variable surfaces as a 401 at call time rather than a crash at construction, which is the failure you want because it names the actual problem. The optional chaining on results is deliberate: the response model marks the nested lists as optional, and guarding them keeps an unusual response from crashing a whole request handler.

Which Request Fields Does search() Accept?

The SearchRequest model documents nine fields, and each maps to a documented Web Search API parameter (SDK models reference, fetched 2026-09-10).

query is the only required field and accepts search operators inline. count caps results per section, and the sections are web and news, so count: 10 can return up to ten of each. freshness takes day, week, month, year, or a date range string in the form YYYY-MM-DDtoYYYY-MM-DD, and the SDK notes that when the query itself carries a temporal keyword, the broader of the two timeframes wins. offset paginates in multiples of count with a documented range of 0 through 9. country sets the geographic focus, language takes a BCP 47 tag, and safesearch configures content moderation.

Two fields control live crawling: livecrawl selects which result sections get full page content attached, and livecrawlFormats picks the format of that crawled content. Used together they collapse the usual search-then-fetch two-step into one call. One caution: the Web Search API reference marks livecrawl and livecrawl_formats as deprecated in favor of an extraction object with extraction_mode set to highlights or full_page (you.com/docs/api-reference/search, accessed September 2026). The old fields still work, but new code should pass the extraction object, which the SDK accepts on the same search call and which also unlocks highlights, the query-relevant passages that snippets are not. Crawled pages are billed per page on top of the call, so request them only when you will read them.

Decision framework: start with query and count alone, then add one filter at a time when a real requirement names it. Freshness helps an update feed and hurts a troubleshooting query that needs the canonical documentation page. The tradeoff is precision against recall, and it only pays when the query actually needs the narrowing. If you cannot name the behavior a filter encodes, leave it off.

How Do You Read the Response Without Crashing on Missing Fields?

The SearchResponse model marks results and its nested web and news lists as optional, so defensive access is the correct default, not paranoia. Each web result carries url, title, description, snippets, thumbnailUrl, pageAge, authors, and faviconUrl. News results carry url, title, description, thumbnailUrl, and pageAge, without the snippets array. Note the camelCase: the SDK renames the API's snake_case fields (page_age, favicon_url) on the way in, so raw HTTP examples and SDK code will not share field names.

The concrete failure mode to detect: an empty web list flowing into downstream logic as a successful retrieval. An empty response, a missing results object, and a thrown error are three different conditions, and collapsing them into one code path is how an application ends up citing sources that do not exist. Separate them explicitly.

const web = result.results?.web ?? []

if (web.length === 0) {
  console.log("No web results for this query")
} else {
  for (const hit of web) {
    console.log(hit.url, (hit.snippets ?? []).length)
  }
}

Preserve the URL alongside whatever text you pass downstream. Flattening a result to its description discards the passages that would later support a citation, and reconstructing provenance after the fact is far more work than keeping it from the start.

How Do You Handle Errors and Retries?

The SDK raises typed error classes, so a 401 from search and a 500 from search are distinct branches instead of one stringly-typed catch (SDK error reference, fetched 2026-09-10). Every HTTP error response subclasses YouError, which carries message, statusCode, headers, body, and the raw response.

import * as errors from "@youdotcom-oss/sdk/models/errors"

try {
  const result = await you.search({ query: "your query" })
} catch (error) {
  if (error instanceof errors.SearchUnauthorizedError) {
    // 401: fix the key in YOU_API_KEY_AUTH
  } else if (error instanceof errors.SearchForbiddenError) {
    // 403: the key lacks scope for this path
  } else if (error instanceof errors.SearchInternalServerError) {
    // 500: safe to retry with backoff
  } else if (error instanceof errors.YouError) {
    console.log(error.statusCode, error.message)
  } else {
    throw error
  }
}

ConnectionError, RequestTimeoutError, and RequestAbortedError sit outside the API error family and cover transport failures, while ResponseValidationError fires when a response does not match its model, which usually means the API changed and the SDK needs an upgrade.

Retries are configurable per call or across the whole client with a retryConfig. The README's example uses a backoff strategy with initialInterval, maxInterval, exponent, and maxElapsedTime values, applied either at the call site or at SDK initialization. Without a retryConfig the SDK falls back to the default retry strategy provided by the API, so make the choice explicit in production code rather than inheriting a default you never read. Retry on 429 and 5xx only. A 401 or 403 will not succeed on the second try, and the API's 429 responses carry a Retry-After header worth honoring (you.com/docs/rate-limits, accessed September 2026).

What Are Standalone Functions and When Do You Need Them?

Every method is also published as a standalone function, and the README recommends them for browsers, serverless runtimes, and anywhere bundle size matters, because a bundler tree-shakes unused functionality out of the final build (SDK standalone functions section, fetched 2026-09-10).

import { YouCore } from "@youdotcom-oss/sdk/core.js"
import { search } from "@youdotcom-oss/sdk/funcs/search.js"

const you = new YouCore({
  apiKeyAuth: process.env["YOU_API_KEY_AUTH"] ?? "",
})

const res = await search(you, { query: "your query" })
if (res.ok) {
  const { value: result } = res
} else {
  console.log("search failed:", res.error)
}

Note the different result shape: standalone functions return a wrapper with an ok flag instead of throwing, which suits pipelines that prefer explicit branch handling over try/catch nesting. One YouCore instance can be shared across an application.

How Much Overhead Does the SDK Add?

The repository ships a benchmark script that runs curl, the full SDK, and a mocked-network SDK over the same query and compares them. In the run published in the README, the mocked variant averaged 0.27 milliseconds per call, which isolates request building and response parsing from network latency (youdotcom-typescript-sdk README, fetched 2026-09-10). That is the SDK's own measurement of its own overhead on one machine, not an API latency claim. Run the script yourself with npx tsx api-performance.ts if the number matters to your architecture.

What Else Ships on the Same Client?

The same You instance carries contents, which takes a list of URLs and returns each page as HTML or Markdown, and research, which returns a research-grade answer with sources you can iterate. The example file in the repository demonstrates all of them with runnable code, including a streaming agent run consumed with a for await loop per the MDN async iteration reference.

If your application is an agent rather than a service, the MCP server comparison guide covers when one MCP install beats an embedded SDK across multiple clients. For the framework-native wiring in a LangChain agent, see the LangChain web search tool guide, and for the same API from Python, the Python SDK guide mirrors this one. The full parameter reference lives in the Web Search API documentation.

Next action: run the four-line quickstart against a query from your own domain, print every field of one web result, then wire the error branches from this guide before your first deployment. When that loop works, move your real queries over with a key from the You.com platform. Usage rates are listed on the You.com pricing page.

Related Guides

    Share Article:

  1. LI Test

  2. LI Test

Related resources.

Self-Hosted LLM Serving: Picking a Stack That Survives Real Traffic

Self-Hosted LLM Serving: Picking a Stack That Survives Real Traffic

September 16, 2026

Blog

What Is On-Premise AI? Deploying Intelligence Inside Your Own Infrastructure

What Is On-Premise AI? Deploying Intelligence Inside Your Own Infrastructure

September 15, 2026

Blog

How to Run an LLM Locally: A Practical Walkthrough for Developers

How to Run an LLM Locally: A Practical Walkthrough for Developers

September 15, 2026

Blog

How to Add Web Search to the Vercel AI SDK With the You.com API

How to Add Web Search to the Vercel AI SDK With the You.com API

September 14, 2026

Blog

How to Build RAG With Web Search: A Practical Pipeline Guide

September 11, 2026

Blog