# KaTom Restaurant Supply Scraper (`crawlerbros/katom-restaurant-supply-scraper`) Actor

Scrape KaTom Restaurant Supply (katom.com) - a national wholesale commercial kitchen equipment retailer. Search by keyword, browse curated categories, or fetch specific products by URL. Get price, brand, SKU, stock status, specs, images, ratings, and reviews.

- **URL**: https://apify.com/crawlerbros/katom-restaurant-supply-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## KaTom Restaurant Supply Scraper

Scrape [KaTom Restaurant Supply](https://www.katom.com) — a national wholesale retailer of commercial kitchen equipment and foodservice supplies serving over 1.5 million operators since 1987. Search by keyword, browse a top-level category, or pull specific products by URL. Get price, brand, SKU, stock status, technical specs, images, and rating/review counts. No login, no cookies, no paid proxy required.

### What this actor does

- **Three modes:** `search` (keyword), `byCategory` (browse a top-level category, optionally narrowed by sub-category), `byUrl` (fetch specific product pages)
- **Filters:** brand, price range, in-stock only, free-shipping only, quick-ship only, sort order (relevance / price ascending / price descending)
- **Optional deep enrichment:** turn on `fetchFullDetails` to also pull each product's full description, all product images, and rating/review count from its detail page
- **Empty fields are omitted** — every record only contains fields KaTom actually returned

### Output per product

- `sku` — KaTom item number (e.g. `491-36019`)
- `title`, `fullTitle` — product name (`fullTitle` includes brand + model)
- `brand`, `modelNumber`
- `price`, `currency`, `originalPrice` (list/retail price when discounted)
- `unitOfMeasure` (e.g. `Each`, `Set`, `Case`)
- `category`, `categoryPath`, `topCategory`
- `inStock`, `availability` (e.g. "IN STOCK: Ships in 1 Business Day"), `qtyOnHand`
- `freeShipping`, `quickShip`
- `weightLbs`
- `imageUrl`, `imageUrls[]` (multiple, when `fetchFullDetails` is on)
- `specs` — structured technical attributes when present (capacity, horsepower, voltage, phase, hertz, color, controls, certifications, special features, dimensions, etc.)
- `description` (when `fetchFullDetails` is on, or always for `byUrl` mode)
- `rating`, `reviewCount` (when `fetchFullDetails` is on, or always for `byUrl` mode)
- `productUrl`, `sourceUrl`
- `recordType: "product"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byCategory` / `byUrl` |
| `searchQuery` | string | `blender` | Free-text query (mode=search) |
| `topCategory` | string | – | One of KaTom's 10 top-level categories (mode=byCategory) |
| `subCategory` | string | – | Optional exact leaf category name to narrow `topCategory`, e.g. `Commercial Blenders` |
| `productUrls` | array | – | KaTom product URLs or bare item numbers (mode=byUrl) |
| `brand` | string | – | Only include products whose brand contains this text |
| `priceMin` / `priceMax` | int | – | Price range (USD) |
| `inStockOnly` | bool | `false` | Only in-stock products |
| `freeShippingOnly` | bool | `false` | Only products tagged free shipping |
| `quickShipOnly` | bool | `false` | Only products tagged Quick Ship |
| `sortBy` | string | `relevance` | `relevance` / `priceAsc` / `priceDesc` |
| `fetchFullDetails` | bool | `false` | Fetch each product's detail page for a full description, all images, and rating |
| `maxItems` | int | `20` | Hard cap on emitted records (1–1000) |

#### Example: search with a price cap

```json
{
  "mode": "search",
  "searchQuery": "ice machine",
  "priceMax": 5000,
  "inStockOnly": true,
  "maxItems": 50
}
```

#### Example: browse a category with full details

```json
{
  "mode": "byCategory",
  "topCategory": "Restaurant Equipment",
  "subCategory": "Commercial Blenders",
  "sortBy": "priceAsc",
  "fetchFullDetails": true,
  "maxItems": 30
}
```

#### Example: fetch specific products

```json
{
  "mode": "byUrl",
  "productUrls": ["https://www.katom.com/491-36019.html", "141-BB145"]
}
```

### Use cases

- **Price monitoring** — track commercial kitchen equipment pricing across brands and categories
- **Competitive intelligence** — compare foodservice equipment assortment and stock levels
- **Procurement research** — pull specs (capacity, voltage, dimensions) for equipment sourcing
- **Catalog enrichment** — feed structured product data into internal PIM/ERP systems
- **Market research** — analyze commercial kitchen equipment brand distribution and pricing tiers

### Data source

KaTom Restaurant Supply's product catalog. This actor was originally scoped against WebstaurantStore.com, but that site enforces a Cloudflare Turnstile interactive JS challenge on every request (confirmed via both `curl_cffi` browser impersonation and a real Playwright browser — both consistently received HTTP 403 challenge pages), which makes it inaccessible without a paid CAPTCHA-solving or residential-proxy service — a violation of this project's zero-cost policy. KaTom Restaurant Supply was selected as a directly comparable, freely accessible alternative: a large, well-established US commercial kitchen and restaurant-supply wholesaler with the same target audience (foodservice operators) and a comparably broad product catalog, but with no bot-blocking on its public catalog data.

### Limitations

- **Individual product-detail-page fetches (`mode=byUrl`, or `fetchFullDetails=true`) can occasionally miss a small fraction of products.** Unlike KaTom's search/category API (which the actor calls directly and has been 100% reliable across every verification run), KaTom's individual product *pages* sit behind Cloudflare bot protection that intermittently blocks even legitimate cloud-datacenter traffic — including after this actor's built-in direct-connection + proxy-rotation retry sequence (8 attempts per page). When this happens the actor logs a clear status message with how many products it could and couldn't resolve, rather than failing the whole run; simply re-run with the same URLs to pick up the rest. This does not affect `search` or `byCategory` mode listings, which never need to load an individual product page.

- **`inStockOnly` only excludes items explicitly marked out-of-stock.** KaTom's own search index does not always populate a stock flag for backorder/vendor-fulfilled/dropship items (it's simply absent, not `false`) — those items pass through the `inStockOnly` filter since there is no data to positively exclude them on. Items with a confirmed `inStock: false` are always excluded.

- **Brand is free-text, not a dropdown.** KaTom carries 500+ distinct brands — too many for a fixed enum. The filter does a case-insensitive substring match; common brands (Vitamix, Cambro, Vollrath, Hatco, Winco, Carlisle, True Refrigeration, Turbo Air, etc.) are listed in the field description as examples.

- **`subCategory` requires an exact (case-insensitive) match** to one of KaTom's ~1,000 leaf category names (e.g. `Commercial Blenders`, `Reach-in Refrigerators`). There are too many leaf categories to expose as a dropdown; an incorrect value returns 0 results rather than a fuzzy match.

- **Reviews are not paginated separately.** `reviewCount` reflects the total on the product page; only a handful of the most relevant review snippets are exposed by KaTom's own product page, so full historical review text is not extracted.

- **Pricing reflects standard web pricing.** Some commercial/wholesale accounts see negotiated or volume pricing after login; this actor scrapes the publicly visible price shown to anonymous visitors, which is what KaTom itself displays without requiring sign-in.

- Non-US/international storefronts are not applicable — KaTom Restaurant Supply ships within the United States only, so no multi-market/locale variant exists to expose.

### FAQ

**Do I need a KaTom account?** No. All data (including pricing) is scraped from KaTom's publicly visible catalog pages, which require no login.

**Does this use a paid proxy?** No. The actor calls KaTom's own public product-search API directly over plain HTTPS; no residential proxy or CAPTCHA-solving service is used or required.

**Why is `fetchFullDetails` off by default?** It adds one extra HTTP request per product (to fetch the full description, image gallery, and rating). For fast bulk price/stock checks, leave it off; turn it on when you need product descriptions or ratings.

**What's the difference between `category`, `categoryPath`, and `topCategory`?** `category` is the specific leaf category (e.g. `Commercial Blenders`); `categoryPath` is the full breadcrumb (e.g. `Restaurant Equipment > Food Prep Equipment > Commercial Blenders`); `topCategory` is just the top-level department (e.g. `Restaurant Equipment`).

**What does `specs` contain?** A dynamic set of technical attributes KaTom publishes for that specific product type — e.g. blenders expose `horsepower`/`capacityOz`/`voltage`, refrigerators expose `capacityLbs`/`temperatureRange`, etc. Only attributes KaTom actually lists for that product appear; nothing is fabricated.

**How current is the data?** Pricing, stock status, and lead times are read live from KaTom's own search index at run time — the same data KaTom's own website displays to shoppers.

# Actor input Schema

## `mode` (type: `string`):

What to fetch.

## `searchQuery` (type: `string`):

Free-text product search, e.g. `blender`, `ice machine`, `stainless steel work table`.

## `topCategory` (type: `string`):

One of KaTom's top-level navigation categories.

## `subCategory` (type: `string`):

Optional exact leaf category name to narrow a top-level category, e.g. `Commercial Blenders`, `Reach-in Refrigerators`, `Ice Machines with Bins`. Must match KaTom's own category name exactly (case-insensitive) or it will return 0 results.

## `productUrls` (type: `array`):

KaTom product page URLs (e.g. `https://www.katom.com/491-36019.html`) or bare KaTom item numbers (e.g. `491-36019`).

## `brand` (type: `string`):

Only include products whose brand contains this text (case-insensitive), e.g. `Vitamix`, `Cambro`, `Vollrath`, `Hatco`, `Winco`, `Carlisle`, `True Refrigeration`, `Turbo Air`. KaTom carries 500+ brands so this is free-text rather than a fixed dropdown.

## `priceMin` (type: `integer`):

Drop products priced below this amount.

## `priceMax` (type: `integer`):

Drop products priced above this amount.

## `inStockOnly` (type: `boolean`):

Only include products currently in stock.

## `freeShippingOnly` (type: `boolean`):

Only include products KaTom tags with free shipping.

## `quickShipOnly` (type: `boolean`):

Only include products KaTom tags as Quick Ship (expedited dispatch).

## `sortBy` (type: `string`):

Result ordering (mode=search / mode=byCategory).

## `fetchFullDetails` (type: `boolean`):

For search/category results, also fetch each product's detail page for a full description, all images, and rating/review count. Slower (one extra request per product) but more complete. Always on for mode=byUrl.

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

Hard cap on emitted records.

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

Optional. Product search/category listing never needs a proxy (it calls KaTom's own public search API directly). Individual product detail-page fetches (mode=byUrl, or fetchFullDetails=true) try a direct connection first and only fall back to Apify's free datacenter (AUTO) proxy group if KaTom's Cloudflare protection blocks the direct request.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "blender",
  "topCategory": "Restaurant Equipment",
  "productUrls": [],
  "inStockOnly": false,
  "freeShippingOnly": false,
  "quickShipOnly": false,
  "sortBy": "relevance",
  "fetchFullDetails": false,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `products` (type: `string`):

Dataset containing all scraped KaTom products.

# 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 = {
    "mode": "search",
    "searchQuery": "blender",
    "topCategory": "Restaurant Equipment",
    "productUrls": [],
    "inStockOnly": false,
    "freeShippingOnly": false,
    "quickShipOnly": false,
    "sortBy": "relevance",
    "fetchFullDetails": false,
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/katom-restaurant-supply-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 = {
    "mode": "search",
    "searchQuery": "blender",
    "topCategory": "Restaurant Equipment",
    "productUrls": [],
    "inStockOnly": False,
    "freeShippingOnly": False,
    "quickShipOnly": False,
    "sortBy": "relevance",
    "fetchFullDetails": False,
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/katom-restaurant-supply-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "search",
  "searchQuery": "blender",
  "topCategory": "Restaurant Equipment",
  "productUrls": [],
  "inStockOnly": false,
  "freeShippingOnly": false,
  "quickShipOnly": false,
  "sortBy": "relevance",
  "fetchFullDetails": false,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call crawlerbros/katom-restaurant-supply-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=crawlerbros/katom-restaurant-supply-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RbmfMsKESXR08V4jR/builds/L2sGoxdtrm7C5EV8L/openapi.json
