# Wayfair Scraper · Products, Prices, Stock & Ratings (`memo23/wayfair-scraper`) Actor

Scrape Wayfair products from wayfair.com, .ca, .co.uk and .ie. Paste a keyword, category, brand, SKU or listing/product URL. Each row is SKU, title, brand, price, discount %, stock, variant count, rating and image. Optional PDP specs, dimensions and materials. Pure HTTP, no browser.

- **URL**: https://apify.com/memo23/wayfair-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** E-commerce
- **Features:** Limited permissions
- **Stats:** 60 total users, 25 monthly users, 97.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 product results

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

## Wayfair Scraper · Products, Prices, Stock & Ratings

<p align="center">
  <img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/logo-wayfair.png" alt="Wayfair Scraper logo" width="128" />
</p>

Turn any Wayfair keyword, category, brand, SKU or URL into one product row: SKU, title, brand, price, was-price, discount %, stock, variant count, rating and image. Four storefronts — wayfair.com, wayfair.ca, wayfair.co.uk, wayfair.ie. Turn on `fetchDetails` for the spec table, parsed dimensions, materials and About This Product.

| Input | Row(s) emitted |
|---|---|
| Keyword (`sofa`, `office chair`) | Listing cards (~48 per page) |
| Search / category / brand URL | Same listing cards, paginated with `curpage=N` |
| SKU or product URL | One product row (PDP fields when `fetchDetails` is on) |

> Pure HTTP. No browser, no third-party CF-bypass service.

### Why Use This Scraper?

- **Listing cards are complete** — sale price, was-price, discount %, variant count, stock, rating, reviews, image and URL come from the search page. No per-product crawl unless you ask for it.
- **Four storefronts** — US, Canada, UK, Ireland. Paste a `.ca` / `.co.uk` / `.ie` URL or set `country`.
- **Stock that fills** — `IN_STOCK` / `LOW_STOCK` / `OUT_OF_STOCK` / `BACKORDERED` from the listing payload, plus Wayfair's leftover-count sentence on the product page.
- **Sale math** — `savings` and `discountPercent` from price vs was-price. `"5 Colors, 2 Sizes"` becomes `variantCount` 10.
- **Optional specs** — `fetchDetails` adds the DescriptionList table, H×W×D + weight, materials, feature bullets and delivery. Billed only on a hit.
- **Cheaper than the listing leader** — $0.002 per product row vs $0.005 on the current Store leader.

### Overview

Built for price monitors, marketplace feeds and brand teams who need public Wayfair catalog rows without an official API. One dataset row per product. Nested objects flatten by default (`specifications_Overall Dimensions`, `dimensions_width`) so CSV/Excel stay usable. Residential proxy is recommended — Wayfair's PerimeterX wall 429s most datacenter IPs.

### Supported Inputs

| Kind | Example |
|---|---|
| Keyword | `sofa`, `office chair`, `area rug` |
| Search URL | `https://www.wayfair.com/keyword.php?keyword=sofa` |
| Category URL | `https://www.wayfair.com/furniture/sb0/sofas-c413892.html` |
| Category filter | Furniture, Outdoor, Rugs, Lighting, … |
| Brand | `Latitude Run`, `Wade Logan` |
| SKU | `W100694092`, `CXVA1530` |
| Product URL | `https://www.wayfair.com/furniture/pdp/…-w100694092.html` |

**Not supported:** login-only lists, Wayfair Business / B2B portals, Wayfair.de (shut down), review text, AI summaries.

`startUrls` wins. If it is empty, the actor builds a URL from `searchQuery` / `category` / `brand` / `skus` + `country`.

### Use Cases

| Who | What they do with the rows |
|---|---|
| Price monitors | Track sale vs was-price and `discountPercent` across sofas, rugs, lighting |
| Retail / marketplace teams | Build a Wayfair product feed without an official API |
| Brands | Watch how their SKUs are priced, stocked and badged |
| Data teams | Category assortment, ratings, promo flags, variant counts |

### How It Works

<p align="center">
  <img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-wayfair.png" alt="How Wayfair Scraper works" width="900" />
</p>

1. Build start URLs from `startUrls`, or from keyword / category / brand / SKU.
2. Fetch each listing page (paginated with `curpage=N`, about 48 products per page).
3. Parse the server-rendered `ListingCard` grid — price, stock, variants, rating.
4. Optionally fetch the product page for specs, dimensions, materials and description.
5. Apply price / rating / in-stock filters and push one dataset row per product.

Chrome 131 TLS impersonation is the fetch stack. A plain rustls fingerprint is 429'd.

### Input Configuration

| Field | Type | Required | Notes |
|---|---|---|---|
| `startUrls` | string\[] | No | Search, category, brand or product URLs. Wins over the filters below. Example: `https://www.wayfair.com/keyword.php?keyword=sofa`. |
| `searchQuery` | string | No | Keyword when no URL is given. Example: `sofa`. Default empty. |
| `country` | enum | No | `com` / `ca` / `co.uk` / `ie`. Ignored when a full URL is pasted. Default `com`. |
| `category` | enum | No | Top-level browse (Furniture, Outdoor, …). Used only when URLs are empty. |
| `brand` | string | No | Brand name for a brand-scoped search. Example: `Latitude Run`. |
| `skus` | string\[] | No | Wayfair SKUs (`W100694092`) or manufacturer part numbers (`HMCO04210`). |
| `sortBy` | enum | No | Relevance, price, rating, newest, best seller. Default `relevance`. |
| `priceMin` / `priceMax` | number | No | Drop products outside this price range (storefront currency). |
| `ratingMin` | number | No | Drop products rated below this (0–5). Unrated are kept. |
| `inStockOnly` | boolean | No | Keep in-stock / low-stock only. Rows with no stock evidence are kept. Default `false`. |
| `fetchDetails` | boolean | No | Fetch each product page (extra request + `additional-data` event on a hit). Default `false`. |
| `maxItems` | integer | No | Hard cap on rows. Default `100`. Always set this. |
| `maxPages` | integer | No | Max listing pages per start URL (`curpage=N`). Default `20`, hard cap `80`. |
| `proxy` | proxy | No | Residential recommended. Prefill uses Apify `RESIDENTIAL`. |

#### Example input

Keyword, listing only:

```json
{
  "searchQuery": "sofa",
  "country": "com",
  "maxItems": 30
}
```

Category URL with specs:

```json
{
  "startUrls": ["https://www.wayfair.com/furniture/sb0/sofas-c413892.html"],
  "fetchDetails": true,
  "maxItems": 20
}
```

SKU lookup:

```json
{
  "skus": ["W100694092"],
  "fetchDetails": true,
  "maxItems": 1
}
```

### Output Overview

One row per product. Listing fields (`price`, `previousPrice`, `discountPercent`, `variantCount`, `stockStatus`) fill when Wayfair shows them. `specifications`, `dimensions`, `materials`, `description`, `featureBullets` and `brandUrl` fill when `fetchDetails` is on. Flatten is on by default: nested objects become `specifications_Overall Dimensions`, `dimensions_width`. Turn `flatten` off only if you want nested JSON.

### Output Samples

Real row from a 12 Sep 2026 cloud run — keyword `sofa`, `fetchDetails: true`. Flattened keys shown as nested for reading.

```json
{
  "sku": "W117455547",
  "title": "L-Shaped Sofa With Reversible Chaise, Convertible Couch With Washable Covers, Compact Living Room Furniture For Apartments & Small Spaces",
  "brand": "Latitude Run",
  "brandUrl": "https://www.wayfair.com/brand/bnd/latitude-run-b40128.html",
  "productUrl": "https://www.wayfair.com/furniture/pdp/latitude-run-l-shaped-sofa-with-reversible-chaise-w117455547.html",
  "price": 334.99,
  "previousPrice": 749.99,
  "savings": 415,
  "discountPercent": 55,
  "currency": "USD",
  "stockStatus": "IN_STOCK",
  "isPurchasable": true,
  "inventoryMessage": "25 Left in Stock",
  "variantCount": 3,
  "rating": 3.3,
  "promoFlag": "Sale",
  "materials": ["Chenille", "Solid Wood", "Memory Foam"],
  "dimensions": {
    "raw": "33.85'' H X 76'' W X 28'' D",
    "height": 33.85,
    "width": 76,
    "depth": 28,
    "weightLb": 104,
    "unit": "in"
  },
  "country": "com",
  "detailFetched": true
}
```

### Key Output Fields

**Identity**

| Field | Description |
|---|---|
| `sku` | Wayfair SKU (`W100694092`, `CXVA1530`) |
| `title` / `brand` / `brandUrl` | Product name, manufacturer, brand page |
| `productUrl` / `canonicalUrl` | Canonical PDP |

**Price**

| Field | Description |
|---|---|
| `price` / `previousPrice` / `currency` | Sale price, struck-through was-price, ISO currency |
| `savings` / `discountPercent` | Dollars off and percent off, when both prices exist |

**Availability**

| Field | Description |
|---|---|
| `stockStatus` | `IN_STOCK`, `LOW_STOCK`, `OUT_OF_STOCK`, `BACKORDERED` |
| `isPurchasable` / `inventoryMessage` | Shoppable flag + Wayfair's own sentence |
| `variantCount` | Option combinations from the card (“5 Colors, 2 Sizes” → 10) |

**Merchandising**

| Field | Description |
|---|---|
| `rating` / `reviewCount` | Stars (0–5) and review count |
| `promoFlag` | Sale, Warehouse Clearout, … |
| `imageUrl` / `images` | Primary image + extras |
| `breadcrumbs` / `category` / `subCategory` | Category path |

**Enrichment (`fetchDetails`)**

| Field | Description |
|---|---|
| `specifications` | Spec table (material, dimensions text, weight capacity, …) |
| `dimensions` | Parsed H×W×D (inches) and weight (lb) |
| `materials` | Material values from the spec table |
| `description` / `featureBullets` | About This Product + bullets |
| `estimatedDeliveryMessage` | Get it by … / FREE Delivery |

### Pricing

| Event | When | Rate |
|---|---|---|
| Actor start | Once per run, per GB of memory | $0.005 |
| Product result | Each dataset row | $0.002 |
| Product detail enrichment | `fetchDetails` hit with extra fields | $0.001 |

Listing-only runs do not charge `additional-data`.

### What makes this richer than the competition

| Capability | Typical Store actors | This actor |
|---|---|---|
| Four storefronts + keyword / category / brand / SKU | Leader has this; cheap listing actors often URL-only | Yes |
| Stock that actually fills on listing | Leader's users asked for it; listing cards often left it null | Listing RSC + PDP leftover count |
| `discountPercent` + `variantCount` | piotrv / stealth sell these | On the card, no extra HTTP |
| Specs / dimensions / materials | khadinakbar at $0.004 | `fetchDetails` at $0.001 extra |
| 429 wall | Constant 429 threads on the leader | Chrome 131 impersonation |

### FAQ

**Do I need a Wayfair account?** No. Public listing and product pages only.

**Why is `stockStatus` null?** The listing payload usually carries inventory next to the SKU. A few cards have no blob — those stay null unless you turn on `fetchDetails`. Free-delivery text is not treated as stock.

**US only?** No. Set `country` or paste a `.ca` / `.co.uk` / `.ie` URL.

**429 Access denied?** Use a residential proxy. Datacenter IPs are refused. The actor impersonates Chrome 131.

**How many products per page?** About 48. `maxPages` caps how far pagination goes. Always set `maxItems`.

**Does `fetchDetails` always bill?** Only when the product page adds extra fields. Empty or blocked PDPs are not charged.

**Reviews / AI summaries?** Out of scope. Separate product.

**Can I mix URL kinds?** Yes. Paste any mix of search, category, brand and product URLs in `startUrls`.

### Support

Open an issue on the actor's [Issues tab](https://apify.com/memo23/wayfair-scraper/issues) or email <muhamed.didovic@gmail.com>.

### Additional Services

Need a custom export shape, a scheduled monitor, or a field the listing does not print? Email <muhamed.didovic@gmail.com>.

### Explore More Scrapers

- [**Etsy Scraper**](https://apify.com/memo23/etsy-scraper) — listings, shops and reviews
- [**Pinterest Scraper**](https://apify.com/memo23/pinterest-scraper) — pins, boards and search
- [**Best Buy Scraper**](https://apify.com/memo23/bestbuy-scraper) — prices, per-ZIP stock and ranked search results with ads flagged

Full list at [apify.com/memo23](https://apify.com/memo23).

### 🤖 For AI Agents & LLM Apps

Compact reference for agents calling this actor via the [Apify MCP server](https://mcp.apify.com) or the Apify API (actor: `memo23/wayfair-scraper`).

**Purpose:** Turn a Wayfair keyword, category, brand, SKU or URL into one product row each — SKU, title, brand, price, discount, stock, variants, rating, image, URL — over HTTP.

**Minimal input:**

```json
{
  "searchQuery": "sofa",
  "country": "com",
  "maxItems": 30
}
```

**Output:** one row per product — `sku`, `title`, `brand`, `price`, `previousPrice`, `savings`, `discountPercent`, `currency`, `stockStatus`, `variantCount`, `rating`, `reviewCount`, `promoFlag`, `imageUrl`, `productUrl`, `breadcrumbs`, `country`, `scrapedAt`. `fetchDetails` adds `specifications`, `dimensions`, `materials`, `description`, `featureBullets`, `brandUrl`, `estimatedDeliveryMessage`.

**Behaviors an agent should know:**

- Always set `maxItems`. Each listing page is ~48 products and paginates with `curpage=N`.
- `startUrls` wins over keyword / category / brand / SKU.
- Residential proxy is the safe default on Apify. Datacenter IPs often get 429.
- `fetchDetails` (off) is one extra request per product and charges `additional-data` only on a hit.
- Pay-per-event: $0.005 start + $0.002 per row + $0.001 on a detail hit.

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Wayfair LLC or any of its subsidiaries. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available product pages — no authenticated endpoints, paid features, or content behind a Wayfair login. Users are responsible for ensuring their use complies with Wayfair's Terms of Service, applicable data-protection law (GDPR, CCPA, etc.), and any contractual obligations of their own organization.

***

### SEO Keywords

Wayfair scraper, scrape Wayfair, Wayfair API, Apify Wayfair, Wayfair product scraper, Wayfair price scraper, furniture price data, Wayfair.ca scraper, Wayfair.co.uk scraper, home goods product feed, Wayfair SKU lookup, Wayfair category scrape, Wayfair stock status, Wayfair ratings scraper, crawlerbros Wayfair alternative, sofa price monitor, Wayfair discount percent

# Actor input Schema

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

Search, category, brand or product URLs on wayfair.com / .ca / .co.uk / .ie. Each listing URL is paginated until Maximum items is reached. When this is set, keyword/category/brand/SKU below are ignored. Example: https://www.wayfair.com/keyword.php?keyword=sofa. Default empty.

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

Keyword used only when Wayfair URLs is empty. Valid: any public Wayfair search term. Example: sofa. Default empty.

## `country` (type: `string`):

Regional storefront used when building a search/category/brand URL. Values: com, ca, co.uk, ie. Ignored when you paste a full URL (the domain wins). Example: com. Default: com.

## `category` (type: `string`):

Top-level Wayfair category browse. Used only when Wayfair URLs is empty. Values: furniture, outdoor, rugs, lighting, and the other enum options. Example: furniture. Default empty.

## `brand` (type: `string`):

Brand / manufacturer name. Used only when Wayfair URLs is empty. Example: Latitude Run. Default empty.

## `skus` (type: `array`):

Wayfair SKUs (W100694092) or manufacturer part numbers (HMCO04210). Each is looked up on Wayfair. Used only when Wayfair URLs is empty. Example: W100694092. Default empty.

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

Sort order applied to keyword/category/brand listing URLs. Values: relevance, price_low_to_high, price_high_to_low, top_rated, newest, best_seller. Example: relevance. Default: relevance.

## `priceMin` (type: `integer`):

Drop products priced below this amount in the storefront currency. Example: 100. Default unset (no floor).

## `priceMax` (type: `integer`):

Drop products priced above this amount in the storefront currency. Example: 800. Default unset (no ceiling).

## `ratingMin` (type: `number`):

Drop products with a rating below this value (0-5). Products with no rating are kept. Example: 4. Default unset.

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

Keep only products Wayfair marks as IN_STOCK or LOW_STOCK. Products with no stock evidence are kept. Example: false. Default: false.

## `fetchDetails` (type: `boolean`):

Fetch each product page for specs, dimensions, materials, description, feature bullets, delivery and a sharper stock read. One extra HTTP request per product. Bills the additional-data event only when extra fields are found. Example: false. Default: false.

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

Hard cap on product rows written to the dataset. Always set this. Example: 30. Default: 100.

## `maxPages` (type: `integer`):

Maximum paginated listing pages (curpage=N) per start URL. About 48 products per page. Range 1-80. Example: 2. Default: 20.

## `proxy` (type: `object`):

Proxy used for Wayfair requests. Paying users are automatically routed through a residential proxy pool. Leave at the default setting unless supplying your own proxy URLs.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.wayfair.com/keyword.php?keyword=sofa"
  ],
  "searchQuery": "sofa",
  "country": "com",
  "brand": "Latitude Run",
  "sortBy": "relevance",
  "inStockOnly": false,
  "fetchDetails": false,
  "maxItems": 10,
  "maxPages": 20,
  "proxy": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per product: SKU, title, brand, price, discount, stock, variant count, specs, image and URL.

# 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 = {
    "startUrls": [
        "https://www.wayfair.com/keyword.php?keyword=sofa"
    ],
    "searchQuery": "sofa",
    "maxItems": 10,
    "proxy": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/wayfair-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 = {
    "startUrls": ["https://www.wayfair.com/keyword.php?keyword=sofa"],
    "searchQuery": "sofa",
    "maxItems": 10,
    "proxy": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/wayfair-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 '{
  "startUrls": [
    "https://www.wayfair.com/keyword.php?keyword=sofa"
  ],
  "searchQuery": "sofa",
  "maxItems": 10,
  "proxy": {
    "useApifyProxy": true
  }
}' |
apify call memo23/wayfair-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/wayfair-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/I6KpCNqjigUp8CmRe/builds/DKM5DuQFKpQTUBLME/openapi.json
