# Rock & Dirt Scraper – Heavy Equipment Listings (`muhammadafzal/rock-and-dirt-scraper`) Actor

Extract Rock & Dirt heavy equipment listings with prices, specs, hours, sellers, locations, images, and price history for sourcing and market research.

- **URL**: https://apify.com/muhammadafzal/rock-and-dirt-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 rock & dirt listing extracteds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## Rock & Dirt Heavy Equipment Scraper

Extract structured public listings from Rock & Dirt for equipment sourcing, price research, dealer inventory analysis, and market monitoring. The Actor accepts filtered Rock & Dirt search pages or individual listing pages and returns one stable, schema-validated dataset item per listing.

It covers public equipment, cranes, trucks, trailers, attachments, parts, dismantled machinery, and auction listings that use Rock & Dirt's `/search/` and `/listings/` routes. It does not sign in, contact sellers, submit forms, bypass access controls, or scrape authenticated account pages.

### What the scraper extracts

| Field group | Examples |
|---|---|
| Identity | `listingId`, `title`, `listingUrl`, `sourceUrl` |
| Equipment | `type`, `category`, `equipmentClass`, `year`, `make`, `model` |
| Price | `price`, `currency`, `priceDisclaimer`, `priceHistory` |
| Usage and identifiers | `condition`, `hoursUsed`, `mileage`, `stockNumber`, `serialNumber`, `vin` |
| Listing content | `description`, category-specific `specifications`, `imageUrls`, `thumbnailUrl`, `youtubeUrl` |
| Location | `city`, `region`, `country`, `postalCode`, `location`, `latitude`, `longitude` |
| Seller | `sellerName`, `sellerType`, `sellerWebsite`, `sellerUrl`; optional public `sellerPhone` and `sellerEmail` |
| Auction and dates | `isAuction`, `auctionUrl`, `createdAt`, `updatedAt`, `scrapedAt` |

Optional fields are always present as `null` or an empty array when Rock & Dirt does not publish them. This keeps exports predictable for spreadsheets, databases, and AI agents.

### When to use it

Use this Actor when you need to:

- compare asking prices, hours, years, makes, and models;
- monitor a filtered category, manufacturer, region, or dealer inventory;
- collect image URLs and descriptions for sourcing analysis;
- enrich known Rock & Dirt listing URLs with public specifications and price history;
- export public marketplace listings to JSON, CSV, Excel, or an API workflow.

Do not use it to contact sellers without an appropriate lawful basis, build unsolicited outreach lists, reproduce copyrighted images or descriptions, access private pages, or circumvent a CAPTCHA, paywall, login, or other access control.

### Input

| Field | Type | Default | Purpose |
|---|---|---|---|
| `startUrls` | request list | Excavators search | One to 20 public `rockanddirt.com/search/...` or `rockanddirt.com/listings/...` URLs. Copying a filtered search URL preserves its filters. |
| `maxResults` | integer | `20` | Maximum unique listings written, from 1 to 1,000. |
| `maxPages` | integer | `3` | Maximum pages read for each search URL, from 1 to 100. Direct listing URLs are unaffected. |
| `includeDetails` | boolean | `true` | Visit each detail page for full images, specifications, description, seller profile, price history, and precise location. |
| `includeSellerContact` | boolean | `false` | Include public business phone/email fields. Leave disabled unless your lawful use case requires them. |
| `maxConcurrency` | integer | `2` | Simultaneous public requests, from 1 to 5. |
| `proxyConfiguration` | object | disabled | Optional Apify Proxy configuration for run environments where direct access is blocked. |

#### Search with detail enrichment

```json
{
  "startUrls": [
    {
      "url": "https://www.rockanddirt.com/search/excavators?category=Excavators"
    }
  ],
  "maxResults": 25,
  "maxPages": 3,
  "includeDetails": true,
  "includeSellerContact": false,
  "maxConcurrency": 2,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

#### Enrich one known listing

```json
{
  "startUrls": [
    {
      "url": "https://www.rockanddirt.com/listings/2019-john-deere-210g-lc-29404245"
    }
  ],
  "maxResults": 1,
  "includeDetails": true
}
```

#### Run through the Apify API

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/muhammadafzal~rock-and-dirt-scraper/runs" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":[{"url":"https://www.rockanddirt.com/search/excavators?category=Excavators"}],"maxResults":10}'
```

Keep API tokens in authorization-aware tooling or environment variables. Do not commit them to source control or expose them in logs.

### Output example

```json
{
  "listingId": "29404245",
  "title": "2019 John Deere 210G LC Excavators EARTHMOVING",
  "listingUrl": "https://www.rockanddirt.com/listings/2019-john-deere-210g-lc-29404245",
  "sourceUrl": "https://www.rockanddirt.com/search/excavators?category=Excavators",
  "type": "Equipment",
  "category": "Excavators",
  "equipmentClass": "EARTHMOVING",
  "year": 2019,
  "make": "John Deere",
  "model": "210G LC",
  "price": 86900,
  "currency": "USD",
  "condition": "used",
  "hoursUsed": 4200,
  "location": "Van Buren Charter Township, Michigan, United States",
  "sellerName": "Construction Station",
  "sellerPhone": null,
  "imageUrls": [
    "https://cdn1.boatline.com/v1/media/6a98f8e2b22dff4e24142ee1.jpg"
  ],
  "isAuction": false,
  "updatedAt": "2026-09-03T04:35:25.000Z",
  "scrapedAt": "2026-09-06T08:00:00.000Z"
}
```

The default dataset contains only listing records. `SUMMARY` and `OUTPUT` in the default key-value store report the outcome (`SUCCEEDED`, `PARTIAL`, `EMPTY`, `BLOCKED`, or `REJECTED`), page counts, delivered results, charged events, estimated event cost, and warnings.

### Pay-per-event pricing

| Event | Price | Trigger |
|---|---:|---|
| Actor start | $0.00005 | Once when a run starts |
| Listing extracted | $0.005 | After one valid listing is saved to the dataset |

Examples:

- One listing costs up to **$0.00505** in Actor events.
- 25 listings cost up to **$0.12505**.
- 100 listings cost up to **$0.50005**.

The Actor states the maximum event cost at startup, respects `maxResults` and the run's maximum charge, deduplicates by listing ID, saves each result before charging it, and stops when the platform reports that the event-charge limit has been reached. Optional Apify platform usage pass-through is not part of this pricing contract.

### Reliability and limits

Rock & Dirt currently serves search and detail data in server-rendered page JSON, so the Actor uses lightweight HTTP requests rather than a browser. It sends coherent browser-style headers, persists sessions, retries transient failures with bounded attempts, and paginates the same public search route. Direct access is the default because it is the lowest-cost measured path; Apify Proxy is available as an explicit fallback.

The Actor never fabricates results. A valid no-match search produces an `EMPTY` summary with zero result events. Invalid domains or routes produce an actionable `REJECTED` outcome. Repeated challenges produce `BLOCKED`; partial valid results are preserved and reported as `PARTIAL`. Target-site changes, removed listings, geographic variation, and temporary rate limits can affect availability.

Search pages currently expose about 20 listings per page. With detail enrichment enabled, each returned listing normally adds one detail request. `maxResults`, `maxPages`, concurrency, retries, and platform charge limits bound run size and cost.

### Legal and data responsibility

This Actor extracts information displayed on public Rock & Dirt pages. Rock & Dirt and all equipment brands are trademarks of their respective owners; this Actor is independent and is not endorsed by Rock & Dirt. Review the website's terms, robots rules, copyright restrictions, database rights, privacy law, and your intended use before running at scale.

Seller contact extraction is disabled by default. If enabled, handle business phone and email data lawfully, minimize retention, secure exports, honor deletion or objection rights where applicable, and do not use the data for spam, harassment, discrimination, or prohibited profiling. Image URLs point to third-party content and do not grant reuse rights.

For support, include the Actor run ID, a redacted input, the affected public URL, expected outcome, and actual `SUMMARY` status. Never include tokens, proxy credentials, or private personal data in a support request.

# Actor input Schema

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

Use this when you have a public Rock & Dirt search or listing URL. Paste filtered /search/... URLs or individual /listings/... URLs, for example https://www.rockanddirt.com/search/excavators?category=Excavators. Defaults to that excavator search; authenticated pages and other domains are rejected.

## `maxResults` (type: `integer`):

Use this to cap unique listing records written to the dataset. Range 1–1,000; default 20. Listing-event charges cannot exceed maxResults × $0.005, plus the one-time start event.

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

Use this to cap pagination for each search URL. Range 1–100; default 3. It does not limit direct listing URLs.

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

Use this when you need full descriptions, all images, price history, specifications, dealer fields, and precise location from each listing page. Defaults to true; disable for faster search-card results.

## `includeSellerContact` (type: `boolean`):

Use this only when your lawful use case needs business contact fields displayed publicly on the listing. Defaults to false; when false, sellerPhone and sellerEmail are null.

## `maxConcurrency` (type: `integer`):

Use this to limit simultaneous public requests. Range 1–5; default 2. Lower values are gentler on Rock & Dirt.

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

Use this only when direct public requests are blocked in your run environment. The default disables Apify Proxy because the measured direct route works.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.rockanddirt.com/search/excavators?category=Excavators"
    }
  ],
  "maxResults": 20,
  "maxPages": 3,
  "includeDetails": true,
  "includeSellerContact": false,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One structured equipment listing per dataset item.

## `summary` (type: `string`):

Outcome, request counts, delivered listings, charged events, and warnings.

# 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.rockanddirt.com/search/excavators?category=Excavators"
        }
    ],
    "maxResults": 20,
    "maxPages": 3,
    "includeDetails": true,
    "includeSellerContact": false,
    "maxConcurrency": 2,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/rock-and-dirt-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.rockanddirt.com/search/excavators?category=Excavators" }],
    "maxResults": 20,
    "maxPages": 3,
    "includeDetails": True,
    "includeSellerContact": False,
    "maxConcurrency": 2,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/rock-and-dirt-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.rockanddirt.com/search/excavators?category=Excavators"
    }
  ],
  "maxResults": 20,
  "maxPages": 3,
  "includeDetails": true,
  "includeSellerContact": false,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call muhammadafzal/rock-and-dirt-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/rock-and-dirt-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/eWQf778pZjizJe2K6/builds/zym3yQRcUo74arnuK/openapi.json
