JSON API

query the web, images, and news over a single public endpoint and get back clean, structured JSON: the exact same data that powers the results pages, with none of the HTML.

the API is public: no key, no signup, no auth header. there are no rate limits or pagination caps either, so be a good citizen, the upstream is shared.

making a request

send a POST to /api with a JSON body.

POST /api
Content-Type: application/json

{
  "query": "metasearch",
  "type": "web",
  "page": 0
}

request fields

field type description
query string required. the search query.
type string optional, defaults to web. one of web, images, news.
page integer optional, defaults to 0. the result offset. 0 is the first page; increment to paginate. no upper bound.

examples

curl

curl -X POST https://search.tiago.zip/api \
  -H "Content-Type: application/json" \
  -d '{"query":"metasearch","type":"web","page":0}'

javascript

const res = await fetch("https://search.tiago.zip/api", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ query: "metasearch", type: "web", page: 0 }),
});

const data = await res.json();
console.log(data.results);

responses

every successful response echoes query, type, and page, exposes more_results_available so you know whether to fetch the next page, and carries the results for the requested type.

web (type: "web")

results is an object grouping the different result kinds. fields are null when absent for a given query.

{
  "query": "metasearch",
  "type": "web",
  "page": 0,
  "badResults": false,
  "more_results_available": true,
  "results": {
    "web": {
      "results": [
        {
          "title": "…",
          "url": "https://…",
          "description": "…",
          "age": "…",
          "meta_url": { "hostname": "…", "favicon": "…" },
          "profile": { "name": "…", "img": "…" },
          "thumbnail": { "src": "…" },
          "deep_results": { "buttons": [{ "title": "…", "url": "…" }] },
          "cluster": [{ "title": "…", "label": "…", "url": "…", "description": "…" }]
        }
      ]
    },
    "news": { "results": [ … ] },
    "videos": { "results": [ … ] },
    "discussions": { "results": [ … ] },
    "faq": { "results": [ … ] },
    "infobox": { "results": [ … ] },
    "rich": [ … ],
    "qanda": …,
    "locations": …,
    "images": …,
    "mixed": [ … ]
  }
}

rich carries instant answers (calculator, weather, currency, crypto, timezones, unit conversions, and more), each tagged with a subtype. mixed mirrors the upstream ordering of the main column.

images (type: "images")

{
  "query": "teto",
  "type": "images",
  "page": 0,
  "more_results_available": true,
  "results": [
    {
      "title": "…",
      "url": "https://…",
      "source": "…",
      "thumbnail": "https://…",
      "properties": { "url": "https://…", "width": 1200, "height": 800 },
      "meta_url": { "hostname": "…", "favicon": "…" }
    }
  ]
}

news (type: "news")

{
  "query": "elections",
  "type": "news",
  "page": 0,
  "more_results_available": true,
  "results": [
    {
      "title": "…",
      "url": "https://…",
      "description": "…",
      "age": "…",
      "meta_url": { "hostname": "…", "favicon": "…" },
      "profile": { "name": "…", "img": "…" },
      "thumbnail": { "src": "…" },
      "is_live": false
    }
  ]
}

pagination

start at page: 0. if the response has more_results_available: true, request page: 1, then 2, and so on. when it is false there is nothing more to fetch.

errors

errors come back as JSON with an error string and a matching status code.

status meaning
400 bad body, missing query, unknown type, or invalid page.
502 the upstream search failed.
{ "error": "missing required field: query" }

autocomplete (/suggest)

send a GET to /suggest with a partial query.

GET /suggest?q=weath

query parameters

param type description
q string required. the partial query to complete, up to 100 characters.

response

suggestions is an ordered array. plain completions carry just a query; rich entities (people, places, and more) set entity and add the best-effort fields below.

{
  "suggestions": [
    { "query": "weather" },
    { "query": "weather radar" },
    {
      "query": "elon musk",
      "entity": true,
      "name": "Elon Musk",
      "desc": "businessman and entrepreneur (born 1971)",
      "category": "person",
      "img": "https://imgs.search.brave.com/…"
    }
  ]
}
field type description
query string the suggested query. always present.
entity boolean true on entity suggestions; absent otherwise.
name string the entity's display name.
desc string a short description.
category string e.g. person, place.
img string thumbnail URL, when one is available.

curl

curl "https://search.tiago.zip/suggest?q=weath"

notes

made and hosted in the EU 🇪🇺