# PistonHeads Scraper — UK Used Car Listings & Prices (`studio-amba/pistonheads-scraper`) Actor

Scrape used-car listings from PistonHeads (pistonheads.com), the UK's enthusiast car marketplace (owned by CarGurus). Search by make, model, postcode and seller type. Extract prices, mileage, year, spec (engine, fuel, transmission), seller type and photos. No login or cookies required.

- **URL**: https://apify.com/studio-amba/pistonheads-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 result scrapeds

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/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

## PistonHeads Scraper

Scrape used-car listings from [pistonheads.com](https://www.pistonheads.com) — the UK's long-running enthusiast car marketplace (owned by CarGurus). Search by make, model, postcode and seller type, and get structured JSON with prices, mileage, year, engine spec (size, power, fuel, transmission), seller type and photos.

No login, no cookies, no browser automation. The actor talks directly to PistonHeads' own GraphQL search API, so runs are fast and results are clean.

### Why use this actor

- **Enthusiast/performance market research** — PistonHeads skews toward performance and classic cars (M cars, 911s, classic Porsches) compared to mass-market sites, useful for tracking a different slice of the used-car market.
- **Price research** — track asking prices for a specific make/model across the UK.
- **Market monitoring** — schedule runs to catch new listings for a saved search.
- **Lead generation** — filter by private sellers or trade sellers within a radius of any UK postcode.
- **Data science** — build depreciation curves and spec-vs-price datasets from year, mileage, engine power and price.

### Input

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `make` | string | `BMW` | Car make, matched against PistonHeads' own make list (e.g. `Porsche`, `Ford`, `Tesla`). |
| `model` | string | — | Optional model filter (e.g. `911`, `M3`, `Fiesta`). Requires `make`. |
| `postcode` | string | — | UK postcode to centre the search on. Leave empty to search nationwide. |
| `distanceMiles` | integer | `50` | Search radius in miles from `postcode`. Only used when a postcode is set. |
| `sellerType` | string | `all` | One of `all`, `Private`, `Trade`. |
| `maxResults` | integer | `40` | Maximum number of listings to return. Each API page carries 20 listings. |
| `proxyConfiguration` | object | automatic | PistonHeads has no anti-bot protection on its search API — the default automatic Apify proxy is enough, no residential proxy needed. |

#### Example input

```json
{
    "make": "Porsche",
    "model": "911",
    "postcode": "SW1A 1AA",
    "distanceMiles": 100,
    "sellerType": "Trade",
    "maxResults": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
}
```

### Output

Each dataset item is one car listing:

| Field | Example | Description |
|-------|---------|-------------|
| `listingTitle` | `2001 BMW 5 SERIES (E39) M5` | Listing headline |
| `make` / `model` | `BMW` / `M5` | Structured make and model |
| `year` | `2001` | Registration year |
| `price` | `38000` | Numeric price in GBP (`null` when price is on application) |
| `priceText` | `£38,000` | Price as displayed (or `POA`) |
| `isPriceOnApplication` | `false` | Whether the seller hides the price |
| `mileage` | `70814` | Numeric mileage in miles |
| `bodyType` | `Saloon` | Body style |
| `colour` | `Black` | Exterior colour |
| `fuelType` | `Petrol` | Fuel type |
| `transmissionType` | `Manual` | Transmission type |
| `engineSizeCc` | `4900` | Engine displacement in cc |
| `enginePowerBhp` | `394` | Engine power in bhp |
| `location` | `Linlithgow, United Kingdom` | Seller location |
| `distanceMiles` | `28` | Distance from search postcode, when set |
| `sellerType` / `sellerName` | `Private` / `Private Seller` | Seller type and name |
| `imageUrl` / `imageUrls` | `https://img.pistonheads.com/Fullsize/...` | Listing photos |
| `url` | `https://www.pistonheads.com/buy/listing/20895444` | Direct listing URL |
| `scrapedAt` | `2026-08-13T14:15:14.970Z` | Collection timestamp |

#### Example output

```json
{
    "listingTitle": "2001 BMW 5 SERIES (E39) M5",
    "make": "BMW",
    "model": "M5",
    "year": 2001,
    "price": 38000,
    "priceText": "£38,000",
    "isPriceOnApplication": false,
    "currency": "GBP",
    "mileage": 70814,
    "mileageText": "70,814 miles",
    "bodyType": "Saloon",
    "colour": "Black",
    "fuelType": "Petrol",
    "transmissionType": "Manual",
    "engineSizeCc": 4900,
    "enginePowerBhp": 394,
    "location": "Linlithgow, United Kingdom",
    "distanceMiles": null,
    "sellerType": "Private",
    "sellerName": "Private Seller",
    "isOnlineRetailer": false,
    "isFeatured": false,
    "isVatOmitted": false,
    "imageUrl": "https://img.pistonheads.com/Fullsize/bmw/m5/m5/bmw-m5-m5-S4972961-1.jpg",
    "numberOfImages": 4,
    "advertId": "20895444",
    "url": "https://www.pistonheads.com/buy/listing/20895444",
    "scrapedAt": "2026-08-13T14:15:14.970Z"
}
```

### How to scrape Pistonheads data

1. Open the actor and press **Try for free** (or run it via the Apify API).
2. Set `make` (and optionally `model`) to the car you want to research.
3. Optionally set `postcode` and `distanceMiles` to search a specific area, or leave both empty to search nationwide.
4. Optionally set `sellerType` to `Private` or `Trade`.
5. Set `maxResults` and run it. Results land in the dataset as clean JSON, downloadable as JSON, CSV or Excel.

To scrape PistonHeads data on a schedule, create an Apify Schedule that runs this actor daily — useful for tracking new stock on a saved search.

### Cost estimate

One API request returns 20 listings plus one small facet lookup per run, so runs stay cheap: roughly 2-3 requests per 40 cars. A 500-listing run typically completes in under a minute, with no residential proxy overhead.

Usage cost only settles after the run reports SUCCEEDED — reading the dataset mid-run will undercount what you'll actually be charged.

### Limitations

- PistonHeads lists UK vehicles only.
- The search API exposes listing-grid data. Full description text and the complete detail-page photo gallery are not included in this version.
- Price/mileage range filters are not exposed by PistonHeads' search API in a way this actor can pass through — filter the dataset after scraping if you need a price band.

### Related Scrapers

- [AutoTrader UK Scraper](https://apify.com/studioamba/autotrader-uk-scraper) — the UK's largest general car marketplace.
- [Cinch UK Scraper](https://apify.com/studioamba/cinch-co-uk-scraper) — UK online used-car retailer.
- [AutoScout24 Scraper](https://apify.com/studioamba/autoscout24-scraper) — pan-European car marketplace.
- [Willhaben Cars Scraper](https://apify.com/studioamba/willhaben-cars-scraper) — Austrian car classifieds.
- [European Car Search](https://apify.com/studioamba/european-car-search) — cross-market car search.

### Legal

This actor scrapes publicly visible listing data only. It collects no personal data and requires no login. Users are responsible for complying with PistonHeads' terms of service and applicable law when using scraped data.

# Actor input Schema

## `make` (type: `string`):

Car make to search for (e.g. 'BMW', 'Porsche', 'Ford'). Matched against PistonHeads' own make list.

## `model` (type: `string`):

Car model to filter by (e.g. 'M3', '911', 'Fiesta'). Requires the make to be set and matched.

## `postcode` (type: `string`):

UK postcode to centre the search on. Leave empty to search nationwide (PistonHeads' default).

## `distanceMiles` (type: `integer`):

Search radius in miles from the postcode. Only used when a postcode is set.

## `sellerType` (type: `string`):

Filter by seller type.

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

Maximum number of car listings to scrape. Each search page returns 20 listings.

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

Proxy settings. PistonHeads has no anti-bot protection on its search API — the default automatic Apify proxy works fine, no RESIDENTIAL proxy needed.

## Actor input object example

```json
{
  "make": "BMW",
  "distanceMiles": 50,
  "sellerType": "all",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (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 = {
    "make": "BMW",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/pistonheads-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 = {
    "make": "BMW",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/pistonheads-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 '{
  "make": "BMW",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call studio-amba/pistonheads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/pistonheads-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/EeqNgX8PdZA8f2seV/builds/mzxZspomvNKMQzNbG/openapi.json
