Quickstart

This guide shows how to make your first Search API request and get structured organic results back.

Prerequisites

You need a Zyte API key.

Basic request

Send a POST request to https://api.zyte.com/v1/search with domain and query. Use include to control what you get back.

input.json
{
    "domain": "search.engine.com",
    "query": "web scraping tools",
    "include": ["organic"]
}
curl \
    --user YOUR_ZYTE_API_KEY: \
    --header 'Content-Type: application/json' \
    --data @input.json \
    --compressed \
    https://api.zyte.com/v1/search \
    | jq .organicResults
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

HttpClientHandler handler = new HttpClientHandler()
{
    AutomaticDecompression = DecompressionMethods.All
};
HttpClient client = new HttpClient(handler);

var apiKey = "YOUR_ZYTE_API_KEY";
var bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(apiKey + ":");
var auth = System.Convert.ToBase64String(bytes);
client.DefaultRequestHeaders.Add("Authorization", "Basic " + auth);
client.DefaultRequestHeaders.Add("Accept-Encoding", "br, gzip, deflate");

var input = new Dictionary<string, object>(){
    {"domain", "search.engine.com"},
    {"query", "web scraping tools"},
    {"include", new[] {"organic"}}
};
var inputJson = JsonSerializer.Serialize(input);
var content = new StringContent(inputJson, Encoding.UTF8, "application/json");

HttpResponseMessage response = await client.PostAsync("https://api.zyte.com/v1/search", content);
var body = await response.Content.ReadAsByteArrayAsync();

var data = JsonDocument.Parse(body);
var organicResults = data.RootElement.GetProperty("organicResults").ToString();

Console.WriteLine(organicResults);
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;

class Example {
  private static final String API_KEY = "YOUR_ZYTE_API_KEY";

  public static void main(final String[] args)
      throws InterruptedException, IOException, ParseException {
    Map<String, Object> parameters =
        ImmutableMap.of(
            "domain", "search.engine.com",
            "query", "web scraping tools",
            "include", List.of("organic"));
    String requestBody = new Gson().toJson(parameters);

    HttpPost request = new HttpPost("https://api.zyte.com/v1/search");
    request.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON);
    request.setHeader(HttpHeaders.ACCEPT_ENCODING, "gzip, deflate");
    request.setHeader(HttpHeaders.AUTHORIZATION, buildAuthHeader());
    request.setEntity(new StringEntity(requestBody));

    CloseableHttpClient client = HttpClients.createDefault();
    client.execute(
        request,
        response -> {
          HttpEntity entity = response.getEntity();
          String apiResponse = EntityUtils.toString(entity, StandardCharsets.UTF_8);
          JsonObject jsonObject = JsonParser.parseString(apiResponse).getAsJsonObject();
          JsonArray organicResults = jsonObject.get("organicResults").getAsJsonArray();
          Gson gson = new GsonBuilder().setPrettyPrinting().create();
          System.out.println(gson.toJson(organicResults));
          return null;
        });
  }

  private static String buildAuthHeader() {
    String auth = API_KEY + ":";
    String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
    return "Basic " + encodedAuth;
  }
}
const axios = require('axios')

axios.post(
  'https://api.zyte.com/v1/search',
  {
    domain: 'search.engine.com',
    query: 'web scraping tools',
    include: ['organic']
  },
  {
    auth: { username: 'YOUR_ZYTE_API_KEY' }
  }
).then((response) => {
  const organicResults = response.data.organicResults
  console.log(organicResults)
})
<?php

$client = new GuzzleHttp\Client();
$response = $client->request('POST', 'https://api.zyte.com/v1/search', [
    'auth' => ['YOUR_ZYTE_API_KEY', ''],
    'headers' => ['Accept-Encoding' => 'gzip'],
    'json' => [
        'domain' => 'search.engine.com',
        'query' => 'web scraping tools',
        'include' => ['organic'],
    ],
]);
$data = json_decode($response->getBody());
$organicResults = json_encode($data->organicResults);
echo $organicResults.PHP_EOL;
import requests

api_response = requests.post(
    "https://api.zyte.com/v1/search",
    auth=("YOUR_ZYTE_API_KEY", ""),
    json={
        "domain": "search.engine.com",
        "query": "web scraping tools",
        "include": ["organic"],
    },
)
organic_results = api_response.json()["organicResults"]
print(organic_results)
import requests

api_response = requests.post(
    "https://api.zyte.com/v1/search",
    auth=("YOUR_ZYTE_API_KEY", ""),
    json={
        "domain": "search.engine.com",
        "query": "web scraping tools",
        "include": ["organic"],
    },
)
organic_results = api_response.json()["organicResults"]
print(organic_results)

The response contains a structured organicResults array:

{
    "status": "success",
    "url": "https://www.example-engine.com/search?q=web+scraping+tools",
    "fetchedAt": "2026-05-11T09:36:57Z",
    "meta": {
        "requestedAt": "2026-05-11T09:36:39Z"
    },
    "organicResults": [
        {
            "rank": 1,
            "title": "Zyte - Web Scraping API",
            "url": "https://www.zyte.com/",
            "snippet": "The leading web scraping platform...",
            "displayedUrl": "zyte.com"
        }
    ]
}

Getting raw HTML

Use include: ["html"] to get the raw rendered HTML instead of parsed results. You can also request both at once:

curl \
    --user YOUR_ZYTE_API_KEY: \
    --header 'Content-Type: application/json' \
    --data '{
        "domain": "search.engine.com",
        "query": "web scraping tools",
        "include": ["html", "organic"]
    }' \
    https://api.zyte.com/v1/search

More results

Set maxResults to get up to 100 results in a single call. The platform fetches multiple pages automatically and returns them in one organicResults array:

input.json
{
    "domain": "search.engine.com",
    "query": "web scraping tools",
    "include": ["organic"],
    "maxResults": 100
}
curl \
    --user YOUR_ZYTE_API_KEY: \
    --header 'Content-Type: application/json' \
    --data @input.json \
    --compressed \
    https://api.zyte.com/v1/search \
    | jq .organicResults
var input = new Dictionary<string, object>(){
    {"domain", "search.engine.com"},
    {"query", "web scraping tools"},
    {"include", new[] {"organic"}},
    {"maxResults", 100}
};
Map<String, Object> parameters =
    ImmutableMap.of(
        "domain", "search.engine.com",
        "query", "web scraping tools",
        "include", List.of("organic"),
        "maxResults", 100);
axios.post(
  'https://api.zyte.com/v1/search',
  {
    domain: 'search.engine.com',
    query: 'web scraping tools',
    include: ['organic'],
    maxResults: 100
  },
  { auth: { username: 'YOUR_ZYTE_API_KEY' } }
).then((response) => {
  console.log(response.data.organicResults)
})
$response = $client->request('POST', 'https://api.zyte.com/v1/search', [
    'auth' => ['YOUR_ZYTE_API_KEY', ''],
    'json' => [
        'domain' => 'search.engine.com',
        'query' => 'web scraping tools',
        'include' => ['organic'],
        'maxResults' => 100,
    ],
]);
api_response = requests.post(
    "https://api.zyte.com/v1/search",
    auth=("YOUR_ZYTE_API_KEY", ""),
    json={
        "domain": "search.engine.com",
        "query": "web scraping tools",
        "include": ["organic"],
        "maxResults": 100,
    },
)
organic_results = api_response.json()["organicResults"]
api_response = requests.post(
    "https://api.zyte.com/v1/search",
    auth=("YOUR_ZYTE_API_KEY", ""),
    json={
        "domain": "search.engine.com",
        "query": "web scraping tools",
        "include": ["organic"],
        "maxResults": 100,
    },
)
organic_results = api_response.json()["organicResults"]

Geo-targeting

Pass queryParameters to target a specific country and language:

input.json
{
    "domain": "search.engine.com",
    "query": "web scraping tools",
    "include": ["organic"],
    "queryParameters": {
        "style": "engineSpecific",
        "gl": "us",
        "hl": "en"
    }
}
curl \
    --user YOUR_ZYTE_API_KEY: \
    --header 'Content-Type: application/json' \
    --data @input.json \
    --compressed \
    https://api.zyte.com/v1/search \
    | jq .organicResults
var input = new Dictionary<string, object>(){
    {"domain", "search.engine.com"},
    {"query", "web scraping tools"},
    {"include", new[] {"organic"}},
    {"queryParameters", new Dictionary<string, object>(){
        {"style", "engineSpecific"},
        {"gl", "us"},
        {"hl", "en"}
    }}
};
Map<String, Object> parameters =
    ImmutableMap.of(
        "domain", "search.engine.com",
        "query", "web scraping tools",
        "include", List.of("organic"),
        "queryParameters", ImmutableMap.of(
            "style", "engineSpecific",
            "gl", "us",
            "hl", "en"));
axios.post(
  'https://api.zyte.com/v1/search',
  {
    domain: 'search.engine.com',
    query: 'web scraping tools',
    include: ['organic'],
    queryParameters: {
      style: 'engineSpecific',
      gl: 'us',
      hl: 'en'
    }
  },
  { auth: { username: 'YOUR_ZYTE_API_KEY' } }
).then((response) => {
  console.log(response.data.organicResults)
})
$response = $client->request('POST', 'https://api.zyte.com/v1/search', [
    'auth' => ['YOUR_ZYTE_API_KEY', ''],
    'json' => [
        'domain' => 'search.engine.com',
        'query' => 'web scraping tools',
        'include' => ['organic'],
        'queryParameters' => [
            'style' => 'engineSpecific',
            'gl' => 'us',
            'hl' => 'en',
        ],
    ],
]);
api_response = requests.post(
    "https://api.zyte.com/v1/search",
    auth=("YOUR_ZYTE_API_KEY", ""),
    json={
        "domain": "search.engine.com",
        "query": "web scraping tools",
        "include": ["organic"],
        "queryParameters": {
            "style": "engineSpecific",
            "gl": "us",
            "hl": "en",
        },
    },
)
organic_results = api_response.json()["organicResults"]
api_response = requests.post(
    "https://api.zyte.com/v1/search",
    auth=("YOUR_ZYTE_API_KEY", ""),
    json={
        "domain": "search.engine.com",
        "query": "web scraping tools",
        "include": ["organic"],
        "queryParameters": {
            "style": "engineSpecific",
            "gl": "us",
            "hl": "en",
        },
    },
)
organic_results = api_response.json()["organicResults"]

For city-level targeting, add a uule value. Generate one from a city name using the uule_grabber Python library:

import uule_grabber
uule_grabber.uule("Chicago, USA")  # w+CAIQ...

AI Overview

Add "aiOverview" to include to trigger full browser rendering. The AI Overview block will be present in the raw html field:

input.json
{
    "domain": "search.engine.com",
    "query": "web scraping tools",
    "include": ["aiOverview", "organic", "html"]
}
curl \
    --user YOUR_ZYTE_API_KEY: \
    --header 'Content-Type: application/json' \
    --data @input.json \
    --compressed \
    https://api.zyte.com/v1/search
var input = new Dictionary<string, object>(){
    {"domain", "search.engine.com"},
    {"query", "web scraping tools"},
    {"include", new[] {"aiOverview", "organic", "html"}}
};
Map<String, Object> parameters =
    ImmutableMap.of(
        "domain", "search.engine.com",
        "query", "web scraping tools",
        "include", List.of("aiOverview", "organic", "html"));
axios.post(
  'https://api.zyte.com/v1/search',
  {
    domain: 'search.engine.com',
    query: 'web scraping tools',
    include: ['aiOverview', 'organic', 'html']
  },
  { auth: { username: 'YOUR_ZYTE_API_KEY' } }
).then((response) => {
  const { organicResults, html } = response.data
  console.log(organicResults)
})
$response = $client->request('POST', 'https://api.zyte.com/v1/search', [
    'auth' => ['YOUR_ZYTE_API_KEY', ''],
    'json' => [
        'domain' => 'search.engine.com',
        'query' => 'web scraping tools',
        'include' => ['aiOverview', 'organic', 'html'],
    ],
]);
api_response = requests.post(
    "https://api.zyte.com/v1/search",
    auth=("YOUR_ZYTE_API_KEY", ""),
    json={
        "domain": "search.engine.com",
        "query": "web scraping tools",
        "include": ["aiOverview", "organic", "html"],
    },
)
data = api_response.json()
organic_results = data["organicResults"]
html = data["html"]  # parse AI Overview from here
api_response = requests.post(
    "https://api.zyte.com/v1/search",
    auth=("YOUR_ZYTE_API_KEY", ""),
    json={
        "domain": "search.engine.com",
        "query": "web scraping tools",
        "include": ["aiOverview", "organic", "html"],
    },
)
data = api_response.json()
organic_results = data["organicResults"]
html = data["html"]  # parse AI Overview from here

Note

Parsed aiOverview extraction is coming in a future release. For now, the AI Overview block is available in the raw html field.

Next steps