# PakWheels Scraper — Pakistan Used Cars, Prices & Dealers (`oswaldocarabano/pakwheels-scraper`) Actor

Scrape PakWheels.com used car listings in Pakistan: price in PKR, make, model, version, year, mileage, engine, fuel, city, seller type, inspection score and photos. Optional ad pages add colour, body, registration and features. Dealer directory with address and phone. No login.

- **URL**: https://apify.com/oswaldocarabano/pakwheels-scraper.md
- **Developed by:** [Oswaldo Carabano](https://apify.com/oswaldocarabano) (community)
- **Categories:** E-commerce, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## PakWheels Scraper — Pakistan Used Cars, Prices & Dealers

A PakWheels scraper and unofficial PakWheels API for used car prices in Pakistan. Extract used car listings from **PakWheels.com**, Pakistan's largest car marketplace (about **84,500 live ads** on 23 Sep 2026), into a clean, typed dataset: price in PKR, make, model, version, year, mileage, engine, fuel, transmission, city, seller type, PakWheels inspection score and every photo. Turn on one switch to also open each ad and get the description, colour, body type, registration city, assembly, the full feature list, the PakWheels inspection report and the seller block. A second mode exports the **PakWheels dealer directory** (showrooms with address, business phone, rating and reviews).

- **No login, no cookies, no browser.** Plain HTTP requests against the public pages.
- **Up to 82 fields per row**, every key present on every row (`null` when the source has no value).
- **Pay only for rows delivered.** Error rows and duplicates are never charged.
- **Low price per row**: $0.90 per 1,000 listings ($0.99 with detail pages) and a $0.00001 start fee.
- **Fast by default**: on the Apify platform the default input returns 100 rows in under 30 s (8 s measured), and 1,000 listings take about 1.5 minutes at 512 MB.

### Who uses it

- **Car dealers and importers**: price your stock against every comparable ad in Lahore, Karachi, Islamabad or any other city.
- **Market analysts and journalists**: track car prices in Pakistan by make, model, year and city over time.
- **Lenders, insurers and leasing companies**: residual values by model year and mileage.
- **Lead generation**: the PakWheels car dealer directory with business phone and address.

### What you get

#### Listing fields (always included)

Fill rates measured on the Apify platform on 30 Sep 2026 over **n = 1,279 unique listings from 13 different searches** (all Pakistan, Lahore, Karachi, Islamabad, Rawalpindi, Peshawar, Honda Civic 2016–2022, Suzuki under PKR 15 lakh, hybrids, electric cars, inspected cars, dealers only, private sellers only, a pasted search URL). A first sample of 441 listings on 23 Sep gave the same picture.

| Field | What it is | Filled |
|---|---|---|
| `listing_id`, `url`, `title` | PakWheels ad reference (stable across runs), public URL, card title | 100 % |
| `make`, `model`, `version` | e.g. Toyota / Corolla / Altis Grande 1.8 | 100 % / 100 % / 94.1 % |
| `year`, `mileage_km`, `engine_cc` | model year, odometer in km, displacement in cc (as numbers) | 100 % / 100 % / 97.8 % |
| `price`, `currency`, `price_text` | asking price in PKR as an integer, plus the original "lacs/crore" text | 99.5 % (the rest are "Call for price" ads: `price` is `null` and `price_on_call` is `true`) |
| `fuel_type`, `transmission`, `battery_kwh` | Petrol / Diesel / Hybrid / Electric…, Automatic / Manual, battery size for EVs | 100 % / 100 % / EVs only |
| `city`, `seller_type` | city of the ad; `individual` or `dealer` for every row | 100 % |
| `is_featured`, `is_managed_by_pakwheels` | featured ad, sale managed by PakWheels | 100 % (true 45.5 % / 7.6 %) |
| `inspection_rating`, `has_auction_sheet`, `has_video` | PakWheels inspection score out of 10, auction sheet badge, video | inspected cars only (8.0 % of the sample) / 100 % / 100 % |
| `images`, `image_count`, `image_url` | every photo URL of the ad (median 11, max 115) | 99.5 % |
| `updated_text`, `updated_at_approx`, `updated_at_precision` | "Updated 3 days ago", its ISO approximation and its precision | 100 % |

In the 23 Sep sample, `price` equalled the "lacs/crore" text on 435 of 435 priced cards — validated against the expected value, not just "not null".

#### Detail page fields (optional: "Open each ad")

Fill rates measured on the Apify platform on 30 Sep 2026 over **n = 294 detail pages** from six searches (Karachi, Islamabad, Rawalpindi, Peshawar, inspected cars from dealers, electric cars).

| Field | What it is | Filled |
|---|---|---|
| `description` | the seller's full text | 98.6 % |
| `color`, `body_type`, `registered_in`, `assembly`, `engine_type` | e.g. White, Sedan, Islamabad, Imported, Hybrid | 100 % |
| `last_updated`, `location`, `city_area` | calendar date, "DHA, Karachi Sindh", "DHA" | 100 % / 100 % / 76.5 % |
| `features`, `features_flat` | the full feature list by group (median 18 features per car) | 97.6 % |
| `detail_images` | full-size photo list | 99.3 % |
| `inspection_overall_rating`, `inspection_date`, `inspection_categories`, `inspection_report_url` | the PakWheels inspection report with per-category scores | inspected cars only (every inspected car in the sample had it) |
| `seller_member_since`, `seller_phone_verified`, `seller_email_verified`, `seller_trusted` | seller account age and verification badges | 71.4 % / 78.2 % true / 47.3 % true / 20.4 % true |
| `seller_is_showroom_dealer`, `seller_dealer_url`, `seller_dealer_address`, `seller_dealer_timings` | showroom name, page, address and opening hours | 28.6 % of rows in the sample are showrooms |
| `posted_via`, `detail_attributes` | how the ad was posted; the raw attribute table | 57.5 % / 100 % |

#### Dealer directory (outputType = dealers)

One row per showroom from the PakWheels dealer directory: `name`, `city`, `address`, `phone` (the **business** phone published in the directory), `is_verified`, `is_featured`, `reviews_count`, `rating_stars`, `logo_url`, `dealer_url`.

### How to use it

**Quick start** — leave everything empty and click Start: you get the 100 most recently updated ads in Pakistan.

**Filter like on the site** — every filter below was verified to narrow the results on the live site (23 Sep 2026): city, make, model, year range, price range (PKR), mileage range, engine cc range, transmission, engine type, body type, assembly (local/imported), registration city, colour, seller type, PakWheels-inspected only, managed-by-PakWheels only, keyword and sort order.

**Or paste a search URL** — apply filters on pakwheels.com and paste the address bar, e.g. `https://www.pakwheels.com/used-cars/search/-/ct_karachi/mk_honda/`.

Example input:

```json
{
  "city": "lahore",
  "make": "toyota",
  "model": "corolla",
  "yearFrom": 2018,
  "priceTo": 6000000,
  "maxItems": 300,
  "scrapeDetails": true
}
```

Example output row (shortened, values illustrative):

```json
{
  "record_type": "listing",
  "listing_id": 11988742,
  "url": "https://www.pakwheels.com/used-cars/proton-saga-2022-for-sale-in-karachi-11988742",
  "title": "Proton Saga 2022 1.3L Ace A/T",
  "make": "Proton", "model": "Saga", "version": "1.3L Ace A/T", "year": 2022,
  "price": 2470000, "currency": "PKR", "price_text": "PKR 24.7 lacs",
  "mileage_km": 28000, "fuel_type": "Petrol", "engine_cc": 1299, "transmission": "Automatic",
  "city": "Karachi", "seller_type": "dealer", "image_count": 18,
  "color": "Red", "body_type": "Sedan", "registered_in": "Karachi", "assembly": "Local",
  "city_area": "Zamzama", "features_flat": ["ABS", "Air Bags", "Cruise Control", "..."],
  "seller_member_since": "2020-01-18", "seller_phone_verified": true
}
```

### Pricing

Pay per event — you only pay for what is delivered:

| Event | Price | When |
|---|---|---|
| Listing | **$0.0009** per listing | each listing row delivered |
| Detail page | **$0.00009** per listing | only with "Open each ad" on, on top of the listing |
| Dealer | **$0.002** per dealer | each dealer row (outputType = dealers) |
| Actor start | $0.00001 | platform minimum, once per run |

1,000 listings cost $0.90; with detail pages, $0.99. Error rows are never charged, and a listing is never charged twice within a run (duplicates across pages are skipped). When your maximum charge limit is reached the run stops cleanly and says so — no free rows, no surprise.

### Privacy

- **Private sellers (about 87 % of PakWheels ads, measured over 84,486 ads on 23 Sep 2026; 84 % of the 1,279 rows above)**: the seller's name is withheld by default and phone numbers typed into the description are masked. Turn on "Include private sellers' names" only if you have a lawful basis to process them.
- **Dealers and showrooms**: business name, address, opening hours and business phone are always included.
- **Seller phone numbers from ads are never collected**: PakWheels shows them only to signed-in users, and this actor never signs in.
- To ask for your data to be removed from this actor's output, email privacy@actorstack.dev.

### Speed and limits

Measured on the Apify platform on 30 Sep 2026 at 512 MB and the default settings: 100 listings in 8–25 s, 1,000 listings in 96 s (peak memory 228 MB), 150 listings with detail pages in about 2 minutes, 40 dealers in 7 s. PakWheels answered every request from Apify on the first attempt, without a proxy. If the site ever refuses requests, the actor moves to a fallback route at once, pauses politely only when there is nothing else to try, and tells you in the status message.

A single search pages through all its results (the index ends where the site stops returning new ads). For the whole country, split by city or make and run several searches.

### FAQ

**Is there an official PakWheels API?** Not a public one: the site's JSON endpoints require a signed-in session. This actor works as an unofficial PakWheels API: call it from the Apify API, Python or JavaScript client, or schedule it, and get the same rows as JSON, CSV or Excel.

**Is the data real-time?** Yes — every run reads the live site. Schedule it daily to build a price history.

**How many listings can I get?** Up to 100,000 per run (about 84,000 ads are live). A search stops when PakWheels stops returning new ads.

**Why is `price` empty on some rows?** Those ads say "Call for price": `price` is `null` and `price_on_call` is `true`, never a made-up number.

**Can I get the seller's phone number?** No. PakWheels shows it only to signed-in users, and this actor never signs in. Dealer rows (outputType = dealers) carry the showroom's **business** phone from the public directory.

**Can I get a dealer's inventory?** Run listings with "Seller type: Dealers only" and a city; each row has `seller_type: dealer`, and with detail pages on, the showroom name, page and address.

**Which values do filters take?** The words as they appear in PakWheels URLs: city `lahore`, make `toyota`, model `corolla`, body type `suv`. Keywords are sent in PakWheels' own format (lower case, letters, numbers, `.` and `-`).

**What happens with a wrong filter value or a search with no results?** The run finishes green with a single `error` row explaining what to fix, and nothing is charged.

**Does it use a proxy?** No proxy is needed today. You can pass your own in "Proxy configuration"; if your proxy fails, the run says so in an error row instead of failing.

# Actor input Schema

## `outputType` (type: `string`):

Listings is one row per used car ad. Dealers is one row per showroom from the PakWheels dealer directory (use "City" to pick one of the 31 city directories, or leave it empty for the national directory of about 2,080 dealers). One row type per run.

## `searchUrl` (type: `string`):

Paste a search from pakwheels.com — apply filters on the site and copy the address bar, e.g. https://www.pakwheels.com/used-cars/search/-/ct\_karachi/mk\_honda/. When set, the filters below are ignored (except "Seller type" if the URL does not already choose one).

## `city` (type: `string`):

City as in PakWheels URLs, e.g. lahore, karachi, islamabad, rawalpindi, peshawar, multan, faisalabad. Leave empty for all of Pakistan. For outputType = dealers, the dealer-directory city.

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

e.g. toyota, suzuki, honda, kia, hyundai, mg, changan. Leave empty for all makes.

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

e.g. corolla, civic, alto, city, sportage. Use the spelling of PakWheels URLs.

## `yearFrom` (type: `integer`):

Minimum model year.

## `yearTo` (type: `integer`):

Maximum model year.

## `priceFrom` (type: `integer`):

Minimum price in Pakistani rupees. 1 lac = 100,000; 1 crore = 10,000,000.

## `priceTo` (type: `integer`):

Maximum price in Pakistani rupees.

## `mileageFrom` (type: `integer`):

Minimum odometer reading.

## `mileageTo` (type: `integer`):

Maximum odometer reading.

## `engineCcFrom` (type: `integer`):

Minimum engine displacement.

## `engineCcTo` (type: `integer`):

Maximum engine displacement.

## `transmission` (type: `string`):

Gearbox.

## `engineType` (type: `string`):

Fuel / powertrain.

## `bodyType` (type: `string`):

e.g. sedan, hatchback, suv, crossover, mini-van, pick-up.

## `assembly` (type: `string`):

Locally assembled or imported.

## `registeredIn` (type: `string`):

Registration city or province, e.g. islamabad, lahore, punjab, sindh.

## `color` (type: `string`):

e.g. white, black, silver, grey.

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

Every row is tagged with its seller type either way. With "Any", the item limit is shared in proportion to how many ads each type has (87% individuals on PakWheels).

## `onlyInspected` (type: `boolean`):

Only cars with a PakWheels inspection report (about 2,700 ads).

## `onlyManagedByPakWheels` (type: `boolean`):

Only cars whose sale PakWheels manages itself (about 2,200 ads).

## `keyword` (type: `string`):

Free-text search, e.g. "civic reborn" or "automatic". Same as the PakWheels search box.

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

Each order was verified against the live site by checking the values actually come sorted.

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

Stop after this many rows. PakWheels shows about 25 listings per results page. The default of 100 finishes in seconds; see the README for measured throughput on large runs.

## `scrapeDetails` (type: `boolean`):

Adds description, colour, body type, registration city, assembly, engine type, location area, the full feature list, the PakWheels inspection report and the seller block (dealer name, address, opening hours, verification badges). One extra request per listing and its own charge event.

## `includePrivateSellerContact` (type: `boolean`):

Off by default: for individual (non-dealer) sellers the name is withheld and phone numbers typed into the description are masked. Dealer and showroom names and addresses are always included. Seller phone numbers are never collected — PakWheels only shows them to signed-in users.

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

Requests in flight at once. The default of 4 was measured safe (55 of 55 requests succeeded at up to 6.5 requests per second). Lower values are slower without improving reliability.

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

Not needed: PakWheels served every measured request directly. If requests start being refused, the actor switches to a fallback on its own. Set a proxy here only to force one.

## Actor input object example

```json
{
  "outputType": "listings",
  "city": "lahore",
  "make": "toyota",
  "transmission": "any",
  "engineType": "any",
  "assembly": "any",
  "sellerType": "any",
  "onlyInspected": false,
  "onlyManagedByPakWheels": false,
  "sortBy": "newest",
  "maxItems": 30,
  "scrapeDetails": false,
  "includePrivateSellerContact": false,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per listing: price, make, model, version, year, mileage, engine, fuel, city, seller type, inspection score and photos — plus detail-page fields when enabled.

## `runSummary` (type: `string`):

Counts, matching totals per seller type, stop reason and request statistics.

## `errors` (type: `string`):

Pages or detail pages that could not be fetched. Always present, empty on a clean run. Never charged.

# 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 = {
    "city": "lahore",
    "make": "toyota",
    "maxItems": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("oswaldocarabano/pakwheels-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 = {
    "city": "lahore",
    "make": "toyota",
    "maxItems": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("oswaldocarabano/pakwheels-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 '{
  "city": "lahore",
  "make": "toyota",
  "maxItems": 30
}' |
apify call oswaldocarabano/pakwheels-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,oswaldocarabano/pakwheels-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/O0X52MLlgVAYhGke6/builds/8BWUJc3U1Wqxa0qyA/openapi.json
