1. 2scraper
  2. E-commerce & retail
  3. Sleep Number
Open source · MITFree to run · paid add-ons optional

Sleep Number Scraper

Smart beds, mattresses and bedding from sleepnumber.com — one row per size, with its own price and sale price.

  • Playwright
  • Selenium
  • Puppeteer
  • Scraping Browser API
  • JSON
  • CSV
sleepnumber-scraper
# Category or collection listing
$ python3 playwright_scraper.py --category mattresses --format both --out mattresses
✓ 9 sample rows · 24 columns in sample_output.json
24columns per size-variant row
88products in the site's sitemap, Sep 2026
52size variants on /categories/mattresses, Sep 2026
100%price coverage on every listing measured, Sep 2026
Available Sleep Number scrapers

What the Sleep Number scraper collects

Reads sleepnumber.com category, collection and product pages and writes one row per size variant: sku, price, original price, discount, rating, review count and availability. The data comes from the page's own server-rendered hydration payload, with prices in exact integer cents, to JSON and CSV.

Category or collection listing

Input: A category or collection slug

One row per size variant of every product on the listing, with per-size price, sale price, rating and availability.

Product detail

Input: A product's URL slug

The same rows for one model: every size it is sold in.

Quick start

From zero to Sleep Number data in 3 steps

  1. Install

    Clone the repository and install one browser engine. Python 3.9+.

    $ git clone https://github.com/2scraper/sleepnumber-scraper.git && cd sleepnumber-scraper
    $ pip install -r requirements.txt -r requirements-playwright.txt
    $ playwright install chromium
    $ python3 playwright_scraper.py --category mattresses --format both --out mattresses
  2. Run a scraper

    Pick what you need and run it. Every flag is documented in the README.

    $ python3 playwright_scraper.py --category mattresses --format both --out mattresses
  3. Get structured data

    Rows land in JSON or CSV (--format), with a .meta.json sidecar recording status, pages fetched and why the run stopped.

Output

Sleep Number data fields

24 columns per row in a predictable schema. The most useful ones:

FieldWhat it holds
skuSize-variant id, e.g. QCM10 for a Queen ComfortMode
titleProduct name
sizeSize of this variant (Twin, Queen, King…)
priceCurrent (sale) price, as a number
currencyISO currency code from the site's own data (USD)
original_priceRegular price, only when genuinely higher than price
discount_pctDiscount computed from price and original_price
promo_badgeThe promotion text the site shows
ratingAverage review rating; null when unreviewed
review_countNumber of reviews; null when unreviewed
in_stockAvailability flag
product_typemattress, base, bedding, furniture…
categoryCategory name
product_slugThe model's slug
price_sourceWhich view the price came from, and whether JSON-LD confirmed it
urlVariant URL on www.sleepnumber.com
[
  {
    "source": "sleepnumber.com",
    "scraped_at": "2026-09-17T15:08:07.263728+00:00",
    "url": "https://www.sleepnumber.com/collections/mattresses-comfortmode-collection/TCM10",
    "sku": "TCM10",
    "title": "ComfortMode™ Mattress",
    "brand": "Sleep Number",
    "price": 989.1,
    "currency": "USD",
    "original_price": 1099.0,
    "discount_pct": 10.0,
    "price_source": "payload",
    "rating": 4.7222,
    "review_count": 180,
    "in_stock": true,
    "image_url": "https://cdn.sleepnumber.com/image/upload/f_auto,q_auto:eco/v1773780981/workarea/catalog…",
    "category": "Mattresses",
    "size": "Twin",
    "product_id": "AF1E5D37DF",
    "product_slug": "comfortmode",
    "collection_slug": "mattresses-comfortmode-collection",
    "product_type": "mattress",
    "promo_badge": "$109.90 OFF",
    "page": 1,
    "position": 1
  },
  {
    "source": "sleepnumber.com",
    "scraped_at": "2026-09-17T15:08:07.263756+00:00",
    "url": "https://www.sleepnumber.com/collections/mattresses-comfortmode-collection/XCM10",
    "sku": "XCM10",
    "title": "ComfortMode™ Mattress",
    "brand": "Sleep Number",
    "price": 1079.1,
    "currency": "USD",
    "original_price": 1199.0,
    "discount_pct": 10.0,
    "price_source": "payload",
    "rating": 4.7222,
    "review_count": 180,
    "in_stock": true,
    "image_url": "https://cdn.sleepnumber.com/image/upload/f_auto,q_auto:eco/v1773780981/workarea/catalog…",
    "category": "Mattresses",
    "size": "Twin XL",
    "product_id": "AF1E5D37DF",
    "product_slug": "comfortmode",
    "collection_slug": "mattresses-comfortmode-collection",
    "product_type": "mattress",
    "promo_badge": "$119.90 OFF",
    "page": 1,
    "position": 2
  }
]

First 2 of 9 rows from a real run — sample_output.json. Long values shortened here.

Built for Sleep Number

Handles what breaks naive Sleep Number scrapers

One row per size

ComfortMode spans seven sizes and seven prices. Each size is its own row keyed on its own sku, so diff_runs.py reports a Queen going on sale while the King does not.

Reads the hydration payload, not the paint

The product grid is painted client-side. The scraper decodes React Router's turbo-stream payload, which carries every product, variant and price in integer cents before a script runs.

No phantom discounts

The site's regular price equals its sale price on most items. original_price stays null unless the regular price is genuinely higher, so the file is not full of 0% discounts.

Landing pages and refusals named correctly

A curated /categories/ page with no product list reports no_listing, a CloudFront refusal reports blocked, and the site's 200-KB 404 page is told apart by its route data — none of them pass as "zero products".

Everything built in

Scraping infrastructure included

The same tested core runs every 2scraper repository, so the hard parts work the same way on every site.

CAPTCHA handling

Detects the challenge a page really serves and, with a 2Captcha key, solves it only when it blocks the data — a capped number of solves per page.

Proxy rotation

Single proxy or a pool from a file, rotated on blocks with a fresh browser per exit. Credentials stay out of argv and logs.

Fingerprints

Optional complete device identity from the 2Captcha Fingerprint API — user agent, client hints, locale and timezone that agree with each other.

Honest run metadata

Every run writes a .meta.json sidecar and distinct exit codes: complete, blocked, empty and partial are never confused, and a failed run never overwrites good data.

Diff two runs

diff_runs.py compares two complete Sleep Number snapshots by id — new, removed and changed rows for monitoring.

Use cases

What teams do with Sleep Number data

Mattress price monitoring

Track every size's price and sale price over time and catch per-size promotions.

Promotion tracking

Record promo badges and computed discounts across beds, bases, bedding and furniture.

Competitive benchmarking

Compare Sleep Number's per-size pricing with other bed and mattress retailers.

Full-catalogue snapshots

The sellable catalogue is small — 88 products in the sitemap when measured — so a complete pass takes minutes.

Access & pricing

Free to run. Pay only for what the site requires.

Free to run · paid add-ons optional

No key, captcha solving or fingerprint is needed, and from a home connection the scraper needs nothing at all. Every datacentre address — VPS, CI runner, container — gets a CloudFront 403 refusal with no challenge on it, so from a server you need a residential proxy or the Scraping Browser API, which brings its own residential exit. Any residential exit country returns the same USD prices.

Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.

Good to know

  • Selenium cannot authenticate a password proxy, so on this site it needs a residential connection, an IP-authenticated proxy or a local forwarding proxy.
  • The Scraper API's own exits are refused; it works here only routed through a Scraping Browser session (--cdp-url).
  • rating and review_count are null on unreviewed products.

2scraper vs. hosted scraper APIs

2scraperTypical hosted API
CodeOpen source, MIT — read and patch itClosed
CostFree; optional services billed only when usedSubscription or per request / per result
Runs onYour machine, server or CIThe vendor's infrastructure
OutputJSON/CSV files + run metadataAPI responses
When the site changesFix it yourself or open an issue / PRWait for the vendor
FAQ

Sleep Number scraper FAQ

Why does it get HTTP 403 from my server?

Sleep Number refuses datacentre addresses outright. Run it from a residential connection, or set a residential proxy in .env, or use the Scraping Browser API.

Do I need captcha solving?

No. Nothing on this site renders a challenge; what helps against the refusal is a different exit address.

Does the proxy country matter?

No. The same category through GB and US residential exits returned the same skus with identical USD prices. Pin a region only if you want a reproducible exit.

Why one row per size instead of per product?

Each size has its own sku and its own price, and that size dimension is what a mattress price monitor most needs.

How does pagination work?

?page=N is ignored by the site, so pages are planned from the payload's own arithmetic. Every category measured fits on one page of 100, and --concurrency is refused.

Is it legal to scrape Sleep Number?

It reads public catalogue pages. Respect robots.txt, the site's terms, the law in your jurisdiction and a sane request rate.