DEV Community

Cover image for Google search api json response example: Full schema and parsing
SerpApi.Org
SerpApi.Org

Posted on • Originally published at serpapi.org

Google search api json response example: Full schema and parsing

I spent three hours debugging a production pipeline last week because of a silent crash. The culprit? Googleโ€™s Custom Search API unexpectedly omitted the pagemap object on a niche query. When building automated data pipelines, assuming every search result shares an identical JSON schema is a recipe for runtime errors.

To help you build more resilient search integrations, let's look at the actual anatomy of the API's JSON response and how to parse it defensively.

Quick Setup & Query Execution

To query the API, you issue a standard GET request:

GET https://www.googleapis.com/customsearch/v1?key=YOUR_API_KEY&cx=YOUR_CX_ID&q=query
Enter fullscreen mode Exit fullscreen mode
  • key: Your Google Cloud credentials.
  • cx: Your 17-character Search Engine ID. (Pro-tip: You must toggle "Search the entire web" in your Programmable Search Engine settings, or your broader queries will return empty arrays).
  • Quotas: The free tier caps you at 100 queries/day. After that, it costs $5 per 1,000 queries.

The JSON Response Schema

The response payload contains three root-level keys:

  1. queries: Metadata tracking current, next, and previous page states.
  2. searchInformation: Search execution time and total result estimations.
  3. items: The array of search results containing title, link, snippet, and optional metadata.

Defensive Parsing in TypeScript

The danger lies inside the items array. While basic keys like title and link are reliably returned as strings, rich metadata inside the pagemap object (like cse_thumbnail) is highly inconsistent.

In my experience, roughly 35% of web results lack a thumbnail. Direct access like item.pagemap.cse_thumbnail[0].src will crash your code with a TypeError.

Always use optional chaining and fallback values:

interface SearchItem {
  title: string;
  link: string;
  snippet: string;
  pagemap?: {
    cse_thumbnail?: Array<{ src: string }>;
  };
}

function parseSearchResults(items: SearchItem[]) {
  if (!items || !Array.isArray(items)) return [];

  return items.map(item => ({
    title: item.title || 'Untitled',
    url: item.link,
    // Safe traversal using optional chaining
    thumbnail: item?.pagemap?.cse_thumbnail?.[0]?.src ?? null
  }));
}
Enter fullscreen mode Exit fullscreen mode

The 100-Result Pagination Wall

The native API has a hard limitation: you cannot retrieve more than 100 results per query.

Results are served in batches of 10. To request the next page, grab the startIndex value from the queries.nextPage[0] object and append it as your &start= parameter. Attempting to query &start=101 will immediately throw a 400 Bad Request error.

Furthermore, treat searchInformation.totalResults as a loose approximation. Google uses probabilistic estimators to calculate this count on page one. As you page deeper, duplicate filters are dynamically applied, causing this number to drop drastically from page to page.

When to Look for Alternatives

If your application needs to crawl deeper than 100 results, requires stable result counts, or needs cost-effective geo-targeting, Google's native API might stall your growth. In my high-scale web scraping projects, migrating to dedicated parsing services like SerpApi (for example, utilizing their Bing search API) bypassed these structural limits entirely while offering consistent, normalized JSON schemas.


Originally published at Google search api json response example: Full schema and parsing

Top comments (0)