# GoodCarBadCar Sales Scraper (`crawlerbros/goodcarbadcar-sales-scraper`) Actor

Scrape U.S. and Canada automotive sales figures from GoodCarBadCar.net - sales by brand, by model, by manufacturer, by vehicle segment (SUV, truck, car), and total industry sales by year. No login, no API key, no paid proxy required.

- **URL**: https://apify.com/crawlerbros/goodcarbadcar-sales-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Automation, Lead generation, Other
- **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/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

## GoodCarBadCar Sales Scraper

Scrape U.S., Canada, and global automotive sales figures from [GoodCarBadCar.net](https://www.goodcarbadcar.net) — sales rankings by brand, by model, by manufacturer, by vehicle segment (compact car, SUV, pickup truck, etc.), and total industry sales by year for major world markets. No login, no API key, no paid proxy required.

### What this actor does

- **Two modes:**
  - `byReport` (default) — **22 report types**: brand rankings, model rankings, manufacturer rankings, 9 vehicle-segment rankings (compact car, midsize car, small car, small/midsize/large SUV, all SUVs, pickup truck, commercial van, sports car), and yearly industry totals for the US, Canada, China, Japan, Brazil, Asia (regional), Europe (regional), Africa (by country), and Australia/Oceania (by country). Each row includes current-period sales, same-period-last-year sales, % change, and year-to-date figures where available.
  - `byModelUrl` — full year-by-year (and month-by-month) sales history for one or more specific vehicle model pages, across every market GoodCarBadCar tracks for that model (typically United States + Canada).
- **Empty fields are omitted**

### Output fields

**`byReport` mode:**

- `recordType` — `"salesFigure"`
- `report` — the report type requested
- `entity` — brand / model / year label for the row
- `sales`, `salesLastYear`, `changePercent` — current-period figures
- `ytdSales`, `ytdSalesLastYear`, `ytdChangePercent` — year-to-date figures (segment/brand/model reports only)
- `rank` — row position in the report
- `sourceUrl` — the report page scraped

**`byModelUrl` mode:**

- `recordType` — `"modelSales"`
- `model` — the vehicle model name (e.g. "Toyota 4Runner")
- `market` — the sales market this row covers (e.g. "United States", "Canada")
- `period` — the year (or partial year, e.g. "2026(Jan–Jun)" for the current in-progress year)
- `sales` — total units sold that year in that market
- `yoyChangePercent` — year-over-year % change (omitted for a series' first year, which has no prior-year comparison)
- `monthlySales` — object of the same year's month-by-month unit counts, keyed `jan`–`dec` (only months with published data are included)
- `sourceUrl` — the model page scraped

### Input options

| Field | Description |
|---|---|
| `mode` | `byReport` (rankings/totals) or `byModelUrl` (full history for a specific vehicle) |
| `report` | Which report to scrape (`byReport` mode; see enum: `us-by-brand`, `us-by-model`, `us-by-manufacturer`, `us-compact-car`, `us-midsize-car`, `us-small-car`, `us-small-suv`, `us-midsize-suv`, `us-large-suv`, `us-suv`, `us-pickup-truck`, `us-commercial-van`, `us-misc-sports-car`, `us-yearly-totals`, `canada-yearly-totals`, `china-yearly-totals`, `japan-yearly-totals`, `brazil-yearly-totals`, `asia-yearly-totals`, `europe-yearly-totals`, `africa-yearly-totals`, `australia-oceania-yearly-totals`) |
| `modelUrls` | Full GoodCarBadCar.net model page URLs, e.g. `https://www.goodcarbadcar.net/toyota-4runner-sales-figures/` (`byModelUrl` mode). Find these by browsing a brand's page (e.g. `/brands/toyota-sales-data-reports/`) |
| `maxItems` | Max rows to return |
| `proxyConfiguration` | Optional Apify proxy (free AUTO datacenter group used only if needed) |

### Example: rankings report

```json
{
  "mode": "byReport",
  "report": "us-by-brand",
  "maxItems": 100
}
```

### Example: full model history

```json
{
  "mode": "byModelUrl",
  "modelUrls": ["https://www.goodcarbadcar.net/toyota-4runner-sales-figures/"],
  "maxItems": 200
}
```

### Use cases

- **Automotive market research** — track brand/model sales trends over time and across markets
- **Investor & analyst research** — monitor automaker performance ahead of earnings
- **Journalism** — source up-to-date sales rankings and YoY comparisons for reporting
- **Dealer/OEM competitive intelligence** — benchmark segment performance against competitors
- **Data science & forecasting** — build historical sales datasets for demand modeling

### FAQ

**How current is the data?** GoodCarBadCar updates its rankings monthly as automakers report sales; this actor always scrapes the live page, so results reflect the latest published figures.

**Why do some rows lack `ytdSales`?** The yearly-totals reports (`us-yearly-totals`, `canada-yearly-totals`, `china-yearly-totals`, `japan-yearly-totals`, `brazil-yearly-totals`, `asia-yearly-totals`, `europe-yearly-totals`, `africa-yearly-totals`, `australia-oceania-yearly-totals`) show full-year history and don't have a year-to-date column — only the segment/brand/model reports do.

**Why do `africa-yearly-totals` and `australia-oceania-yearly-totals` use `entity` for a country instead of a brand/model?** Those two source pages report sales per-country per-year (not per-brand), so each record is one country's total for one year — `entity` holds the country name and `period` holds the year.

**How do I find a `modelUrls` value?** Browse `goodcarbadcar.net/brands/<brand>-sales-data-reports/` and copy the link for the specific model you want (e.g. "Toyota 4Runner Sales Figures").

**Why does `byModelUrl` return more history than `byReport`?** The report tables show a current-month snapshot + year-to-date total; individual model pages carry that model's complete published year-by-year (and month-by-month) sales history, often going back 15-20+ years.

**Do I need a GoodCarBadCar membership?** No — the pages this actor scrapes are publicly available without a paid membership.

# Actor input Schema

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

byReport: scrape a curated ranking/totals report table. byModelUrl: fetch full year-by-year (and month-by-month) sales history for one or more specific vehicle model pages.

## `report` (type: `string`):

Which sales-figures report to scrape. Segment/brand/model reports return current-month + year-to-date rankings; yearly-totals reports return the full year-by-year history.

## `modelUrls` (type: `array`):

Full GoodCarBadCar.net individual model/brand-market page URLs to fetch complete sales history for (mode=byModelUrl). Example: "https://www.goodcarbadcar.net/toyota-4runner-sales-figures/". Find these URLs by browsing a brand's page on goodcarbadcar.net (e.g. /brands/toyota-sales-data-reports/) and copying a specific model's link.

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

Maximum number of rows to return from the report table.

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

Optional. Only used automatically if goodcarbadcar.net starts blocking requests; the free AUTO datacenter group is used.

## Actor input object example

```json
{
  "mode": "byReport",
  "report": "us-by-brand",
  "modelUrls": [],
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `salesFigures` (type: `string`):

Dataset containing all scraped sales-figure rows.

# 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": "byReport",
    "report": "us-by-brand",
    "modelUrls": [],
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/goodcarbadcar-sales-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": "byReport",
    "report": "us-by-brand",
    "modelUrls": [],
    "maxItems": 100,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/goodcarbadcar-sales-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 '{
  "mode": "byReport",
  "report": "us-by-brand",
  "modelUrls": [],
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call crawlerbros/goodcarbadcar-sales-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlerbros/goodcarbadcar-sales-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/lZdc62gcSifNnTbAE/builds/Z3vGYd4EmKRte3Pdm/openapi.json
