Google Shopping API
Scrape Google Shopping search results, filters, and categorized product groups as structured JSON
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_resultswith 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
shoprsparameter. - Price & Shipping Filters: First-class parameters for
min_price,max_price,sort_by(price asc/desc),free_shipping, andon_sale. - Worldwide Coverage: 84 regional Google domains, 150+ interface languages, 240+ country codes, location-level geo-targeting via
locationoruule. - Device Emulation: Desktop or mobile layout with the
deviceparameter. - Pagination: Navigate through result pages using the returned
pagination.nextlink. - No Blocks or CAPTCHAs: All anti-bot measures are handled automatically by Scrape.do.
Endpoint
GET https://api.scrape.do/plugin/google/shoppingParameter keys are case-insensitive. You can use q, Q, hl, HL, etc.
Request Parameters
Required
| Parameter | Type | Description |
|---|---|---|
token | string | Your Scrape.do API authentication token |
q | string | Search query. URL-encode spaces and special characters. Examples: laptop, wireless+headphones, running+shoes |
Device
| Parameter | Type | Default | Description |
|---|---|---|---|
device | string | desktop | Device type. One of desktop, mobile |
Pagination
| Parameter | Type | Default | Description |
|---|---|---|---|
start | integer | 0 | Result offset for pagination. Use the pagination.next path from the response to paginate |
Filters (first-class)
| Parameter | Type | Default | Description |
|---|---|---|---|
min_price | integer | — | Minimum price filter (e.g., 100) |
max_price | integer | — | Maximum price filter (e.g., 500) |
sort_by | integer | 0 | Sort order. 0 = relevance (default), 1 = price low to high, 2 = price high to low |
free_shipping | boolean | false | Filter to products with free shipping |
on_sale | boolean | false | Filter to products currently on sale |
shoprs | string | — | Opaque 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
| Parameter | Type | Default | Description |
|---|---|---|---|
hl | string | en | Host language |
gl | string | us | Country perspective |
google_domain | string | google.com | Google domain to query |
location | string | — | Location name (e.g., Austin,Texas,United States). Auto-encoded to UULE when uule is not set |
uule | string | — | Google-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
Basic search
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
| Field | Type | Always present | Description |
|---|---|---|---|
position | int | yes | 1-based position in the results list |
title | string | yes | Product title |
product_id | string | Google product catalog ID | |
product_link | string | Direct link to the Google Shopping product page | |
source | string | Retailer name ("Best Buy", "Amazon.com", "Walmart") | |
source_icon | string | Retailer favicon as base64 data URI or URL | |
price | string | Formatted price ("$189.00", "1.299,00 TL") | |
extracted_price | float | Numeric price value (189) | |
old_price | string | Original price before discount ("$399") | |
extracted_old_price | float | Numeric original price | |
rating | float | Product rating out of 5 | |
reviews | int | Number of user reviews | |
snippet | string | Summary from reviews ("Performs well (720 user reviews)") | |
extensions | string[] | Badges and metadata (["52% OFF"], ["Nearby, 17 mi", "30% OFF"]) | |
thumbnail | string | Product image as base64 data URI or URL | |
delivery | string | Delivery/returns info ("Free delivery by Tue", "15-day returns") | |
tag | string | Discount or promotional badge ("52% OFF", "Low price") | |
badge | string | Alternative badge text | |
second_hand_condition | string | Condition for used items: "Refurbished", "Used", or "Renewed" | |
multiple_sources | bool | true when the product is sold by multiple retailers | |
immersive_product_page_token | string | Base64 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..." }
]
}
]carousel_filters
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"
}| Field | Type | Description |
|---|---|---|
current | int | Current start offset |
next | string | Path 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
| Value | Meaning |
|---|---|
0 (default) | Relevance. Google's default ordering |
1 | Price: low to high |
2 | Price: 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
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 type | Example options |
|---|---|
| Features | For Gaming, Touchscreen, Convertible, Energy Star |
| Screen Size | Under 14 inches, 14–15 inches, 15–16 inches, Over 16 inches |
| Price | Under $500, $500–$1,000, $1,000–$2,000, Over $2,000 |
| Brand | HP, Lenovo, Dell, Apple, ASUS, Acer |
| CPU | Intel Core i5, Intel Core i7, AMD Ryzen 5, AMD Ryzen 7 |
| RAM | 4 GB, 8 GB, 16 GB, 32 GB |
| Storage | 256 GB, 512 GB, 1 TB |
| Operating System | Windows 11, ChromeOS, macOS |
| Condition | New, Used, Refurbished |
| Seller | Best 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
| Status | Error | Description |
|---|---|---|
400 | token is required | Missing authentication token |
400 | q (search query) is required | Missing q parameter |
400 | device must be one of: desktop, mobile | Invalid device value |
400 | invalid google_domain | Domain not in the supported list |
400 | start must be a non-negative integer | Invalid pagination offset |
502 | request failed | Transient upstream failure. Retry |
502 | unexpected response | Non-200 response from Google |
500 | decompression failed | Response body decompression error |
500 | failed to parse search results | HTML parsing error |

