What the Farfetch scraper collects
Opens farfetch.com category, hub, search and brand listing pages in a real browser and writes one row per product — brand, price, list price, discount, stock, image — to JSON and CSV. Detail mode opens each product page too and writes one row per size, with colour and material composition.
Listing pages
Input: A filtered category, search or brand URLOne row per product: title, brand, price, original price, computed discount, stock, image and category, with pagination followed across --pages.
Product detail (per size)
Input: A listing URL; each product page on it is openedOne row per size variant, keyed on the variant sku, with per-size availability, colour, material composition, the full image set and the whole structured discount chain.
From zero to Farfetch data in 3 steps
Install
Clone the repository and install one browser engine. Python 3.9+.
$ git clone https://github.com/2scraper/farfetch-scraper && cd farfetch-scraper $ pip install -r requirements.txt $ pip install -r requirements-playwright.txt && playwright install chromium $ python3 smoke_test.py
Run a scraper
Pick what you need and run it. Every flag is documented in the README.
$ python3 playwright_scraper.py --url "https://www.farfetch.com/shopping/kids/girls-clothing-4/items.aspx" --pages 1 --format both --out girls_clothing$ python3 playwright_scraper.py --url "https://www.farfetch.com/shopping/kids/girls-clothing-4/items.aspx" --pages 1 --mode detail --out sizesGet structured data
Rows land in JSON or CSV (
--format), with a.meta.jsonsidecar recording status, pages fetched and why the run stopped.
Farfetch data fields
16 columns per row in a predictable schema. The most useful ones:
| Field | What it holds |
|---|---|
sku | Farfetch product id, recovered from the product URL |
title | Product name, in the market's language |
brand | Designer or brand, as the site stores it |
price | What a customer pays, as a number |
currency | ISO currency code; follows the market you were served |
original_price | List price before discounts, when the item is on sale |
discount_pct | Discount computed from price and original_price |
in_stock | Availability flag |
image_url | Product image URL |
category | Category label, derived from the URL or set with --category |
price_source | How the price was read: jsonld+dom, jsonld or dom |
url | Product page URL |
scraped_at | UTC timestamp of the run |
[
{
"source": "farfetch.com",
"scraped_at": "2026-09-07T13:23:21.139407+00:00",
"url": "https://www.farfetch.com/de/shopping/kids/diesel-kids-jogginganzug-mit-logo-detail-item…",
"sku": "33139701",
"title": "Jogginganzug mit Logo-Detail",
"brand": "Diesel Kids",
"price": 52.0,
"currency": "EUR",
"original_price": 130.0,
"discount_pct": 60.0,
"rating": null,
"review_count": null,
"in_stock": true,
"image_url": "https://cdn-images.farfetch-contents.com/33/13/97/01/33139701_64411000_480.jpg",
"category": "girls-clothing-4",
"price_source": "jsonld+dom"
},
{
"source": "farfetch.com",
"scraped_at": "2026-09-07T13:23:21.139531+00:00",
"url": "https://www.farfetch.com/de/shopping/kids/michael-kors-kids-gefutterter-kapuzenmantel-i…",
"sku": "30081471",
"title": "Gefütterter Kapuzenmantel",
"brand": "Michael Kors Kids",
"price": 82.0,
"currency": "EUR",
"original_price": 185.0,
"discount_pct": 55.7,
"rating": null,
"review_count": null,
"in_stock": true,
"image_url": "https://cdn-images.farfetch-contents.com/30/08/14/71/30081471_59638081_480.jpg",
"category": "girls-clothing-4",
"price_source": "jsonld+dom"
}
]First 2 of 3 rows from a real run — sample_output.json. Long values shortened here.
Handles what breaks naive Farfetch scrapers
The real sale price, not the middle one
Farfetch's JSON-LD publishes the middle of three prices on a discounted tile. The parser reconciles it with the rendered tile, so price is what a customer pays and discount_pct is computed, not copied from a printed badge.
Pagination that cannot silently stop at page 1
The visible pager has no usable anchor, so the scraper reads <link rel="next"> and rebuilds ?page=N behind it — and stops on a page that adds no new sku, not on a missing selector.
Blocked, empty and never-loaded told apart
Akamai's refusal exits 3, a page that really held nothing exits 4, a dead proxy or timeout exits 5, and a run cut short exits 6 with the failed pages named in the sidecar.
Price provenance on every row
price_source records whether a price was confirmed against the rendered tile, so diff_runs.py reports a rendering difference as source_changed rather than a false price change.
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.
Scraping Browser API
Point --cdp-endpoint at a managed Chromium with its own exit country — no browser infrastructure to run yourself.
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 Farfetch snapshots by id — new, removed and changed rows for monitoring.
What teams do with Farfetch data
Price and discount monitoring
Track price, original_price and discount_pct per sku on a schedule and diff runs to catch markdowns.
Assortment tracking
See what a brand or category lists, and what disappeared since the last complete run.
Size availability
Use detail mode to follow in-stock sizes for specific products, keyed on the variant sku.
Cross-market pricing
Fetch the same category from different exit countries and join on sku — Farfetch sets prices per market rather than converting them.
Free to run. Pay only for what the site requires.
Free to run · paid add-ons optional
No key and no account are needed to start: an ordinary local Chromium on a clean residential IP cleared Akamai Bot Manager and returned all 96 products of a filtered category. A datacentre address gets Akamai's Access Denied, though. Residential proxies or the Scraping Browser API buy volume from many addresses and a specific country's prices; captcha solving covers a challenge that does not clear; fingerprints give a local browser a consistent identity.
Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.
Good to know
- rating and review_count are null on every listing row: the listing JSON-LD carries no aggregateRating.
- Detail mode, --concurrency, --resume and proxy pools are Playwright-only for now.
- in_stock has never been observed false, so treat a false with more suspicion than a true.
2scraper vs. hosted scraper APIs
| 2scraper | Typical hosted API | |
|---|---|---|
| Code | Open source, MIT — read and patch it | Closed |
| Cost | Free; optional services billed only when used | Subscription or per request / per result |
| Runs on | Your machine, server or CI | The vendor's infrastructure |
| Output | JSON/CSV files + run metadata | API responses |
| When the site changes | Fix it yourself or open an issue / PR | Wait for the vendor |
Farfetch scraper FAQ
Do I need a proxy or an API key?
Not for a category page from a clean residential IP — that was measured with no key and no proxy. You need a proxy or the Scraping Browser API for volume, for a specific country, or from a datacentre address, which Farfetch refuses.
Why are prices in EUR when I asked for a .com URL?
A fresh, cookie-less visit is geo-redirected on exit IP, so currency and language follow the address. Pick the market with the proxy's country or the Scraping Browser API's country segment, and check currency in the output.
Why did I get 0 products?
Usually a bare hub URL such as /shopping/kids/items.aspx, which carries no products. Use a filtered category URL.
What formats does it write?
JSON and CSV with the same 16 columns, plus a <out>.meta.json sidecar recording status, failed pages and per-column coverage.
Can I resume a run that died halfway?
Yes. Every multi-page run writes a checkpoint, and --resume continues from it (Playwright engine).
Is it legal to scrape Farfetch?
It reads public catalogue data and never submits the sign-up form. Follow Farfetch's terms and the law in your jurisdiction, and scrape at a rate that does not degrade the site.