# BizBuySell Scraper - Businesses for Sale & Cash Flow (`scrapewise/bizbuysell-scraper`) Actor

Scrape BizBuySell businesses for sale by keyword, state, city or URL: asking price, cash flow, category, seller financing, broker and phone. Optional listing page with revenue, EBITDA, inventory, employees, rent and reason for selling. New-listing alerts.

- **URL**: https://apify.com/scrapewise/bizbuysell-scraper.md
- **Developed by:** [Scrapewise Data](https://apify.com/scrapewise) (community)
- **Categories:** Lead generation, Real estate
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.13 / 1,000 listing delivereds

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

## BizBuySell Scraper: businesses for sale, cash flow, revenue and brokers

Scrape [BizBuySell](https://www.bizbuysell.com), the largest marketplace of businesses for sale in the United States,
**without an account**. Search by keyword, state or city, paste any BizBuySell search URL, or paste listing links.
Every listing comes with the asking price, cash flow (SDE), location, category, seller financing, price-reduced and
"hot" flags, who listed it (broker or owner), the broker company, contact name and phone, and its **position in the
results**.

Turn on the full listing page and you also get **gross revenue**, EBITDA, inventory and FF\&E (and whether they are
included in the price), year established, employees, real estate, rent and lease, facilities, competition, growth,
financing terms, support and training, **reason for selling**, the full description and the city and street when
published.

Built for **deal flow**: schedule the same search every day and get only the listings that are new, or whose asking
price changed. A quiet day costs nothing.

### At a glance

- **Price per 1,000 listings, Free plan:** US$ 2.50
- **Full listing page (optional):** US$ 4.00 per 1,000, on top, plus US$ 0.005 per run that opens listing pages
- **Fee per run start for searches:** None
- **Keywords, US states and cities, search URLs and listing links:** Yes
- **Asking price, cash flow and gross revenue filters:** Yes, with BizBuySell's own filters
- **Listed in the last N days filter:** Yes
- **Seller financing, real estate included, price reduced:** Yes, as filters and as fields
- **Broker company, contact name and phone:** Yes, when the listing shows them
- **Only new listings since the last run (`onlyNew`):** Yes, free when nothing is new
- **Asking price tracking between runs:** Yes
- **BizBuySell categories, listing type, year established and sort order:** Yes, BizBuySell's own filters
- **Industry and category path:** Yes, from BizBuySell's own category tree
- **Error rows (bad URL, no results, site refusal):** Free, with an `errorCode`
- **Spend control:** a per-search limit and an optional cap for the whole run (`maxTotalItems`)

### What it fixes

- **Gross revenue on search results, not only on pasted links.** With full listing pages on, every row of a
  keyword, state or category search gets the gross revenue, EBITDA, year established, inventory and FF\&E of its
  own page.
- **Year established, real estate, building size, rent and lease expiration are filled** when the listing
  publishes them, and the lease date also comes as a real date (`leaseExpirationDate`, `2030-01-01`), never as
  1970-01-01.
- **Full category path:** `industry` ("Restaurants & Food"), `subcategory` ("Bars, Pubs & Taverns") and
  `categoryFull` ("Restaurants & Food > Bars, Pubs & Taverns"), from BizBuySell's own category tree: on every row
  with the listing page, on every row of a category search or category URL, and on featured rows of other
  searches.
- **Your limit is respected.** A `limit`, `results_wanted` or `maxListings` pasted from another BizBuySell actor
  gives that many listings and that many charges, not this form's default of 50.
- **Proxy settings never break the run.** No custom proxy session names that the proxy can refuse, and a pasted
  `"useApifyProxy": false` is replaced by the default Apify Proxy, which the searches need.
- **Fewer refusals.** When BizBuySell refuses a search, the Actor retries it by itself before giving up.
- **When was it listed?** BizBuySell shows the listing date only to paying members, so no actor can read it from
  the public page. Use `listedWithinDays` (BizBuySell's own "added in the last N days" filter) for fresh listings,
  and `onlyNew` + `trackPriceChanges` on a schedule: `firstSeenAt` is the first time your search saw the listing.

### Switching from another BizBuySell actor? Your existing input works

Paste the input you already use. These names and values are read as they are:

| You may already send | Read as |
|---|---|
| `keyword`, `queries`, `searchKeyword` | `searchTerms` |
| `location`, `searchLocation`, `state` + `area` (`"texas"` + `"dallas"`) | `locations` |
| `startUrls` (text or `{ "url": ... }`), `urls`; `mode: "url"` or `useQueryBuilder: false` | URLs only, other filters ignored |
| `category` (`restaurants-and-food`), `industryIds` (`["17"]`) | `categories` |
| `limit`, `results_wanted`, `maxItemsPerSearch` | `maxItems` |
| `maxListings` | `maxTotalItems` (cap for the whole run) |
| `max_pages`, `maxPages` | `maxPages` |
| `minAskingPrice`, `maxAskingPrice` | `minPrice`, `maxPrice` |
| `minCashflow`, `maxCashflow` | `minCashFlow`, `maxCashFlow` |
| `minGrossRevenue`, `minGrossIncome`, `maxGrossIncome` | `minRevenue`, `maxRevenue` |
| `establishmentDate` (a year) | `establishedAfter` |
| `listingType`: `all`, `established`, `asset-sale` | `listingType` |
| `sortBy`: `default`, `newest`, `price-asc`, `price-desc`, `cashflow-desc` | `sortBy` |
| `fetchDetails`, `enrich_data`, `includeListingDetails` | `includeDetails` |
| `incrementalMode` | `onlyNew` + `trackPriceChanges` |

```json
{ "keyword": "laundromat", "location": "Florida", "listingType": "established", "maxAskingPrice": 900000, "sortBy": "price-asc", "maxListings": 25 }
```

```json
{ "useQueryBuilder": true, "state": "texas", "area": "dallas", "industryIds": ["17"], "minCashflow": 100000, "limit": 50, "enrich_data": true }
```

When a single URL comes with a single keyword (as some actors take them), the keyword filters that URL: one
search, not two.

### One real row

From a test on 2026-10-08 (location "Florida", with the listing page). Long texts are shortened here, and the
contact fields are replaced with placeholders; the Actor returns them as the listing shows them.

```json
{
  "type": "listing",
  "listingId": "2522913",
  "title": "Established Commercial Painting Contractor",
  "url": "https://www.bizbuysell.com/business-opportunity/established-commercial-painting-contractor/2522913/",
  "askingPrice": 16000000,
  "cashFlow": 3850000,
  "location": "Jacksonville, FL",
  "state": "FL",
  "category": "Building & Construction Service",
  "sellerFinancing": true,
  "realEstateIncluded": false,
  "priceReduced": false,
  "hotProperty": true,
  "listedBy": "broker",
  "brokerCompany": "<broker company>",
  "contactName": "<broker name>",
  "contactPhone": "<phone>",
  "imageCount": 6,
  "position": 61,
  "page": 2,
  "searchInput": "Florida",
  "hasDetails": true,
  "grossRevenue": 16380000,
  "inventory": 145000,
  "inventoryIncludedInPrice": false,
  "ffe": 675000,
  "ffeIncludedInPrice": true,
  "employees": "32 (30 Full-time, 2 Contractors)",
  "financing": "Seller financing available\nDetails will be provided during due diligence.",
  "supportAndTraining": "The owner is willing to provide a reasonable transition period to introduce key customer and vendor relationships...",
  "reasonForSelling": "retiring",
  "tagline": "Serving Multiple States with Experienced Team",
  "address": {"street": null, "city": "Jacksonville", "state": "Florida"},
  "scrapedAt": "2026-10-08T01:56:45Z"
}
```

Rows also carry `ebitda`, `summary`, `industry`, `subcategory`, `categoryFull`, `categoryId`, `listingType`
(`established`, `asset sale`, `startup`, `real estate`...), `recentlyAdded`, `recentlyUpdated`, `brokerProfileUrl`,
`image` and, with the listing page, `description`, `facilities`, `competition`, `growthAndExpansion`,
`yearEstablished`, `realEstate` (Leased or Owned), `buildingSqft`, `rent`, `leaseExpiration`, `leaseExpirationDate`,
`detailLocation`, `categoryPath` (the primary and secondary categories the seller picked), `images` and
`otherDetails` (any other line the listing has). A value the seller marked "Not Disclosed" comes back as `null`.
BizBuySell's search results carry the category only for featured listings, so on a keyword or location search
without the listing page `industry` can be `null`; search by category, or turn on the listing page, to have it on
every row.

### How to use it

**By keyword and location.** Each keyword runs in each location:

```json
{
  "searchTerms": ["laundromat", "car wash"],
  "locations": ["Texas", "Phoenix, AZ"],
  "maxPrice": 800000,
  "maxItems": 200
}
```

**By URL.** Open BizBuySell, pick a state, city or industry, and paste the address. The Actor pages through the
results by itself:

```json
{
  "startUrls": [
    "https://www.bizbuysell.com/texas-businesses-for-sale/",
    "https://www.bizbuysell.com/restaurants-and-food-businesses-for-sale/"
  ],
  "minCashFlow": 200000
}
```

**By listing link.** Paste listing URLs (they contain `/business-opportunity/`). Each comes back with the full page.

**By category.** Use BizBuySell's industries or narrower categories, alone or with keywords and locations:

```json
{
  "categories": ["Restaurants & Food", "Laundromats"],
  "locations": ["Florida", "Austin, TX"],
  "listingType": "established",
  "sortBy": "cashflow-desc",
  "maxItems": 50,
  "maxTotalItems": 150
}
```

**Filters:** `minPrice`/`maxPrice` (asking price), `minCashFlow`/`maxCashFlow`, `minRevenue`/`maxRevenue`,
`listedWithinDays`, `establishedAfter` (a year), `listingType` (`established`, `asset-sale`, `startup`) and
`categories` use BizBuySell's own filters; `sortBy` uses BizBuySell's own orders (newest, asking price, cash flow).
A search URL keeps its own filters too (the `?q=` part BizBuySell adds). `sellerFinancingOnly`, `realEstateIncludedOnly` and
`priceReducedOnly` keep only matching listings; the others are skipped and not charged.

### Daily deal alerts

Schedule the Actor with the same input every day and turn on:

- **`onlyNew`**: only listings this search never returned before. The first run delivers up to `maxItems` and
  remembers everything it read; later runs deliver only what is new. Listings already seen are not charged.
- **`trackPriceChanges`**: every row gets `previousPrice`, `priceChange`, `priceChangePct`, `isPriceDrop`,
  `isNewListing`, `firstSeenAt` and `previousSeenAt`. With `onlyNew` on too, listings whose asking price changed are
  delivered as well.
- **`onlyPriceDrops`**: with both of the above, of the listings seen before, only the ones that got cheaper.

Tip: combine `onlyNew` with `listedWithinDays: 7` for a cheap daily feed of fresh listings.

The memory lives in a key-value store in your own account (`bizbuysell-scraper-state`), one entry per search and
filters. Delete it to start over.

### Who uses this

- **Search funds and individual buyers** screening small businesses by cash flow, price and location.
- **Private equity and holding companies** building acquisition pipelines in one industry.
- **Business brokers** watching competing listings, prices and price cuts in their territory.
- **SBA lenders, valuation firms and researchers** collecting asking-price multiples by industry and state.

### Limits and good to know

- BizBuySell returns 50 listings per page and up to 10,000 per search. Split large searches by state or filters.
- BizBuySell's cash flow and revenue filters also let through listings whose seller did not disclose that figure
  (the field comes back `null`).
- Gross revenue, EBITDA and the detailed information are only on the listing page (`includeDetails`). Cash flow is
  on every row when the seller published it.
- New-franchise ads that BizBuySell mixes into the results are skipped; set `includeFranchises` to keep them.
  Broker ads and partner real-estate auctions mixed into the results are always skipped.
- `maxItems` is per search (each keyword, location and category combination, or URL); `maxTotalItems` caps the
  whole run, and `maxPages` the result pages read per search.
- Searches work with the default Apify Proxy (a proxy turned off in the input is replaced by it). If you get
  `BLOCKED` rows, switch the proxy to the RESIDENTIAL group with country US.
- Contact names and phones are the ones the listing publishes for buyers. Use them according to the laws that apply
  to you (for example, US telemarketing rules).

### Pricing

Pay per listing: **US$ 2.50 per 1,000 listings** on the Free plan (lower on paid Apify plans), plus **US$ 4.00 per
1,000** for listings delivered with the full listing page and US$ 0.005 per run that opens listing pages. Search-only
runs have no start fee. Error rows, duplicates and listings skipped by filters or `onlyNew` are never charged.

### Error codes

| errorCode | Meaning |
|---|---|
| `INVALID_INPUT` | The URL is not a BizBuySell search or listing link, a location was not understood, or a filter is wrong |
| `NO_RESULTS` | BizBuySell found no listing for this search and filters |
| `NOT_FOUND` | The listing does not exist (sold, removed or a wrong link) |
| `BLOCKED` | The site refused every attempt on fresh IPs; run again in a few minutes |
| `NOT_REACHED` | The run timeout came before this input |
| `UNEXPECTED` | Anything else; run again, and open an issue if it repeats |

### FAQ

**Do I need a BizBuySell account?** No. The Actor reads public listings only.

**Does it get sold listings?** No. Only listings that are live on BizBuySell at run time.

**Can I search outside the US?** BizBuySell's US site only. Canadian and other listings that appear in US searches
are delivered as they are.

### Changelog

- **2026-10-09**: input from other BizBuySell actors works as it is (see the table above); new `categories`,
  `listingType`, `establishedAfter`, `sortBy`, `maxTotalItems` and `maxPages`; `industry`, `subcategory`,
  `categoryFull`, `categoryId` and `listingType` on every row; with the listing page, `yearEstablished`,
  `realEstate`, `buildingSqft`, `rent` and `leaseExpiration` are now filled (they were always `null`), plus
  `leaseExpirationDate` and `detailLocation`; search URLs keep their `?q=` filters; broker ads and real-estate
  auctions no longer come as listings; fewer refused searches.
- **2026-10-08**: first version.

# Actor input Schema

## `searchTerms` (type: `array`):

Words to search in BizBuySell listings, one per line (for example laundromat, hvac, car wash, amazon fba). Each keyword runs as its own search, combined with every location below. Leave empty to list everything in the locations.

## `locations` (type: `array`):

US states or cities, one per line: Texas, TX, Dallas TX or Miami, Florida. Leave empty to search the whole country.

## `categories` (type: `array`):

BizBuySell categories, one per line, as on the site: an industry (Restaurants & Food, Service Businesses, Online & Technology) or a narrower one (Bars, Pubs & Taverns, Laundromats). The URL piece (restaurants-and-food) and BizBuySell's category ids (17) also work. Each category runs in each location and with each keyword. Leave empty for all categories.

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

A list of URLs copied from bizbuysell.com, for example \["https://www.bizbuysell.com/texas-businesses-for-sale/", "https://www.bizbuysell.com/restaurants-and-food-businesses-for-sale/"]. Search, state, city and category URLs are paged by the Actor (the page number in the URL is ignored, its ?q= filters are kept). Listing URLs (/business-opportunity/...) come back with the full listing page. Items can also be objects such as {"url": "https://..."}.

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

Only listings asking at least this much. Uses BizBuySell's own filter.

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

Only listings asking at most this much. Uses BizBuySell's own filter.

## `minCashFlow` (type: `integer`):

Only listings with at least this seller's discretionary earnings (SDE) per year. Uses BizBuySell's own filter. BizBuySell's filter also lets through listings whose seller did not disclose cash flow (cashFlow null).

## `maxCashFlow` (type: `integer`):

Only listings with at most this cash flow per year. Uses BizBuySell's own filter.

## `minRevenue` (type: `integer`):

Only listings with at least this gross revenue per year. Uses BizBuySell's own filter.

## `maxRevenue` (type: `integer`):

Only listings with at most this gross revenue per year. Uses BizBuySell's own filter.

## `listedWithinDays` (type: `integer`):

Only listings added in the last N days (for example 7). Uses BizBuySell's own filter.

## `establishedAfter` (type: `integer`):

Only businesses established after this year (for example 2015). Uses BizBuySell's own filter.

## `listingType` (type: `string`):

All listings, only established businesses, only asset sales or only startups. Uses BizBuySell's own filter.

## `sellerFinancingOnly` (type: `boolean`):

Only listings where the seller offers financing. Listings that do not match are skipped and not charged; maxItems counts only matching listings.

## `realEstateIncludedOnly` (type: `boolean`):

Only listings that include the real estate. Listings that do not match are skipped and not charged; maxItems counts only matching listings.

## `priceReducedOnly` (type: `boolean`):

Only listings whose asking price was reduced. Listings that do not match are skipped and not charged; maxItems counts only matching listings.

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

Stop each search (each keyword and location pair, or URL) after this many listings. BizBuySell pages 50 at a time, up to 10,000 per search. 0 = up to 10,000.

## `maxTotalItems` (type: `integer`):

Optional cap across all searches and URLs together, so a run with many keywords, locations or categories never delivers (or charges) more than this. 0 or empty = no cap.

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

BizBuySell's own order for the results: its default, newest first, asking price or cash flow. With a limit, this decides which listings you get.

## `maxPages` (type: `integer`):

Optional: stop each search after this many result pages of 50. 0 or empty = no page limit (up to 200).

## `includeDetails` (type: `boolean`):

Also open each listing's own page: gross revenue, EBITDA, inventory and FF\&E, year established, employees, real estate, rent and lease, facilities, competition, growth, financing terms, support and training, reason for selling, the full description and the street address when published. Charged as a second event per listing, plus one small fee per run that opens listing pages.

## `includeFranchises` (type: `boolean`):

BizBuySell mixes new-franchise ads into the results. They are skipped by default; turn this on to keep them.

## `onlyNew` (type: `boolean`):

For scheduled runs. Remembers which listings each search (with its filters) already returned, in a named key-value store in your account ('bizbuysell-scraper-state'), and delivers only listings not seen before. The first run delivers up to the limit and marks everything it read as seen. Seen listings are not delivered and not charged. Delete the store to start over.

## `trackPriceChanges` (type: `boolean`):

Compares each listing's asking price with the one seen in your previous runs of the same search and adds previousPrice, priceChange, priceChangePct, isPriceDrop, isNewListing, firstSeenAt and previousSeenAt. With 'Only new listings' on too, listings whose price changed are delivered as well.

## `onlyPriceDrops` (type: `boolean`):

With 'Only new listings' and 'Track asking price changes' both on: of the listings seen before, deliver only those whose asking price went down.

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

Works with the default Apify Proxy. If you get BLOCKED rows, switch to the RESIDENTIAL group with country US.

## Actor input object example

```json
{
  "searchTerms": [
    "laundromat"
  ],
  "locations": [
    "Texas"
  ],
  "listingType": "all",
  "sellerFinancingOnly": false,
  "realEstateIncludedOnly": false,
  "priceReducedOnly": false,
  "maxItems": 50,
  "sortBy": "default",
  "includeDetails": false,
  "includeFranchises": false,
  "onlyNew": false,
  "trackPriceChanges": false,
  "onlyPriceDrops": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `resultsCsv` (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 = {
    "searchTerms": [
        "laundromat"
    ],
    "locations": [
        "Texas"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapewise/bizbuysell-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 = {
    "searchTerms": ["laundromat"],
    "locations": ["Texas"],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapewise/bizbuysell-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 '{
  "searchTerms": [
    "laundromat"
  ],
  "locations": [
    "Texas"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call scrapewise/bizbuysell-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapewise/bizbuysell-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/3BlmurKxjsc7hvJ0L/builds/DsqlhlL00eKDSnt4B/openapi.json
