> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tako.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tako Search on the Vercel AI Gateway

> Ground any model on the Vercel AI Gateway in Tako's curated data and the live web with one option — no Tako account required.

Tako Search is a built-in tool on the [Vercel AI Gateway](https://vercel.com/docs/ai-gateway). Add one option to a `generateText` call and any model on the gateway can search Tako's curated knowledge graph and the live web, then answer with sourced figures and an embeddable chart. Vercel runs the search and bills for it, so you need no Tako account and no Tako key.

This page covers authenticating, reading the cards a search returns, and the two behaviors that most often make a working integration look broken.

<Info>
  **Which Vercel integration do you want?** This page covers the AI Gateway's built-in tool: search only, no Tako account, Vercel bills you. If you want `answer` and `contents` as well, and you're happy to hold a Tako API key and let us bill you, use [`@takoviz/ai-sdk`](/documentation/integrations/vercel-ai-sdk) instead. You use both through the Vercel AI SDK, and both expose a function called `takoSearch`, but their options aren't interchangeable.
</Info>

## Install

The gateway tool ships in the AI SDK itself. You don't install a Tako package.

```bash theme={null}
npm install ai
```

## Authenticate

Create a key in the Vercel dashboard under **AI Gateway → API Keys**:

```bash theme={null}
export AI_GATEWAY_API_KEY=vck_...
```

On Vercel deployments, use the automatically available `VERCEL_OIDC_TOKEN` instead and set nothing.

<Warning>
  Without a payment card on file, every request returns `403 customer_verification_required`. Add one in the Vercel dashboard. The free credits it unlocks are rate-limited, so **top up with paid credits** before you build against it.
</Warning>

## Quick start

Pass `gateway.tools.takoSearch()` in `tools`. The gateway executes the search, feeds the results back to the model, and returns one finished answer:

<CodeGroup>
  ```typescript generateText theme={null}
  import { gateway, generateText, stepCountIs } from 'ai';

  const { text } = await generateText({
    model: 'openai/gpt-5.6-sol',
    prompt: 'How big is Nvidia? Give me its latest annual revenue figure.',
    tools: {
      tako_search: gateway.tools.takoSearch(),
    },
    stopWhen: stepCountIs(4),
  });

  console.log(text);
  ```

  ```typescript streamText theme={null}
  import { gateway, streamText, stepCountIs } from 'ai';

  const result = streamText({
    model: 'openai/gpt-5.6-sol',
    prompt: 'How big is Nvidia? Give me its latest annual revenue figure.',
    tools: { tako_search: gateway.tools.takoSearch() },
    stopWhen: stepCountIs(4),
  });

  for await (const part of result.fullStream) {
    if (part.type === 'text-delta') process.stdout.write(part.text);
  }
  ```
</CodeGroup>

<Accordion title="Example output">
  ```text theme={null}
  Nvidia's latest annual revenue was $215.9 billion for fiscal year 2026, ended
  January 25, 2026. That was up about 65% from $130.5 billion the prior year.

  [Source: Nvidia financial data via Fiscal.ai]
  ```

  Drop the `tools` option and the same model answers "\$130.5 billion for fiscal year 2025" — a real figure, one year stale, presented with no indication that a newer one exists.
</Accordion>

## Parameters

```typescript theme={null}
gateway.tools.takoSearch({
  effort: 'fast',            // 'instant' | 'fast' (default) | 'deep'
  sources: {                 // omit to search both; only the sources you list are searched
    data: { count: 2, includeContents: false, maxRows: 50, contentFormat: 'json_compact' },
    web: { count: 3, highlights: true, includeDomains: ['reuters.com'] },
  },
  includeRelated: 5,
  location: { latitude: 37.77, longitude: -122.42 },
  countryCode: 'US',
  locale: 'en-US',
  timezone: 'America/New_York',
});
```

Options you set here are developer defaults — the gateway applies them over anything the model generates. For the complete wire schema see Vercel's [Web Search reference](https://vercel.com/docs/ai-gateway/models-and-providers/web-search); for retrieval behavior see the [Tako Search guide](/documentation/integrating-tako/search/for-coding-agent).

<Warning>
  `sources.data.includeContents` is the parameter that adds row charges, and models set it on their own if you don't pin it. Search first, read each card's `content.export_pricing`, then export.
</Warning>

## Read the cards

This is what makes Tako different from the gateway's other search tools: alongside web results, a Tako search returns [**knowledge cards**](/documentation/getting-started/what-is-tako/knowledge-cards) — structured series with their sources, and a rendered chart you can embed.

Web results arrive alongside the cards in `web_results`, each carrying `title`, `url`, `snippet`, `source_name`, `content`, and `publish_date` where the source reports one. Each card carries these fields, among others — the [full card schema](/api-reference/search-v3#response-cards) covers the rest:

| Field                    | What it is                                                     |
| ------------------------ | -------------------------------------------------------------- |
| `title`                  | The card's headline                                            |
| `embed_url`              | An iframe URL for the interactive chart                        |
| `image_url`              | A static PNG of the same chart                                 |
| `webpage_url`            | The card's page on Tako                                        |
| `sources`                | Publisher attribution, e.g. `Fiscal.ai`                        |
| `data_freshness`         | `coverage_end` and `last_updated` (`data_as_of` is deprecated) |
| `content.export_pricing` | Row cost and ceiling, if you want the raw data                 |

**Collect them across steps, and dedupe.** The gateway runs the tool loop, so one
prompt can produce several searches, and overlapping searches return the same
series more than once. Keep the freshest copy of each:

```typescript theme={null}
const { steps } = await generateText({
  model: 'openai/gpt-5.6-sol',
  prompt: 'How has US unemployment trended over the last five years?',
  tools: { tako_search: gateway.tools.takoSearch({ sources: { data: { count: 2 } } }) },
  toolChoice: 'required',
  stopWhen: stepCountIs(3),
});

const periodEnd = (card) => {
  const v = card.data_freshness?.coverage_end;
  if (!v) return '';
  return v.length === 4 ? `${v}-12-31`
    : v.length === 7 ? new Date(Date.UTC(+v.slice(0, 4), +v.slice(5, 7), 0)).toISOString().slice(0, 10)
    : v;
};

const byTitle = new Map();
for (const c of steps.flatMap((s) => s.toolResults).flatMap((t) => t.output?.cards ?? [])) {
  const prev = byTitle.get(c.title);
  if (!prev || periodEnd(c) > periodEnd(prev)) byTitle.set(c.title, c);
}

for (const card of byTitle.values()) {
  console.log(card.title, card.embed_url, card.data_freshness?.coverage_end);
}
```

**Output** — three cards in, two out:

```text theme={null}
United States Unemployment Rate (Seasonally Adjusted)
  https://tako.com/embed/zMsR5sdsw4PNqDA2lCJ7/   2026-01
United States Harmonised Unemployment Rate
  https://tako.com/embed/stCzZezoK_2vdIYsTNPk/   2026-01
```

Cards are windowed to the time range a query implies, so the same metric returns
at different vintages depending on how the model phrased each search. Three
things that recipe gets right:

* **`steps`, not `toolResults`** — on a multi-step call the top-level
  `toolResults` holds the last step only.
* **`title`, not `card_id`** — every request mints a fresh id, so an id-based
  dedupe removes nothing.
* **Pad before comparing** — `coverage_end` is ISO 8601 reduced precision, so a
  raw string compare puts `2026` below `2026-06`.

A card that carries projections reports a `coverage_end` in the future, and
nothing in the response marks it as a projection, so it wins this comparison.
If that matters to you, drop cards whose period ends after today — but note that
also drops the current month and the current year, whose periods haven't closed
either.

An embed posts a `tako::resize` message carrying its rendered height. Handle it and set that iframe's height, or the chart clips. See [Embedding Knowledge Cards](/documentation/integrating-tako/embedding-knowledge-cards) for the handler and dark-mode options.

## Inline the underlying rows

A search returns each card's headline figure and chart. To give an agent the
series itself — to filter it, join it, or compute on it — set
`sources.data.includeContents`:

```typescript theme={null}
const { steps } = await generateText({
  model: 'openai/gpt-5.6-sol',
  prompt: "Nvidia's annual revenue history",
  tools: {
    tako_search: gateway.tools.takoSearch({
      sources: { data: { count: 1, includeContents: true, maxRows: 8 } },
    }),
  },
  toolChoice: 'required',
  stopWhen: stepCountIs(3),
});

const [card] = steps.flatMap((s) => s.toolResults).flatMap((t) => t.output?.cards ?? []);
console.log(card.content.dataset);
```

**Output**

```json theme={null}
{
  "columns": [
    { "name": "Timestamp", "type": "datetime" },
    { "name": "total_revenues - NVIDIA Corporation Total Revenues (Normalized)", "type": "number" }
  ],
  "rows": [
    ["2019-01-27T00:00:00+00:00", 11716000000],
    ["2020-01-26T00:00:00+00:00", 10918000000],
    ["2021-01-31T00:00:00+00:00", 16675000000],
    ["2022-01-30T00:00:00+00:00", 26914000000],
    ["2023-01-29T00:00:00+00:00", 26974000000],
    ["2024-01-28T00:00:00+00:00", 60922000000],
    ["2025-01-26T00:00:00+00:00", 130497000000],
    ["2026-01-25T00:00:00+00:00", 215938000000]
  ],
  "total_rows": 22,
  "truncated": true,
  "ref": "https://tako.com/card/kNnM5fuLvIUJxouKkVrx/",
  "sources": [{ "name": "Fiscal.ai", "index": "data" }],
  "provenance": "query"
}
```

Columns are typed and unit-labeled, and `ref` links back to the card the rows
came from.

**Read the field that matches your `contentFormat`.** Each format returns a
different type, so each lands in its own field. One is populated when rows are
delivered — but a response shares a row budget across cards, so a later card can
come back with no rows at all. Test `content.content_format` for null to tell a
quote from a delivery, and fetch that card's rows from
[`/api/v1/contents`](/api-reference/contents) using its `export_pricing` quote:

| `contentFormat`          | Rows arrive in      | Type                                |
| ------------------------ | ------------------- | ----------------------------------- |
| `json_compact` (default) | `content.dataset`   | typed columns plus positional rows  |
| `json_records`           | `content.records`   | list of row objects keyed by column |
| `csv`                    | `content.data`      | CSV text                            |
| `card_json`              | `content.card_data` | card-type-specific object           |

`card_json` is the one to guard. Card types that have no `card_json` shape fall
back to `json_compact` on search rather than erroring, so a request that asked
for `card_json` can return its rows in `content.dataset`. Branch on the
`content.content_format` the response reports, not on the format you asked for.

`content.cost` is what this response billed for the rows it inlined; on a card
with no inlined rows it's a quote and Vercel billed nothing. Price a later
export from `content.export_pricing` alone — the two cover different row counts.
Omit `maxRows` and each card returns 20 rows, with `truncated: true` when more
remain. Vercel bills every inlined row.

<Warning>
  **A model can attribute a figure to these rows that isn't in them.** Check any
  figure it cites against the rows themselves.
  Asked to compute a growth rate from a payload like this one, a model reported
  "from the returned rows" and used a figure that appears nowhere in them — it
  had read the card's description instead. The arithmetic was right; the
  provenance claim was not.
</Warning>

## Examples

### Compare two companies over time

The interesting questions need more than one lookup. Ask when one company passed
another and the model searches both, reads the rows, and reconciles the dates —
no orchestration on your side:

```typescript theme={null}
const { text } = await generateText({
  model: 'openai/gpt-5.6-sol',
  prompt: "When did Nvidia's annual revenue overtake Intel's, and how far apart are they now?",
  tools: {
    tako_search: gateway.tools.takoSearch({
      sources: { data: { count: 2, includeContents: true, maxRows: 12 } },
    }),
  },
  toolChoice: 'required',
  stopWhen: stepCountIs(6),
});
```

**Output** — after four searches:

```text theme={null}
Nvidia first overtook Intel in the annual periods ending around January 2024:

- Nvidia FY2024: $60.9 billion
- Intel FY2023:  $54.2 billion
- Nvidia's lead: $6.7 billion

Using their latest comparable completed fiscal years:

- Nvidia FY2025, ended Jan. 26, 2025: $130.5 billion
- Intel FY2024, ended Dec. 28, 2024:  $53.1 billion
- Current gap: $77.4 billion

So Nvidia now generates roughly 2.46x Intel's revenue, or 146% more.

The fiscal-year labels differ because Nvidia's year ends in January, while
Intel's ends in December.
```

Note the last line: the model caught the fiscal-calendar mismatch on its own,
because each card carries its own period boundaries.

<iframe width="100%" src="https://tako.com/embed/bbmz-3vNm3f_1Yo7_ypn/" title="Chart: NVIDIA and Intel annual total revenues" scrolling="no" frameborder="0" className="rounded-xl" />

### Screen the market

Ranking cards are same-day. This one is a leaderboard of 30 trading items
refreshed during the session:

```typescript theme={null}
const { text } = await generateText({
  model: 'openai/gpt-5.6-sol',
  prompt: "What are today's top performing stocks?",
  tools: {
    tako_search: gateway.tools.takoSearch({ sources: { data: { count: 1 } } }),
  },
  toolChoice: 'required',
  stopWhen: stepCountIs(4),
});
```

**Output**

```text theme={null}
Today's top-performing stocks, September 3, 2026, ranked by percentage gain:

  1  SunPower                  SPWR   +47.0%
  2  ChargePoint Holdings      CHPT   +31.9%
  3  Cypherpunk Technologies    CYPH   +25.7%
  4  GCL Global Holdings        GCL    +21.7%
  5  Katapult Holdings          KPLT   +20.9%

These are session gainers — not recommendations — and sharp moves often
involve volatile, smaller-cap stocks.
```

<iframe width="100%" src="https://tako.com/embed/fvYC3l4ZPRnq7cGmKs7X/" title="Chart: today's top performing stocks" scrolling="no" frameborder="0" className="rounded-xl" />

### Test a hypothesis

Some questions have a defensible answer rather than a lookup. This one needs
three separate series and one piece of domain knowledge — that "core" is defined
as *excluding* energy, which is what makes the gap between headline and core
diagnostic:

```typescript theme={null}
const { text } = await generateText({
  model: 'openai/gpt-5.6-sol',
  prompt: 'Is US inflation being driven by energy prices, as of September 2026?',
  tools: {
    tako_search: gateway.tools.takoSearch({ sources: { data: { count: 3 } } }),
  },
  toolChoice: 'required',
  stopWhen: stepCountIs(5),
});
```

**Output** — after eight searches:

```text theme={null}
Partly — energy was a major driver of headline inflation, but not the only
source of U.S. inflation.

As of September 2026, the latest available CPI observations in the retrieved
data were for July 2026:

  Headline CPI   3.4% year over year
  Core CPI       2.5%   (excluding food and energy)
  Energy CPI    14.4%
  Gasoline CPI  24.6%

Because energy represents roughly 7% of the CPI basket, a 14.4% increase would
mechanically contribute around 1 percentage point to headline inflation —
approximately one-quarter to one-third of the 3.4% total.

Bottom line: energy was an important — and unusually fast-rising — component of
U.S. headline inflation in mid-2026, but underlying inflation remained
significant even after energy was excluded.
```

<Warning>
  **Without a date, "latest" resolves to the model's training cutoff, not today.**
  Say when "now" is. A model's clock stops at that cutoff, and nothing in
  the gateway tells it otherwise, so "latest" resolves to whenever it believes the
  present to be. Asked this same question with no date, it answered **"No — not
  primarily"** from February 2026 figures while July 2026 cards sat unread in the
  same result set. The date changed the conclusion, not only the numbers.
</Warning>

<figure>
  <iframe width="100%" src="https://tako.com/embed/jYlitu3uJLJEUK3xXdlS/" title="Chart: United States energy inflation rate" scrolling="no" frameborder="0" className="rounded-xl" />
</figure>

## Chat Completions on the gateway

The same tool works over the OpenAI-compatible endpoint. Use snake case for config keys:

```bash theme={null}
curl https://ai-gateway.vercel.sh/v1/chat/completions \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5.6-sol",
    "messages": [{"role": "user", "content": "How big is Nvidia? Give me its latest annual revenue figure."}],
    "tools": [{"type": "vercel:tako_search", "config": {
      "query": "Nvidia annual revenue",
      "sources": {"data": {"count": 3}}
    }}],
    "tool_choice": "required",
    "max_tokens": 2000
  }'
```

**Output**

```json theme={null}
{
  "choices": [{ "message": {
    "content": "Nvidia's latest annual revenue was $215.9 billion for fiscal year 2026, which ended January 25, 2026. That was 65% higher than the prior year's $130.5 billion.",
    "provider_metadata": { "gateway": { "gatewayToolCalls": { "tako_search": 1 } } }
  }}],
  "usage": { "cost": 0.030827 }
}
```

`config` keys are snake case here, not the camel case the AI SDK takes. `query` is
required on this path and fixes the search for every request — edit `messages`
alone and you still search `Nvidia annual revenue`.

This path returns the finished answer only — no raw cards, so no `embed_url`. Read `choices[0].message.provider_metadata.gateway.gatewayToolCalls` for the search count. Use the AI SDK when you want the cards.

<Warning>
  Keep `max_tokens` generous. Reasoning models spend the budget before writing prose — at 300 this request returns `finish_reason: "length"` and empty content.
</Warning>

## Pricing

Vercel bills gateway searches on top of model tokens, so [Vercel's AI Gateway rates](https://vercel.com/docs/ai-gateway/models-and-providers/web-search) are what you pay. `sources.data.includeContents` adds a row surcharge derived from [Tako's Contents pricing](/documentation/integrating-tako/contents/pricing).

## Resources

* [Vercel AI Gateway — Web Search](https://vercel.com/docs/ai-gateway/models-and-providers/web-search)
* [Tako Search on the AI Gateway model page](https://vercel.com/ai-gateway/models/tako-search)
* [`@takoviz/ai-sdk`](/documentation/integrations/vercel-ai-sdk) — the direct integration, with `answer` and `contents`
* [Card schema](/api-reference/search-v3#response-cards) — every field a card returns
* [Embedding Knowledge Cards](/documentation/integrating-tako/embedding-knowledge-cards)
