# Google Shopping Search API > Source: https://scrape.do/documentation/google-scraper-api/shopping/search/ Scrape Google Shopping search results, sponsored product ads, filters, and categorized product groups as structured JSON The Google Shopping API is a specialized plugin that searches Google Shopping and returns organic product listings plus sponsored product ads 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. > [!NOTE] > **Credit Usage:** Each successful request costs **10 credits**. For bulk processing, use the [Async API with plugins](/documentation/async-api/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. - **Sponsored Ads Separated**: PLA ads from Google's sponsored strip are returned in a dedicated `ads` array, never mixed into `shopping_results`, so organic positions stay clean. - **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 ``` > [!NOTE] > Parameter 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](#filter--sort-reference) below | > [!NOTE] > 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](/documentation/google-scraper-api/localization) for the full list of supported `hl`, `gl`, and `google_domain` values. --- ## Example Usage ### Basic search **cURL (API mode)** ```bash curl --location --request GET 'https://api.scrape.do/plugin/google/shopping?token=&q=laptop' ``` **Python (API mode)** ```python import requests import json 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)) ``` **Node.js (API mode)** ```javascript const axios = require('axios'); const 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); }); ``` *(Go, Ruby, Java, C#, PHP examples are also available on the HTML version.)* ```bash curl "https://api.scrape.do/plugin/google/shopping?q=laptop&token=YOUR_TOKEN" ``` ### With price range ```bash 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 ```bash curl "https://api.scrape.do/plugin/google/shopping?q=laptop&sort_by=1&on_sale=true&token=YOUR_TOKEN" ``` ### Location-targeted (auto-UULE) ```bash curl "https://api.scrape.do/plugin/google/shopping?q=laptop&location=Austin,Texas,United+States&token=YOUR_TOKEN" ``` ### Turkish locale ```bash 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 ```bash curl "https://api.scrape.do/plugin/google/shopping?q=laptop&device=mobile&token=YOUR_TOKEN" ``` --- ## Response ### Top-Level Structure ```json { "search_parameters": { ... }, "search_information": { ... }, "shopping_results": [ ... ], "ads": [ ... ], "filters": [ ... ], "carousel_filters": [ ... ], "categorized_shopping_results": [ ... ], "pagination": { ... } } ``` ### `search_parameters` Echo of the request parameters sent by the client. ```json { "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` ```json { "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. ```json { "position": 1, "title": "Lenovo IdeaPad Slim 3 Chromebook FHD", "product_id": "7000474567848623813", "catalog_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 (same as `catalog_id` for catalog-backed entries; an offer-specific identifier otherwise) | | `catalog_id` | string | | Durable Google catalog identifier you can persist and replay against [`/plugin/google/shopping/product?catalog_id=…`](/documentation/google-scraper-api/shopping/product). Region-scoped — re-search per region (`gl=de`, `gl=fr`, …) to get region-specific catalog ids. Omitted when Google didn't surface a catalog for the card. | | `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. Replay it against [`/plugin/google/shopping/product`](/documentation/google-scraper-api/shopping/product) to get the full product page (sellers, variants, specs, reviews, videos). | ### `ads` Sponsored product listings from Google's "Sponsored products" strip. They are returned separately from `shopping_results`, and every item includes `sponsored: true`, so you can process paid placements without changing organic rank calculations. `ads` is only present when Google serves sponsored listings for that request. Ad delivery varies by query, region, and timing, so the same request can return `ads` on one call and omit the key on another. Sponsored listings are returned for both `device=desktop` and `device=mobile`. Use `tracking_link` as the ad's destination. Google usually renders the ad card with only its `/aclk` redirect, so `link` is frequently empty on desktop and always empty on mobile. Mobile ads also come back without `thumbnail`. Google can run the same offer as both a sponsored listing and an organic result on the same page, so a product can appear in `ads` and `shopping_results` at once. The two arrays use different identifiers (`ads` entries carry `merchant_id` and `offer_id`, while `shopping_results` entries carry `product_id` and `catalog_id`), so they cannot be joined on a shared key. Keep them as separate lists, or match on merchant and title if you need a merged view. ```json [ { "position": 1, "sponsored": true, "title": "24\" x 15\" Natural Bamboo Large Serving Tray with Handles", "source": "JPI Display", "merchant_id": "142452751", "offer_id": "shopify_US_8313971540290_45108053475650", "link": "https://jpidisplay.com/products/24-x-15-natural-bamboo-large-serving-tray-with-handles", "tracking_link": "https://www.google.com/aclk?sa=L&ai=...&adurl=", "price": "$36.50", "extracted_price": 36.5, "rating": 4.8, "reviews": 5, "thumbnail": "data:image/webp;base64,UklGRjIL...", "delivery": "Free" } ] ``` ### `ads[]` Fields | Field | Type | Always present | Description | |-------|------|:-:|-------------| | `position` | int | yes | 1-based position within the sponsored strip | | `sponsored` | bool | yes | Always `true` for paid listings | | `title` | string | yes | Product title | | `source` | string | | Merchant name (`"Walmart"`, `"Temu"`, etc.) | | `merchant_id` | string | | Google merchant identifier for the advertiser | | `offer_id` | string | | Merchant-specific offer identifier | | `link` | string | | Direct merchant landing URL. Frequently empty — Google usually renders the ad card with only its `/aclk` redirect, and it is always empty on `device=mobile`. Prefer `tracking_link` | | `tracking_link` | string | | Google ad-click URL that records the click and redirects to `link` | | `price` | string | | Formatted price (`"$36.50"`) | | `extracted_price` | float | | Numeric price value | | `old_price` | string | | Original price before discount, when shown | | `extracted_old_price` | float | | Numeric original price | | `rating` | float | | Product rating out of 5 | | `reviews` | int | | Number of user reviews | | `thumbnail` | string | | Product image as base64 data URI or URL | | `delivery` | string | | Delivery/shipping info (`"Free"`) | | `tag` | string | | Promotional badge (`"Sale"`, etc.) | ### `filters` Sidebar filter groups. Use `options[].shoprs` as the `shoprs` parameter on a follow-up call. See [Filter & Sort Reference](#filter--sort-reference) below. ```json [ { "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`. ```json [ { "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. ```json [ { "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. ```json { "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 | > [!NOTE] > **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`). ```bash # 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 | ```bash curl "https://api.scrape.do/plugin/google/shopping?q=laptop&sort_by=1&token=$TOKEN" ``` #### Free shipping: `free_shipping` ```bash curl "https://api.scrape.do/plugin/google/shopping?q=laptop&free_shipping=true&token=$TOKEN" ``` #### On sale: `on_sale` ```bash 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: ```bash 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 ```bash curl -s "https://api.scrape.do/plugin/google/shopping?q=laptop&token=$TOKEN" | jq '.filters[:2]' ``` ```json [ { "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 ```bash 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. > [!NOTE] > `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: ```json [ { "text": "Nearby", "shoprs": "CAEYAyoGbGFwdG9wMg4IAxIGTmVhcmJ5GAJIAQ" }, { "text": "Deals", "shoprs": "CAESBEoCGAEYBioGbGFwdG9wMhUIBhIHT24gc2FsZRgCIgRKAhgBSAE" } ] ``` ```bash 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 ```bash 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. > [!WARNING] > 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. ```js // Example: rendering either format in an const src = result.thumbnail; // already a valid src for ``` --- ## Error Handling All endpoints return errors in a consistent JSON format: ```json { "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 | ---