Skip to main content
These practices get your agent relevant pages in as few characters of context as possible. Each section stands alone. The samples run with no API key.

Describe the page you want

Write the query as a description of the page that would answer the question. Search is semantic, so describe the page in plain language instead of stacking keywords. Name the kind of page you want: documentation, postmortem, release notes, comparison.

Split a broad question into parallel searches

Run one narrow search per aspect of a broad question instead of one wide query. Cap how many run at once so you stay under your rate limit, 10 requests per second by default. This sample runs three searches, at most two at a time, and prints one citable block per query:
You see three blocks of three sources each, about 5,400 characters in total:
Example output · results vary

Narrow with filters, not extra words

Use site to restrict results to one site and published_after to get recent pages. A filter removes every page that doesn’t match it. If you set published_after, the results also leave out pages with no known publish date. This sample keeps pages on nodejs.org published in the last 30 days:
You see a publish date, a title and a URL per result, all on nodejs.org:
Example output · results vary
For recent results, use published_after, not query_time. query_time sets only an upper bound: "7d" searches the index as it stood 7 days ago and excludes everything newer. See Date and time filters for every accepted format.

Choose the mode

Leave mode at its default, pro, unless response time matters more than depth. Each mode is billed as its own SKU. See Credits. In SDK 0.1.x, the Python and TypeScript clients accept only pro. This request calls the HTTP API with realtime:
curl
The response’s mode field names the mode that served the request:
Example output · results vary

Control context size

Set the size of a search response in the request, then set the size of the prompt block when you render it. If you set neither, you get 10 results whose snippets often run to several thousand characters each. to_context() adds whole results in rank order and stops before the result that would pass max_chars. Call cited() with the same limits to get the results that the block kept. This sample asks for 5 short results and renders them into a block of at most 1,200 characters:
You see that the block kept 3 of the 5 results:
Example output · results vary
See Context size for the option names in each language.

Read snippets first, then fetch

Answer from the search snippets when you can. Each snippet is page text chosen for the query, so it often holds the answer. Fetch a page only if its snippet falls short, you need exact wording, or the user names a URL. When you fetch, ask for the part you need. prompt makes a model read the page and return only its answer in content. max_chars caps the characters of content, which defaults to 50000. SDK 0.1.x sends neither, so this request calls the HTTP API:
curl
content holds two sentences instead of the whole page:
Example output · results vary
See Fetch for live and what each fetch costs.

Group an agent run with a session ID

Send the same session ID on every search and fetch in one agent run, so Keenable can group the run’s requests. Name your app on every request too, so Keenable attributes the traffic to your product. If you send both the header and the session_id parameter, the header wins. The keyless /public endpoints require X-Keenable-Title. The SDKs send Keenable SDK unless you set the client source. This request tags one search with an app name and a session ID:
curl
You see an ordinary search response. Over MCP, pass session_id as a tool argument. See MCP.

Handle 429 and 402

On 429, wait for the time in the Retry-After header, then retry the same request. See 429 Rate limit exceeded and Rate limits. On 402, stop: your organization is out of credits, and every retry returns 402 until someone adds credits. See 402 Out of credits.

Next steps