# Lowe's Scraper — Products, Prices & Reviews (`tortuga/lowes-scraper`) Actor

Scrape Lowes.com search results, product pages and reviews: price, was-price, savings, rating, brand, model, availability, images and specifications. Any keyword or URL.

- **URL**: https://apify.com/tortuga/lowes-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** E-commerce
- **Stats:** 6 total users, 4 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 product scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Lowe's Scraper

> **Status, October 2026:** Lowe's has been blocking most automated access to its search and category pages since early October, so search runs may return no items. Product pages and reviews still work most of the time. Items that are not delivered are not charged, and the actor now gives up on a blocked page after a few attempts to keep proxy costs down. We check it daily.

Scrape Lowes.com search results, product pages and customer reviews into a clean dataset: price, was-price, savings, sale end date, rating, review count, brand, model and item numbers, availability, pickup / delivery / shipping, badges (Top Gift, Value Pick, Featured Deal, Trending Now, Tool Only), rank on the page and sponsored flag. Turn on details for the description, the full specification table, every image, videos, manuals, variants (sizes and colors with their own product ids), UPC, dimensions, warranty and the collection a product belongs to, and turn on reviews for the review texts.

No headless browser and no login on your side: the Actor reads the JSON state Lowe's embeds in its own pages, so one request returns 24 products. Download the results as JSON, CSV or Excel, or pull them through the API into your own app, Google Sheets or an LLM pipeline. You pay per item you get.

See also: the companion [Walmart Scraper](https://apify.com/tortuga/walmart-scraper), which has the same input and output shape.

### What data does Lowe's Scraper extract?

Every product from a search page (the `result` event):

| Field | Description |
|---|---|
| `type` | `"product"` |
| `omniItemId`, `itemNumber`, `modelId` | Lowe's product id (the number at the end of `/pd/.../5013207487`), the item number ("Item #4913878" on the site) and the manufacturer model |
| `name`, `url`, `imageUrl`, `images` | Product title (brand + description), canonical product URL, full-size main image and all images Lowe's lists for the tile |
| `brand` | Brand (`null` for a few marketplace listings without one) |
| `price`, `wasPrice`, `savingsAmount`, `savingsPercent`, `currency` | Current price, strike-through price, the difference and the percentage, `USD` |
| `priceText`, `saleEndDate` | Price as displayed (`$99.00`, or `$19.98 - $209.98` for products with variants); when the sale ends (`2026-10-31`) |
| `priceType` | `NETWORK` (Lowe's price for visitors without a store), `STORE` (price of the store Lowe's assigned to the request) or `SOS` (special order / marketplace, shipped by the vendor). See "Which store do the prices come from?" |
| `variantPriceMin`, `variantPriceMax` | Price range across sizes / colors when the tile shows one instead of a single price |
| `unitPrice` | Per-unit price when Lowe's shows one (flooring, bulk items) |
| `rating`, `reviewCount` | Average rating (0-5) and number of ratings |
| `availability`, `inStock`, `availabilityText` | `IN_STOCK` / `OUT_OF_STOCK` / `UNKNOWN` and a boolean. `UNKNOWN` = the search page could not price or source the item ("See Product Page for Pickup and Delivery Options"); details fill it in |
| `fulfillment` | `{shipping, pickup, delivery, sameDayDelivery, freeShipping, shippingText, pickupText, deliveryText, arrivesBy, storeQuantity, networkQuantity, lowStock}`: which methods are available, the parcel promise date, units on hand at the store and in the online network |
| `badges` | `Top Gift`, `Value Pick`, `Featured Deal`, `Trending Now`, `Tool Only`, `Last Chance Savings`, `Only at Lowes`, ... |
| `promotions` | Promotion texts: `FREE GIFT WITH PURCHASE`, `Buy 1 and Get 1`, financing offers |
| `isSponsored` | `true` for sponsored tiles (usually 4 per page). A product shown as an ad and again organically is saved once, as organic |
| `isMarketplace`, `sellerName`, `programType` | Third-party marketplace listing or not; seller name (`Lowe's` or the marketplace seller); `Stock`, `Consumer-SOS` (special order) or `Marketplace` |
| `category`, `categoryPath` | Leaf category of the product (`Drills`, `Hammer Drills`); the full path comes with details |
| `collection` | The set / bundle the product belongs to (`{id, type, url}`, "Shop the Set") |
| `variantCount`, `variantAttribute`, `variants` | Number of sizes / colors, the attribute they vary by, and the color siblings the tile lists (`{omniItemId, name, options, url, imageUrl}`) |
| `specifications`, `highlights`, `packageQuantity` | The 2-3 key specs shown on the tile, marketing bullets, package quantity |
| `position`, `page` | Rank among the tiles of the page (ads included, in display order) and page number |
| `location` | Store context Lowe's priced the page for: `{storeNumber, zipCode, city, state}` |
| `searchTerm`, `sourceUrl`, `scrapedAt` | Provenance |

With **Include product details** on, or for product URLs (the extra `detail` event), each product also gets:

| Field | Description |
|---|---|
| `description`, `pageTitle` | Full description as plain text; the marketing title of the product page (`Kobalt Next-Gen 24-volt ... (1-Battery, Charger and Soft Bag included) KDD 2024A-03`) |
| `specifications`, `specificationGroups` | The complete specification table as a dict (`{"Battery Voltage": "24-volt", ...}`, 40+ rows) and grouped the way the page shows it (`General`, `Dimensions`, `Features`, `Warranty`, ...) |
| `images`, `videos`, `documents` | All product images; videos (`{title, url, thumbnailUrl}`); manuals and guides as PDF links (`{title, type, url}`) |
| `variantOptions`, `variants` | Option dimensions (`[{name: "Common Measurement (W x L)", values: [...]}]`) and every variant with its own product id and URL (`{omniItemId, options, name, url, available, isSelected}`). Each variant is its own product page; open it for its price |
| `upc`, `gtin`, `manufacturer` | Consumer barcode, case barcode, manufacturer (only when the spec table names one) |
| `warranty` | Warranty rows of the spec table (`Warranty: 5-year limited; Battery Warranty: 3-year limited`) |
| `dimensions` | `{height, width, depth, lengthUnit, weight, weightUnit}` of the packaged item |
| `collection` | Adds the set's name, price, was-price and member item ids |
| `lowesExclusive`, `energyStar`, `sellingChannels`, `maxPurchaseQuantity`, `prop65Warning`, `hazmat`, `hazmatInfo`, `status`, `listedAt` | Flags and facts from the catalog record |
| `socialProof` | Lowe's own popularity notes (`1K+ bought last week`) |
| `storeAisle`, `storeBay` | Where the item sits in the store Lowe's assigned to the request |
| `price`, `wasPrice`, `priceType`, `location` | The product page's own price. Search tiles Lowe's could not price get one here, often a store price with a was-price |

With **Include reviews** on, or for review-page URLs (the `review` event), one item per review:

| Field | Description |
|---|---|
| `type` | `"review"` |
| `omniItemId`, `productName`, `productUrl` | Product the review belongs to |
| `reviewId`, `legacyId`, `rating`, `title`, `text`, `submittedAt` | Review ids, stars (1-5), title, text (`null` for star-only reviews), ISO date |
| `reviewerName` | Reviewer's nickname as Lowe's shows it above the review date ("Donnie57", "Kim R"; placeholders such as "No name" are kept as the reviewer typed them); `null` when the review shows no name (some star-only ratings) |
| `reviewerId`, `reviewerLocation` | Always `null` on Lowe's: the page shows no reviewer id, profile or location (the keys are kept so review items have the same shape as in our Walmart and Viator Actors) |
| `positiveFeedback`, `negativeFeedback` | Helpful / not helpful votes |
| `verifiedPurchase`, `incentivized`, `recommended`, `badges` | Verified purchaser flag, "received an incentive" flag, "would recommend", badge texts |
| `photosCount`, `photos`, `videos` | Customer photos and videos |
| `sellerResponse`, `sellerResponseDate`, `sellerResponseBy` | Brand or Lowe's reply when present (`Kobalt Team`) |
| `ratingDimensions`, `isRatingOnly`, `language`, `syndicated`, `syndicatedFrom`, `scrapedAt` | Secondary ratings, star-only flag, locale, syndication source |

When reviews are on, the product item additionally carries `ratingCounts` (1-5 star breakdown), `recommendedCount`, `notRecommendedCount`, `recommendedPercentage`, `ratingsOnlyCount` and `reviewSummary` (Lowe's AI summary of the reviews). Reviewer avatars are not collected, and neither is the internal author id that Lowe's review data carries but never shows.

### How to use Lowe's Scraper

1. Type one or more **Search terms** (one per line) and/or paste **Start URLs**: search pages, product pages (`/pd/...`) or review pages (`/reviews/...`).
2. Pick **Sort by** (Top Sellers, Most Popular, Highest Rated, New Arrivals).
3. Set **Max items** to cap the run (and the cost). Products and reviews both count.
4. Turn on **Include product details** and/or **Include reviews** only if you need them: each costs extra requests and events (see below).
5. Click **Start**. Results appear in the **Dataset** tab; export from there or use the API.

Category pages (`https://www.lowes.com/pl/...`) are not supported: they do not load through the Unblocker proxy (every attempt times out). Search for the category name instead ("cordless drills", "area rugs"); Lowe's search covers the whole catalog.

### Input example

```json
{
  "searchTerms": ["cordless drill"],
  "startUrls": [
    { "url": "https://www.lowes.com/pd/Kobalt-24-volt-Max-1-2-in-Metal-Ratcheting-Brushless-Cordless-Drill-1-Battery-Included-and-Charger-Included/5013207487" }
  ],
  "maxItems": 200,
  "maxPagesPerSearch": 5,
  "sortBy": "best_sellers",
  "includeSponsored": true,
  "includeDetails": false,
  "includeReviews": false,
  "maxReviewsPerProduct": 20,
  "reviewSort": "newest",
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["UNBLOCKER"], "apifyProxyCountry": "US" }
}
```

### Output example

A product from a search page:

```json
{
  "type": "product",
  "omniItemId": "50040962",
  "itemNumber": "506283",
  "modelId": "DCD771C2",
  "name": "DEWALT 20-volt Max 1/2-in Keyless Cordless Drill 2 -Batteries Included, and Charger Included",
  "url": "https://www.lowes.com/pd/DEWALT-20-Volt-Max-1-2-in-Cordless-Drill-Charger-Included/50040962",
  "brand": "DEWALT",
  "price": 129.0,
  "wasPrice": 179.0,
  "savingsAmount": 50.0,
  "savingsPercent": 27,
  "priceText": "$129.00",
  "priceType": "NETWORK",
  "saleEndDate": "2026-10-31",
  "variantPriceMin": null,
  "variantPriceMax": null,
  "currency": "USD",
  "unitPrice": null,
  "rating": 4.6,
  "reviewCount": 1398,
  "availability": "IN_STOCK",
  "inStock": true,
  "availabilityText": null,
  "fulfillment": {
    "shipping": true, "pickup": false, "delivery": true, "sameDayDelivery": false, "freeShipping": true,
    "shippingText": "Ships, arrives 2026-10-06", "pickupText": null, "deliveryText": null,
    "arrivesBy": "2026-10-06", "storeQuantity": 3, "networkQuantity": 79, "lowStock": true
  },
  "badges": [],
  "promotions": [],
  "isSponsored": false,
  "isMarketplace": false,
  "sellerName": "Lowe's",
  "programType": "Stock",
  "imageUrl": "https://mobileimages.lowes.com/productimages/98901790-b0c3-4fcd-ac02-26524801b302/94752317.jpeg",
  "images": ["https://mobileimages.lowes.com/productimages/98901790-b0c3-4fcd-ac02-26524801b302/94752317.jpeg", "..."],
  "category": "Drills",
  "categoryPath": [],
  "collection": { "id": "GR_9671", "type": "PCR_GROUP", "url": "https://www.lowes.com/collections/DEWALT-20V-1-2-in-Cordless-Drill-Kit-20V-Max-Cordless-Reciprocating-Saw/GR_9671" },
  "variantCount": 0,
  "variantAttribute": null,
  "variants": [],
  "specifications": { "Cordless": "Yes", "Brushless": "No", "Battery Included": "Yes" },
  "highlights": [],
  "packageQuantity": 1,
  "position": 4,
  "page": 1,
  "location": { "storeNumber": "1539", "zipCode": null, "city": null, "state": null },
  "searchTerm": "cordless drill",
  "sourceUrl": null,
  "scrapedAt": "2026-10-02T21:10:08+00:00"
}
```

With `includeDetails: true` a product additionally carries, for example:

```json
{
  "pageTitle": "Kobalt Next-Gen 24-volt 1/2-in Keyless Brushless Cordless Drill (1-Battery, Charger and Soft Bag included) KDD 2024A-03",
  "description": "This new generation Kobalt drill driver uses the most innovative electronics and motor technology to deliver up to 850 in-lb of torque ...",
  "specifications": { "Package Quantity": "1", "Battery Type": "Lithium ion (Li-ion)", "Battery Voltage": "24-volt", "Maximum Chuck Size": "1/2-in", "Warranty": "5-year limited" },
  "specificationGroups": { "General": { "Battery Voltage": "24-volt" }, "Warranty": { "Warranty": "5-year limited", "Battery Warranty": "3-year limited" } },
  "warranty": "Warranty: 5-year limited; Battery Warranty: 3-year limited",
  "upc": "195532000342",
  "gtin": "20195532000346",
  "images": ["https://mobileimages.lowes.com/productimages/2ebf015b-659b-4c82-b909-38aa892c89c4/97265246.jpeg", "..."],
  "videos": [{ "title": "Kobalt 24V Max Brushless Drill Driver Kit Overview", "url": "https://cdnapisec.kaltura.com/p/4215793/sp/421579300/playManifest/entryId/1_itmhknf0/format/applehttp/protocol/https", "thumbnailUrl": "https://mobileimages.lowes.com/productimages/ecd5812d-35e6-4c1f-9314-3cf52f32717a/4913878-Gen3-Drill-Driver-KIT_thumbnail.jpg" }],
  "documents": [{ "title": "Use and Care Manual", "type": "USE_AND_CARE_GUIDE", "url": "https://pdf.lowes.com/productdocuments/bdb07167-0a9c-457e-87b1-f25257337efb/60077854.pdf" }],
  "dimensions": { "height": 9.45, "width": 6.3, "depth": 12.8, "lengthUnit": "Inches", "weight": 8.11, "weightUnit": "lbs." },
  "categoryPath": ["Tools", "Power Tools", "Drills & Drivers", "Drills"],
  "collection": { "id": "GR_28003", "type": "PCR_GROUP", "name": "24V Brushless Drill Driver & 105-Piece Bit Set", "url": "https://www.lowes.com/collections/Kobalt-24V-Brushless-Drill-Driver-105-Piece-Bit-Set/GR_28003", "price": 123.98, "wasPrice": 188.98, "items": ["5013207487", "5015524807"] },
  "variantOptions": [{ "name": "Common Measurement (W x L)", "values": ["2 x 3", "2 x 7", "5 x 7", "8 x 10"] }],
  "variants": [{ "omniItemId": "5017295587", "options": { "Common Measurement (W x L)": "2 x 3" }, "name": "2 x 3", "url": "https://www.lowes.com/pd/allen-roth-Tess-2-x-3-ft-.../5017295587", "available": true, "isSelected": false }],
  "socialProof": ["1K+ bought last week", "10K+ bought last month"],
  "storeAisle": "4",
  "storeBay": "ENDCAP FRONT",
  "maxPurchaseQuantity": 10,
  "prop65Warning": true,
  "hazmat": true,
  "hazmatInfo": "Item is a lithium ion battery with Watt hours (Wh) </= to 100 Wh and Battery Packed with Equipment"
}
```

A review:

```json
{
  "type": "review",
  "omniItemId": "5013207487",
  "reviewId": "4eb70325-c68f-5903-b68a-158645bd6758",
  "legacyId": "272381997",
  "rating": 1,
  "title": "Junk after a year",
  "text": "I purchased this at Christmas and now it's having a problem where it will work for one trigger pull then it won't work until I pull the battery out and reset it.",
  "submittedAt": "2026-09-27",
  "reviewerName": "Jim",
  "reviewerId": null,
  "reviewerLocation": null,
  "positiveFeedback": 0,
  "negativeFeedback": 0,
  "verifiedPurchase": false,
  "incentivized": false,
  "recommended": false,
  "badges": [],
  "photosCount": 0,
  "photos": [],
  "videos": [],
  "sellerResponse": "Hi Jim! Thank you for reviewing your Kobalt KDD 2024A-03 cordless drill kit. We're sorry to hear that you are having trouble with the trigger ...",
  "sellerResponseDate": "2026-09-28",
  "sellerResponseBy": "Kobalt Team",
  "ratingDimensions": null,
  "isRatingOnly": false,
  "language": "en_US",
  "syndicated": false,
  "syndicatedFrom": null,
  "productName": "Kobalt 24-volt 1/2-in Keyless Brushless Cordless Drill 1 -Batteries Included, and Charger Included",
  "productUrl": "https://www.lowes.com/pd/Kobalt-24-volt-Max-1-2-in-Metal-Ratcheting-Brushless-Cordless-Drill-1-Battery-Included-and-Charger-Included/5013207487",
  "scrapedAt": "2026-10-02T21:10:08+00:00"
}
```

### Proxy note

Lowes.com answers datacenter and residential proxy traffic with Akamai's "Access Denied", so this Actor uses **Apify's Unblocker proxy** (group `UNBLOCKER`, US) by default. Unblocker is billed to your Apify account per answered request: 10 Unblocker units, about **$0.0015 on the free plan** and less on paid plans. Requests the proxy cannot complete are free. One request returns either a search page (24 products), one product page, or 10 reviews. The proxy renders search and product pages in a browser, which takes 25-65 seconds per page (reviews answer in about a second); about one request in four fails on the first try and is retried automatically.

The Actor is built around that price: it requests a further result page only when **Max items** still needs it, and opens product pages and review requests only when you ask for them. The `SUMMARY` record in the run's key-value store reports `successfulRequests`, so you can check the proxy cost of every run. You can switch to another proxy group in the input; the Actor then retries block pages on fresh IPs and reports them as `blockedPages`.

### How much does it cost?

Pay per event, no subscription: **$0.003 per product**, **+ $0.004 per product page opened** (details), **$0.0008 per review**, plus the proxy requests above and a few cents of platform usage per thousand items. Worked example for 100 products from one search, on the free plan:

| Run | Requests (proxy cost) | Events | Total |
|---|---|---|---|
| 100 products, search data only | 5 search pages ($0.0075) | 100 x $0.003 = $0.30 | about $0.31 |
| + product details | + 100 product pages ($0.15) | + 100 x $0.004 = $0.40 | about $0.86 |
| + 20 reviews per product (set Max items to 2,100) | + 200 review requests ($0.30) | + 2,000 x $0.0008 = $1.60 | about $2.76 |

Search data alone is by far the cheapest per product: one $0.0015 request brings 24 products. Turn details and reviews on only for the products you need them for, for example by running a second pass on product URLs you selected from the first dataset.

### How to scrape Lowe's search results by keyword

Put the keywords into **Search terms**. Each term is searched on Lowes.com and paginated automatically, 24 products per page including the few sponsored tiles Lowe's mixes in (`isSponsored`; turn **Include sponsored products** off for organic results only). Lowe's serves at most 600 products (25 pages) per query, so one term yields up to 600 products; use several terms or narrower terms to go deeper. `position` and `page` give the rank of every product, which makes the output usable for share-of-search and rank tracking. Four of Lowe's sort orders are supported (Top Sellers, Most Popular, Highest Rated, New Arrivals); the two price sorts need a selected store on Lowe's side and are not available to the Actor.

### How to track Lowe's prices and stock

Schedule the Actor (daily for fast-moving items) with the same search terms or product URLs and compare `price`, `wasPrice`, `saleEndDate`, `availability` and `badges` between runs, joining on `omniItemId`. Product URLs can be passed in bulk in **Start URLs**; each returns one fully detailed item. Note that 15-30 % of search tiles come without a price (Lowe's search page cannot price every item for a visitor without a store; `availability` is `UNKNOWN` for them) and that the search page shows the was-price for some sale items only; with **Include product details** on, every product gets the price of its own product page, which includes the was-price when there is one.

### How to scrape Lowe's product reviews

Either turn on **Include reviews** (reviews for every product found), or paste review-page URLs such as `https://www.lowes.com/reviews/kobalt-kdd-2024a-03-drills/5013207487` to get reviews only. **Max reviews per product** caps each product; **Sort reviews** picks newest, oldest, most relevant, most helpful, highest or lowest rating, or photo reviews first. Lowe's serves 10 reviews per request and lists star-only reviews too (`text` is `null` for them). For monitoring, sort by newest and deduplicate on `reviewId`.

### Which store and ZIP code do the prices come from?

Lowe's prices and stock are store-specific. The Actor does not select a store: Lowe's assigns one to each request. Search pages are priced for Lowe's default context for visitors without a store (store 1539, no ZIP, `priceType: "NETWORK"`); product pages sometimes get the store Lowe's geo-locates the proxy's IP to (then `priceType` is `"STORE"` and `location` carries the store number and ZIP). Every item carries the store context it was priced for in `location` and `priceType`, so you can verify it. Choosing a store or ZIP code is not supported.

### Does it work without login or a browser?

Yes. Everything comes from public pages as an anonymous visitor sees them; you do not run a browser, the Unblocker proxy does. No account, no cookies on your side. Member-only (MyLowe's Rewards) prices and in-cart prices are not available.

### Integrations and API

Use the run in Zapier, Make, n8n, Google Sheets, or call it from Python/Node with the Apify client. See the **API** tab for ready-made snippets.

### Is it legal to scrape Lowe's?

This Actor collects only data that Lowe's shows publicly to logged-out visitors: product listings, prices, marketplace seller names, and the text, rating and reviewer nickname of customer reviews, as the review page shows them. It does not log in and does not collect avatars, contact details or the hidden author ids in Lowe's review data. Reviewer nicknames, and review texts written by individuals, can be personal data under GDPR and similar laws: make sure you have a lawful basis for processing them, and do not use them to contact or profile individuals. You are responsible for how you use the data and for complying with Lowe's terms and applicable law.

### Support

Found a bug or need a field added? Open an issue in the **Issues** tab; it is usually answered within a day.

# Actor input Schema

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

Keywords to search on Lowes.com, one per line (e.g. "cordless drill", "area rug"). Each term is searched separately and paginated automatically: one request returns 24 products (sponsored tiles included).

## `startUrls` (type: `array`):

Lowes.com URLs to scrape instead of (or in addition to) search terms: search pages (https://www.lowes.com/search?searchTerm=cordless+drill), product pages (https://www.lowes.com/pd/Kobalt-24-volt-Max/5013207487, returned with full details) or review pages (https://www.lowes.com/reviews/kobalt-kdd-2024a-03-drills/5013207487, returns reviews only). Category pages (/pl/...) do not load through the Unblocker proxy and are skipped with an error; search for the category name instead.

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

Stop after this many dataset items in total. Products and reviews both count, so with reviews on raise it accordingly (100 products with 20 reviews each = 2,100 items). Keeps cost predictable.

## `maxPagesPerSearch` (type: `integer`):

How many result pages to open per search term or search URL (24 products each, one proxy request per page). Lowe's itself stops after 600 products (25 pages).

## `sortBy` (type: `string`):

Result order for search terms and search URLs, as on Lowe's own "Sort By" menu. Lowe's offers "Price (Low to High)" / "Price (High to Low)" only to visitors who selected a store, and ignores them otherwise, so they are not available here.

## `includeSponsored` (type: `boolean`):

Lowe's mixes a few sponsored tiles into the results (usually 4 on the first page). They are saved with isSponsored = true. Turn this off to keep organic results only.

## `includeDetails` (type: `boolean`):

Also open every product page to get the description, full specification table, all images, videos, manuals, variants (sizes / colors with their own product ids), UPC, dimensions, warranty, collection / set, store aisle and the product page's own price (listing tiles Lowe's could not price get one here). One extra proxy request and one extra `detail` charge per product (see pricing).

## `includeReviews` (type: `boolean`):

Also collect customer reviews for every product, as separate items with type = "review" (rating, title, text, date, helpful votes, verified purchase, photos, brand response). Lowe's serves 10 reviews per request. Reviewer names are never collected.

## `maxReviewsPerProduct` (type: `integer`):

Cap on reviews per product (also applies to review-page start URLs). Lowe's lists star-only reviews too; they come with text = null.

## `reviewSort` (type: `string`):

Order in which reviews are collected (matters when a cap is set). "Newest" is Lowe's default and best for monitoring; "Lowest rating" surfaces complaints.

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

Lowes.com answers datacenter and residential proxies with Akamai's "Access Denied", so the default is Apify's Unblocker proxy (group UNBLOCKER, US). It is billed to your Apify account per successful request: 10 Unblocker units, about $0.0015 on the free plan and less on paid plans. One request returns a search page (24 products), one product page, or 10 reviews. Search and product pages are rendered in a browser by the proxy and take 25-65 seconds each.

## Actor input object example

```json
{
  "searchTerms": [
    "cordless drill"
  ],
  "startUrls": [],
  "maxItems": 100,
  "maxPagesPerSearch": 10,
  "sortBy": "featured",
  "includeSponsored": true,
  "includeDetails": false,
  "includeReviews": false,
  "maxReviewsPerProduct": 20,
  "reviewSort": "newest",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

No description

# 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"
    ],
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "UNBLOCKER"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/lowes-scraper").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"],
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["UNBLOCKER"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/lowes-scraper").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"
  ],
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call tortuga/lowes-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tortuga/lowes-scraper"
        }
    }
}
```

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/KsbmeFNizAkSUqZFG/builds/jvZdY1xuKW34btsmz/openapi.json
