# Wayfair Product Scraper (`axiomworks/wayfair-product-scraper`) Actor

Scrape Wayfair products from keywords, SKUs or URLs for search, category and brand pages. Get product names, brands, SKUs, ratings, availability, images and selected options, with optional page-level dimensions, weight, descriptions and specifications. Supports three regional Wayfair stores.

- **URL**: https://apify.com/axiomworks/wayfair-product-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.45 / 1,000 results

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

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 Product Scraper

**Returns:** one row per Wayfair product with sku, name, brand, price, listPrice, isOnSale, rating, reviewCount, availability and url.
**Input:** `{"searchQueries": ["accent chair"], "maxItems": 50, "minPrice": 100, "maxPrice": 400, "onlyOnSale": true}`
**Best for:** furniture price monitoring, sale and discount tracking, competitor assortment research.

```json
{
  "sku": "HGHM1255",
  "name": "Hertford 26\" Wide Mid Century Upholstered Solid Wood Accent Chair with an Extra Pillow",
  "brand": "Sand & Stable\u2122",
  "price": 132.99,
  "currency": "USD",
  "listPrice": 199,
  "isOnSale": true,
  "rating": 4.38,
  "reviewCount": 9972,
  "url": "https://www.wayfair.com/furniture/pdp/sand-stable-hertford-26-wide-mid-century-upholstered-solid-wood-accent-chair-with-an-extra-pillow-hghm1255.html"
}
```

### What does Wayfair Product Scraper do?

Wayfair Product Scraper collects product data from Wayfair search results, category pages, brand pages and individual product pages. It returns one clean record per product with the name, brand, SKU, current price, struck-through "was" price, sale price, discount percentage, currency, rating, review count, availability, stock message, delivery message, main image and the selected variant options. When product page details are switched on, each record also contains overall dimensions, product weight, all structured dimensions, the full specifications table, the marketing description and the category breadcrumb.

You can use it for furniture and home-goods price tracking, assortment and brand research, catalog building and market analysis. It works on three Wayfair stores: wayfair.com (prices in USD), wayfair.ca (CAD) and wayfair.co.uk (GBP). It reads only public pages that load for a logged-out visitor. No login, no account and no cookies are involved.

This is an independent tool. It is not affiliated with, endorsed by or sponsored by Wayfair.

Start from keywords, SKUs, search URLs, category URLs, brand URLs or product URLs. You can mix them in one run.

Results are de-duplicated by SKU across all inputs, so the same product is never returned twice in one run.

Listing-only mode (product page details off) is a fast way to track prices each day.

Every record has an `id` (the SKU) and a `sourceUrl` (the product page it came from).

Output is available as JSON, CSV, Excel, XML or through the API.

### What data can you get?

Each dataset item is one product. The fields below are available. Fields marked "details only" are filled when product page details are on, and listing-only fields come from the search or category card.

| Field | Type | Description |
|---|---|---|
| `id` | string | Stable record ID, equal to the SKU |
| `sourceUrl` | string | Canonical product page the record came from |
| `sku` | string | Wayfair SKU, such as W100576387 (C prefix on wayfair.ca, U prefix on wayfair.co.uk) |
| `name` | string | Product name |
| `brand` | string | Manufacturer or house brand as Wayfair shows it |
| `url` | string | Canonical product URL without query string |
| `variantUrl` | string | Product URL with the `piid` parameter of the shown variant |
| `variantId` | string | ID of the shown variant |
| `price` | number | Current price for a logged-out visitor |
| `currency` | string | USD, CAD or GBP |
| `listPrice` | number | Struck-through "was" price, when Wayfair shows one |
| `salePrice` | number | Set only when Wayfair labels the price "Sale" |
| `isOnSale` | boolean | True when a sale price exists or the list price is above the price |
| `discountPercent` | integer | Percentage from labels such as "33% Off" |
| `rating` | number | Average customer rating from 0 to 5 |
| `reviewCount` | integer | Number of customer reviews |
| `availability` | string | IN_STOCK, OUT_OF_STOCK, BACKORDERED or similar |
| `stockMessage` | string | Card message such as "491 Left in Stock" (listing results only) |
| `deliveryMessage` | string | Card message such as "FREE 2-Day Delivery" (listing results only) |
| `imageUrl` | string | Main product image, 800 pixels |
| `selectedOptions` | array | Options of the shown variant as name and value pairs |
| `optionsCount` | integer | Number of visual choices, such as colors, offered |
| `promoFlag` | string | Promotional flag on the card, such as "Big Furniture Sale" |
| `sponsored` | boolean | True for sponsored ad cards |
| `categoryPath` | array | Category breadcrumb (details only) |
| `brandUrl` | string | Brand page URL (details only) |
| `description` | string | Marketing description (details only) |
| `overallDimensions` | string | Overall dimensions (details only) |
| `productWeight` | string | Overall product weight (details only) |
| `dimensions` | object | All structured dimensions, key to value (details only) |
| `specifications` | object | Full specifications table, key to value (details only) |
| `detailsScraped` | boolean | True when the product page was parsed |
| `position` | integer | 1-based rank within its search or listing; null for direct product inputs |
| `searchQuery` | string | The keyword that found the product |
| `inputUrl` | string | The listing or product URL that led to the record |
| `store` | string | wayfair.com, wayfair.ca or wayfair.co.uk |
| `scrapedAt` | string | ISO timestamp of the scrape |

#### What the price fields mean

`price` is what Wayfair charges now. `listPrice` is the struck-through "was" price shown next to it. `salePrice` is filled only when Wayfair itself labels the current price "Sale", so many discounted items have a `listPrice` and a `discountPercent` but no `salePrice`. `isOnSale` is a convenience flag that is true in either case.

Prices, stock and delivery messages are what a logged-out visitor sees without entering a ZIP or postal code. Member-only prices and ZIP-specific delivery dates are not collected, and delivery messages are generic.

### How to use Wayfair Product Scraper

1. Open the Actor and go to the Input tab.
2. Add search keywords, start URLs or both. A keyword is what you would type into the Wayfair search box.
3. Choose the store for keywords and SKUs. URLs keep the store they point to.
4. Set Max products to the number of records you need.
5. Keep product page details on if you want dimensions, weight, specifications and categories. Turn them off for the fastest price-only runs.
6. Keep the default residential proxy. Wayfair blocks datacenter addresses.
7. Click Start and download the results from the Output tab.

Inputs are processed in this order: product URLs and SKUs first, then listing URLs, then keyword searches. Broad keywords such as "accent chair" are redirected by Wayfair to a category page. The Actor follows that redirect and keeps paging through the category. A SKU used as a keyword (for example W100576387) leads straight to its product page and returns one record.

Pagination uses the `curpage` parameter. A run stops when it reaches Max products, the page limit, a page with no product cards or a page that adds no new product. Sponsored cards repeat between pages, and they are de-duplicated by SKU.

Wayfair does not show an empty page for nonsense keywords. It returns loosely matching products instead. The Actor checks that at least one product on the first page relates to your keyword and otherwise returns nothing for that query, with a warning in the log.

### Input

| Field | Type | Description |
|---|---|---|
| `searchQueries` | array of strings | Keywords as typed in the Wayfair search box. A SKU also works |
| `startUrls` | array | Search, category (`/sb0/`, `/sb1/`, `/cat/`), brand (`/brand/bnd/`) or product (`/pdp/`) URLs. Bare SKUs are accepted too |
| `store` | string | `wayfair.com`, `wayfair.ca` or `wayfair.co.uk` for keywords and SKUs. Default `wayfair.com` |
| `maxItems` | integer | Maximum number of products, 1 to 5000. Default 50 |
| `maxPagesPerQuery` | integer | Listing pages per query or URL, 1 to 100. Default 10 |
| `includeDetails` | boolean | Open each product page for dimensions, weight, specifications, description and category. Default true |
| `includeSponsored` | boolean | Keep sponsored cards, flagged with `sponsored: true`. Default true |
| `minPrice` | number | Only products priced at or above this amount in the store's currency. Applied to listing cards. Default none |
| `maxPrice` | number | Only products priced at or below this amount. Applied before product pages are opened, so it saves requests. Default none |
| `minRating` | number | Only products with an average rating of at least this value (0-5). Unrated products are skipped. Default none |
| `onlyOnSale` | boolean | Only products where the list price is above the current price. Default false |
| `proxyConfiguration` | object | Apify Proxy settings. Residential is required and is enforced if missing |

Example input:

```json
{
  "searchQueries": ["boucle swivel accent chair"],
  "startUrls": [
    { "url": "https://www.wayfair.com/furniture/sb0/accent-chairs-c416225.html" },
    { "url": "https://www.wayfair.com/brand/bnd/ivy-bronx-b44318.html" }
  ],
  "store": "wayfair.com",
  "maxItems": 100,
  "maxPagesPerQuery": 5,
  "includeDetails": true,
  "includeSponsored": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "US"
  }
}
```

The proxy country defaults to the store: US for wayfair.com, CA for wayfair.ca and GB for wayfair.co.uk. You can override it with `apifyProxyCountry`.

### Output

Results are stored in the default dataset. This example shows a record with product page details:

```json
{
  "id": "HGHM1255",
  "sourceUrl": "https://www.wayfair.com/furniture/pdp/sand-stable-hertford-26-wide-mid-century-upholstered-solid-wood-accent-chair-with-an-extra-pillow-hghm1255.html",
  "sku": "HGHM1255",
  "name": "Hertford 26\" Wide Mid Century Upholstered Solid Wood Accent Chair with an Extra Pillow",
  "brand": "Sand & Stable™",
  "price": 132.99,
  "currency": "USD",
  "listPrice": 199,
  "salePrice": null,
  "isOnSale": true,
  "discountPercent": 33,
  "rating": 4.38,
  "reviewCount": 9972,
  "availability": "IN_STOCK",
  "stockMessage": "491 Left in Stock",
  "deliveryMessage": "FREE 2-Day Delivery",
  "selectedOptions": [{ "name": "Upholstery Material", "value": "Beige" }],
  "optionsCount": 4,
  "promoFlag": "Big Furniture Sale",
  "sponsored": false,
  "categoryPath": ["Furniture", "Living Room Furniture", "Chairs & Seating", "Accent Chairs"],
  "overallDimensions": "29'' H X 26'' W X 32'' D",
  "productWeight": "29.32 lb.",
  "detailsScraped": true,
  "position": 1,
  "searchQuery": "accent chair",
  "store": "wayfair.com"
}
```

The `dimensions` and `specifications` objects are shortened in this example. In real output they hold every row Wayfair lists, usually 20 or more specification keys.

The dataset has an overview table view with the image, name, brand, SKU, price, was price, sale price, discount, currency, rating, reviews, availability, stock, dimensions, weight, category, sponsored flag, rank, query and URL.

### How much does it cost?

The Actor is charged per result: you pay for each product record saved to the dataset. See the Pricing tab of the Actor page for the current rate. Platform usage such as proxy traffic is billed separately by Apify according to your plan.

Wayfair pages are large and the Actor needs a residential proxy, so traffic is the main cost driver. With product page details on, the Actor makes one extra request for every product. For large daily price-tracking runs, turn product page details off. Listing cards already contain the price, list price, sale price, rating, review count, stock and delivery message, and a listing page holds 30 to 48 products in a single request.

### Use with AI agents (MCP)

You can call this Actor from AI assistants through the Apify MCP server. Add this to your MCP client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/wayfair-product-scraper"
    }
  }
}
```

Example prompts:

- "Find the 20 best-rated boucle swivel accent chairs on Wayfair and compare their prices."
- "Get the price, list price and discount for Wayfair SKU W100576387."
- "List Ivy Bronx products on Wayfair that are currently on sale."
- "Scrape the first 50 products from this Wayfair category page without product page details."

### Integrations and API

Run the Actor from your own code with the Apify API. Replace `YOUR_API_TOKEN` with your token (in cURL, set the `APIFY_TOKEN` environment variable).

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("axiomworks/wayfair-product-scraper").call(run_input={
    "searchQueries": ["accent chair"],
    "maxItems": 50,
    "includeDetails": False,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["sku"], item["name"], item["price"], item["currency"])
```

**JavaScript**

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('axiomworks/wayfair-product-scraper').call({
    searchQueries: ['accent chair'],
    maxItems: 50,
    includeDetails: false,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => process.stdout.write(`${item.sku} ${item.price}\n`));
```

**cURL**

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~wayfair-product-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries": ["accent chair"], "maxItems": 50, "includeDetails": false}'
```

You can also connect the dataset to Google Sheets, Make, Zapier, n8n or a webhook, and schedule the Actor to run every day for price monitoring. Compare each day's `price` and `listPrice` by `sku` to spot changes.

### FAQ

**Do I need a Wayfair account?** No. The Actor only reads pages that load for a logged-out visitor.

**Why is a residential proxy required?** Wayfair uses bot protection that blocks datacenter IP addresses. The Actor uses Apify residential proxies by default and enforces them even if your input leaves the proxy out. Some first attempts are blocked. The Actor retries them on a fresh proxy session, so runs normally recover.

**Why did I get fewer products than Max products?** The listing may hold fewer products than you asked for, the page limit may have been reached, or Wayfair stopped returning new products. Sponsored cards that repeat between pages are counted once.

**Why is `salePrice` empty for a discounted product?** `salePrice` is set only when Wayfair labels the price "Sale". Use `listPrice`, `discountPercent` and `isOnSale` for other discounts.

**Why are `stockMessage` and `deliveryMessage` empty for some records?** Those messages come from listing cards. Records built from a product URL or SKU use the product page only and carry the `availability` status instead.

**What happens with a wrong URL or nonsense keyword?** The Actor logs a warning, saves nothing for that input and finishes without a long wait. If nothing at all was saved, the run finishes successfully with zero items and a status message that names the cause. A `RUN_SUMMARY` record in the key-value store lists the inputs, pages fetched, products saved, inputs not found, inputs that failed and blocked attempts.

**Can I scrape other countries?** The Actor supports wayfair.com, wayfair.ca and wayfair.co.uk. Other Wayfair brands and country stores are not supported.

**Are delivery dates included?** No. Delivery messages are generic because no ZIP code is set.

**What if Wayfair changes its site?** Wayfair updates its pages often. If a page returns zero cards, the log says so. Report it through the Issues tab and it will be looked at.

### Is it legal to scrape Wayfair?

The Actor collects publicly visible product information such as names, prices, ratings and specifications. It does not log in, does not bypass or solve CAPTCHAs, and does not collect personal data: reviewer names are not scraped. Web scraping of public data is generally lawful in many jurisdictions, but rules differ by country and by use. Wayfair's terms of service may restrict automated access, and you are responsible for how you use the data. Respect copyright and trademark rights, keep request volumes modest, and take legal advice for commercial use if you are unsure. Wayfair product names and images belong to Wayfair and the brands that sell on it.

### Feedback

Found a bug or missing field? Open an issue from the Issues tab of this Actor with the input you used and the run link. Feature requests are welcome, for example more stores or extra fields.

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords as typed in the Wayfair search box, e.g. 'boucle swivel accent chair'. One search per entry. A Wayfair SKU such as 'W100576387' also works and returns that product. Leave empty if you supply startUrls.

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

Wayfair search (keyword.php?keyword=...), category (/sb0/, /sb1/, /cat/), brand (/brand/bnd/...) or product (/pdp/...) URLs on wayfair.com, wayfair.ca or wayfair.co.uk. Filters and sort in the query string are kept. Bare SKUs are accepted too.

## `store` (type: `string`):

Wayfair store used for searchQueries and bare SKUs: wayfair.com (USD), wayfair.ca (CAD) or wayfair.co.uk (GBP). URLs keep their own store. Default wayfair.com.

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

Maximum number of product records in total, 1-5000. Default 50. The run stops as soon as this many are saved.

## `maxPagesPerQuery` (type: `integer`):

Maximum listing pages per search, category or brand URL, 1-100. Default 10. A search page holds about 30 products, a category or brand page about 48.

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

If true (default), open each product page to add dimensions, weight, specifications, description and category path (one extra request per product). Set false for fast, cheaper price tracking from listing cards only.

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

If true (default), keep sponsored ad cards, which are always flagged sponsored=true. Set false to return organic results only.

## `minPrice` (type: `number`):

Only return products priced at or above this amount in the store's currency, e.g. 100. Applied to listing cards; products without a price are skipped when a price filter is set. Default none.

## `maxPrice` (type: `number`):

Only return products priced at or below this amount in the store's currency, e.g. 500. Applied to listing cards before product pages are opened, so it saves requests. Default none.

## `minRating` (type: `number`):

Only return products with an average rating of at least this value, 0-5, e.g. 4.5. Unrated products are skipped when set. Default none.

## `onlyOnSale` (type: `boolean`):

If true, return only products with a sale or reduced price (listPrice above price). Default false.

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

Apify Proxy settings. Wayfair blocks datacenter IPs, so a residential proxy is required and is enforced if missing. The country defaults to the store's country (US, CA, GB).

## Actor input object example

```json
{
  "searchQueries": [
    "accent chair"
  ],
  "startUrls": [],
  "store": "wayfair.com",
  "maxItems": 10,
  "maxPagesPerQuery": 10,
  "includeDetails": true,
  "includeSponsored": true,
  "onlyOnSale": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `products` (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 = {
    "searchQueries": [
        "accent chair"
    ],
    "startUrls": [],
    "maxItems": 10,
    "includeDetails": true,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/wayfair-product-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 = {
    "searchQueries": ["accent chair"],
    "startUrls": [],
    "maxItems": 10,
    "includeDetails": True,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/wayfair-product-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 '{
  "searchQueries": [
    "accent chair"
  ],
  "startUrls": [],
  "maxItems": 10,
  "includeDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call axiomworks/wayfair-product-scraper --silent --output-dataset

```

## MCP server setup

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