# B\&H Photo Scraper (`parsebird/bh-photo-scraper`) Actor

Scrape B\&H Photo Video product listings from category, brand, and search pages: prices, discounts, stock status, ratings, reviews, images, key features, MPN, and SKU. Export to JSON, CSV, or Excel.

- **URL**: https://apify.com/parsebird/bh-photo-scraper.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Stats:** 2 total users, 1 monthly users, 81.8% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.79 / 1,000 products

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

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### B\&H Photo Scraper

B\&H Photo Scraper extracts **product listings from B\&H Photo Video** (bhphotovideo.com) category, brand, and search pages: product name, brand, current and regular price, savings, stock status, rating, review count, images, key features, B\&H #, MFR # (MPN), and SKU. Paste a B\&H URL and get one clean row per product.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">
Track camera, lens, audio, and computer prices on B&H: paste any category, brand, filtered, sorted, or search results URL and get 28 products per page with prices, discounts, stock status, ratings, and full category paths, ready for price monitoring or catalog analysis.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
Actor: parsebird/bh-photo-scraper — scrapes B&H Photo Video (bhphotovideo.com) product listings. Input: {"startUrls": [{"url": "https://www.bhphotovideo.com/c/buy/Digital-Cameras/ci/9811/N/4288586282"}, {"url": "https://www.bhphotovideo.com/c/search?q=video%20monitor&sts=ma"}] (array of {url} objects: B&H category /c/buy/..., filtered or sorted /c/products/..., search /c/search?q=..., or brand and category landing pages /c/browse/... which are expanded into their subcategories; filters and sort in the URL are kept; a /pn/N or pn=N in the URL sets the first page; single product pages are not supported), "results_wanted": 20 (max products saved in total across all URLs; 0 or negative = no limit), "max_pages": 3 (listing pages per URL, 1-200; B&H shows 28 products per page), "proxyConfiguration": {"useApifyProxy": false} (optional; the actor connects through Apify Proxy by itself and moves to residential IPs if B&H refuses requests)}. Run via ApifyClient("YOUR_TOKEN").actor("parsebird/bh-photo-scraper").call(run_input=input). Output, one row per product: name, brand, price, original_price, price_in_cart (true for MAP items whose final price B&H shows only in the cart; price is then the advertised price), savings, currency (USD), category, category_path[] {id, name, url}, in_stock, stock_availability (in_stock|out_of_stock|pre_order|special_order|backordered|discontinued|other), stock_status_text, reviews, rating, featured_image, images[], description_text, key_features[], url, sku, bhId, mpn, condition, badge, used_price, is_new_arrival, is_bh_exclusive, short_url, _source, search_query, source_url, page, position, scraped_at. Pricing: pay per product saved. Get your API token at https://console.apify.com/account#/integrations. Full API spec: https://apify.com/parsebird/bh-photo-scraper/api
```

### What is B\&H Photo Scraper?

B\&H Photo Scraper is a **B\&H Photo data extraction tool** that reads the public product listings on [B\&H Photo Video](https://www.bhphotovideo.com/), the New York retailer of cameras, lenses, pro video and audio gear, computers, drones, and electronics. B\&H has no public product API, so this scraper works as a **B\&H Photo API alternative** for price monitoring, competitor research, catalog building, and market analysis.

The easiest way to try it: keep the prefilled **Digital Cameras** URL, click **Start**, and open the dataset. You get 20 cameras with prices, stock status, ratings, images, and key features in a few seconds.

No B\&H account is needed.

### What can B\&H Photo Scraper do?

- 🔗 **Paste any B\&H listing URL** — category pages (`/c/buy/...`), filtered and sorted pages (`/c/products/...?filters=...&sort=...`), and search results (`/c/search?q=...`). Filters and sort order in the URL are kept as pasted.
- 🗂️ **Category and brand landing pages** — pages such as `/c/browse/Photography/...` or the Canon brand store have no product grid. B\&H Photo Scraper opens their subcategories and collects products from each one.
- 💲 **Prices and deals** — current price, regular (strikethrough) price, instant savings, and the lowest used price B\&H offers for the item.
- 📦 **Stock status** — a simple `in_stock` flag, a normalized availability value (in stock, out of stock, pre-order, special order, discontinued), and the exact text B\&H shows.
- ⭐ **Ratings and reviews** — average star rating and review count.
- 🧾 **Identifiers** — B\&H SKU, B\&H # (`bhId`), and manufacturer part number (MFR #) for matching products across stores.
- 🖼️ **Images and key features** — main image, gallery images, and the "Key Features" bullet list from the listing.
- 📄 **Page control** — choose how many pages to read per URL (up to 200) and start from any page by pasting a URL that already has `/pn/N`.

Because B\&H Photo Scraper runs on the Apify platform, you also get:

- ⏰ [Scheduling](https://docs.apify.com/platform/schedules) to track B\&H prices and stock daily or weekly.
- 🔌 [API access](https://docs.apify.com/api/v2) and client libraries for Python and JavaScript.
- 🔗 [Integrations](https://apify.com/integrations) with Make, Zapier, Google Sheets, Slack, webhooks, and more.
- 📦 Export to JSON, CSV, Excel, XML, or HTML from the Storage tab or the API.

### What data can you extract from B\&H Photo?

| Field | Description |
|-------|-------------|
| `name` | Product title as shown on B\&H |
| `brand` | Brand name |
| `price` | Current price in USD |
| `original_price` | Regular price shown struck through, when the item is on sale |
| `price_in_cart` | `true` when B\&H shows a grayed-out price with "Add to Cart for Price"; `price` is then the advertised price |
| `savings` | Instant savings amount |
| `currency` | Currency code (`USD`) |
| `category` | Listing category name (on search pages, the product's own category) |
| `category_path` | B\&H category breadcrumb for the product: `id`, `name`, `url` |
| `in_stock` | `true` when B\&H shows the item as In Stock |
| `stock_availability` | `in_stock`, `out_of_stock`, `pre_order`, `special_order`, `backordered`, `discontinued`, or `other` |
| `stock_status_text` | Stock text exactly as B\&H shows it, e.g. "New Item - Coming Soon" |
| `rating` / `reviews` | Average rating (out of 5) and number of reviews |
| `featured_image` / `images` | Main image and all gallery images (500×500) |
| `description_text` / `key_features` | Key Features bullets, joined and as a list |
| `url` | Product page URL |
| `sku` / `bhId` / `mpn` | B\&H SKU number, B\&H # and manufacturer part number |
| `condition` | `new`, `used`, `refurbished`, or `open_box` |
| `used_price` | Lowest used price B\&H offers for this item, if any |
| `badge` | Listing badge such as `TOP_SELLER` |
| `search_query` | Search term, for rows from a search results page |
| `source_url` / `page` / `position` | The URL you pasted, the listing page number, and the row's position in the run |

### How to scrape B\&H Photo

1. Open [B\&H Photo Scraper](https://apify.com/parsebird/bh-photo-scraper) in Apify Console and sign in (or create a free Apify account).
2. On [bhphotovideo.com](https://www.bhphotovideo.com/), open the category, brand, or search page you want. Apply any filters and sort order you like.
3. Copy the URL from your browser and paste it into **B\&H Photo URLs**. Add as many URLs as you need.
4. Set **Max products** (total for the run) and **Max pages per URL**.
5. Click **Start** and wait for the run to finish.
6. Open the **Output** tab and download the products as JSON, CSV, Excel, XML, or HTML, or read them through the API.

### How much does it cost to scrape B\&H Photo?

B\&H Photo Scraper uses pay-per-event pricing. You pay only for the products saved to your dataset. Compute and proxy usage are included in the event price, so there is no separate usage bill.

| Event | Apify plan | Price per product | Price per 1,000 products |
|-------|-----------|-------------------|--------------------------|
| `product-scraped` | Free | $0.00099 | **$0.99** |
| `product-scraped` | Bronze | $0.00089 | **$0.89** |
| `product-scraped` | Silver and Gold | $0.00079 | **$0.79** |

One event is one product saved to the dataset. For example, a full B\&H category of 1,442 digital cameras (52 pages) costs about $1.43 on the Free plan. Apify's free plan includes monthly platform credits, which you can use for this scraper. Set a spending limit on the run and the scraper stops when it is reached.

### Input example

```json
{
    "startUrls": [
        { "url": "https://www.bhphotovideo.com/c/buy/Digital-Cameras/ci/9811" },
        { "url": "https://www.bhphotovideo.com/c/buy/Mirrorless-Lenses/ci/17912" },
        { "url": "https://www.bhphotovideo.com/c/search?q=video%20monitor&sts=ma" }
    ],
    "results_wanted": 100,
    "max_pages": 5
}
```

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `startUrls` | array | No | Digital Cameras category | B\&H category, brand, filtered, or search results URLs as `{ "url": "..." }` objects |
| `results_wanted` | integer | No | 20 | Max products saved in total. Use 0 or a negative value for no limit |
| `max_pages` | integer | No | 3 | Max listing pages per URL, from 1 to 200 (28 products per page) |
| `proxyConfiguration` | object | No | Automatic | Optional. The scraper connects through Apify Proxy by itself; set one only to force a specific proxy |

URLs are processed in order, and `results_wanted` counts across all of them. With `results_wanted: 100` and a first URL that has more than 100 products, the run stops before it reaches the second URL. Set `results_wanted` to 0 and use `max_pages` when you want a fixed number of pages from each URL.

### Output example

```json
{
    "name": "Canon PowerShot ELPH 360 HS A Digital Camera (Black)",
    "brand": "Canon",
    "price": 379,
    "original_price": null,
    "price_in_cart": false,
    "savings": null,
    "currency": "USD",
    "category": "Digital Cameras",
    "category_path": [
        { "id": 989, "name": "Photography", "url": "https://www.bhphotovideo.com/c/browse/Photography/ci/989/N/4294538916" },
        { "id": 9811, "name": "Digital Cameras", "url": "https://www.bhphotovideo.com/c/buy/Digital-Cameras/ci/9811/N/4288586282" },
        { "id": 8612, "name": "Point & Shoot Cameras", "url": "https://www.bhphotovideo.com/c/buy/Point-Shoot-Cameras/ci/8612/N/4288586279" }
    ],
    "in_stock": true,
    "stock_availability": "in_stock",
    "stock_status_text": "In Stock",
    "reviews": 134,
    "rating": 4.8,
    "featured_image": "https://static.bhphoto.com/images/images500x500/canon_7280c001_powershot_elph_360_hs_1757407699_1919557.jpg",
    "images": [
        "https://static.bhphoto.com/images/images500x500/canon_7280c001_powershot_elph_360_hs_1757407699_1919557.jpg",
        "https://static.bhphoto.com/images/multiple_images/images500x500/1757408018_IMG_2569575.jpg"
    ],
    "description_text": "20.2MP 1/2.3\" CMOS Image Sensor; DIGIC 4+ Image Processor; 12x Optical Zoom Lens; 25-300mm (35mm Equivalent)",
    "key_features": [
        "20.2MP 1/2.3\" CMOS Image Sensor",
        "DIGIC 4+ Image Processor",
        "12x Optical Zoom Lens",
        "25-300mm (35mm Equivalent)"
    ],
    "url": "https://www.bhphotovideo.com/c/product/1919557-REG/canon_7280c001_powershot_elph_360_hs.html",
    "sku": 1919557,
    "bhId": "CAPS360B",
    "mpn": "7280C001",
    "condition": "new",
    "badge": "TOP_SELLER",
    "used_price": 359.95,
    "is_new_arrival": false,
    "is_bh_exclusive": false,
    "short_url": "https://bhpho.to/3VHjcoo",
    "_source": "bhphotovideo.com",
    "search_query": null,
    "source_url": "https://www.bhphotovideo.com/c/buy/Digital-Cameras/ci/9811/N/4288586282",
    "page": 1,
    "position": 4,
    "scraped_at": "2026-10-11T00:23:39+00:00"
}
```

The output example is shortened (the real row has all gallery images and every key feature). Download results in JSON, CSV, Excel, XML, or HTML.

### Use cases

- **Price monitoring** — schedule a daily run on the categories you sell in and track B\&H prices, sale prices, and instant savings over time.
- **Competitor research** — compare your catalog and prices with B\&H by brand, MPN, or category.
- **Stock tracking** — watch new releases move from "New Item - Coming Soon" to In Stock.
- **Product catalogs** — build lists of cameras, lenses, or audio gear with images, key features, and manufacturer part numbers.
- **Market analysis** — count products per brand in a category, or see which items carry the most reviews and the best ratings.

### Use the B\&H Photo Scraper API

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("parsebird/bh-photo-scraper").call(run_input={
    "startUrls": [{"url": "https://www.bhphotovideo.com/c/buy/Mirrorless-Lenses/ci/17912"}],
    "results_wanted": 0,
    "max_pages": 10,
})
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
    if product["original_price"]:
        print(product["brand"], product["name"], product["original_price"], "->", product["price"])
```

**JavaScript**

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('parsebird/bh-photo-scraper').call({
    startUrls: [{ url: 'https://www.bhphotovideo.com/c/search?q=video%20monitor&sts=ma' }],
    results_wanted: 200,
    max_pages: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const inStock = items.filter((p) => p.in_stock);
console.log(`${inStock.length} of ${items.length} monitors are in stock`);
```

See the [API tab](https://apify.com/parsebird/bh-photo-scraper/api) for all endpoints and the [Apify API client docs](https://docs.apify.com/api/client/python) for more options.

### How it works

1. B\&H Photo Scraper opens each URL you paste and reads the product list B\&H includes in the page.
2. Category and brand landing pages without a product list are expanded into their subcategories.
3. It reads the total product count, then pages through the listing (28 products per page) until it reaches `max_pages`, the last page, or `results_wanted`.
4. Products are cleaned into one flat row each. Duplicates (the same product found on two URLs) are saved only once.
5. B\&H is protected by Cloudflare. The scraper connects through Apify Proxy, retries refused requests on a fresh IP, and moves to residential IPs if B\&H keeps refusing.

### Is it legal to scrape B\&H Photo?

B\&H Photo Scraper only reads product listings that B\&H shows publicly to logged-out visitors. It does not log in, add items to a cart, or collect any personal data. Product images and descriptions belong to B\&H and the manufacturers, so check your rights before you republish them. Make sure your use complies with B\&H's terms, data protection laws, and any other rules that apply to you, and consult a lawyer if in doubt. Read more in Apify's post [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

### Other e-commerce scrapers

- [Amazon Search Scraper](https://apify.com/parsebird/amazon-search-scraper) — Amazon search results with prices, ratings, and badges in 18 marketplaces.
- [Walmart Product Scraper](https://apify.com/parsebird/walmart-product-scraper) — Walmart product details and prices.
- [Target Product Scraper](https://apify.com/parsebird/target-product-scraper) — Target.com listings with TCIN, brand, price, and ratings.
- [Wayfair Scraper](https://apify.com/parsebird/wayfair-scraper) — Wayfair products, prices, and ratings in the US, CA, UK, and IE.
- [GSMArena Phone Specs Scraper](https://apify.com/parsebird/gsmarena-phone-specs-scraper) — full phone specifications from GSMArena.

### FAQ

**Do I need a B\&H account?**
No. B\&H Photo Scraper reads public listings without logging in.

**Which URLs can I paste?**
Category pages (`/c/buy/...`), filtered or sorted category pages (`/c/products/...?filters=...&sort=...`), search results (`/c/search?q=...`), and category or brand landing pages (`/c/browse/...`), which are expanded into their subcategories. Single product pages (`/c/product/...`) are not supported.

**How many products are on one page?**
B\&H shows 28 products per listing page, fewer on the last page. With `max_pages: 3` you get up to 84 products per URL. When a URL is a landing page that gets expanded into subcategories, `max_pages` applies to each subcategory, so use `results_wanted` to cap the total.

**Why do some products show `price_in_cart: true`?**
For some items, manufacturers don't allow the final price to be advertised. B\&H then shows a grayed-out price with "Add to Cart for Price" or "Tell Me More". The scraper saves that displayed price in `price` and sets `price_in_cart` to `true`, because the price in the cart can be lower.

**Why did my search return products from categories?**
B\&H sends some searches straight to a category. For example, a search for `lens` opens the Lenses landing page, so the scraper collects products from its subcategories. In that case `search_query` is empty and `category` shows the subcategory.

**Why is `category_path` empty for search results?**
B\&H's search results don't include the category breadcrumb for each product. Category and brand pages do. `category` is also empty for search rows.

**What does `in_stock` mean?**
`in_stock` is `true` only when B\&H shows "In Stock". Items that are temporarily out of stock, on pre-order ("New Item - Coming Soon"), special order, or discontinued are `false`. `stock_status_text` keeps B\&H's exact wording.

**Are prices in US dollars?**
Yes. B\&H lists prices in USD, and `currency` is always `USD`.

**Why is `mpn` empty for some products?**
B\&H kits and bundles (for example a camera with a lens and accessories) often have no manufacturer part number. The scraper leaves the field empty instead of guessing.

**Do I need a proxy?**
No. B\&H is protected by Cloudflare, so B\&H Photo Scraper connects through Apify Proxy by itself and moves to residential IPs when B\&H refuses requests. Proxy costs are included in the price per product. Set a proxy only if you want to force one for every request, for example Residential with country US.

**Can I schedule runs or connect the results to other tools?**
Yes. Use [Apify schedules](https://docs.apify.com/platform/schedules) for recurring runs and [integrations](https://apify.com/integrations) to send results to Google Sheets, Slack, Zapier, Make, or a webhook. Results are also available through the [API](https://apify.com/parsebird/bh-photo-scraper/api).

**Something doesn't work. What should I do?**
Open an issue on the [Issues tab](https://apify.com/parsebird/bh-photo-scraper/issues) with your input and run link.

# Changelog

This Actor's version history is a separate document: https://apify.com/parsebird/bh-photo-scraper/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

Paste B\&H category, brand, or search results URLs copied from your browser, e.g. <code>https://www.bhphotovideo.com/c/buy/Digital-Cameras/ci/9811</code> or <code>https://www.bhphotovideo.com/c/search?q=video%20monitor</code>. Filters and sort order in the URL are kept. Category landing pages (/c/browse/...) are expanded into their subcategories. Single product pages are not supported.

## `results_wanted` (type: `integer`):

Stop after saving this many products in total across all URLs. Set 0 for no limit (then <b>Max pages per URL</b> decides when to stop).

## `max_pages` (type: `integer`):

Read at most this many listing pages for each URL. B\&H shows 28 products per page (fewer on the last page). Allowed range: 1 to 200.

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

You don't need to set a proxy. The scraper connects through Apify Proxy on its own and moves to residential IPs if B\&H refuses requests. Set a proxy here only if you want to force one, e.g. Residential with country US.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.bhphotovideo.com/c/buy/Digital-Cameras/ci/9811/N/4288586282"
    }
  ],
  "results_wanted": 20,
  "max_pages": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# 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 = {
    "startUrls": [
        {
            "url": "https://www.bhphotovideo.com/c/buy/Digital-Cameras/ci/9811/N/4288586282"
        }
    ],
    "results_wanted": 20,
    "max_pages": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/bh-photo-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 = {
    "startUrls": [{ "url": "https://www.bhphotovideo.com/c/buy/Digital-Cameras/ci/9811/N/4288586282" }],
    "results_wanted": 20,
    "max_pages": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/bh-photo-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.bhphotovideo.com/c/buy/Digital-Cameras/ci/9811/N/4288586282"
    }
  ],
  "results_wanted": 20,
  "max_pages": 3
}' |
apify call parsebird/bh-photo-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/bh-photo-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

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