     [Blog](https://scrapfly.io/blog)   /  [python](https://scrapfly.io/blog/tag/python)   /  [How to Scrape Lowe's Product, Price, Search, and Store Location Data](https://scrapfly.io/blog/posts/how-to-scrape-lowe)   # How to Scrape Lowe's Product, Price, Search, and Store Location Data

 by [Ziad Shamndy](https://scrapfly.io/blog/author/ziad) Aug 13, 2026 14 min read [\#python](https://scrapfly.io/blog/tag/python) [\#scrapeguide](https://scrapfly.io/blog/tag/scrapeguide) 

 [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-lowe "Share on LinkedIn") [  ](https://x.com/intent/tweet?url=https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-lowe&text=How%20to%20Scrape%20Lowe%27s%20Product%2C%20Price%2C%20Search%2C%20and%20Store%20Location%20Data "Share on X") [  ](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-lowe "Share on Facebook")    

 

 

Summarize this article with

 [  ](https://chat.openai.com/?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-lowe) [  ](https://claude.ai/new?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-lowe) [  ](https://x.com/i/grok?text=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-lowe) [  ](https://www.perplexity.ai/search/new?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-lowe) [  ](https://www.google.com/search?udm=50&aep=11&q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-lowe) 



         

Scrape a Lowe's product page and you will probably pull the SKU and description without trouble, then find the price field empty.

This guide extracts product and price records, search results, and nearby store locations from Lowe's current embedded state and store-locator response. The maintained scraper does not select a shopping store or extract selected-store inventory. Treat returned prices as location-dependent unless the response confirms the context you intended. Start with the product page's embedded JSON, then handle Akamai at the fetch layer.



## Key Takeaways

- Lowe's product and price data lives in embedded page state (`__PRELOADED_STATE__`, with a `__NEXT_DATA__` fallback), not in a public catalog API.
- The product state is nested under `productDetails[productId]`; reading `productDetails` as one flat record returns null fields.
- The maintained scraper parses product pages and search results, and queries the nearby-store JSON endpoint.
- Lowe's prices can vary by store and ZIP. The current scraper does not pin a chosen store or return selected-store inventory.
- Lowe's is protected by Akamai Bot Manager, so a plain Python request receives an Access Denied response before the parser sees page data.
- The maintained fetch uses Scrapfly ASP, a US exit, and the residential proxy pool.

**Get web scraping tips in your inbox**Trusted by 100K+ developers and 30K+ enterprises. Unsubscribe anytime.







## What Product and Price Data Can You Scrape From Lowe's?

The maintained product parser returns the title, brand, item and model numbers, product ID, retail and selling prices, description, specifications, images, and observed location fields. The source is Lowe's embedded page state.

The data falls into two groups. Product fields cover title, brand, item number, model number, product ID, description, specifications, and images. Pricing fields include the retail and selling price returned for the resolved location context.

The maintained scraper also walks search results and queries Lowe's store-locator JSON for nearby store records. It does not select one of those stores for shopping and does not extract selected-store inventory, pickup, delivery, or fulfillment data.

| Approach | JavaScript handling | Speed | Data completeness | Main failure |
|---|---|---|---|---|
| `requests` + BeautifulSoup | None | Fast | Low | Akamai blocks the fetch before parsing |
| Playwright or Selenium | Full | Slow | High after a successful fetch | Browser and fingerprint maintenance |
| Embedded page state through Scrapfly | No browser rendering in the maintained config | Fast to parse | Product, price, description, images, and specifications | Price remains location-dependent unless the response context is asserted |

Reading embedded JSON keeps the parser independent of visible page selectors. The remaining work is fetching the protected page and handling Lowe's nested state correctly.



## Why Do Lowe's Scrapers Return Empty Prices or Get Blocked?

Lowe's combines a protected fetch layer with nested, location-dependent page state. A scraper can fail before it receives HTML, or fetch a page and still read the wrong JSON level.

- **A plain request is blocked.** In our August 13 check, Lowe's returned HTTP 403 with Akamai indicators including `akamai-grn`, `AKA_A2`, and an `edgesuite.net` reference.
- **The product record is nested.** `productDetails` is keyed by product ID, with product and price fields below that key. Treating it as one flat record returns null values.
- **Price depends on location context.** Lowe's states that prices can differ between stores and ZIP codes. The current scraper returns the price resolved for its response; it does not prove a chosen store.
- **A store page is not a store-selection action.** Opening a store details URL showed that location's page, but did not select it for shopping in our August 13 check.
- **Datacenter exits are less reliable on this target.** The tested residential route returned the page after the default datacenter attempt hit a transient shield failure.

The parser and the fetch layer are separate. Fix the nested JSON path first, then use the maintained Scrapfly configuration to get the protected page.

For the full fetch-layer mechanics, see our [Akamai bypass guide](https://scrapfly.io/blog/posts/how-to-bypass-akamai-anti-scraping).



## Where Does Lowe's Product and Pricing Data Live?

Open a Lowe's product page with browser developer tools and you will find the product and price data in embedded JSON inside the HTML. The data sits in a `__PRELOADED_STATE__` script and several `ld+json` blocks, not a public API.

### Reading the Product ID, Item Number, and Model Number From a Lowe's URL

Lowe's product URLs follow the pattern `lowes.com/pd/<product-slug>/<product-id>`. The numeric product ID at the end is the value the page is keyed on, and the same value appears as the `sku` in the page's structured data.

Three identifiers show up on a Lowe's product detail page and are easy to confuse. The **product ID** is the number in the URL and doubles as the SKU. The **item number** is Lowe's internal catalog item, a different value.

The **model number** is the manufacturer's own model identifier. The model number is the one shoppers cross-reference against other retailers and against the UPC.

### Finding the Embedded JSON in a Lowe's Product Page

To locate the data, open the product page, view source or use the Elements tab, and search for `__PRELOADED_STATE__` and for `<script type="application/ld+json">`. The two together carry everything the scraper needs.

The `__PRELOADED_STATE__` object holds the full product record. The record includes the product ID, item number, model number, brand, price, selling price, and a nested price object with the currency.

The `ld+json` blocks carry the Product schema. The schema includes the SKU, brand, an Offer with the price currency, and specification rows as PropertyValue entries.

The parser reads the price Lowe's resolved for the returned response. Since the maintained scraper does not assert a selected store, treat that value as location-dependent rather than chosen-store pricing.

This discovery approach relies on a technique that works across many modern sites, covered in our guide to [guide to scraping hidden web data](https://scrapfly.io/blog/posts/how-to-scrape-hidden-web-data)



## How to Scrape Lowe's Product and Pricing Data From Embedded JSON

Fetch the product page through the maintained protected request configuration shown later, then parse Lowe's nested `__PRELOADED_STATE__`. The code below follows the canonical scraper's field paths.

Install the parser and Scrapfly SDK:

shell```shell
pip install parsel "scrapfly-sdk[all]"
```



python```python
import json
import re
from parsel import Selector


def extract_preloaded_state(html: str) -> dict:
    # Get Lowe's page state from __PRELOADED_STATE__ or __NEXT_DATA__.
    sel = Selector(text=html)
    script = sel.xpath("//script[contains(text(),'__PRELOADED_STATE__')]/text()").get()
    if script:
        match = re.search("__PRELOADED_STATE__.*?=\\s*(\\{.*\\})", script, re.DOTALL)
        if match:
            return json.loads(match.group(1))
    raw = sel.css("script#__NEXT_DATA__::text").get()
    if raw:
        return json.loads(raw).get("props", {}).get("pageProps", {}) or {}
    return {}


def parse_product(html: str, url: str) -> dict:
    # Parse product data from Lowe's nested page state.
    state = extract_preloaded_state(html)
    product_id = state.get("productId")
    details = state.get("productDetails") or {}
    detail = details.get(product_id) or next(iter(details.values()), {})
    product = detail.get("product") or {}
    location = detail.get("location") or {}

    price_info = (detail.get("mfePrice") or {}).get("price") or {}
    additional = price_info.get("additionalData") or {}
    price = additional.get("retailPrice")
    selling_price = additional.get("sellingPrice")
    if price is None or selling_price is None:
        for entry in (location.get("price") or {}).get("pricingDataList") or []:
            price = price if price is not None else entry.get("retailPrice")
            selling_price = selling_price if selling_price is not None else entry.get("finalPrice")

    images = [
        f"https://mobileimages.lowes.com{image_url}" if image_url.startswith("/") else image_url
        for image_url in [entry.get("value") for entry in product.get("imageUrls") or []]
        if image_url
    ]
    store = location.get("storeNumber") or (state.get("storeDetails") or {}).get("id")

    return {
        "product_id": product_id or product.get("omniItemId"),
        "item_number": product.get("itemNumber"),
        "model_id": product.get("modelId"),
        "url": url,
        "name": product.get("title"),
        "brand": product.get("brand"),
        "price": float(price) if price is not None else None,
        "selling_price": float(selling_price) if selling_price is not None else None,
        "currency": price_info.get("currency"),
        "description": product.get("romanceCopy") or product.get("description"),
        "specifications": {
            row["key"]: row["value"]
            for row in product.get("specs") or []
            if row.get("key") and row.get("value")
        },
        "images": images,
        "store_number": str(store) if store else None,
        "zip_code": location.get("zipcode") or (state.get("storeDetails") or {}).get("zip"),
    }
```



The product ID keys `productDetails`; the product record and location-dependent price sit below that key. Treat `store_number` and `zip_code` as observed response context, not proof that the scraper selected that store.

For more on locating script nodes, see our [CSS selector guide](https://scrapfly.io/blog/posts/parsing-html-with-css) and [JSON parsing guide](https://scrapfly.io/blog/answers/what-are-some-ways-to-parse-json-datasets-in-python).



Scrapfly

#### Scale your web scraping effortlessly

Scrapfly handles proxies, browsers, and anti-bot bypass — so you can focus on data.

[Try Free →](https://scrapfly.io/register)## What Does Location Change in Lowe's Pricing?

Lowe's states that prices can vary between stores and ZIP codes. The maintained scraper fetches a US product page and parses the price Lowe's returns, but it does not implement the store-selector action needed to prove that a chosen store is active.

### Why a Hand-Set Store Cookie Is Not Enough

Lowe's uses a store-number cookie (`sn`), but it also resolves location from the request and its own store-selection flow. In a June 2026 test, a hand-set store cookie was overridden by the proxy location, and Lowe's minted a wider cookie bundle with a different store.

One returned `sd` cookie looked like this:

json```json
{"id":"1770","zip":"42718","city":"Campbellsville","state":"KY","name":"Campbellsville Lowe's","region":"6"}
```



That response proves the location bundle can override one manually supplied value. It does not prove a reliable method for selecting store 1770.

### Current Implementation Boundary

Do not label the current output as selected-store pricing or inventory. A future selected-store implementation must replay Lowe's actual store-set request, assert the returned store ID on the follow-up product response, isolate the inventory source, and pass live tests before the article expands its promise.

Until then, keep the same country and proxy strategy across a monitoring run, record the response context when available, and compare prices only within that consistent setup. Our guide covers the monitoring layer. For cookie continuity, see [our guide to handling cookies in web scraping](https://scrapfly.io/blog/posts/how-to-handle-cookies-in-web-scraping).

The store locator in the next section finds nearby store records. It does not select one for shopping.



## How Do You Find Lowe's Products and Nearby Stores at Scale?

Use Lowe's search pages to discover products and its store-locator JSON endpoint to find nearby store records. Both parsers below follow the maintained scraper.

### Parsing Search Results

python```python
def parse_search(html: str) -> dict:
    state = extract_preloaded_state(html)
    results = []
    for item in state.get("itemList") or []:
        product = item.get("product") or {}
        if not product.get("omniItemId"):
            continue
        price_info = (item.get("location") or {}).get("price") or {}
        price = price_info.get("sellingPrice")
        if price is None:
            for entry in price_info.get("pricingDataList") or []:
                price = entry.get("finalPrice")
                break
        product_url = product.get("pdURL")
        image = product.get("alternateImageUrl") or product.get("imageUrl")
        results.append({
            "product_id": product["omniItemId"],
            "item_number": product.get("itemNumber"),
            "model_id": product.get("modelId"),
            "url": f"https://www.lowes.com{product_url}" if product_url and product_url.startswith("/") else product_url,
            "name": product.get("description"),
            "brand": product.get("brand"),
            "price": float(price) if price is not None else None,
            "currency": "$" if price is not None else None,
            "image": f"https://mobileimages.lowes.com{image}" if image and image.startswith("/") else image,
        })
    return {
        "data": results,
        "total_pages": (state.get("pagination") or {}).get("pageCount") or 1,
        "page_size": state.get("pageSize") or 24,
    }
```



The maintained `scrape_search()` function fetches the first page, caps pagination at `max_pages`, then requests each next page with `&offset=<page_size * (page - 1)>`.

### Parsing Nearby Store Locations

Request `/store/api/search?maxResults=10&searchTerm=<ZIP>&responseGroup=large`, then parse `stores[].store`:

python```python
import json


def parse_store_locations(response) -> list:
    payload = json.loads(response.content)
    locations = []
    for entry in payload.get("stores") or []:
        store = entry.get("store") or {}
        if not store.get("id"):
            continue
        try:
            distance = float(entry["distance"])
        except (KeyError, TypeError, ValueError):
            distance = None
        locations.append({
            "store_number": store["id"],
            "name": store.get("store_name") or store.get("storeName"),
            "address": store.get("address"),
            "city": store.get("city"),
            "state": store.get("state"),
            "zip_code": store.get("zip"),
            "phone": store.get("phone"),
            "distance": distance,
        })
    return locations
```



Nearby-store output is a location dataset. It does not select a store for shopping or make a product response inventory-specific.



## How to Scrape Lowe's Reliably at Scale With Scrapfly

At scale the primary blocker is Akamai Bot Manager. Route requests through a fetch layer that handles the challenge before the product parser runs.

ScrapFly's [Web Scraping API](https://scrapfly.io/products/web-scraping-api) combines anti-bot handling, proxy routing, sessions, caching, and SDKs behind one endpoint.

- [Anti-Scraping Protection bypass](https://scrapfly.io/docs/scrape-api/anti-scraping-protection) - handles supported anti-bot challenges, including the Akamai wall observed on Lowe's.
- [Smart proxy rotation](https://scrapfly.io/docs/scrape-api/proxy) - residential and datacenter pools with country and ASN geo-targeting.
- [Session management](https://scrapfly.io/docs/scrape-api/session) - keeps cookies, headers, and IPs consistent across multi-step flows.
- [Caching](https://scrapfly.io/docs/scrape-api/getting-started#api_param_cache) - caches successful responses for repeated jobs.
- [Python](https://scrapfly.io/docs/sdk/python), [TypeScript](https://scrapfly.io/docs/sdk/typescript), [Scrapy](https://scrapfly.io/docs/sdk/scrapy), and [integrations](https://scrapfly.io/docs/integration/getting-started) cover common application stacks.

The maintained Lowe's scraper uses `asp=True`, `country="US"`, and `proxy_pool="public_residential_pool"`. It does not enable JavaScript rendering.

Testing on Lowe's showed that the residential route returned the page after a default datacenter attempt hit a transient shield failure. Keep that as a target-specific tested route, not a universal proxy claim.

python```python
from scrapfly import ScrapflyClient, ScrapeConfig

client = ScrapflyClient(key="YOUR SCRAPFLY KEY")


def scrape_lowes_product(url: str) -> dict:
    result = client.scrape(ScrapeConfig(
        url=url,
        asp=True,
        country="US",
        proxy_pool="public_residential_pool",
    ))
    return parse_product(result.scrape_result["content"], url)


if __name__ == "__main__":
    data = scrape_lowes_product(
        "https://www.lowes.com/pd/DEWALT-20-volt-Max-Brushless-Drill-1-Battery-Included-Charger-Included-and-Soft-Bag-included/5014148635"
    )
    print(data)
```



The returned record contains the product and price fields parsed above. It does not include selected-store inventory or prove that a particular store was active.

For product details, see the [Web Scraping API](https://scrapfly.io/products/web-scraping-api).



## FAQ

Does Lowe's have a public API for product data?No public catalog API is documented for this workflow. The maintained scraper reads product and price fields from Lowe's embedded page state and uses the JSON store-locator endpoint for nearby-store records.







How do I check product availability at a specific Lowe's store?Not with the implementation in this guide. The maintained scraper can find nearby store records, but it does not replay Lowe's store-selection action or extract selected-store inventory. Add and test that flow before reporting store-specific availability.







Do I need Selenium or Playwright to scrape Lowe's?No. The maintained scraper fetches the page through Scrapfly ASP and parses the embedded state without enabling JavaScript rendering. Browser automation would add overhead without changing the parser.







Why did my old Lowe's ZIP-in-URL scraper stop working?Older examples use a `pd/<product-id>/productdetail/<digits>/Guest/<ZIP>` route. The maintained July 2026 scraper does not depend on that route; it reads the current product page's embedded state instead.







Can I scrape Lowe's product ratings and reviews too?Not in this implementation. The maintained parser covers product, pricing, search, and nearby-store data. Review text and ratings need a separately verified source before they belong in this guide.









## Summary

Lowe's product state is nested under `productDetails[productId]`, with pricing below the selected product's `mfePrice` and `location` objects. Read those nested records instead of treating `productDetails` as one flat product.

Plain HTTP requests currently receive an Akamai Access Denied response, so the maintained scraper uses ASP, a US exit, and the residential proxy pool before parsing the embedded JSON.

The canonical scraper also covers search pagination and Lowe's JSON store-locator response. Prices remain location-dependent, and this implementation does not select a shopping store or return selected-store inventory.



Legal Disclaimer and PrecautionsThis tutorial covers popular web scraping techniques for education. Interacting with public servers requires diligence and respect:

- Do not scrape at rates that could damage the website.
- Do not scrape data that's not available publicly.
- Do not store PII of EU citizens protected by GDPR.
- Do not repurpose *entire* public datasets which can be illegal in some countries.

Scrapfly does not offer legal advice but these are good general rules to follow. For more you should consult a lawyer.

 

   [  Add as a preferred source ](https://google.com/preferences/source?q=scrapfly.io) Table of Contents















 

  Table of Contents- [Key Takeaways](#key-takeaways)
- [What Product and Price Data Can You Scrape From Lowe's?](#what-product-and-price-data-can-you-scrape-from-lowe-s)
- [Why Do Lowe's Scrapers Return Empty Prices or Get Blocked?](#why-do-lowe-s-scrapers-return-empty-prices-or-get-blocked)
- [Where Does Lowe's Product and Pricing Data Live?](#where-does-lowe-s-product-and-pricing-data-live)
- [Reading the Product ID, Item Number, and Model Number From a Lowe's URL](#reading-the-product-id-item-number-and-model-number-from-a-lowe-s-url)
- [Finding the Embedded JSON in a Lowe's Product Page](#finding-the-embedded-json-in-a-lowe-s-product-page)
- [How to Scrape Lowe's Product and Pricing Data From Embedded JSON](#how-to-scrape-lowe-s-product-and-pricing-data-from-embedded-json)
- [What Does Location Change in Lowe's Pricing?](#what-does-location-change-in-lowe-s-pricing)
- [Why a Hand-Set Store Cookie Is Not Enough](#why-a-hand-set-store-cookie-is-not-enough)
- [Current Implementation Boundary](#current-implementation-boundary)
- [How Do You Find Lowe's Products and Nearby Stores at Scale?](#how-do-you-find-lowe-s-products-and-nearby-stores-at-scale)
- [Parsing Search Results](#parsing-search-results)
- [Parsing Nearby Store Locations](#parsing-nearby-store-locations)
- [How to Scrape Lowe's Reliably at Scale With Scrapfly](#how-to-scrape-lowe-s-reliably-at-scale-with-scrapfly)
- [FAQ](#faq)
- [Summary](#summary)
 
    Join the Newsletter  Get monthly web scraping insights 

 

  



Scale Your Web Scraping

Anti-bot bypass, browser rendering, and rotating proxies, all in one API. Start with 1,000 free credits.

  No credit card required  1,000 free API credits  Anti-bot bypass included 

 [Start Free](https://scrapfly.io/register) [View Docs](https://scrapfly.io/docs/onboarding) 

 Not ready? Get our newsletter instead. 

 

 ## Related Articles

 [  

### How to Bypass Akamai when Web Scraping in 2026

In this article we'll take a look at a popular anti bot service Akamai Bot Manager. How does it detect web scrapers and ...

 

 ](https://scrapfly.io/blog/posts/how-to-bypass-akamai-anti-scraping) [     

 python scrapeguide 

### How to Scrape Marriott Hotel Prices and Availability

Learn how to scrape Marriott hotel prices and room availability with Python in 2026, including search inputs, the JSON b...

 

 ](https://scrapfly.io/blog/posts/how-to-scrape-marriott) [  

 python project 

### How to Build a Price Tracker Using Python

A complete walkthrough for building a single-site price tracker in Python: async scraping with httpx and parsel, durable...

 

 ](https://scrapfly.io/blog/posts/how-to-build-a-price-tracker-in-python) 

  



   



 Scale your web scraping effortlessly, **1,000 free credits** [Start Free](https://scrapfly.io/register)