# Home Depot, Lowe's & Menards Prices + Store Availability (US) (`yugenox/home-improvement-prices`) Actor

Local prices, sale prices, ratings and nearby-store availability for Home Depot, Lowe's and Menards products, read from Google Shopping by keyword or model number and US ZIP code, plus the retailer's item ID and product URL when Google links it. Optional store address, phone and hours. No login.

- **URL**: https://apify.com/yugenox/home-improvement-prices.md
- **Developed by:** [Yugenox Corp](https://apify.com/yugenox) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 4 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 result rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Home Depot, Lowe's & Menards Prices + Nearby Store Stock (US)

Get **prices, sale prices, ratings and nearby-store availability** for products sold by **The Home Depot, Lowe's and Menards**, by keyword or model number and **US ZIP code**, with the **retailer's own item ID and product page URL**. The data comes from **Google**: for each search the actor reads the Google Shopping results for that retailer near your ZIP code and returns one clean row per listing, with the local price and Google's "In store, <city>" or "Pickup, <city>" flag, and the store's own product link from Google Shopping's product listing (item ID + URL). Filter by store city, or add the nearest store's address, phone and opening hours. No login, no cookies, nothing to set up.

This actor is not affiliated with or endorsed by The Home Depot, Lowe's or Menards. It never visits their websites; it only reads public Google results (Google Shopping, including each listing's product page there, and Google Images of the retailers' sites as a fallback for product IDs).

### What you get

| | |
|---|---|
| **Price** | The local price in USD near your ZIP code, the regular (was) price, % off, and the unit price such as `$5.16/ct` |
| **Nearby store** | `in_store` or `pickup` when Google flags the listing at a store near the ZIP code, plus that store's city (or its distance in miles, when Google shows a distance) |
| **Product** | Title, brand, model number (when the title has one), rating, review count, delivery promise, return policy, and the "& more" flag (other stores sell it too) |
| **Retailer item ID + URL** | The Home Depot item ID (9 digits), Lowe's item ID or Menards product ID, also as `sku`, and the product page link (`productUrl`, also as `url`), from the store's own link in Google Shopping's product listing, with how it was found, a confidence score and the store's own title for it (see below) |
| **Tracking ids** | Google's product id and offer id, stable across runs, so you can follow one product's price over time |
| **State** | The state of your ZIP code (`zipState`), and of the flagged store (`storeState`) when the store lookup lists a store in that city |
| **Store details** (optional) | Store name, address, state, phone, today's opening-hours line, the Home Depot store number when Google links the store page, and the other nearby stores Google lists |

### How to use it

1. Add **search terms**: keywords (`cordless drill`, `LED shop light`) or a brand plus a model number (`milwaukee 2904-22`).
2. Pick **retailers**: The Home Depot, Lowe's, Menards (all three by default). Menards only has stores in the Midwest.
3. Add **ZIP codes** to get local prices and nearby-store flags. Optionally keep **only listings at stores in certain cities** ("Fort Worth", "Marietta").
4. Product IDs and URLs are added by default (**Add the retailer's product ID and product page URL**). Turn it off if you only need prices.
5. Optional: **Only listings available at a nearby store**, **Only exact model-number matches**, **Add the nearest store's details**, or **Also read the second results page** (set *Max listings per search* to 80 or 0 for that).

Each search term is searched once per retailer and ZIP code. One Google Shopping page holds about 40 listings.

#### Input examples (all run on Apify on 2026-10-01)

Prices, nearby-store flags and product IDs for one product type at two retailers near Atlanta (the default input). 80 rows; product IDs for 76 of them (Home Depot 40 of 40, Lowe's 36 of 40):

```json
{
  "searchTerms": ["cordless drill"],
  "retailers": ["homedepot", "lowes"],
  "zipCodes": ["30339"]
}
```

Only what is on the shelf near you. 69 listings flagged in store or pickup near 30339; 19 without a flag were skipped and not charged:

```json
{
  "searchTerms": ["paint roller"],
  "retailers": ["homedepot", "lowes"],
  "zipCodes": ["30339"],
  "onlyInStore": true
}
```

All three retailers in Madison, WI, with each retailer's nearest store. 94 listings + 3 store rows:

```json
{
  "searchTerms": ["hammer"],
  "retailers": ["homedepot", "lowes", "menards"],
  "zipCodes": ["53703"],
  "includeStoreInfo": true
}
```

Two products in two cities: 313 listings in 52 s (with product IDs off):

```json
{
  "searchTerms": ["led shop light", "extension cord"],
  "retailers": ["homedepot", "lowes"],
  "zipCodes": ["60601", "98101"]
}
```

Only what Google flags at stores in Dallas or Fort Worth (Lowe's, ZIP 75201). 22 listings kept (Dallas 21, Ft. Worth 1); 25 at other stores or without a flag were skipped and not charged, and the status message listed the store cities Google showed (Dallas, Garland, Ft. Worth, Carrollton):

```json
{
  "searchTerms": ["garden hose"],
  "retailers": ["lowes"],
  "zipCodes": ["75201"],
  "storeCities": ["Ft. Worth", "Dallas"]
}
```

One exact model. With **Only exact model-number matches** on, the run returned just the matching Home Depot kit (in store at Lithia Springs, `modelMatch: true`) and skipped 38 related listings without charging them:

```json
{
  "searchTerms": ["milwaukee 2904-22"],
  "retailers": ["homedepot", "lowes"],
  "zipCodes": ["30339"],
  "onlyModelMatches": true
}
```

### Output example

A listing with its Home Depot item ID (impact driver, Home Depot, ZIP 60601 in Chicago; run on Apify on 2026-10-01). The Shopping title has no model number, so `modelNumber` comes from the end of the store's link:

```json
{
  "type": "product",
  "retailer": "homedepot",
  "retailerName": "The Home Depot",
  "query": "impact driver",
  "zip": "60601",
  "zipState": "IL",
  "title": "Ryobi ONE+ 18V Cordless 1/4 in Impact Driver",
  "brand": "RYOBI",
  "modelNumber": "PCL235B",
  "modelMatch": null,
  "retailerProductId": "318621812",
  "sku": "318621812",
  "productUrl": "https://www.homedepot.com/p/RYOBI-ONE-18V-Cordless-1-4-in-Impact-Driver-Tool-Only-PCL235B/318621812",
  "url": "https://www.homedepot.com/p/RYOBI-ONE-18V-Cordless-1-4-in-Impact-Driver-Tool-Only-PCL235B/318621812",
  "idMatch": "offer",
  "idConfidence": 1,
  "productPageTitle": "RYOBI ONE+ 18V Cordless 1/4 in. Impact Driver (Tool Only)",
  "price": 59,
  "currency": "USD",
  "wasPrice": null,
  "discountPercent": null,
  "unitPrice": null,
  "rating": 4.7,
  "reviewCount": 149,
  "availability": "in_store",
  "storeCity": "Chicago",
  "storeState": null,
  "storeDistanceMiles": null,
  "deliveryPromise": "Free delivery",
  "returns": "90-day returns",
  "merchant": "Home Depot",
  "otherSellers": true,
  "googleProductId": "16245853475903550476",
  "googleOfferId": "9744810362083739752",
  "googleIds": {
    "cid": "16245853475903550476",
    "gid": "6883394024718937586",
    "oid": "9744810362083739752",
    "pid": "1237354393890892499",
    "iid": "9828235175994078486"
  },
  "imageUrl": null,
  "position": 1,
  "page": 1,
  "googleQuery": "impact driver home depot near 60601",
  "googleUrl": "https://www.google.com/search?q=impact+driver+home+depot+near+60601&tbm=shop&gl=us&hl=en",
  "scrapedAt": "2026-10-01T18:04:40.031Z"
}
```

A store row (with **Add the nearest store's details**, from the Madison, WI example). Google listed a Lowe's in Madison, **Indiana** first; the row is the first store in the ZIP code's state, and the full list stays in `nearbyStores`:

```json
{
  "type": "store",
  "retailer": "lowes",
  "retailerName": "Lowe's",
  "zip": "53703",
  "zipState": "WI",
  "name": "Lowe's Home Improvement",
  "address": "Franklin, WI",
  "state": "WI",
  "storeState": "WI",
  "phone": "(414) 281-2840",
  "hours": "Closed · Opens 6 AM Thu",
  "rating": null,
  "reviewCount": null,
  "category": null,
  "website": null,
  "storeNumber": null,
  "googleKgId": "/g/1xgzcbsh",
  "source": "local_pack",
  "nearbyStores": [
    { "name": "Lowe's Home Improvement", "address": "Madison, IN", "state": "IN", "phone": "(812) 801-2000", "hours": "Closed · Opens 6 AM", "googleKgId": "/g/1tdw46k5" },
    { "name": "Lowe's Home Improvement", "address": "Franklin, WI", "state": "WI", "phone": "(414) 281-2840", "hours": "Closed · Opens 6 AM Thu", "googleKgId": "/g/1xgzcbsh" },
    { "name": "Lowe's Home Improvement", "address": "Appleton, WI", "state": "WI", "phone": "(920) 636-2782", "hours": "Closed · Opens 6 AM Thu", "googleKgId": "/g/1tdky7dr" }
  ],
  "googleQuery": "lowes near 53703",
  "googleUrl": "https://www.google.com/search?q=lowes+near+53703&gl=us&hl=en",
  "scrapedAt": "2026-10-01T04:02:59.161Z"
}
```

When Google shows a single-store panel instead of a list (as for `home depot near 30339`), the row has the full street address, rating, review count, category and store page link, and for Home Depot the store number read from that link (`121`). In a list, Google often shows only a street or a city as the address.

The **Listings** and **Stores** tabs of the dataset show the main columns as tables. Every run also saves a `RUN_REPORT` record with how each Google page went.

### How much does it cost?

You pay per event:

| Event | Price | When |
|---|---|---|
| Actor start | $0.015 | Once per run (per GB of memory; the default 256 MB is one) |
| Google search page | $0.005 | Each Google Shopping page or store lookup that Google answered |
| Result row | $0.002 | Each listing or store row saved |
| Product ID + URL | $0.009 | Each saved listing that has the retailer's item ID and product page URL (also when it comes from the ID cache of an earlier run). Listings without one are not charged for it |

The default input above (2 search pages, 80 rows, 76 with a product ID) costs $0.015 + $0.010 + $0.160 + $0.684 = **$0.869**. Without product IDs (turn the option off) it is $0.185. A page is charged when Google answered it, even if it held no listings from the chosen retailer (for example Menards outside the Midwest). Blocked, timed-out, wrong-country or unreadable attempts are retried on a new connection and never charged, and a page that comes back after *Max rows* was reached is not charged. Other sellers' listings, duplicates and listings removed by your filters (nearby store, model number, store cities) are never saved or charged. The Google requests the actor makes to find product IDs are not charged: you pay per ID found.

### Use cases

- **Price comparison** between Home Depot, Lowe's and Menards for the same product type in the same city.
- **Local price and promotion monitoring**: schedule a daily run and track rows by `googleProductId`.
- **Retail arbitrage and reselling**: find sale items that Google flags in a store near you.
- **Contractor and procurement quotes**: local prices and the nearest store's phone and hours in one table.
- **Market research**: brands, price points and ratings each retailer shows for a category, city by city.
- **Joining with your own data**: the retailer item ID and product URL connect each local price to your catalog, a repricer or another Home Depot / Lowe's data source.

### FAQ

**Where does the data come from?** From Google. For "cordless drill" + Lowe's + 30339 the actor reads Google Shopping's results for `cordless drill lowes near 30339`, keeps the listings sold by Lowe's, and returns them with the price, flags and ids Google shows; product IDs and URLs come from the store's own link in each listing's Google Shopping product listing. It never sends a request to homedepot.com, lowes.com or menards.com.

**Is "in_store" a stock count?** No. Store availability is the nearby-store flag Google shows ("In store, Marietta" / "Pickup, Marietta"), not a stock count. Google picks the nearby store; the actor reports its city in `storeCity` (or `storeDistanceMiles` when Google shows a distance instead). `online_only` means the first results page for your ZIP code showed no nearby-store flag for that listing. `null` means the search had no ZIP code, or the listing came from the second results page, where Google shows no flags.

**Can I leave the ZIP codes empty?** Yes, but Google then picks a location by itself (it can change from one request to the next). Prices can be the local price of some US area, and the actor leaves out Google's store flags because they would refer to a store you don't know. Use ZIP codes when location matters. *Only listings available at a nearby store* needs at least one ZIP code.

**Why does the local price differ from the online price?** With a ZIP code you get the price Google shows for that area, which can differ from the online price (for example $219 near one store and $229 online).

**How are the product IDs and URLs found?** From the store's own link in Google Shopping's product listing, never from the retailer's site. For each listing the actor opens its Google Shopping product listing (the panel Google shows when you click a result), which lists the stores selling that product with their own product links; it takes the link of the listing's own store (`idMatch: "offer"`, `idConfidence: 1`) and reads the ID from it (`homedepot.com/p/…/318621812`, `lowes.com/pd/…/5014148635`, `menards.com/main/p-1642874277741664.htm`), with tracking parameters removed. Other stores in that listing (eBay, Walmart, the brand's shop) are ignored. `productPageTitle` is the store's own title for that link, and when the Shopping title has no model number, `modelNumber` comes from the link (Home Depot) or the store's title (Lowe's). Only when a listing's product listing has no link to its store, the actor searches Google Images of that store's site for the listing's model number (`site:lowes.com "DCF870B"`) and takes a page only if that model number is on it (`idMatch: "model"`); listings without a model number are never matched by their wording. Then it asks the product listing once more, because Google's list of stores changes between answers.

**Why do some listings have no ID?** Sometimes Google's product listing has no link to the store that sold the listing (it happens mostly with Lowe's), and the listing has no model number to look up, or Google has no page with it. Such a listing stays without an ID rather than get a guess, and is not charged for one. In our tests on Apify on 2026-10-01 (fresh runs, no cache): impact drivers near Chicago 36 of 37 listings (Home Depot 15/15, Menards 7/7, Lowe's 14/15); Lowe's ceiling fans near Charlotte 38 of 40; Lowe's garden hoses near Dallas 36 of 40. Every ID in those runs was checked against the listing title.

**Can an ID be for another variant than the listing title says?** Rarely: Google sometimes groups variants (colors, sizes) under one listing, and the store's link then points to the variant the store sells at that price. When the store's page names another color, size or count than Google's title, the ID is kept (the price in the row is that offer's) but `idConfidence` is 0.9, and `productPageTitle` shows the store's own title. In the tests above that was 5 of 123 IDs (for example a 46-in fan listed by the store as 36-in). An ID taken from another offer of the same Google product at that store (not the listing's own offer) has `idConfidence` 0.95, and is never used when its page contradicts the listing.

**Are IDs cached?** Yes. Found IDs are kept for 30 days in a key-value store named `home-improvement-prices-ids` in your Apify account, by Google's product id (and listings that were looked up in full without a result for 7 days), so a repeat run doesn't look them up again and finishes sooner. IDs from the cache are charged like any other ID. You can delete that store at any time.

**How do I filter by store city?** Add the cities to **Only these store cities**. Case, dots and the usual abbreviations don't matter ("Ft. Worth" = "Fort Worth", "St. Louis" = "Saint Louis", "Marietta, GA" = "Marietta"). It needs ZIP codes, because Google only flags nearby stores for a ZIP code. If no listing is flagged in your cities, the status message lists the store cities Google did show, so you can pick from them.

**What is not included?** UPC codes, stock quantities, aisle and bay, and retailer store numbers (except Home Depot store numbers when Google links the store page). Google doesn't show these.

**How many results can I get?** About 40 listings per search (search term × retailer × ZIP code). The second page usually adds about 30–40 more (77 listings in total in our test), though most second-page listings have no nearby-store flag, so set *Max listings per search* to 0 and turn the second page on to get everything Google shows. Use more search terms or ZIP codes for more rows.

**Exact model numbers?** Search the brand plus the model (`milwaukee 2904-22`). For a bare model number such as `DCD771C2`, Google mostly shows related products (in our test none of 45 titles had it). `modelMatch` is true when a listing's title contains the model you searched. Turn on **Only exact model-number matches** to keep (and pay for) only those. Note that some retailer titles on Google leave the model number out, so that filter can also skip the right product.

**Why are Menards listings sometimes missing nearby-store flags?** Google often shows Menards listings without a store flag. Menards also only has stores in the Midwest, so searches elsewhere mostly return other sellers, and those listings are not included.

**Which store do I get with "Add the nearest store's details"?** The first store Google lists for "<retailer> near <ZIP>" that is in the ZIP code's state (or whose address doesn't show a state). Google sometimes lists a far store first, for example a Lowe's in Madison, IN for a Madison, WI ZIP code. A store in another state is never used. If Google lists only stores in other states, no store row is saved and the status message says so. All stores Google listed are in `nearbyStores`.

**How fast is it?** A Google results page usually answers in 5–30 s, sometimes over a minute. Pages run in parallel, so 8 pages took about 55 s. Product IDs add one Google request per listing (8 at a time; in our tests a 40-listing search took 65–190 s in total); a repeat run takes the IDs from the cache and is about as fast as one without IDs. Slow pages get a second request automatically. If you set a short run timeout, the actor stops in time, keeps what it has (listings whose ID lookup had not finished are saved without an ID, and not charged for one), and the status message says how many IDs were skipped for time and how many pages it could not read.

**What if Google blocks a request or answers for another country?** The page is retried on a new connection, and nothing is charged for the failed attempt. If Google is unavailable for a long time, the run stops with a plain status message and keeps everything it found.

**Is it legal to scrape Google Shopping results?** This Actor only collects publicly available data: product listings, prices, product page links and store details that anyone can see in Google Shopping and Google Search without an account. Collecting publicly available data is generally legal, but you're responsible for how you use it, including Google's and the retailers' terms. If you're unsure, check with a lawyer. More on this: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

**Does it collect personal data?** No. Rows contain product listings and business store details only. No reviews, reviewer names or account data.

# Actor input Schema

## `searchTerms` (type: `array`):

Products to look up, e.g. "cordless drill" or "LED shop light". For one exact product, use the brand plus the model number, e.g. "milwaukee 2904-22" (for a bare model number Google mostly shows related products). Each term is searched separately for every retailer and ZIP code.

## `retailers` (type: `array`):

Which stores' listings to keep. Each retailer is one Google Shopping search per term and ZIP code. Menards only has stores in the Midwest.

## `zipCodes` (type: `array`):

Localizes results to the stores near each ZIP code: local prices plus Google's nearby-store flag ("In store, Marietta" / "Pickup, Marietta"). Leave empty to search without a location: Google then picks a location itself, so prices may be one area's local price and listings get no nearby-store flag.

## `storeCities` (type: `array`):

Keep only listings that Google flags at a store in one of these cities, e.g. "Fort Worth" or "Marietta". Case, dots and the usual abbreviations don't matter ("Ft. Worth" = "Fort Worth", "St. Louis" = "Saint Louis"). Needs ZIP codes. Listings at other stores or without a store flag are skipped and not charged; the status message lists the store cities Google showed, so you can pick from them.

## `onlyInStore` (type: `boolean`):

Keep only listings that Google flags as in store or pickup near the ZIP code. Needs at least one ZIP code.

## `onlyModelMatches` (type: `boolean`):

For searches that contain a model number (e.g. "milwaukee 2904-22"): keep only listings whose title contains that model number. Related products Google also shows are skipped and not charged. Note that some retailer titles on Google leave the model number out, so this can skip the right product too. Keyword searches are not affected.

## `includeStoreInfo` (type: `boolean`):

Adds one row per retailer and ZIP code with the store Google shows for "<retailer> near <ZIP>": name, address, phone, opening-hours line, rating, and the other nearby stores. Needs ZIP codes. Costs one extra search page per retailer and ZIP.

## `includeProductIds` (type: `boolean`):

Adds the Home Depot / Lowe's / Menards item ID (retailerProductId, also as sku) and the product page link (productUrl, also as url) to each listing. They come from the store's own link in Google Shopping's product listing for that listing (Google's product page, never the retailer's site itself). When that listing carries no link to the store, the ID is looked up in Google's index of the store's site by the listing's model number (exact model-number matches only). Charged per listing that gets an ID.

## `maxIdLookups` (type: `integer`):

Every listing's ID comes from its own Google Shopping product listing (one lookup per listing). A listing whose product listing has no link to the store, and whose title names a model number, gets one more Google search for that model number; this caps those extra searches for the whole run. 0 = no extra searches. You pay per ID found, not per search.

## `maxItemsPerQuery` (type: `integer`):

Listings to keep for each search term × retailer × ZIP code. One Google Shopping page holds about 40; to also use the second page, set 80 (or 0 = no limit) and turn on the option below.

## `includePage2` (type: `boolean`):

Reads a second Google Shopping page when the first one did not reach Max listings per search (about 40 more listings, mostly without a nearby-store flag). Costs one more search page per search.

## `maxItems` (type: `integer`):

Hard cap on rows for the whole run. 0 = no cap.

## `proxyConfiguration` (type: `object`):

Google results are read through Apify's GOOGLE_SERP proxy. Keep the default.

## `_noSerpProxy` (type: `boolean`):

Internal (canaries): behave exactly like an account without the GOOGLE_SERP proxy group.

## `_concurrency` (type: `integer`):

Internal: Google pages fetched in parallel (1-8).

## `_hedgeAfterSecs` (type: `integer`):

Internal: a page with no answer after this many seconds gets a second request on another connection. 0 = off.

## `_noIdCache` (type: `boolean`):

Internal: do not read or write the named key-value store that remembers product IDs between runs.

## Actor input object example

```json
{
  "searchTerms": [
    "cordless drill"
  ],
  "retailers": [
    "homedepot",
    "lowes"
  ],
  "zipCodes": [
    "30339"
  ],
  "onlyInStore": false,
  "onlyModelMatches": false,
  "includeStoreInfo": false,
  "includeProductIds": true,
  "maxIdLookups": 100,
  "maxItemsPerQuery": 40,
  "includePage2": false,
  "maxItems": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "GOOGLE_SERP"
    ]
  },
  "_noSerpProxy": false,
  "_concurrency": 4,
  "_hedgeAfterSecs": 20,
  "_noIdCache": false
}
```

# Actor output Schema

## `results` (type: `string`):

All product listings (and store rows, if requested).

## `report` (type: `string`):

How every Google page went (answered, retried, blocked) and what was charged.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchTerms": [
        "cordless drill"
    ],
    "retailers": [
        "homedepot",
        "lowes"
    ],
    "zipCodes": [
        "30339"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "GOOGLE_SERP"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/home-improvement-prices").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchTerms": ["cordless drill"],
    "retailers": [
        "homedepot",
        "lowes",
    ],
    "zipCodes": ["30339"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["GOOGLE_SERP"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/home-improvement-prices").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "cordless drill"
  ],
  "retailers": [
    "homedepot",
    "lowes"
  ],
  "zipCodes": [
    "30339"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "GOOGLE_SERP"
    ]
  }
}' |
apify call yugenox/home-improvement-prices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yugenox/home-improvement-prices"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/2SOa5oZDER17nyecL/builds/eLX4eOY6tqOp6XnT5/openapi.json
