logo

Google Shopping API

Scrape Google Shopping search results, filters, and categorized product groups as structured JSON

Google Shopping API

The Google Shopping API is a specialized plugin that searches Google Shopping and returns product listings from every major retailer as structured JSON. Each result includes the product title, price (and original price when discounted), retailer name and icon, rating and review count, delivery info, discount badges, and a Google product ID you can use to link back to the Shopping catalog page.

Credit Usage: Each successful request costs 10 credits. For bulk processing, use the Async API with plugins.

Key Features

  • Structured JSON Output: 40 products per page with 19+ parsed fields each: title, price, extracted_price, rating, reviews, retailer, thumbnail, delivery, discount tags, and more.
  • Categorized Results: Google's editorial groupings (e.g., "Gaming laptops", "Budget-friendly laptops", "2-in-1 laptops") come back in categorized_shopping_results with their own product lists.
  • Filters: 18+ filter groups per query (features, screen size, price range, brand, etc.) returned in the response. Apply any of them on subsequent calls via the opaque shoprs parameter.
  • Price & Shipping Filters: First-class parameters for min_price, max_price, sort_by (price asc/desc), free_shipping, and on_sale.
  • Worldwide Coverage: 84 regional Google domains, 150+ interface languages, 240+ country codes, location-level geo-targeting via location or uule.
  • Device Emulation: Desktop or mobile layout with the device parameter.
  • Pagination: Navigate through result pages using the returned pagination.next link.
  • No Blocks or CAPTCHAs: All anti-bot measures are handled automatically by Scrape.do.

Endpoint

GET https://api.scrape.do/plugin/google/shopping

Parameter keys are case-insensitive. You can use q, Q, hl, HL, etc.


Request Parameters

Required

ParameterTypeDescription
tokenstringYour Scrape.do API authentication token
qstringSearch query. URL-encode spaces and special characters. Examples: laptop, wireless+headphones, running+shoes

Device

ParameterTypeDefaultDescription
devicestringdesktopDevice type. One of desktop, mobile

Pagination

ParameterTypeDefaultDescription
startinteger0Result offset for pagination. Use the pagination.next path from the response to paginate

Filters (first-class)

ParameterTypeDefaultDescription
min_priceintegerMinimum price filter (e.g., 100)
max_priceintegerMaximum price filter (e.g., 500)
sort_byinteger0Sort order. 0 = relevance (default), 1 = price low to high, 2 = price high to low
free_shippingbooleanfalseFilter to products with free shipping
on_salebooleanfalseFilter to products currently on sale
shoprsstringOpaque filter token from filters[].options[].shoprs or carousel_filters[].shoprs. See Filter & Sort Reference below

Individual filter params (min_price, max_price, sort_by, free_shipping, on_sale) take precedence over shoprs when both are provided.

Localization

ParameterTypeDefaultDescription
hlstringenHost language
glstringusCountry perspective
google_domainstringgoogle.comGoogle domain to query
locationstringLocation name (e.g., Austin,Texas,United States). Auto-encoded to UULE when uule is not set
uulestringGoogle-encoded location parameter. Overrides location when both are set

See Localization for the full list of supported hl, gl, and google_domain values.


Example Usage

curl --location --request GET 'https://api.scrape.do/plugin/google/shopping?token=<SDO-token>&q=laptop'
import requests
import json

token = "<SDO-token>"
query = "laptop"

url = f"https://api.scrape.do/plugin/google/shopping?token={token}&q={query}"

response = requests.request("GET", url)

print(json.dumps(response.json(), indent=2))
const axios = require('axios');

const token = "<SDO-token>";
const query = "laptop";

const url = `https://api.scrape.do/plugin/google/shopping?token=${token}&q=${query}`;

axios.get(url)
  .then(response => {
    console.log(JSON.stringify(response.data, null, 2));
  })
  .catch(error => {
    console.error(error);
  });
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	token := "<SDO-token>"
	query := "laptop"

	url := fmt.Sprintf(
		"https://api.scrape.do/plugin/google/shopping?token=%s&q=%s",
		token, query,
	)

	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(body))
}
require 'net/http'
require 'json'

token = "<SDO-token>"
query = "laptop"

url = URI("https://api.scrape.do/plugin/google/shopping?token=#{token}&q=#{query}")

response = Net::HTTP.get(url)

puts JSON.pretty_generate(JSON.parse(response))
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class GoogleShopping {
    public static void main(String[] args) throws Exception {
        String token = "<SDO-token>";
        String query = "laptop";

        String url = String.format(
            "https://api.scrape.do/plugin/google/shopping?token=%s&q=%s",
            token, query
        );

        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setRequestMethod("GET");

        BufferedReader reader = new BufferedReader(
            new InputStreamReader(conn.getInputStream())
        );
        String line;
        StringBuilder response = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            response.append(line);
        }
        reader.close();

        System.out.println(response.toString());
    }
}
using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        string token = "<SDO-token>";
        string query = "laptop";

        string url = $"https://api.scrape.do/plugin/google/shopping?token={token}&q={query}";

        using HttpClient client = new HttpClient();
        string response = await client.GetStringAsync(url);

        Console.WriteLine(response);
    }
}
<?php
$token = "<SDO-token>";
$query = "laptop";

$url = "https://api.scrape.do/plugin/google/shopping?token={$token}&q={$query}";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo json_encode(json_decode($response), JSON_PRETTY_PRINT);
?>
curl "https://api.scrape.do/plugin/google/shopping?q=laptop&token=YOUR_TOKEN"

With price range

curl "https://api.scrape.do/plugin/google/shopping?q=laptop&min_price=500&max_price=1500&token=YOUR_TOKEN"

Sort by price (low to high), only on-sale items

curl "https://api.scrape.do/plugin/google/shopping?q=laptop&sort_by=1&on_sale=true&token=YOUR_TOKEN"

Location-targeted (auto-UULE)

curl "https://api.scrape.do/plugin/google/shopping?q=laptop&location=Austin,Texas,United+States&token=YOUR_TOKEN"

Turkish locale

curl "https://api.scrape.do/plugin/google/shopping?q=dizustu+bilgisayar&hl=tr&gl=tr&google_domain=google.com.tr&token=YOUR_TOKEN"

Mobile layout

curl "https://api.scrape.do/plugin/google/shopping?q=laptop&device=mobile&token=YOUR_TOKEN"

Response

Top-Level Structure

{
  "search_parameters": { ... },
  "search_information": { ... },
  "shopping_results": [ ... ],
  "filters": [ ... ],
  "carousel_filters": [ ... ],
  "categorized_shopping_results": [ ... ],
  "pagination": { ... }
}

search_parameters

Echo of the request parameters sent by the client.

{
  "engine": "google_shopping",
  "q": "laptop",
  "google_domain": "google.com",
  "hl": "en",
  "gl": "us",
  "device": "desktop",
  "start": 0
}

Optional fields appear only when sent: location, uule, min_price, max_price, sort_by, free_shipping, on_sale, shoprs.

search_information

{
  "page_title": "laptop - Google Shopping",
  "query_displayed": "laptop",
  "shopping_results_state": "Results for exact spelling"
}

shopping_results

Array of product objects. Returns [] (empty array, never null) when no results are found. Typical first page has ~40 items.

{
  "position": 1,
  "title": "Lenovo IdeaPad Slim 3 Chromebook FHD",
  "product_id": "7000474567848623813",
  "product_link": "https://www.google.com/search?ibp=oshop&q=laptop&prds=catalogid:7000474567848623813,...&hl=en&gl=us&udm=28",
  "source": "Best Buy",
  "source_icon": "data:image/png;base64,iVBORw0KGgo...",
  "price": "$189.00",
  "extracted_price": 189,
  "old_price": "$399",
  "extracted_old_price": 399,
  "rating": 4.6,
  "reviews": 4800,
  "snippet": "Performs well (720 user reviews)",
  "extensions": ["52% OFF"],
  "thumbnail": "https://encrypted-tbn2.gstatic.com/shopping?...",
  "delivery": "15-day returns",
  "tag": "52% OFF",
  "second_hand_condition": "Refurbished",
  "multiple_sources": true,
  "immersive_product_page_token": "eyJlaSI6ImFhX1Nh..."
}

shopping_results[] Fields

FieldTypeAlways presentDescription
positionintyes1-based position in the results list
titlestringyesProduct title
product_idstringGoogle product catalog ID
product_linkstringDirect link to the Google Shopping product page
sourcestringRetailer name ("Best Buy", "Amazon.com", "Walmart")
source_iconstringRetailer favicon as base64 data URI or URL
pricestringFormatted price ("$189.00", "1.299,00 TL")
extracted_pricefloatNumeric price value (189)
old_pricestringOriginal price before discount ("$399")
extracted_old_pricefloatNumeric original price
ratingfloatProduct rating out of 5
reviewsintNumber of user reviews
snippetstringSummary from reviews ("Performs well (720 user reviews)")
extensionsstring[]Badges and metadata (["52% OFF"], ["Nearby, 17 mi", "30% OFF"])
thumbnailstringProduct image as base64 data URI or URL
deliverystringDelivery/returns info ("Free delivery by Tue", "15-day returns")
tagstringDiscount or promotional badge ("52% OFF", "Low price")
badgestringAlternative badge text
second_hand_conditionstringCondition for used items: "Refurbished", "Used", or "Renewed"
multiple_sourcesbooltrue when the product is sold by multiple retailers
immersive_product_page_tokenstringBase64 token for the immersive product page viewer

filters

Sidebar filter groups. Use options[].shoprs as the shoprs parameter on a follow-up call. See Filter & Sort Reference below.

[
  {
    "input_type": "link",
    "type": "Features",
    "options": [
      { "text": "For Gaming",   "shoprs": "CAEYASoGbGFwdG9w..." },
      { "text": "Touchscreen",  "shoprs": "CAEYASoGbGFwdG9w..." }
    ]
  },
  {
    "input_type": "link",
    "type": "Screen Size",
    "options": [
      { "text": "Under 14 inches", "shoprs": "CAESESoPCMakPhIJ..." },
      { "text": "14 – 15 inches",  "shoprs": "CAESGioYCMakPhIS..." }
    ]
  }
]

Horizontal filter chips above the results (e.g., Nearby, Deals). Same mechanic as filters[].options[].shoprs.

[
  { "text": "Nearby", "shoprs": "CAEYAyoGbGFwdG9wMg4IAxIGTmVhcmJ5GAJIAQ" },
  { "text": "Deals",  "shoprs": "CAESBEoCGAEYBioGbGFwdG9wMhUIBhIHT24gc2FsZRgCIgRKAhgBSAE" }
]

categorized_shopping_results

Product groups organized by Google's editorial categories (e.g., "Gaming laptops", "2-in-1 laptops"). Each group contains its own shopping_results[] array with the same schema as the top-level results.

[
  {
    "title": "2-in-1 laptops",
    "shopping_results": [
      {
        "position": 1,
        "title": "Lenovo IdeaPad 5 2-in-1 Touchscreen Laptop",
        "product_id": "17927246548825320348",
        "source": "Walmart",
        "price": "$599.00",
        "extracted_price": 599,
        "rating": 4.3,
        "reviews": 292,
        "thumbnail": "data:image/webp;base64,...",
        "delivery": "Free next-day delivery"
      }
    ]
  }
]

pagination

Present when results exist.

{
  "current": 0,
  "next": "/plugin/google/shopping?q=laptop&start=10"
}
FieldTypeDescription
currentintCurrent start offset
nextstringPath for the next page. Append your token and send as the full URL

Pagination nuance. The top-level shopping_results carries up to 40 items per page, but the next link advances start by 10, not 40. Follow the next link and use the returned start value; don't assume a fixed page size. Pagination ends when pagination is absent.


Filter & Sort Reference

The Google Shopping API exposes two layers of filtering: first-class parameters for common filters (price range, sort order, free shipping, on-sale) and an opaque shoprs token for the long tail of sidebar and carousel filters Google returns inline with every response.

First-Class Filter Parameters

Price range: min_price / max_price

Both are integers in the storefront's currency (USD by default; respects gl/google_domain).

# Laptops between $500 and $1500
curl "https://api.scrape.do/plugin/google/shopping?q=laptop&min_price=500&max_price=1500&token=$TOKEN"

Either bound can be omitted. Pass only min_price for "at least $500", only max_price for "at most $500".

Sort: sort_by

ValueMeaning
0 (default)Relevance. Google's default ordering
1Price: low to high
2Price: high to low
curl "https://api.scrape.do/plugin/google/shopping?q=laptop&sort_by=1&token=$TOKEN"

Free shipping: free_shipping

curl "https://api.scrape.do/plugin/google/shopping?q=laptop&free_shipping=true&token=$TOKEN"

On sale: on_sale

curl "https://api.scrape.do/plugin/google/shopping?q=laptop&on_sale=true&token=$TOKEN"

Combining first-class filters

All first-class parameters can be combined:

curl "https://api.scrape.do/plugin/google/shopping?q=laptop&min_price=500&max_price=1500&sort_by=1&free_shipping=true&on_sale=true&token=$TOKEN"

The shoprs Token

Every response includes Google's sidebar filters in filters[] and horizontal filter chips in carousel_filters[]. Each filter option carries an opaque shoprs value. Pass that value as the shoprs query parameter on a follow-up call to apply that filter.

Step 1: Get Filter Options

curl -s "https://api.scrape.do/plugin/google/shopping?q=laptop&token=$TOKEN" | jq '.filters[:2]'
[
  {
    "input_type": "link",
    "type": "Features",
    "options": [
      { "text": "For Gaming",    "shoprs": "CAEYASoGbGFwdG9wMhwIARIKRm9yIEdhbWluZxgCOgoIlNM6EJXTOjADWIuqIGAC" },
      { "text": "Touchscreen",   "shoprs": "CAEYASoGbGFwdG9wMhgIARIM..." },
      { "text": "Convertible",   "shoprs": "CAEYASoGbGFwdG9w..." }
    ]
  },
  {
    "input_type": "link",
    "type": "Screen Size",
    "options": [
      { "text": "Under 14 inches",  "shoprs": "CAESESoPCMakPhIJ..." },
      { "text": "14 – 15 inches",   "shoprs": "CAESGioYCMakPhIS..." },
      { "text": "Over 16 inches",   "shoprs": "CAEYASoGbGFwdG9w..." }
    ]
  }
]

Step 2: Apply a shoprs value

SHOPRS="CAEYASoGbGFwdG9wMhwIARIKRm9yIEdhbWluZxgCOgoIlNM6EJXTOjADWIuqIGAC"
curl "https://api.scrape.do/plugin/google/shopping?q=laptop&shoprs=$SHOPRS&token=$TOKEN"

The response is another full Shopping result page, filtered to "For Gaming" laptops.

shoprs values are opaque. Don't parse them, construct them, or cache them across queries. Always read the value from a fresh response and send it verbatim.

carousel_filters[] works the same way. Pass its shoprs value:

[
  { "text": "Nearby", "shoprs": "CAEYAyoGbGFwdG9wMg4IAxIGTmVhcmJ5GAJIAQ" },
  { "text": "Deals",  "shoprs": "CAESBEoCGAEYBioGbGFwdG9wMhUIBhIHT24gc2FsZRgCIgRKAhgBSAE" }
]
curl "https://api.scrape.do/plugin/google/shopping?q=laptop&shoprs=CAEYAyoGbGFwdG9wMg4IAxIGTmVhcmJ5GAJIAQ&token=$TOKEN"

Precedence: First-Class vs shoprs

When both a first-class filter and shoprs are provided, individual filter params win. For example, if shoprs encodes "$500–$1000" but the request also passes min_price=200&max_price=800, the final filter is 200–800.

This lets you start from a shoprs-encoded filter set and selectively override individual constraints without decoding and re-encoding the token.

Filter Group Types

Google returns a consistent set of filter groups for most categories. Typical groups returned for q=laptop:

Group typeExample options
FeaturesFor Gaming, Touchscreen, Convertible, Energy Star
Screen SizeUnder 14 inches, 14–15 inches, 15–16 inches, Over 16 inches
PriceUnder $500, $500–$1,000, $1,000–$2,000, Over $2,000
BrandHP, Lenovo, Dell, Apple, ASUS, Acer
CPUIntel Core i5, Intel Core i7, AMD Ryzen 5, AMD Ryzen 7
RAM4 GB, 8 GB, 16 GB, 32 GB
Storage256 GB, 512 GB, 1 TB
Operating SystemWindows 11, ChromeOS, macOS
ConditionNew, Used, Refurbished
SellerBest Buy, Amazon.com, Walmart, B&H Photo

Groups vary by product category. A running shoes query returns groups like Size, Brand, Color, Gender, Activity.

Full Filter Workflow

TOKEN="YOUR_TOKEN"

# 1. Baseline query: inspect the filters Google offers
curl -s "https://api.scrape.do/plugin/google/shopping?q=laptop&token=$TOKEN" \
  | jq '.filters | map({type, sample_options: [.options[:3] | .[] | .text]})'

# 2. Apply a feature filter (For Gaming)
SHOPRS=$(curl -s "https://api.scrape.do/plugin/google/shopping?q=laptop&token=$TOKEN" \
  | jq -r '.filters[] | select(.type == "Features") | .options[] | select(.text == "For Gaming") | .shoprs')

curl -s "https://api.scrape.do/plugin/google/shopping?q=laptop&shoprs=$SHOPRS&token=$TOKEN" \
  | jq '.shopping_results | length'

# 3. Layer first-class filters on top: gaming laptops $800–$2000 sorted by price
curl -s "https://api.scrape.do/plugin/google/shopping?q=laptop&shoprs=$SHOPRS&min_price=800&max_price=2000&sort_by=1&token=$TOKEN" \
  | jq '.shopping_results[:5] | .[] | {title, price, source}'

Handling Transient Empty Results

Deeper Shopping pagination pages can occasionally return a response with shopping_results: [] even when data exists upstream. These are transient; a single retry almost always recovers the full result set.

For paginated Shopping crawls, treat an unexpected empty shopping_results array as a retry-once condition. Only treat a repeated empty response as a true "no more data" state.


Thumbnail & Icon Format

Product thumbnails (thumbnail) and retailer icons (source_icon) can come back as either a base64 data URI (data:image/webp;base64,...) or a standard URL (https://...). Both represent valid image data, so clients must handle both formats transparently.

// Example: rendering either format in an <img>
const src = result.thumbnail;   // already a valid src for <img>

Error Handling

All endpoints return errors in a consistent JSON format:

{
  "error": "error_code",
  "message": "Human readable error message"
}

Common Error Codes

StatusErrorDescription
400token is requiredMissing authentication token
400q (search query) is requiredMissing q parameter
400device must be one of: desktop, mobileInvalid device value
400invalid google_domainDomain not in the supported list
400start must be a non-negative integerInvalid pagination offset
502request failedTransient upstream failure. Retry
502unexpected responseNon-200 response from Google
500decompression failedResponse body decompression error
500failed to parse search resultsHTML parsing error

On this page