By the end of this tutorial, you will have a working Python script that extracts Gumtree UK classified listings into structured JSON: listing title, asking price in GBP, location, vehicle attributes (year, mileage, engine size, fuel type, seller type), and search-card text (empty in this run's 200 car listings).
Gumtree lists second-hand vehicles, electronics, properties, and jobs across the UK. Scraping it manually is tedious, while unproxied requests were blocked after about five pages in August 2026 testing.
In this guide, we use Python and the Apify Actor Gumtree Scraper (reventadata/gumtree-scraper) with Apify residential proxies. Our benchmark run (configured with searchQueries: ["bmw"], category: "cars", maxPrice: 5000, and maxItems: 200) took 141.0 seconds to extract 200 vehicle listings into a clean dataset.
⏱️ Time estimate: About 30 minutes.
Prerequisites
To follow this tutorial, you will need:
-
Python 3.11+ installed locally (
apify-client3.x requires it). - The Apify API client for Python (
pip install "apify-client~=3.0"). - An Apify account and API token.
Sign up for an Apify account. Copy your API token from API & Integrations in Apify Console. Install the client:
pip install "apify-client~=3.0"
The code loads the token from an environment variable:
export APIFY_API_TOKEN="your_apify_token_here"
What you'll achieve
By completing this guide, you will extract live Gumtree UK classified listings into structured records: listing title, asking price in GBP, location, vehicle specs (year, mileage, engine displacement, fuel type), seller classification (Private vs Trade), photo count, and canonical URLs.
Note on Data Boundaries: This Actor extracts data directly from Gumtree UK search result listing tiles, including search-card text (empty in this run's 200 car listings) and parsed attributes. It operates on search result pages and respects site pagination boundaries.
Example use case: Suppose you are tracking the UK second-hand vehicle market to identify private sellers offering cars at £5,000 or less. Configuring category: "cars", maxPrice: 5000, and sellerType: "private" returns an automated dataset with vehicle year, mileage, engine displacement, and fuel type.
Step 1: Access Gumtree Scraper
Navigate to the Gumtree Scraper page on Apify Store.
You can inspect the documentation and review available input parameters. In this tutorial, we use Python to automate the process programmatically.
Step 2: Configure search parameters
The Actor accepts keyword queries via searchQueries, and supports narrowing by category slug (such as cars, phones, property-to-rent, or jobs) and UK location slugs (such as uk, london, or manchester).
When targeting cars, for instance, you specify "category": "cars" and provide your search terms in searchQueries. Gumtree server-renders search listings with about 30 listing tiles per page (up to about 1,500 ads per search across the 50-page site ceiling). Price limits (minPrice and maxPrice) go to Gumtree in the search URL, while filters like sellerType and damage exclusions are applied inside the Actor after fetching.
In our Python script, we initialize the Apify client and define our parameters in run_input:
import os
from apify_client import ApifyClient
# 1. Initialize ApifyClient with token from environment
client = ApifyClient(os.environ["APIFY_API_TOKEN"])
# 2. Define the extraction parameters
run_input = {
"searchQueries": ["bmw"],
"category": "cars",
"maxPrice": 5000,
"maxItems": 20,
}
(Note: This demonstration snippet uses maxItems: 20 for a fast initial test. The benchmark run cited in this guide ran with searchQueries: ["bmw"], category: "cars", maxPrice: 5000, and maxItems: 200.)
Step 3: Configure optional settings and filters
The Actor provides filtering options: minPrice and maxPrice go to Gumtree in the search URL, while item filters (sellerType, excludeDamaged, excludeAccessories, requireKeywordMatch) are applied inside the Actor after fetching. Filtered-out rows never reach your dataset:
| Parameter | Type | Default | Description |
|---|---|---|---|
searchQueries |
array | Required | List of search keywords. Required, with no default. |
category |
string | "" |
Optional category slug (e.g., "cars", "phones", "for-sale", "property-to-rent", "jobs"). One of 11 fixed values. |
location |
string | "uk" |
Gumtree location slug (e.g., "uk", "london", "manchester"). Defaults to the entire UK. |
minPrice & maxPrice
|
integer | None |
Price boundaries in GBP. Omitted from request when empty. |
sellerType |
string | "any" |
Private or Trade. Applied inside the Actor after fetching; on non-motoring categories it returns zero rows. |
minBatteryHealth |
integer | None |
Minimum battery percentage parsed from ad text. Drops ads without stated health. |
minStorageGb |
integer | None |
Minimum device storage capacity in GB. |
excludeDamaged |
boolean | true |
Drops ads admitting damage (cracked, faulty, spares or repairs, iCloud locked). Honours seller negations like "no cracks". |
excludeAccessories |
boolean | true |
Drops phone cases, screen protectors, and chargers. |
excludeFeatured |
boolean | false |
Drops paid promoted placements pinned at the top of pages. |
requireKeywordMatch |
boolean | true |
Ensures every search word is present in the listing title. |
sortBy |
string | "relevance" |
Sort order: "relevance", "date", "price_lowest_first", "price_highest_first", "distance". |
maxItems |
integer | 1000 |
Hard cap on total dataset records pushed before terminating. |
maxPages |
integer | 50 |
Maximum page depth per term, clamped to the site ceiling of 50 (about 1,500 ads). |
Practical filtering recommendations:
-
maxItemsacts as a budget ceiling: SettingmaxItems: 50guarantees the crawler stops immediately once 50 items have been stored. -
sellerTypefiltering: SettingsellerType: "private"retains only private sellers and drops Trade listings in vehicle categories. -
Motoring attribute support: When searching
"cars", listings fillyear,mileage,engineCc,fuelType, andsellerTypewhen the listing card states them. -
Attribute parsing:
batteryHealthandstorageGbare parsed with regex directly from search-card text.
Step 4: Run the Actor
With the configuration ready, trigger the run using client.actor("reventadata/gumtree-scraper").call(run_input=run_input). This command starts the Actor in Apify's cloud environment, streams log events, and waits until execution completes:
# 3. Start the Actor run and wait for it to complete
print("Starting Gumtree UK extraction...")
run = client.actor("reventadata/gumtree-scraper").call(run_input=run_input)
if run is None or run.status != "SUCCEEDED":
status = run.status if run else "unknown"
raise SystemExit(f"Run did not succeed (status: {status}).")
# 4. Fetch the resulting dataset items
dataset = client.dataset(run.default_dataset_id).list_items().items
print(f"Extraction complete! Retrieved {len(dataset)} listings.\n")
Behind the scenes:
- The Actor launches in a container using Apify residential proxies by default: residential completed 25 of 25 pages and datacenter 22 of 25 in August 2026 testing (unproxied requests were blocked after about five pages).
- It parses listing cards server-rendered on the search result pages, extracts prices in GBP, captures vehicle specifications and seller types, and writes clean records to the Apify dataset.
- In our live benchmark run, configured with
searchQueries: ["bmw"],category: "cars",maxPrice: 5000, andmaxItems: 200, the Actor collected 200 vehicle listings.
Step 5: View and download results
Once the run completes, iterate over dataset to inspect and format each record in Python, or export the data as JSON, CSV or Excel:
for item in dataset:
title = item.get("title")
price = item.get("price")
location = item.get("location")
year = item.get("year")
mileage = item.get("mileage")
seller_type = item.get("sellerType")
print(f"Listing: {title}")
if price is None:
print(" Price: unpriced")
else:
print(f" Price: £{price}")
print(f" Location: {location}")
if year:
miles = f"{mileage} miles" if mileage is not None else "mileage not stated"
print(f" Vehicle: {year} ({miles})")
if seller_type:
print(f" Seller: {seller_type}")
print("-" * 50)
Here is a verbatim sample record extracted during our benchmark run:
{
"id": "1802688843",
"title": "BMW, X1, Estate, 2011, Manual, 1995 (cc), 5 doors",
"description": "",
"url": "https://www.gumtree.com/p/bmw/bmw-x1-estate-2011-manual-1995-cc-5-doors/1802688843",
"imageUrl": "https://img.gumtree.com/ePR8PyKf84wPHx7_RYmEag/dc7ed13c2c2a4a2993_52814dfe9ce4/86",
"price": 2250,
"currency": "GBP",
"location": "Ballyclare, County Antrim",
"sellerType": "Private",
"isFeatured": true,
"photoCount": 19,
"year": 2011,
"mileage": 153948,
"engineCc": 1995,
"fuelType": "Diesel",
"batteryHealth": null,
"storageGb": null,
"storageOptionsGb": [],
"isMultiVariant": false,
"matchedKeyword": "bmw"
}
Understanding your results
Each record follows the Actor's dataset schema:
-
id: Gumtree listing identifier string. -
title: Ad title published by the seller. -
description: Search-card text, empty in this run's 200 car listings. -
url: Canonical listing URL. -
imageUrl: First thumbnail URL, ornullwithout photos. -
price: Asking price in GBP, ornullwhen unpriced. -
currency: Always"GBP". -
location: Town and county shown on the tile. -
sellerType:"Private"or"Trade"(motoring categories only). -
isFeatured: Paid promoted ad (Featured, Urgent or Spotlight); see Pro tip 2. -
photoCount: Number of photos on the ad. -
year: Vehicle year. Motoring categories only. -
mileage: Vehicle mileage in miles. Motoring categories only. -
engineCc: Engine size in cc. Motoring categories only. -
fuelType: Fuel type ("Diesel","Petrol", or"Hybrid Electric"seen in this run). Motoring categories only. -
batteryHealth: Battery percentage parsed from text, ornull. -
storageGb: Storage in GB for single-capacity ads, ornull. -
storageOptionsGb: Array of capacities mentioned in ad copy. -
isMultiVariant: True when one ad sells several capacities at several prices, so the tile price belongs to one unstated variant. -
matchedKeyword: Search keyword that matched this ad.
Pro tips
-
Ceiling awareness on deep pagination: Gumtree serves at most 50 pages per search (about 30 per page, capping results at about 1,500 ads per search). For large queries yielding thousands of ads, segment your sweep by specific location slugs like
"london"or narrower price brackets. -
Promoted placements handling: Gumtree pins five promoted ads at the top of each page (measured on pages 1, 2, 3 and 5), regardless of sorting; the Actor flags Featured, Urgent and Spotlight labels as promoted. Set
excludeFeatured: trueif you wish to drop these promoted placements. -
Private versus Trade filtering: When auditing used vehicles, set
sellerType: "private"to exclude Trade sellers, as Gumtree labels them, and focus exclusively on private sales. The Actor applies this filter after fetching, dropping Trade listings before dataset storage. -
Keyword match enforcement:
requireKeywordMatchis enabled by default to drop irrelevant search matches where listing titles omit any word from your query. -
Start small with item caps: When developing automation pipelines, begin with
maxItems: 20to verify data mappings before running larger sweeps.
Troubleshooting
- Empty dataset / Run marked FAILED: The Actor deliberately fails if zero rows are saved, preventing silent downstream failures in production pipelines. If this happens, verify your search term spelling and ensure your price or location filters are not overly restrictive.
-
Seller type returning null: Remember that
sellerTypeis only published by Gumtree for motoring categories (such as"cars"). Non-motoring categories do not publish seller classifications on listing cards. -
Handling invalid categories:
categoryaccepts one of 11 fixed slugs; for any other value the platform refuses the input before the run starts. -
Reading the log: the last summary lines are
Rejected N: reason(only when something was rejected) andPushed N row(s).; read it from Python withclient.log(run.id).get(). For help, use the Actor's Store page (https://apify.com/reventadata/gumtree-scraper).
Pricing and Next Steps
For current pricing and details, see the Store page.
To repeat a search automatically, save it as a task and add an Apify schedule, which starts an Actor or task on a cron expression.
Links:
What categories or vehicle deals are you planning to track on Gumtree UK? Let us know in the comments below!
Top comments (0)