Wayfair Scraper - Furniture, Prices, Stock & Reviews avatar

Wayfair Scraper - Furniture, Prices, Stock & Reviews

Pricing

from $1.00 / 1,000 product results

Go to Apify Store
Wayfair Scraper - Furniture, Prices, Stock & Reviews

Wayfair Scraper - Furniture, Prices, Stock & Reviews

Scrape Wayfair.com furniture and home products by keyword or URL, including product, category, brand and sitemap links. Extract prices, discounts, ratings, variants, stock, images, specifications, dimensions and reviews. Supports scheduled price and stock change tracking.

Pricing

from $1.00 / 1,000 product results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

5 days ago

Last modified

Categories

Security

Limited permissions

Share

Wayfair Scraper: Furniture & Home Goods Prices, Stock & Reviews

Wayfair Scraper turns wayfair.com, the online store for furniture, decor and home goods, into a clean product data API. Search by keyword or paste product, category, brand, search and sitemap links and scrape them directly. Every product comes back as one row with price, was-price, discount, rating, review count, option list, images and key specifications, plus optional full copy, specifications, dimensions, in-stock status for every option and customer reviews, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.

Why This Scraper?

  • Two ways to find products. Search by keyword, or paste product, category, brand, search or sitemap links and scrape them directly.
  • 48 products per request, at no extra cost. Result pages already carry price, was-price, discount, rating, review count, colour and finish options, key specifications and images, so a plain listing run is the cheapest way to watch a whole category.
  • Full detail on demand. Switch on description, specifications, dimensions, materials, the rating breakdown, the full gallery and in-stock status for every option, and pay only for what you use.
  • Customer voice included. Review text, stars, date, first name, location, verified-purchase flag and the options the reviewer bought, in the order you choose, with the store's own summary of what reviewers say.
  • Built for monitoring. Incremental mode returns only new, changed, restocked and, optionally, delisted products on a schedule, a price-and-stock-only mode keeps description or image edits out of your bill, and a refused run fails loudly instead of returning an empty dataset.
  • Missing products are never charged. A product page that no longer exists is skipped, not returned and not billed.
  • Resume a large pull. An interrupted run can continue from where it left off without paying twice for products already collected.

Use Cases

  • Price and discount monitoring: track price drops, was-prices and promotion flags across a brand, a category or a keyword on a schedule.
  • Competitive intelligence for home retailers: compare assortment, pricing, ratings and option depth against the largest online furniture store.
  • Stock and restock alerts: watch specific products for sold-out and back-in-stock changes, option by option, with Incremental mode.
  • Review mining: pull thousands of verified-purchase reviews with the options each reviewer bought to find what breaks, what runs small and what people love.
  • Catalogue and content teams: build a structured feed of descriptions, specifications, dimensions and images for a comparison site or app.

Data You Get

Sample shape: values are illustrative placeholders, not from a live record.

FieldExample
sku"W000000001" (the product code; this is the row's identity)
name / brand / collection"Sample Task Chair" / "Sample Brand" / "Sample Collection"
urllink to this product, without tracking parameters
price / wasPrice / currency212.99 / 244.99 / "USD"
onSale / discountPercent / discountLabel / priceLabeltrue / 13 / "13% Off" / "Sale"
rating / reviewCount4.6 / 477
optionsevery colour, size or finish choice with its link; with a product page read, also inStock for each and selected for the one shown
optionCount / selectedOptions14 / {"Upholstery Color": "Pink"}
imageUrl / imagesmain photo and the gallery
promoFlag / isBestValue / isSponsored"Fall Clearance" / true / false (result pages only)
keySpecskey specifications shown on the result card (result pages only)
stockMessage / deliveryPromise / arrivalMessagethe result card's units-left, delivery and arrival texts (result pages only)
stockStatus"IN_STOCK" or "OUT_OF_STOCK" for the shown option (needs a product page read)
description / highlightsthe product copy and its highlights (needs a product page read)
specifications / dimensions / materialskey-value specifications, measured dimensions and material list (needs a product page read)
category / categoryId / breadcrumbsthe product's category path (needs a product page read)
ratingHistogram / reviewSummaryreview count per star and the store's own summary of the reviews (needs a product page read)
reviewswritten reviews (with Fetch customer reviews)
position / pagewhere the product ranked in the results
changeType / changedFields / firstSeenAt / lastSeenAtincremental mode: "NEW" / [] / timestamps

Every record also carries variantId, optionIds, brandId, brandUrl, videos, detailsFetched, reviewsRequested, reviewsDelivered, searchTerm, sourceUrl and scrapedAt.

How to Use

  1. Pick a mode: search (by keyword) or url (paste Wayfair links).
  2. Fill in the fields for that mode, then apply any sort, price, rating, brand or sale filters you want; they apply to both modes.
  3. Set Max products to control run size and cost, then click Start.
  4. Download the dataset as JSON, CSV or Excel, or read it through the API.

Search by keyword:

{
"mode": "search",
"queries": ["standing desk"],
"maxItems": 50
}

Search with filters, discounted only, cheapest first:

{
"mode": "search",
"queries": ["area rug"],
"sortBy": "priceAsc",
"maxPrice": 150,
"minRating": 4,
"onSaleOnly": true,
"maxItems": 100
}

If you leave urls untouched in url mode, the actor scrapes six sample links, one per link shape. Replace them with your own links.

Paste links, with full product-page detail:

{
"mode": "url",
"urls": [
"https://www.wayfair.com/furniture/sb0/office-chairs-c478390.html",
"https://www.wayfair.com/brand/bnd/lark-manor-b37152.html"
],
"fetchDetails": true,
"maxItems": 40
}

Monitor a category on a schedule, price and stock only:

{
"mode": "url",
"urls": ["https://www.wayfair.com/furniture/sb0/office-chairs-c478390.html"],
"incrementalMode": true,
"changeScope": "priceAndStock",
"emitExpired": true
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/wayfair-scraper").call(run_input={"mode": "search", "queries": ["standing desk"], "maxItems": 50})
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
print(product["name"], product["price"], product["rating"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/wayfair-scraper').call({ mode: 'search', queries: ['standing desk'], maxItems: 50 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

In url mode the actor reads these shapes of link: a keyword search (/keyword.php?keyword=...), a category or search-result page (for example /furniture/sb0/office-chairs-c478390.html), a brand page (/brand/bnd/<brand>-b<id>.html), a product page (/<department>/pdp/<name>-<code>.html, optionally with ?piid= to pick an option) and the store's product sitemaps (/seo-pdp-sitemap~<n>.xml, each listing hundreds of products). Filtered category pages, curated collections and daily-sale pages are read like any other result page, though editorial pages carry few products. Other pages of the store (help, account, cart, financing) are skipped with a warning. If you leave urls untouched, one sample of each shape is used. A result-page link that starts past page 1 is read from that page, and a sortby value written into a link is kept.

Output tab views

The Output tab offers four views: Products (the result-card fields), Product detail (specifications, dimensions, options and gallery), Customer reviews (one row per written review, unwound from the reviews array) and Changes since the last run (incremental status and changed fields; with Compact updates on, also the old and new values of each price or stock change and the per-option changes). Customer reviews are capped per product by Max reviews per product, from 1 to 1000 (default 20).

Keeping a run cheap

A result page already carries price, discount, options, images and rating for about 48 products, at no extra cost. Read each product's page and Fetch customer reviews each need one extra page per product and are billed with one Product page detail event per product that reaches the dataset. They share that one page, so turning both on costs the same as turning on either. Each review returned inside a row is billed with one Customer review event. A pasted product link always reads the product page, because there is no result card behind it to fall back on, so it is billed one Product page detail event whenever it reaches the dataset, whatever the toggle says. Product pages that no longer exist are never returned and never billed.

How Max products and the filters shape a run

When Max products is set, every keyword and link in a run gets its own share of it, split evenly, so one popular search cannot use up the whole run and starve the rest. The price, rating, brand, sale and sponsored filters narrow the rows this actor returns rather than being sent to the store, so a narrowed run reads more result pages per row returned. The store serves at most a few hundred result pages for any one search; when it stops serving new products the run says so and the search counts as a partial scan.

Resume and recurring updates

  • Resume (resumeFromRunId) continues one interrupted run: paste its run or dataset ID and the actor skips everything already collected there, so you don't pay twice.
  • Incremental mode (incrementalMode) is for scheduled runs over the same search or links. Each product is classified NEW, UPDATED (with changedFields), UNCHANGED (suppressed and not billed unless emitUnchanged is on), REAPPEARED or EXPIRED (only after a run that scanned the whole tracked scope, and only with emitExpired). stateKey names or shares the stored state. With Incremental mode off, output is exactly as before.

What counts as a change. Compared: price, was-price, discount, on-sale flag, stock status, the option list with per-option stock, name, brand, description, specifications, dimensions and categories. Excluded by default but still returned in the row: scrape timestamps, the product's rank and page, the sponsored flag, delivery promise and arrival date (they depend on the day and the shipping address), the live units-left message, how the product was found, image and video links (the gallery shown on a result card varies between two page layouts), and ratings and reviews (average rating, review count, rating breakdown, review summary and the review sample, which move with every new review). Option and material lists are compared regardless of the order the store returns them. Switching the exclusions never causes a one-time wave of UPDATED rows: UNCHANGED is decided by re-reading the stored record under the current settings.

  • changeScope: priceAndStock compares only price, was-price, discount, on-sale flag, stock status and per-option stock, so a name, description or specification edit is never a billable UPDATED row. Switching changeScope, or editing ignoreFieldsForChanges, keeps your existing saved state: nothing comes back as NEW, each stored product is simply re-compared under the new setting.
  • compactUpdates turns UPDATED and EXPIRED rows into slim rows (ids, link, name, current price and stock, priceChanges old and new, variantChanges per option as ADDED, REMOVED or CHANGED). NEW rows stay full. A compact row does not carry product-page detail fields or reviews, so no detail or review charge applies to it.
  • expireAfterMissedScans applies with emitExpired. EXPIRED means the product dropped out of the scanned results; it does not prove it is unavailable, because no product page is opened. Use stockStatus for availability.
  • A pasted link that starts past page 1, a run stopped by Max products, Max result pages, the time limit or your maximum cost per run, a resumed run, or a run whose search or filters differ from those the state key was last saved with never produces EXPIRED rows.

EXPIRED rows count against Max products like every other row. They are only produced after a run that scanned the whole tracked scope, so a run that stopped because it reached Max products returns none. Products held back that way stay tracked and are returned, and billed, as EXPIRED on a later complete run.

Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each product, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify, Settings, Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch for keywords plus filters, or url to scrape pasted Wayfair links.
queriesarray["standing desk"]Search keywords (search mode).
urlsarraysix sample links (one per link shape)Wayfair product, search, category, brand or sitemap links (url mode).
sortBystringrelevancerelevance, priceAsc, priceDesc or rating. A sort written into a pasted link wins.
minPricenumber(none)Only keep products at or above this price, in the store's currency.
maxPricenumber(none)Only keep products at or below this price, in the store's currency.
onSaleOnlybooleanfalseKeep only products whose current price is below their was-price.
minRatingnumber(none)Keep only products with an average rating of at least this value (0 to 5).
brandsarray(none)Keep only products from these brands (case and trademark signs ignored).
skipSponsoredbooleanfalseLeave out the paid placements mixed into result pages.
fetchDetailsbooleanfalseRead every product's own page for the full description, specifications, dimensions and per-option stock.
fetchReviewsbooleanfalseAlso collect customer reviews (reads the product page too).
maxReviewsPerProductinteger20Cap on reviews collected per product, from 1 to 1000.
reviewSortstringrelevancerelevance, newest, highest or lowest.
includeReviewImagesbooleanfalseAdd the photo links reviewers attached.
maxItemsinteger20Maximum number of products to return across the whole run, up to 100000. 0 = the 100000 maximum.
maxPagesinteger0Maximum result pages per keyword or link. 0 = no limit set; a safety limit always applies, and the log says when a limit stops a search that still had results.
resumeFromRunIdstring(none)Continue one interrupted run without re-collecting or re-billing its products.
incrementalModebooleanfalseReturn only new and changed products on scheduled runs.
stateKeystring(none)Name or share an incremental-mode state.
changeScopestringallpriceAndStock limits change detection to price, stock and per-option stock.
compactUpdatesbooleanfalseSlim UPDATED and EXPIRED rows with priceChanges and variantChanges.
expireAfterMissedScansinteger1Mark EXPIRED only after this many consecutive complete scans missed the product.
ignoreFieldsForChangesarray(none)Extra fields (or dotted paths such as options.url) that never count as a change.
emitUnchangedbooleanfalseAlso return (and bill) unchanged products.
emitExpiredbooleanfalseAlso return (and bill) products no longer found after a full scan, within the room left under Max products.
proxyobject{"useApifyProxy": true}Connection settings.
mcpConnectorsarray(none)Optional: send a summary of each product to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which products are created.
maxNotifyListingsinteger50Cap on products written to each connector per run.

Output Example

Sample shape: values are illustrative placeholders, not from a live record.

{
"recordType": "product",
"sku": "W000000001",
"variantId": "AB00000001",
"optionIds": "100000001",
"name": "Sample Task Chair",
"brand": "Sample Brand",
"collection": "Sample Collection",
"url": "https://www.wayfair.com/furniture/pdp/sample-brand-sample-task-chair-w000000001.html?piid=100000001",
"price": 212.99,
"wasPrice": 244.99,
"currency": "USD",
"onSale": true,
"discountPercent": 13,
"discountLabel": "13% Off",
"priceLabel": "Sale",
"rating": 4.6,
"reviewCount": 477,
"ratingHistogram": {"1": 10, "2": 8, "3": 28, "4": 75, "5": 356},
"stockStatus": "IN_STOCK",
"category": "Office Chairs",
"breadcrumbs": [{"name": "Furniture", "url": "https://www.wayfair.com/furniture/cat/furniture-c45974.html"}],
"description": "A sample description of the product.",
"specifications": {"Product Type": "Task Chair", "Weight Capacity": "300 lb."},
"dimensions": {"Overall Dimensions": "39'' H X 26'' W X 26'' D"},
"materials": ["Linen", "Foam"],
"selectedOptions": {"Upholstery Color": "Pink"},
"options": [
{"optionKey": "Upholstery Color: Pink", "group": "Upholstery Color", "name": "Pink", "optionId": 100000001, "inStock": true, "selected": true, "url": "https://www.wayfair.com/furniture/pdp/sample-brand-sample-task-chair-w000000001.html?piid=100000001"}
],
"optionCount": 14,
"imageUrl": "https://assets.wfcdn.com/im/0/compr-r85/0000/000000001/i.jpg",
"promoFlag": "Fall Clearance",
"isBestValue": true,
"isSponsored": false,
"position": 3,
"page": 1,
"detailsFetched": true,
"reviewsRequested": true,
"reviews": [
{"reviewId": 1, "rating": 5, "text": "Sample review text.", "date": "09/25/2026", "author": "Sam", "location": "Springfield, ST", "verifiedPurchase": true, "purchasedOptions": {"Upholstery Color": "Green"}, "language": "en", "images": []}
],
"reviewsDelivered": 1,
"changeType": "NEW",
"changedFields": [],
"firstSeenAt": "2026-10-31T12:00:00Z",
"lastSeenAt": "2026-10-31T12:00:00Z",
"scrapedAt": "2026-10-31T12:00:00Z"
}

Plan Requirement

The default connection works: the standard Apify datacenter pool served product and result pages in testing, so no residential proxy is needed to get started. This store does sometimes refuse a page; when it does, the run switches to a fresh connection and retries. If refusals keep coming it escalates, in order, to residential exits, then to backup connections, and finally to Apify Proxy's enhanced group, and it stays on the connection that works for the rest of the run. Residential connections give the most reliable results on a bad day, and you can select them in the Connection section. Proxy traffic is billed on your own Apify plan, and the enhanced group costs more per request. Customer reviews beyond the first few cannot be read on the enhanced group, and the run says so.

If your plan does not include proxy access, the run says so in plain words rather than returning an empty dataset. These are the messages you may see in the run log:

  • Warning: "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable." followed by an upgrade pointer.
  • Info: "Served over the backup connection (the default connection was unavailable)."
  • Failure: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required".
  • Failure: "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested Wayfair pages."
  • Failure: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

You can supply your own proxy URLs instead; custom proxies get no automatic backup connection.

FAQ

How much does it cost?

Four events can appear on a run, and the Pricing tab shows the current rates:

  • Dataset item: one event per product row returned in the dataset (incremental UNCHANGED rows are suppressed and not billed unless Emit unchanged products is on).
  • Product page detail: one event per product row whose own page is read, whether through Read each product's page, Fetch customer reviews or a pasted product link. Turning both toggles on still costs one event per product.
  • Customer review: one event per review returned inside a product row.
  • Actor start: one event each time a run starts.

Use Max products to cap the cost of any run. Failed, empty or missing pages are never billed, and a run that reaches your maximum cost per run stops and says so.

This actor collects only publicly available product data. You are responsible for how you use it: follow Wayfair's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Prices and specifications are generally facts, but product photos and brand names may be subject to third-party rights. Reviews are written by private individuals, so treat them as personal data where privacy law applies.

Can I get only new or changed products on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and restocked products, and unchanged ones are not billed unless you turn on Emit unchanged.

Why does a product show a different price than the website for me?

Prices and delivery promises can depend on the option shown and on the shipping address the connection resolves to. The price on a row is the price of the option named in selectedOptions (or in optionIds). Delivery texts are excluded from change detection for that reason.

Why did my run fail instead of returning an empty dataset?

If the store refuses every request, the run stops with a clear message so "no matches today" is never confused with "nothing could be read". Run it again in a few minutes. If only some pages could be read, you still get what was found, and the run tells you the result is incomplete.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

๐Ÿ”— Want more e-commerce data?

Pair this actor with these related scrapers from the same team:

๐Ÿ›’ Nitori Japan Furniture & Home Goods Scraper
Scrape Nitori Japan (nitori-net.jp) furniture and home goods by keyword, category or...
๐Ÿ›’ Harvey Norman Scraper
Scrape Harvey Norman Australia products: name, brand, price, was-price / discount...
๐Ÿ›’ Netshoes Brazil
Scrape sportswear and footwear from netshoes.com.br. Search by keyword with the store's...
๐Ÿ‘— OTTO.de Scraper
Scrape OTTO.de products by search or URL. Extract prices, discounts, variants...
๐Ÿ›’ Bunnings Scraper
Scrape bunnings.com.au products with full specifications, price, brand, stock, image...
๐Ÿ›’ MUJI Scraper
Scrape MUJI products from the United States, Canada and Australia storefronts. Search by...

๐Ÿ‘‰ Browse all abotapi scrapers

๐Ÿ’ฌ Support

  • ๐Ÿž Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • ๐Ÿ› ๏ธ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • โญ Enjoying it? A quick review on the actor page helps other users find it.