# Sutherlands Home Improvement Scraper (`crawlerbros/sutherlands-scraper`) Actor

Scrape Sutherlands.com - a US home improvement, hardware, and farm & ranch retail chain. Search or browse products by department/brand/SKU with real store pricing, stock status, specs, and images.

- **URL**: https://apify.com/crawlerbros/sutherlands-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Sutherlands Home Improvement Scraper

Scrape [Sutherlands.com](https://sutherlands.com) — a US home improvement, hardware, building materials, and farm & ranch retail chain with roughly 90 stores across the central United States. Search by keyword, browse by department, brand, or exact SKU, and get real store pricing, stock status, specs, images, and category data. No login, no cookies, no proxy required.

### What this actor does

- **Four modes:** `search`, `byCategory`, `byBrand`, `bySku`
- **27 departments** covering Tools, Hardware, Building Materials, Farm & Ranch, Outdoor Power Equipment, Plumbing, Electrical, Lawn & Garden, and more
- **Real pricing** — per-store retail prices pulled directly from Sutherlands' own store inventory (distributor drop-ship cost rows are excluded so prices always reflect what a shopper actually pays)
- **Stock & sale filters** — restrict results to in-stock or on-sale items
- **Price range filter** — min/max USD
- **Brand filters** — browse an exact brand, or keep only records whose brand contains a keyword
- **Category filter** — keep only records whose full category breadcrumb contains a keyword (narrower than `department`)
- **Store availability** — how many physical Sutherlands stores currently carry (or can special-order/ship in) each product
- **Empty fields are omitted** — every record only contains fields Sutherlands actually returned

### Output per product

- `sku` — Sutherlands item number
- `title`, `brand`, `brandUrl`, `mfgNumber`, `upc`
- `category` — full breadcrumb path (e.g. `Tools > Hand Tools > Hammers`)
- `department` — top-level department (e.g. `Tools`)
- `description` — plain text (HTML stripped)
- `specifications` — key/value spec map (material, size, weight, etc.)
- `relevantSpecifications` — which spec keys the retailer highlights for this product
- `variationName` — base product name shared across its color/size variants (apparel and similar variant-driven products only)
- `imageUrl` — product photo
- `productUrl` / `sourceUrl` — canonical Sutherlands.com product page
- `sellUnit` — e.g. `EA`, `BOX`, `CASE`
- `price` — lowest current in-store retail price (USD)
- `priceMin` / `priceMax` — present only when price varies by store
- `inStock` — true if any Sutherlands store shows on-hand inventory
- `onSale` — true if any Sutherlands store currently has it on sale
- `storeCount` — number of physical Sutherlands stores that carry this product
- `shipToStoreCount` — number of additional Sutherlands stores that can special-order/ship this product in
- `popularity`, `sales` — retailer-provided ranking signals
- `recordType: "product"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byCategory` / `byBrand` / `bySku` |
| `searchQuery` | string | `drill` | Free-text keyword search (mode=search) |
| `department` | select | – | One of 27 departments; required for `byCategory`, optional narrowing filter elsewhere |
| `brandName` | string | – | Exact brand to browse (mode=byBrand), e.g. `IRWIN` |
| `skuOrItemNumber` | string | – | Exact SKU / item number (mode=bySku) |
| `brandContains` | string | – | Keep only records whose brand contains this text (any mode) |
| `categoryContains` | string | – | Keep only records whose full category breadcrumb contains this text, e.g. `Hand Tools` (any mode) |
| `minPrice` / `maxPrice` | int | – | USD price range |
| `inStockOnly` | bool | `false` | Only in-stock products |
| `onSaleOnly` | bool | `false` | Only on-sale products |
| `sortBy` | select | `relevance` | `relevance` / `popularityDesc` / `salesDesc` / `nameAsc` / `nameDesc` |
| `maxItems` | int | `50` | Hard cap (1–1000, the upstream search index's own ceiling per query) |

#### Example: cordless drills under $150, in stock

```json
{
  "mode": "search",
  "searchQuery": "cordless drill",
  "maxPrice": 150,
  "inStockOnly": true
}
```

#### Example: browse the Farm & Ranch department

```json
{
  "mode": "byCategory",
  "department": "Farm & Ranch",
  "maxItems": 100
}
```

#### Example: everything by a specific brand

```json
{
  "mode": "byBrand",
  "brandName": "IRWIN",
  "sortBy": "nameAsc"
}
```

#### Example: exact SKU lookup

```json
{
  "mode": "bySku",
  "skuOrItemNumber": "4779450"
}
```

#### Example: hand tools only, narrowed within the Tools department

```json
{
  "mode": "byCategory",
  "department": "Tools",
  "categoryContains": "Hand Tools"
}
```

### Use cases

- **Price monitoring** — track hardware and tool prices at a regional US retailer
- **Market research** — compare product assortment and pricing against national chains
- **Catalog enrichment** — pull specs, images, and categorization for product data pipelines
- **Inventory intelligence** — spot in-stock vs. out-of-stock trends by department
- **Competitive analysis** — benchmark brand coverage and sale cadence

### FAQ

**Do I need an account or proxy?** No. Sutherlands' product search is fully public — no login, cookies, or paid proxy required.

**Why do some products show a `priceMin`/`priceMax` instead of a single `price`?** Sutherlands' catalog is store-specific — the same SKU can carry different shelf prices at different locations. When prices vary, the actor reports the full range; `price` is always the lowest.

**Why don't all products have a price?** A small number of catalog items are only available through drop-ship distributors rather than direct Sutherlands store stock; those internal wholesale unit costs are excluded so the actor never reports a misleadingly low "price."

**How many results can one query return?** The upstream search index returns at most 1000 matches per query (`maxItems` is capped accordingly). Narrow with `department`, `brandName`, or price filters to reach deeper into a large category.

**What's the difference between `category` and `department`?** `department` is the top-level store section (e.g. `Tools`); `category` is the full breadcrumb path down to the most specific subcategory (e.g. `Tools > Hand Tools > Hammers`). Use the `categoryContains` filter to narrow into a subcategory without needing the exact breadcrumb text.

**What do `storeCount` and `shipToStoreCount` mean?** `storeCount` is the number of physical Sutherlands stores that currently carry the product on their shelves. `shipToStoreCount` is the number of *additional* stores that don't stock it on-shelf but can special-order/ship it in. Both are omitted when zero.

**What is `variationName`?** Some products (mostly apparel) are sold in multiple colors/sizes that share one base product name — `variationName` reports that shared base name. It's only present for products that belong to such a variant family.

**How fresh is the data?** Sutherlands' search index reflects live store inventory and pricing at request time.

### Data Source

This actor targets **Sutherlands.com** rather than the originally-scoped Menards.com. Menards is protected by an Incapsula/Imperva bot-management WAF that returns an instant, non-solvable block interstitial (`/_Incapsula_Resource`) identically across plain HTTP requests, TLS-impersonated requests, and headless-browser requests — confirmed both from local testing and from Apify's own cloud datacenter proxy (AUTO group), where the request timed out entirely rather than returning any page content. Per the zero-cost reliability policy, an actor that cannot pass a free-plan datacenter request was replaced with a same-category retailer rather than requiring a paid residential proxy. Sutherlands.com is a genuine US home-improvement/hardware/farm-and-ranch chain whose own storefront search runs on a public, search-only API — real product data and real store pricing, no bot-detection involved.

# Actor input Schema

## `mode` (type: `string`):

What to fetch.

## `searchQuery` (type: `string`):

Free-text keyword search (mode=search), e.g. `cordless drill`, `garden hose`, `chicken coop`.

## `department` (type: `string`):

Restrict results to one department. Required for mode=byCategory; optional narrowing filter for other modes.

## `brandName` (type: `string`):

Exact brand name to browse, e.g. `DeWALT®`, `IRWIN`, `HILLMAN®`. Case-sensitive exact match against Sutherlands' brand catalog.

## `skuOrItemNumber` (type: `string`):

Sutherlands SKU / item number to look up, e.g. `4779450`.

## `brandContains` (type: `string`):

Only keep records whose brand name contains this text (case-insensitive). Works in any mode.

## `categoryContains` (type: `string`):

Only keep records whose full category breadcrumb (e.g. `Tools > Hand Tools > Hammers`) contains this text (case-insensitive). Use this to narrow into a subcategory that has no dedicated `department` value. Works in any mode.

## `minPrice` (type: `integer`):

Drop products priced below this amount at every carrying store.

## `maxPrice` (type: `integer`):

Drop products priced above this amount at every carrying store.

## `inStockOnly` (type: `boolean`):

Only emit products with on-hand inventory at a Sutherlands store.

## `onSaleOnly` (type: `boolean`):

Only emit products currently marked on sale at a Sutherlands store.

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

Result ordering.

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

Hard cap on emitted records. The upstream search index returns at most 1000 matches per query.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "drill",
  "brandName": "IRWIN",
  "inStockOnly": false,
  "onSaleOnly": false,
  "sortBy": "relevance",
  "maxItems": 50
}
```

# Actor output Schema

## `products` (type: `string`):

Dataset containing all scraped Sutherlands products.

# 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 = {
    "mode": "search",
    "searchQuery": "drill",
    "brandName": "IRWIN",
    "inStockOnly": false,
    "onSaleOnly": false,
    "sortBy": "relevance",
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/sutherlands-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 = {
    "mode": "search",
    "searchQuery": "drill",
    "brandName": "IRWIN",
    "inStockOnly": False,
    "onSaleOnly": False,
    "sortBy": "relevance",
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/sutherlands-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "mode": "search",
  "searchQuery": "drill",
  "brandName": "IRWIN",
  "inStockOnly": false,
  "onSaleOnly": false,
  "sortBy": "relevance",
  "maxItems": 50
}' |
apify call crawlerbros/sutherlands-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=crawlerbros/sutherlands-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/grz0mqTm97A0SUQ9C/builds/RtVZupOsakwIGpEUv/openapi.json
