# Musician's Friend Scraper (`crawlerbros/musiciansfriend-scraper`) Actor

Scrape Musician's Friend - instruments, guitars, keyboards, drums, pro audio, and DJ gear. Browse any category or brand hub, run keyword search, or fetch full product detail (variants, pricing, reviews) by URL. No auth, no proxy required.

- **URL**: https://apify.com/crawlerbros/musiciansfriend-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

## Musician's Friend Scraper

Scrape **Musician's Friend** (musiciansfriend.com) — guitars, bass, keyboards, drums & percussion, pro audio, recording gear, DJ gear, and more. Browse any of 90+ categories and brand hubs, run a keyword search, or fetch full product detail (per-variant pricing, availability, and customer reviews) directly by URL. HTTP-only, no login, no proxy required.

### What this actor does

- **Three modes:** `category` (browse a category or brand hub), `search` (keyword search), `byUrl` (fetch full detail for specific product URLs)
- **90+ curated categories & brand hubs** — guitars, bass, keyboards, drums, pro audio, DJ gear, deals, and brand pages like Fender Stratocaster or Gibson Les Paul — plus a free-text override for any other valid category slug
- **Sort control** — Best Match, Best Sellers, Relevance, Customer Ratings, Price (both directions), Newest First, Brand Name A-Z
- **Filters** — min/max starting price, brand name, on-sale-only, minimum customer star rating, and stock condition (New / Used / Open Box / Restock)
- **Optional full-detail enrichment** — turn on `includeFullDetails` to fetch each product's page for long-form description, per-variant pricing/availability/condition, full technical specifications, feature highlights, and a sample of customer reviews
- **Empty fields are omitted** — every record only contains fields Musician's Friend actually populated for that product

### Output per product

Every product includes, when available:

- `productId`, `skuId` — internal identifiers
- `title`, `brandName`, `description`
- `productUrl`, `sourceUrl` — canonical product page
- `imageUrl` — product photo (CDN-hosted)
- `priceLow`, `priceHigh` — starting price range across variants
- `onSale`, `promoLabel` — sale flag and promo badge text (e.g. "Closeout Deal")
- `isUsedOnlyListing` — true when the listing is used-only stock
- `totalReviews`, `overallRating` — from the category/search listing
- `usedItemCount`, `startingUsedPrice` — when used units are available alongside new
- `restockItemCount`, `startingRestockPrice` — when backorder/restock units are available
- `maxSaving`, `maxSavingPercent`, `maxSavingMSRP` — sale-savings context, when the item is discounted
- `category` — the category/brand-hub slug used for the fetch (mode=category only)
- `recordType: "product"`, `scrapedAt`

When `includeFullDetails` is enabled (or always for `mode=byUrl`), the record is additionally enriched with:

- `fullDescription` — long-form product description
- `categoryPath` — breadcrumb trail (e.g. `["Guitars", "Electric Guitars"]`)
- `modelId`, `gtin`, `sku` — model / catalog identifiers
- `brandLogoUrl`
- `variesBy` — which attribute the variants differ by (e.g. `color`)
- `variants[]` — per-variant `variantLabel`, `price`, `currency`, `inStock`, `condition`, `gtin`, `variantUrl`, `image`
- `images[]` — one image per variant
- `rating`, `reviewCount` — from the product's own rating data (falls back to an average of sampled reviews when the site doesn't expose an aggregate)
- `reviews[]` — up to 5 sampled customer reviews (`author`, `title`, `body`, `rating`, `location`, `datePublished`)
- `specifications` — full technical spec sheet grouped by section (e.g. Body, Neck, Fingerboard, Electronics, Hardware), each section a set of spec-name → value pairs (e.g. `Body wood: Mahogany`, `Scale length: 25"`)
- `features[]` — the product page's bullet-point feature highlights

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `category` | `category` / `search` / `byUrl` |
| `categorySlug` | string | `guitars` | Curated category/brand-hub slug (mode=category) |
| `customCategory` | string | – | Any other valid category slug; overrides `categorySlug` (mode=category) |
| `searchQuery` | string | `electric guitar` | Free-text keyword search (mode=search) |
| `productUrls` | array | – | Direct product URLs to fetch full detail for (mode=byUrl) |
| `sortBy` | string | `bestMatch` | Sort order (mode=category/search) |
| `minPrice` | integer | – | Drop products priced below this |
| `maxPrice` | integer | – | Drop products priced above this |
| `brandName` | string | – | Keep only products whose brand contains this text |
| `onSaleOnly` | boolean | `false` | Keep only on-sale products |
| `condition` | string | `any` | Stock condition: `any` / `new` / `used` / `openBox` / `restock` (mode=category only) |
| `minRating` | string | – | Keep only products with an average customer rating at or above this many stars (1–5) |
| `includeFullDetails` | boolean | `false` | Fetch each product's detail page for description, variants, and reviews |
| `maxItems` | integer | `60` | Hard cap on emitted products (1–2000) |
| `proxyConfiguration` | object | off | Optional Apify proxy (AUTO group). Not needed in normal operation |

#### Example: browse a category

```json
{
  "mode": "category",
  "categorySlug": "electric-guitars",
  "sortBy": "priceLowToHigh",
  "maxItems": 100
}
```

#### Example: search with filters

```json
{
  "mode": "search",
  "searchQuery": "usb audio interface",
  "minPrice": 100,
  "maxPrice": 400,
  "onSaleOnly": true,
  "maxItems": 50
}
```

#### Example: browse a brand hub with full detail

```json
{
  "mode": "category",
  "categorySlug": "fender-stratocaster",
  "includeFullDetails": true,
  "maxItems": 20
}
```

#### Example: new-condition, highly-rated products only

```json
{
  "mode": "category",
  "categorySlug": "electric-guitars",
  "condition": "new",
  "minRating": "4",
  "maxItems": 50
}
```

#### Example: used gear with full specs and reviews

```json
{
  "mode": "category",
  "categorySlug": "bass",
  "condition": "used",
  "includeFullDetails": true,
  "maxItems": 20
}
```

#### Example: fetch specific products by URL

```json
{
  "mode": "byUrl",
  "productUrls": [
    "https://www.musiciansfriend.com/guitars/prs-se-studio-standard-electric-guitar/m19477",
    "https://www.musiciansfriend.com/accessories/daddario-exl110-12p-nickel-wound-light-electric-guitar-string-12-pack"
  ]
}
```

#### Example: category slug not in the curated list

```json
{
  "mode": "category",
  "customCategory": "boss-katana",
  "maxItems": 30
}
```

### Use cases

- **Price monitoring** — track pricing and sale status across a category or specific brand hub over time
- **Market research** — analyze brand and pricing distribution across instrument categories
- **Product feed building** — pull structured catalog data for comparison shopping or affiliate sites
- **Deal discovery** — filter `used-gear`, `clearance`, `open-box-musical-instruments`, or `demo-gear-sale` for discounted gear
- **Review analysis** — sample customer reviews and ratings per product with `includeFullDetails`
- **Competitive intelligence** — compare musical instrument retail pricing against other marketplaces

### FAQ

**What data source does this actor use?**
The public musiciansfriend.com website. No login or API key is required.

**Is this affiliated with Musician's Friend?**
No. This is an independent, third-party actor that reads publicly available product pages.

**Why did my `customCategory` return 0 results?**
The slug must exactly match a real Musician's Friend category or brand-hub path segment (the part of the URL after `musiciansfriend.com/`), e.g. `taylor-114ce`. An invalid slug returns 0 products with a status message rather than failing.

**Why doesn't `sortBy` seem to change my search results?**
When a search query closely matches an existing category or brand name (e.g. `"fender stratocaster"`), Musician's Friend internally redirects the search to that category's own listing page, which always opens in its default "Best Match" order — this is upstream site behavior, not an actor bug. Use `mode=category` with the matching `categorySlug`/`customCategory` for guaranteed sort control.

**Why are some fields missing on some products?**
Only fields Musician's Friend actually populated for that product are included — empty/null fields are always omitted rather than sent as blank values. For example, `usedItemCount` only appears when used units are actually available for that listing.

**How fresh is the data?**
Every run scrapes live pages at request time — pricing, sale status, and stock reflect the current state of musiciansfriend.com.

**Does `includeFullDetails` slow things down?**
Yes — it adds one extra request per product to fetch the detail page. Leave it off for fast catalog scans; turn it on when you need descriptions, per-variant availability, specifications, or reviews.

**Does `condition` work with `mode=search`?**
No — the Condition filter (`new`/`used`/`openBox`/`restock`) only applies to `mode=category`, since it relies on Musician's Friend's own category-page filtering. For search results, use `mode=category` with the matching category slug instead, or filter afterwards using the `isUsedOnlyListing` output field.

**How does `minRating` work when a product has no reviews yet?**
Products with no rating data always pass through unaffected — the filter only ever excludes products that have a rating below your threshold, never products with missing rating data.

**Why do `minPrice`/`maxPrice` sometimes return products with no visible price?**
A small number of listings (open-box items, "call for price" items) don't expose a numeric starting price at all. Price filters only exclude products that actually have a price outside your range — a product with no listed price always passes through rather than being silently dropped, so you don't lose otherwise-relevant results.

**Is a proxy required?**
No. The actor works reliably without one. The optional `proxyConfiguration` input is available as a fallback and uses only the free Apify AUTO datacenter group.

# Actor input Schema

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

What to fetch.

## `categorySlug` (type: `string`):

Curated list of the most popular categories and brand hubs. For anything not listed, use `customCategory` below.

## `customCategory` (type: `string`):

Any valid musiciansfriend.com category or brand-hub slug not in the dropdown above, e.g. `taylor-114ce`, `boss-katana`. Takes precedence over `categorySlug` when set.

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

Free-text keyword search, e.g. `fender stratocaster` or `usb audio interface`.

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

Direct musiciansfriend.com product URLs to fetch full detail for (variants, pricing, reviews).

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

Sort order applied to the listing. Note: when a search query exactly matches a category or brand name, Musician's Friend redirects to that category's own listing and this setting may not apply — use `mode=category` instead for guaranteed sort control.

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

Drop products whose starting price is below this amount.

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

Drop products whose starting price is above this amount.

## `brandName` (type: `string`):

Only keep products whose brand contains this text (case-insensitive), e.g. `Fender`.

## `onSaleOnly` (type: `boolean`):

Only keep products currently marked on sale.

## `condition` (type: `string`):

Filter a category or brand hub listing to a single stock condition, using Musician's Friend's own Condition facet. Only applies to mode=category; mode=search does not support this filter.

## `minRating` (type: `string`):

Only keep products with an average customer rating at or above this many stars. Products with no rating data yet always pass through.

## `includeFullDetails` (type: `boolean`):

For mode=category/search, fetch each product's detail page for full description, per-variant pricing/availability, and sample reviews. Slower (one extra request per product) but much richer output. Always on for mode=byUrl.

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

Hard cap on the number of products emitted.

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

Not required in normal operation (the actor uses a browser-impersonating HTTP client that works without a proxy). Enable the free Apify AUTO proxy group only if you start seeing non-200 responses.

## Actor input object example

```json
{
  "mode": "category",
  "categorySlug": "guitars",
  "searchQuery": "electric guitar",
  "productUrls": [],
  "sortBy": "bestMatch",
  "onSaleOnly": false,
  "condition": "any",
  "includeFullDetails": false,
  "maxItems": 15,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Dataset containing all scraped Musician's Friend 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": "category",
    "categorySlug": "guitars",
    "searchQuery": "electric guitar",
    "productUrls": [],
    "sortBy": "bestMatch",
    "onSaleOnly": false,
    "condition": "any",
    "includeFullDetails": false,
    "maxItems": 15,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/musiciansfriend-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": "category",
    "categorySlug": "guitars",
    "searchQuery": "electric guitar",
    "productUrls": [],
    "sortBy": "bestMatch",
    "onSaleOnly": False,
    "condition": "any",
    "includeFullDetails": False,
    "maxItems": 15,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/musiciansfriend-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": "category",
  "categorySlug": "guitars",
  "searchQuery": "electric guitar",
  "productUrls": [],
  "sortBy": "bestMatch",
  "onSaleOnly": false,
  "condition": "any",
  "includeFullDetails": false,
  "maxItems": 15,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call crawlerbros/musiciansfriend-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/mb7cRHGJHrhDhxQEJ/builds/kbCTvXrhv4AHj0I8D/openapi.json
