Interfaze

logo

Beta

pricing

help

docs

blog

sign in

Introducing OpenWebSearch

copy markdown

OpenWebSearch is a router for web indexes like Google SERP, Exa, Brave, Perplexity and more. The router standardizes both the API inputs and outputs, so that you can easily switch between different providers with centralized billing.

Like LLMs, web indexes are becoming commoditized with different indexes having different strengths and weaknesses with access to niche data, performance and cost. Every large model lab including Interfaze has to build their own internal mini-Google for training and eventually launch that index as a service.

So the bet is we'll start seeing a lot more web indexes as a service in the next few years.

Search is worth more than parameters

DeepMind made this case back in 2022. In this paper, Lazaridou et al. took Gopher models from 44M up to 280B parameters and compared closed-book answering against the same models conditioned on Google Search results.

On Natural Questions and HotpotQA, the 7B model with search beat the 280B model without it. On Natural Questions, so did the 1B.

Conditioning on as few as 5 retrieved paragraphs was enough for the 7B model to pass closed-book Gopher-280B, which the authors summed up as "suggesting that searching the Internet is worth more than 273 billion parameters".

  1. Sign in at openwebsearch.ai
  2. Create a key and save it

It's a plain REST endpoint that takes and returns JSON, so it drops into any language and wires up as a tool call like any other API.

fetch

const response = await fetch("https://api.openwebsearch.ai/v1/search", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.OPENWEBSEARCH_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    provider: "exa",
    query: "What changed in browser automation this week?",
    max_results: 5,
  }),
});

const { results, provider, usage } = await response.json();

console.log(`${provider} served ${results.length} results for $${usage.cost}`);

One response shape

Every successful request returns the same top-level object, whichever index served it.

{
  "id": "req-3f0c...",
  "provider": "exa",
  "query": "browser automation",
  "results": [
    {
      "title": "Browser automation in 2026",
      "url": "https://example.com/browser-automation",
      "snippet": "A look at what changed across headless browsers this year.",
      "content": "Full page content when available.",
      "published_date": "2026-08-02",
      "source": "example.com",
      "raw": {}
    }
  ],
  "usage": {
    "cost": 0.007,
    "results_count": 1
  },
  "warnings": []
}

The result fields are the ones RAG and agent pipelines already expect, so you don't need a per-provider adapter:

FieldDescription
titleResult title
urlCanonical result URL
snippetShort excerpt or description
contentFull text when the provider supplies it
published_dateProvider-supplied publication date, never fabricated
sourceDomain or source name
rawThe original untouched provider result

The provider field always names the index that actually served the request, including when a fallback kicked in.

Fallbacks for when an index goes down

Pass an ordered providers list instead of a single provider and the router walks it for you.

{
  "query": "latest advances in fusion energy",
  "providers": ["exa", "perplexity", "brave"],
  "allow_fallbacks": true,
  "max_results": 5
}

The first successful response wins. It moves to the next index when one returns no results, times out, or has a transient failure, and an invalid request stops immediately instead of burning through your whole list.

Provider-specific options

Not every index supports every filter. GET /v1/providers reports each provider's result cap and whether a given parameter is native, emulated, or unsupported, so you can discover capabilities at runtime instead of hardcoding them.

Unsupported parameters are dropped and reported in warnings by default. Set strict_params: true to get a 400 instead of a silent drop.

When you need a native feature that isn't part of the unified schema, scope it under provider_options:

{
  "query": "transformer architecture",
  "provider": "exa",
  "provider_options": {
    "exa": {
      "type": "fast",
      "contents": { "text": true, "highlights": true }
    }
  }
}

Providers

There's no universally best index. Historical depth, people data, freshness and ranking quality all vary, so the point is to pick per job rather than per integration.

ProviderBest forStatus
ParallelToken-dense excerpts for AI agentsLive
BraveIndependent broad-web and media searchLive
ExaPeople, companies and semantic discoveryLive
PerplexityCitation-backed, real-time answersLive
ValyuAcademic, financial and proprietary dataLive
Apify SerpLocalized SERP features and rankingsLive
TavilyFresh news and agent-ready researchComing soon
BingBroad web, local, news and image resultsComing soon
InterfazeResearch, social and financial indexesComing soon

| Octen | Real-time and multimodal web search | Coming soon |

More are on the way, and GET /v1/providers is always the source of truth for live slugs, caps and capabilities.

Extracting the full page

While search gives you the right pages, it's not always easy to extract the content of that page in a structured or markdown format.

Depending on the pages like government sites or linkedin profiles, bot checks and other anti-scraping measures, it's difficult to extract the content of that page in a structured or markdown format.

You can use Interfaze to scrape any page as it figures out the best way to extract the content using AI with access to a full browser and proxies built in.

Interfaze SDK

Vercel AI SDK

LangChain SDK

import { Interfaze, responseFormat } from "interfaze";
import { z } from "zod";

const interfaze = new Interfaze();

const ArticleSchema = z.object({
  title: z.string(),
  author: z.string().optional(),
  published_date: z.string().optional(),
  key_points: z.array(z.string()),
});

// results[0].url came back from the OpenWebSearch call above
const response = await interfaze.chat.completions.create({
  messages: [{ role: "user", content: `Extract the article details from ${results[0].url}` }],
  response_format: responseFormat(z.toJSONSchema(ArticleSchema), "article_schema"),
});

console.log(JSON.parse(response.choices[0]?.message.content ?? "{}"));

When you want the page itself rather than specific fields, run it as a task instead. The scraper task has a fixed pre-defined output, which makes it faster and cheaper than asking for a custom schema:

Interfaze SDK

const page = await interfaze.tasks.scrape(results[0].url);

console.log("Web Scrape Results:", page);

Extraction uses your INTERFAZE_API_KEY, so it's a separate call from the search. Full details are in the web scraping docs.

Billing and usage

Pricing is dynamic because it follows the provider you route to, not a flat platform rate. Most providers bill per request, so a 10-result search costs the same as a 5-result one.

Every response carries its own usage.cost in USD, so spend is attributable request by request rather than reconciled at the end of the month.

The only platform fee is 5% on credit purchases. Top up $100 and you're charged $105, with the full $100 landing in your balance. Nothing is added on top of a search itself, so the cost you see on a response is the cost you pay.

Zero data retention by default

Query text and the results we return are not retained. We keep only the metadata needed to bill and show usage: the request id, the provider that served it, the cost and the latency.

One caveat worth knowing is that whichever provider a request routes to applies its own retention policy to the query it receives. If you need a specific guarantee, check the policies of the indexes you route to and pin your provider list accordingly.

Takeaway

  • One index: set provider and send a normal REST request.
  • High availability: pass an ordered providers list and requests fall through automatically.
  • Switching: change one request field instead of rewriting an integration.
  • Native features: reach them through provider_options and read them back under raw.
  • Billing: one prepaid balance across every provider, with usage.cost on every response.

Web indexes will keep multiplying, so the integration you write today should outlive whichever one currently wins.

Interfaze

logo

Product

Playground

OCR

Models

Leaderboards

Pricing