1. 2scraper
  2. E-commerce & retail
  3. Tractor Supply
Open source · MITNeeds a residential exit or the Scraping Browser API

Tractor Supply Scraper

Tractor Supply categories, departments and searches — priced at a specific store, with stock, pickup and ratings.

  • Playwright
  • Selenium
  • Puppeteer
  • Scraping Browser API
  • JSON
  • CSV
tractorsupply-scraper
# Category
$ ./venv/bin/python playwright_scraper.py --category poultry-feed-treats --pages 3
✓ 12 sample rows · 35 columns in sample_output.json
35columns per product
2modes: category and search
8site sort orders supported
144products in 11 s from a 3-page category run (Sep 2026)
Available Tractor Supply scrapers

What the Tractor Supply scraper collects

Scrapes tractorsupply.com listings — a category, a whole department or a keyword search — into JSON and CSV, with the prices of a specific store chosen by ZIP code. Each of the 35 columns comes from the site's own search endpoint: price range, list price and discount, unit price, rating, stock, ship and pickup availability, brand, model number, badges and variants.

Category

Input: A category slug

One row per product in a category, 48 per page by default (up to 200 with --page-size), priced at the chosen store.

Department

Input: A department URL

Every product in a whole department, such as Pet with 14,678 products, using the parent id the site actually filters on.

Keyword search

Input: A search term, optional sort and ZIP code

One row per search result in any of the site's eight orderings, with a relevance check that warns when the site returns unrelated products.

Quick start

From zero to Tractor Supply data in 3 steps

  1. Install

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

    $ git clone https://github.com/2scraper/tractorsupply-scraper.git && cd tractorsupply-scraper
    $ python3 -m venv venv
    $ ./venv/bin/pip install -r requirements.txt -r requirements-playwright.txt
    $ cp .env.example .env
    $ python3 env_config.py
  2. Run a scraper

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

    $ ./venv/bin/python playwright_scraper.py --category poultry-feed-treats --pages 3
  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

Tractor Supply data fields

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

FieldWhat it holds
skuTractor Supply product id
titleProduct title
brandBrand
model_numberManufacturer model number
pricePrice at the chosen store; the low end of a range for multi-size products
price_maxHigh end of the price range; equals price for a single SKU
original_priceList price, only where price is a single value
discount_pctDiscount computed from price and original_price
price_per_unitUnit price, e.g. 0.33
price_unitUnit for the unit price, e.g. lb
ratingAverage rating
review_countNumber of reviews
in_stockStock at the store; null for multi-variant products the site lists no inventory for
pickup_availableIn-store pickup at the chosen store
variant_countNumber of variants
store_idThe store the prices are for
[
  {
    "source": "tractorsupply.com",
    "scraped_at": "2026-09-28T09:30:13.850406+00:00",
    "url": "https://www.tractorsupply.com/tsc/product/fimco-40-gal-4-nozzle-3-point-hitch-sprayer-5…",
    "sku": "135429599",
    "title": "Fimco 40 gal. 4 Nozzle 3 pt. Hitch Sprayer",
    "brand": "Fimco",
    "price": 549.99,
    "currency": "USD",
    "original_price": 699.99,
    "discount_pct": 21.4,
    "rating": 4.01,
    "review_count": 789,
    "in_stock": true,
    "image_url": "https://media.tractorsupply.com/is/image/TractorSupplyCompany/1354295?$456$",
    "category": "Farm & Ranch > Sprayers > 3 Point Sprayers",
    "price_source": "api",
    "page": 1,
    "position": 1,
    "mode": "category",
    "sort": "popular",
    "item_sku": "1354295",
    "model_number": "5302941",
    "price_max": 549.99,
    "price_per_unit": null,
    "price_unit": null,
    "map_pricing": null,
    "badge": "SALE",
    "promotion": null,
    "variant_count": 1,
    "buyable": true,
    "sold_via": "Online In Stores",
    "ship_available": true,
    "pickup_available": false,
    "store_id": "2314",
    "zip_code": "37027"
  },
  {
    "source": "tractorsupply.com",
    "scraped_at": "2026-09-28T09:30:13.850453+00:00",
    "url": "https://www.tractorsupply.com/tsc/product/fimco-60-gallon-3-point-hitch-mounted-sprayer…",
    "sku": "215225199",
    "title": "Fimco 60 gal. 3-Point Hitch-Mounted Sprayer with 3-Nozzle Broadcast Boom, Deluxe Handgu…",
    "brand": "Fimco",
    "price": 699.99,
    "currency": "USD",
    "original_price": 1299.99,
    "discount_pct": 46.2,
    "rating": 3.91,
    "review_count": 138,
    "in_stock": false,
    "image_url": "https://media.tractorsupply.com/is/image/TractorSupplyCompany/2152251?$456$",
    "category": "Farm & Ranch > Sprayers > 3 Point Sprayers",
    "price_source": "api",
    "page": 1,
    "position": 2,
    "mode": "category",
    "sort": "popular",
    "item_sku": "2152251",
    "model_number": "LG-60-3PT-WP-309-BL-TSC",
    "price_max": 699.99,
    "price_per_unit": null,
    "price_unit": null,
    "map_pricing": null,
    "badge": "SALE",
    "promotion": null,
    "variant_count": 1,
    "buyable": true,
    "sold_via": "In Stores Only",
    "ship_available": false,
    "pickup_available": false,
    "store_id": "2314",
    "zip_code": "37027"
  }
]

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

Built for Tractor Supply

Handles what breaks naive Tractor Supply scrapers

Prices for a named store

Tractor Supply prices per store. --zip chooses it (default 37027, Brentwood TN), store_id and zip_code are on every row, and diff_runs.py refuses to compare runs priced at different stores.

Price ranges read correctly

For multi-size products the endpoint's own price field was often the highest variant. The scraper reports the low end as price and the high end as price_max, and only fills original_price when both are single values.

Bad searches flagged

A query the site cannot match still returns products (a nonsense string returned jeans). The run measures how many page-1 rows mention the query, warns below 20%, and records query_relevance in the sidecar.

Fetches the way the front end does

The grid is painted from a search endpoint, not the HTML. Every engine loads the homepage once and calls that endpoint with same-origin fetch(), and all three share one fetch loop so they agree on retries and exit codes.

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.

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 Tractor Supply snapshots by id — new, removed and changed rows for monitoring.

Use cases

What teams do with Tractor Supply data

Farm and pet supply price monitoring

Track prices, list prices and discounts across categories like feed, pet food or sprayers, store by store.

Regional price comparison

Run the same listing with different --zip values to see where store prices differ.

Assortment and brand analysis

Pull a whole department to count products, brands, badges and variants.

Availability tracking

Record stock, ship and pickup availability at a chosen store over time.

Access & pricing

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

Needs a residential exit or the Scraping Browser API

Akamai Bot Manager refused every client tested except the 2Captcha Scraping Browser API with a US exit (measured Sep 2026): plain HTTP, local Chromium, a US residential proxy and the Scraper API were all denied. So the Scraping Browser API with country-us is required, and the endpoint goes in .env. Proxies and fingerprints are supported for local browsers but were not measured to change Akamai's answer here. This repo does not implement captcha solving, because none of the refusals captured carried a captcha widget.

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

Good to know

  • Only the Scraping Browser API with a US exit was served; the Selenium engine cannot use it.
  • Captcha solving and a Scraper API path are not implemented in this repo.
  • in_stock, ship_available and pickup_available are null on multi-variant 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

Tractor Supply scraper FAQ

What do I need to scrape Tractor Supply?

The 2Captcha Scraping Browser API with a US exit (country-us). It was the only client the site served in testing; put its endpoint in .env, not on the command line.

Why do prices differ between runs?

Prices are per store. Use --zip to pick the stores; the default is 37027 so runs from different exits price the same catalogue at the same store.

Why is in_stock empty for some products?

The site's inventory data lists no multi-variant products, so their stock, ship and pickup columns are null rather than guessed. variant_count shows which rows those are.

How many products can one page return?

48 by default, up to 200 with --page-size. --pages is planned against the total the site states, so asking for too many pages simply fetches them all.

Does Selenium work here?

No. chromedriver cannot send the credentials a Scraping Browser endpoint carries, and a local Chrome is refused, so the Selenium engine reports blocked. Use Playwright or pyppeteer.

Is scraping Tractor Supply legal?

It reads public catalogue data the way the site's own front end does, as an anonymous visitor, and never logs in or adds to a cart. Follow the site's terms and the law where you operate.