# Wholesale Marine Scraper (`crawlerbros/wholesale-marine-scraper`) Actor

Scrape Wholesale Marine (wholesalemarine.com) - boat parts, propellers, covers, electronics, trailer parts, and outdoor gear. Search the full catalog by keyword, browse by category or brand, or fetch full product detail (price, SKU, brand, stock, images, description) from a direct product URL.

- **URL**: https://apify.com/crawlerbros/wholesale-marine-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** E-commerce, Automation, Integrations
- **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

## Wholesale Marine Scraper

Scrape [Wholesale Marine](https://www.wholesalemarine.com) — a large online retailer of boat parts, marine electronics, trailer parts, watersports gear, and outdoor equipment. Search the entire catalog by keyword, browse any product category or brand, or pull rich product detail (price, SKU, brand, stock status, images, full description) straight from a product page URL.

No login, no API key, and no cookies are required — every mode works out of the box.

### What this actor does

- **Keyword search** — full-text product search across the entire catalog, just like the site's own search box.
- **Category browse** — walk any of 200+ product categories (propellers, bimini tops, boat covers, engine parts, thermostats, solenoids, fuel filters, carburetor kits, and more) from the newest to the best-selling item.
- **Brand browse** — pull every product from a specific brand (Yamaha, Mercury Mercruiser, Garmin, Attwood, Jabsco, TACO Marine, and 60+ others).
- **Direct product URL** — feed in one or more exact product page URLs and get back the full product detail record (SKU, UPC/MPN, brand, stock quantity, gallery images, category breadcrumbs, and cleaned description).
- **Sorting** — apply the site's own sort orders (featured, newest, best selling, price low→high, price high→low, name A→Z / Z→A) to any listing mode.
- **Price filtering** — drop products outside a min/max USD price range.
- **Stock filtering** — restrict to in-stock products (only meaningful on `direct_product_url`, since listing pages don't expose per-item stock status).
- **Ratings & reviews** — average customer rating, total review count, and star breakdown for every product that has any (fetched from the store's own review widget; toggle off with `includeRatings` if not needed).
- Every output field is only included when real data is available — no placeholder or "N/A" values.

### Output per product

| Field | Type | Present on | Description |
|---|---|---|---|
| `productId` | string | all | Internal numeric product ID |
| `title` | string | all | Product name |
| `brand` | string | brand\_browse, direct\_product\_url | Manufacturer/brand name |
| `brandUrl` | string (URL) | direct\_product\_url | Link to the brand's page on the site |
| `sku` | string | direct\_product\_url | Manufacturer/vendor SKU |
| `upc` | string | direct\_product\_url | UPC barcode, when a valid one is published |
| `mpn` | string | direct\_product\_url | Manufacturer part number |
| `gtin` | string | direct\_product\_url | Global Trade Item Number, when valid |
| `price` | number | all | Current selling price (USD) |
| `priceFormatted` | string | all | Price formatted as `$X,XXX.XX` |
| `listPrice` | number | when on sale | Original / list price (USD), only when higher than the current price |
| `listPriceFormatted` | string | when on sale | List price formatted |
| `discountAmount` | number | when on sale | `listPrice - price` |
| `discountPercent` | number | when on sale | Discount percentage |
| `currency` | string | all | Always `USD` |
| `inStock` | boolean | direct\_product\_url | Whether the item is currently purchasable |
| `stockQuantity` | integer | direct\_product\_url (when published) | Units currently on hand |
| `description` | string | all | Product blurb (listing) or full cleaned description (detail) |
| `imageUrl` | string (URL) | listing modes | Listing thumbnail image |
| `images` | array of strings (URL) | direct\_product\_url | Full-resolution gallery images |
| `primaryImage` | string (URL) | direct\_product\_url | First/main gallery image |
| `categoryPath` | array of strings | direct\_product\_url | Breadcrumb trail (e.g. `["Engine & Fuel", "Boat Propellers"]`) |
| `categorySlug` | string | category\_browse | The category slug used for this run |
| `variantOptions` | array of objects | direct\_product\_url (when the product has purchase options) | Purchasable options such as Size or Color, e.g. `{"name": "Size", "required": true, "values": ["S", "M", "L"]}`. Color options rendered as unlabeled swatches (no text value on the page) are not included. |
| `specifications` | object | direct\_product\_url (when the product page publishes attribute specs) | Key/value technical specs straight from the product page's own spec block — the exact keys vary by category (e.g. `Material`, `Voltage`, `Style`, `Warranty Length`, `USCG Rating`, `Supplier Number`, `Fast Ship`). Values already captured as `sku`/`mpn`/`upc` are not duplicated here. |
| `ratingValue` | number | when the product has reviews | Average customer star rating (1–5) |
| `reviewCount` | integer | when the product has reviews | Total number of customer reviews |
| `ratingDistribution` | object | when the product has reviews | Review count per star, e.g. `{"1": 2, "2": 1, "3": 0, "4": 4, "5": 57}` |
| `productUrl` | string (URL) | all | Canonical product page URL |
| `recordType` | string | all | Always `product` |
| `scrapedAt` | string (ISO 8601) | all | UTC timestamp of when the record was scraped |

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | select | `keyword_search` | `keyword_search` / `category_browse` / `brand_browse` / `direct_product_url` |
| `searchQuery` | string | `propeller` | Free-text query (mode=keyword\_search) |
| `categoryPath` | select | – | Category to browse (mode=category\_browse) — 200+ curated options |
| `customCategoryPath` | string | – | Any category URL slug not in the dropdown (overrides `categoryPath`) |
| `brandSlug` | select | – | Brand to browse (mode=brand\_browse) — 60+ curated options |
| `customBrandSlug` | string | – | Any brand URL slug not in the dropdown (overrides `brandSlug`) |
| `productUrls` | array of strings | – | Product page URLs to scrape (mode=direct\_product\_url) |
| `sortOrder` | select | `bestselling` | `featured` / `newest` / `bestselling` / `alphaasc` / `alphadesc` / `priceasc` / `pricedesc` |
| `minPrice` | integer | – | Drop products priced below this (USD) |
| `maxPrice` | integer | – | Drop products priced above this (USD) |
| `inStockOnly` | boolean | `false` | Only emit in-stock products (direct\_product\_url only) |
| `includeRatings` | boolean | `true` | Fetch each product's rating/review count (adds one request per product) |
| `maxItems` | integer | `20` | Hard cap on emitted records (1–1000) |

#### Example: keyword search sorted by price

```json
{
  "mode": "keyword_search",
  "searchQuery": "bilge pump",
  "sortOrder": "priceasc",
  "maxItems": 50
}
```

#### Example: browse a category

```json
{
  "mode": "category_browse",
  "categoryPath": "boat-propellers",
  "sortOrder": "bestselling",
  "minPrice": 50,
  "maxPrice": 300,
  "maxItems": 100
}
```

#### Example: browse a brand not in the dropdown

```json
{
  "mode": "brand_browse",
  "customBrandSlug": "CE-Smith",
  "sortOrder": "alphaasc",
  "maxItems": 50
}
```

#### Example: full detail for specific products

```json
{
  "mode": "direct_product_url",
  "productUrls": [
    "https://www.wholesalemarine.com/turning-point-hustler-3-blade-9x-9p-propeller-2111-0910/"
  ],
  "inStockOnly": true
}
```

### Use cases

- **Dropshipping & e-commerce** — sync live prices, stock status, and images from Wholesale Marine to your own storefront.
- **Price monitoring** — track price changes and discounts across an entire category or brand over time.
- **Competitor research** — compare marine parts pricing and catalog breadth against other retailers.
- **Marketplace listing enrichment** — pull SKUs, UPCs/MPNs, specs, and gallery images to populate marketplace listings.
- **Review/reputation analysis** — aggregate rating distributions across a brand or category to spot standout products.
- **Boat parts sourcing** — find every product from a specific brand or category without manually browsing the site.

### FAQ

**Is this affiliated with Wholesale Marine?** No, this is a third-party actor using the publicly accessible wholesalemarine.com website. It is not affiliated with, endorsed by, or sponsored by Wholesale Marine.

**Do I need a proxy or login?** No. All modes work with the default Apify datacenter proxy group, and no account or cookies are required.

**What's the difference between the listing modes and `direct_product_url`?** `keyword_search`, `category_browse`, and `brand_browse` read the fast listing-page cards (title, price, thumbnail, short blurb). `direct_product_url` fetches the full product page for maximum detail — SKU, UPC/MPN, stock quantity, full gallery, and category breadcrumbs — but costs one request per product URL.

**Can I browse a category or brand that isn't in the dropdown?** Yes — use `customCategoryPath` or `customBrandSlug` with the exact URL slug from the site (e.g. the part between `wholesalemarine.com/` and the trailing slash for categories, or between `/brands/` and `.html` for brands).

**Why is `stockQuantity` sometimes missing even in `direct_product_url` mode?** Some products don't publish exact on-hand quantities on their page; only `inStock` (true/false) is guaranteed when the site exposes availability at all.

**Why don't listing modes include stock status?** Wholesale Marine's category/search/brand listing pages don't render a stock indicator on the product card — only the full product page does. Use `direct_product_url` if you need to filter by `inStockOnly`.

**How current are the prices?** Prices are scraped live on every run, straight from the page the actor requests.

**Where do ratings come from?** The store's on-page review widget renders client-side via JavaScript, but its data comes from a public review-summary endpoint that the actor queries directly (one extra request per product) so `ratingValue`, `reviewCount`, and `ratingDistribution` reflect the same real numbers shown on the site. Products with zero reviews simply omit these fields rather than show a fake `0`.

### Limitations

- Stock quantity and in-stock status are only available in `direct_product_url` mode.
- The `categoryPath` and `brandSlug` dropdowns cover the site's full stable taxonomy at the time of writing; use the corresponding `custom*` field for anything newer.
- `variantOptions` only lists dropdown-style options (e.g. Size). Color options rendered as visual swatches with no text label on the page cannot be reported as real values, so they're omitted rather than guessed.

# Actor input Schema

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

What to fetch.

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

Free-text query, e.g. `propeller`, `bimini top`, `bilge pump`.

## `categoryPath` (type: `string`):

Pick a product category to browse. Use `customCategoryPath` instead for a category not listed here.

## `customCategoryPath` (type: `string`):

Override `categoryPath` with any wholesalemarine.com category URL slug not in the dropdown, e.g. `mercury-outboard-parts`. Takes priority over `categoryPath` when set.

## `brandSlug` (type: `string`):

Pick a brand to browse. Use `customBrandSlug` instead for a brand not listed here.

## `customBrandSlug` (type: `string`):

Override `brandSlug` with any wholesalemarine.com brand URL slug not in the dropdown, e.g. `Suzuki-Marine`. Takes priority over `brandSlug` when set. Find the exact slug from a brand page URL: wholesalemarine.com/brands/<slug>.html

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

One or more wholesalemarine.com product page URLs to scrape in full detail.

## `sortOrder` (type: `string`):

Sort order applied to listing pages (mode=keyword\_search / category\_browse / brand\_browse). Ignored for direct\_product\_url.

## `minPrice` (type: `integer`):

Drop products priced below this amount.

## `maxPrice` (type: `integer`):

Drop products priced above this amount.

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

Only emit products currently in stock (mode=direct\_product\_url only; listing pages don't expose stock status).

## `includeRatings` (type: `boolean`):

Fetch each product's customer rating (average score, review count, star breakdown) from the store's review widget. Adds one extra request per product, so disable it for faster runs if ratings aren't needed.

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

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "keyword_search",
  "searchQuery": "propeller",
  "productUrls": [],
  "sortOrder": "bestselling",
  "inStockOnly": false,
  "includeRatings": true,
  "maxItems": 20
}
```

# Actor output Schema

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

Dataset containing all scraped Wholesale Marine 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": "keyword_search",
    "searchQuery": "propeller",
    "productUrls": [],
    "sortOrder": "bestselling",
    "inStockOnly": false,
    "includeRatings": true,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/wholesale-marine-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": "keyword_search",
    "searchQuery": "propeller",
    "productUrls": [],
    "sortOrder": "bestselling",
    "inStockOnly": False,
    "includeRatings": True,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/wholesale-marine-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": "keyword_search",
  "searchQuery": "propeller",
  "productUrls": [],
  "sortOrder": "bestselling",
  "inStockOnly": false,
  "includeRatings": true,
  "maxItems": 20
}' |
apify call crawlerbros/wholesale-marine-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

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