# Spinny Used Car Scraper (`maximedupre/spinny`) Actor

Collect public Spinny used-car listings by city or search URL. Get prices, mileage, car specs, hub details, and source links in a dataset for inventory research and price checks.

- **URL**: https://apify.com/maximedupre/spinny.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** E-commerce, Business, Other
- **Stats:** 3 total users, 2 monthly users, 95.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 car listings

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

### 🚗 Compare Spinny used-car listings in one dataset

Car buyers, dealers, and market researchers can collect public Spinny used-car listings with prices, mileage, car specs, and source links. Search by city or use Spinny search URLs, then review the saved data to compare cars and study inventory without copying each listing by hand.

- Collect [**Used cars in Bangalore**](https://apify.com/maximedupre/spinny/examples/used-cars-in-bangalore) for local price and inventory checks.
- Find [**Used cars under 5 lakhs**](https://apify.com/maximedupre/spinny/examples/used-cars-under-5-lakhs) within a set budget.
- Compare [**Used SUV cars**](https://apify.com/maximedupre/spinny/examples/used-suv-cars) with listed prices and mileage.
- Collect [**Used automatic cars**](https://apify.com/maximedupre/spinny/examples/used-automatic-cars) to review cars with automatic transmission.
- Find [**Used CNG cars**](https://apify.com/maximedupre/spinny/examples/used-cng-cars) for fuel-type research.

#### 📋 Spinny car data you get

Each row is one valid public car listing. It includes the listing ID, source URL, make, model, price in Indian rupees, year made, and mileage in kilometers. When Spinny publishes them, rows also include loan offers, booking deposits, hub details, photo links, availability, and certification tiers.

The Actor saves the first eligible match for each car and ignores later matches for that same listing. A saved row keeps only that first match. Fields that Spinny does not publish may be absent.

#### ▶️ Run a Spinny car search

1. Choose **City search** or **Search URLs**.
2. For City search, enter a Spinny city and any car filters. For Search URLs, add Spinny search-result links with the filters you want.
3. Set **Maximum cars**, or leave it empty to return all available results until the source is exhausted.
4. Start the Actor and open **Car listings** in the Output tab to review the dataset.

#### ⚙️ Input

Only fields for your chosen search method are used. The car limit applies to both methods. Use City search for used cars in Bangalore or used cars in Hyderabad. Use Search URLs to keep source filters such as brand and price range from your Spinny links.

**Input fields**

| Field | Type | What it does |
|---|---|---|
| `searchMethod` | string | Required. Choose `city` for City search or `searchUrls` for Search URLs. |
| `city` | string | Spinny city name, needed for City search. |
| `bodyStyle` | string | Optional City search body style, such as `hatchback`, `sedan`, `suv`, or `muv`. Leave empty for all styles. |
| `fuelType` | string | Optional City search fuel type, such as `petrol`, `diesel`, `cng`, `electric`, or `hybrid`. Leave empty for all fuels. |
| `transmission` | string | Optional City search transmission, such as `manual` or `automatic`. Leave empty for all transmissions. |
| `maxPrice` | integer | Highest listed City search price in Indian rupees. Must be at least 1 when set. Leave empty for any price. |
| `searchUrls` | array of objects | One or more Spinny search-result URLs for Search URLs. Each link keeps its source search filters. |
| `searchUrls[].url` | string | Required within each URL entry. A Spinny search-result link. |
| `maxItems` | integer | Optional cap on valid car listings saved across the run. Must be at least 1 when set. Leave empty to return all available results until the source is exhausted. |

**Example input**

This input comes from a successful default-input run:

```json
{
  "searchMethod": "city",
  "city": "Bangalore",
  "maxItems": 10
}
```

#### 🧾 Output

The Output tab links to the saved car listings. Both search methods return the same listing shape.

**Run output**

| Field | Type | What it does |
|---|---|---|
| `listings` | string | Link to the run's car listings in the default dataset overview. |

**Car listing fields**

All amounts below are in Indian rupees. Mileage is in kilometers. Optional fields appear only when the source provides them. Dotted paths show fields inside objects; `[]` shows entries in an array.

| Field | Type | What it does |
|---|---|---|
| `listingId` | string | Spinny listing ID for matching the same car across exports. |
| `url` | string | Source car listing page. |
| `make` | string | Vehicle make. |
| `model` | string | Vehicle model. |
| `variant` | string | Vehicle variant or trim. |
| `manufacturingYear` | integer | Year the vehicle was made. |
| `registrationYear` | integer | Year the vehicle was registered. |
| `mileage` | number | Distance driven in kilometers. |
| `color` | string | Listed vehicle color. |
| `bodyStyle` | string | Vehicle body style. |
| `fuelType` | string | Vehicle fuel type. |
| `transmission` | string | Transmission type. |
| `transmissionSubtype` | string | More specific source transmission type. |
| `previousOwnerCount` | integer | Listed number of previous owners. |
| `insuranceValidity` | string | Insurance validity stated by Spinny. |
| `price` | number | Current listed price. |
| `pricing` | object | Other published prices and charges. |
| `pricing.originalPrice` | number | Original listed price. |
| `pricing.finalPayableAmount` | number | Final amount to pay, as published by Spinny. |
| `pricing.components` | array of objects | Published taxes, fees, and add-on charges. |
| `pricing.components[].name` | string | Name of the charge. |
| `pricing.components[].amount` | number | Charge amount. |
| `pricing.createdAt` | string | Source date when the price record was created. |
| `financing` | object | Published loan terms and offers. |
| `financing.monthlyEmi` | number | Published monthly loan payment. |
| `financing.offers` | array of objects | Available financing offers. |
| `financing.offers[].loanAmount` | number | Offered loan amount. |
| `financing.offers[].interestRate` | number | Published interest rate as a percent. |
| `financing.offers[].termMonths` | integer | Loan repayment term in months. |
| `financing.offers[].monthlyEmi` | number | Monthly payment for this offer. |
| `bookingDeposit` | object | Published booking deposit terms. |
| `bookingDeposit.amount` | number | Booking deposit amount. |
| `bookingDeposit.maximum` | number | Highest allowed deposit. |
| `city` | string | City where the car is listed. |
| `hub` | object | Car hub offering the vehicle. |
| `hub.id` | string | Source hub ID. |
| `hub.name` | string | Published hub name. |
| `hub.address` | string | Published hub address. |
| `hub.classification` | string | Published hub type. |
| `hub.latitude` | number | Published hub latitude. |
| `hub.longitude` | number | Published hub longitude. |
| `registrationAuthority` | string | Listed vehicle registration authority. |
| `location` | object | Published geographic details. |
| `location.area` | string | Published area name. |
| `location.state` | string | Published state name. |
| `photos` | array of objects | Source-hosted vehicle photos. |
| `photos[].url` | string | Source photo URL. |
| `photos[].label` | string | Source photo label. |
| `photos[].kind` | string | Photo type, including photos with the background removed when published. |
| `media360` | array of objects | Source-published 360-degree media. |
| `media360[].url` | string | Source media URL. |
| `media360[].type` | string | Source media type. |
| `availability` | object | Availability stated by Spinny. |
| `availability.sold` | boolean | Whether Spinny marks the car as sold. |
| `availability.booked` | boolean | Whether Spinny marks the car as booked. |
| `availability.onHold` | boolean | Whether Spinny marks the car as on hold. |
| `availability.upcoming` | boolean | Whether Spinny marks the car as upcoming. |
| `availability.publicationStatus` | string | Source publication status. |
| `availability.availableFrom` | string | Source date when the car becomes available. |
| `certificationTier` | string | Certification tier published by Spinny. |
| `procurementClassification` | string | Vehicle procurement class published by Spinny. |
| `homeTestDriveAvailable` | boolean | Whether Spinny offers a home test drive for this car. |
| `fixedPrice` | boolean | Whether Spinny states that the purchase price is fixed. |
| `assessments` | array of objects | Published vehicle assessments. |
| `assessments[].name` | string | Assessment name. |
| `assessments[].description` | string | Published assessment details. |
| `assessments[].priority` | number | Source priority for the assessment. |
| `benefits` | array of objects | Published benefits and perks. |
| `benefits[].name` | string | Benefit name. |
| `benefits[].description` | string | Published benefit details. |
| `benefits[].priority` | number | Source priority for the benefit. |
| `badges` | array of objects | Promotional badges published for the car. |
| `badges[].label` | string | Published badge text. |
| `badges[].priority` | number | Source priority for the badge. |
| `rankingScore` | number | Spinny's ranking score, not an Actor-calculated score. |
| `shortlistCount` | integer | Shortlist count published by Spinny. |
| `publishedAt` | string | Source listing publication date. |

**Example car listing**

This genuine row comes from the successful default-input run. It is shortened: the large `photos` and `media360` arrays are replaced with `"..."`. All other fields and values are kept as saved.

```json
{
  "listingId": "32351812",
  "url": "https://www.spinny.com/buy-used-cars/bangalore/renault/kwid/10-rxt-2016/32351812/",
  "make": "Renault",
  "model": "Kwid",
  "variant": "1.0 RXT",
  "manufacturingYear": 2016,
  "registrationYear": 2016,
  "mileage": 55974,
  "color": "bronze",
  "bodyStyle": "hatchback",
  "fuelType": "petrol",
  "transmission": "manual",
  "transmissionSubtype": "regular",
  "previousOwnerCount": 2,
  "insuranceValidity": "2027-10-06",
  "price": 272000,
  "pricing": {
    "originalPrice": 272000,
    "finalPayableAmount": 272000,
    "components": [
      {
        "name": "RC transfer, insurance & more",
        "amount": 15360
      },
      {
        "name": "RC transfer facilitation",
        "amount": 4000
      },
      {
        "name": "Insurance",
        "amount": 2860
      },
      {
        "name": "Car cleaning & dry cleaning",
        "amount": 4000
      },
      {
        "name": "Pre delivery servicing cost",
        "amount": 4000
      },
      {
        "name": "Fuel top-up",
        "amount": 500
      },
      {
        "name": "Warranty (Protect)",
        "amount": 4515
      },
      {
        "name": "GST (govt. taxes)",
        "amount": 2253
      }
    ],
    "createdAt": "2026-10-04 16:51:25"
  },
  "financing": {
    "monthlyEmi": 4951,
    "offers": [
      {
        "loanAmount": 163200,
        "interestRate": 13,
        "monthlyEmi": 4951,
        "termMonths": 36
      }
    ]
  },
  "bookingDeposit": {
    "amount": 5000,
    "maximum": 25000
  },
  "city": "Bangalore",
  "hub": {
    "id": "66",
    "name": "Spinny Park, Yelahanka, Bangalore",
    "address": "Spinny Park,  4JB8+4M4, Hunasamaranahalli, Yelahanka, Bengaluru-562157",
    "classification": "park",
    "latitude": 13.142731,
    "longitude": 77.616743
  },
  "registrationAuthority": "KA01",
  "location": {
    "area": "Yelahanka",
    "state": "Karnataka"
  },
  "photos": "...",
  "media360": "...",
  "availability": {
    "sold": false,
    "booked": false,
    "onHold": true,
    "upcoming": false,
    "publicationStatus": "published"
  },
  "certificationTier": "budget",
  "procurementClassification": "budget",
  "homeTestDriveAvailable": true,
  "fixedPrice": true,
  "assessments": [],
  "benefits": [
    {
      "name": "Warranty",
      "description": "Engine and transmission: 6 months\nComprehensive: 2 months"
    },
    {
      "description": "Servicing and dry cleaning"
    },
    {
      "description": "5-day money back guarantee"
    },
    {
      "name": "Great performance in segment",
      "description": "Stands out with a powerful 1.0L engine punching 67 bhp power & 91 Nm torque",
      "priority": 10
    }
  ],
  "badges": [
    {
      "label": "Performance",
      "priority": 10
    }
  ],
  "rankingScore": 0.4080287597363691,
  "shortlistCount": 1,
  "publishedAt": "2026-10-05 09:49:53"
}
```

#### 💳 Pricing

One **Car listing** charge applies to each valid public used-car listing saved to your dataset. Listings that cannot be read or fail validation are not paid listings. A run with no saved listings has no car listing charge. See the Store pricing panel for current tier prices.

#### 🔌 Integrations

Use the Apify API to start runs and read the saved dataset. You can also export the dataset from Apify for your own reports or data tools.

https://www.youtube.com/watch?v=bNACk1_S_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

#### ❓ FAQ

##### Why are my city filters ignored when I use Search URLs?

Search URLs uses the filters in each Spinny link. The separate city, body style, fuel type, transmission, and maximum price fields apply only to City search.

##### How do I filter by brand or a price range?

Use Search URLs and add a Spinny search-result link with those source filters. City search offers a maximum price field in Indian rupees.

##### What if one search URL fails?

The Actor continues collecting valid listings from the other submitted search URLs. Check the run's warning logs for failed URLs.

##### Will the same car appear more than once?

The Actor saves the first eligible occurrence of a listing and ignores later matches for the same listing. It does not combine data from later matches into the saved row.

##### Why are some fields missing?

Extra fields, such as financing offers or certification tiers, depend on what Spinny publishes. A failed read does not mean that a car was sold or removed.

##### What happens if I leave Maximum cars empty?

The Actor returns all available results until the source is exhausted. A search can return fewer cars than a limit you set.

##### Is this Spinny's official website or a car-buying service?

Spinny's source website is [spinny.com](https://www.spinny.com/). This Actor collects its public used-car listings for research. It does not buy or book cars, apply for financing, or schedule test drives.

### 📝 Changelog

**v0.0** (06-10-2026)

- Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~spinny/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Related Actors

- [CarAndBike India Used Car Scraper](https://apify.com/maximedupre/carandbike) collects another Indian used-car source for price and inventory comparisons.
- [Carsales.com.au Scraper](https://apify.com/maximedupre/carsales-scraper) collects Australian vehicle listings with prices, specs, and seller details.
- [Autotrader Scraper](https://apify.com/maximedupre/autotrader-scraper) collects US car listings for vehicle price and mileage research.
- [OLX Scraper](https://apify.com/maximedupre/olx-scraper) collects public marketplace listings for price checks across its supported European markets.
- [Spinny Used Car Search Scraper](https://apify.com/stealth_mode/spinny-used-car-search-scraper) offers another Spinny search-URL workflow for used-car listing research.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `searchMethod` (type: `string`):

Choose how to find car listings.

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

Enter a Spinny city name. This is needed for City search.

## `bodyStyle` (type: `string`):

Limit City search to this body style. Leave blank for all body styles.

## `fuelType` (type: `string`):

Limit City search to this fuel type. Leave blank for all fuel types.

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

Limit City search to this transmission. Leave blank for all transmissions.

## `maxPrice` (type: `integer`):

Highest listed car price for City search, in Indian rupees. Leave blank for any price.

## `searchUrls` (type: `array`):

Add one or more Spinny search-result URLs for Search URLs. Each link keeps its Spinny search filters, such as city, brand, body style, and price range.

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

Stop after this many valid car listings across the run. Leave blank to return all available results until the source is exhausted. Applies to City search and Search URLs.

## Actor input object example

```json
{
  "searchMethod": "city",
  "city": "Bangalore",
  "maxItems": 10
}
```

# Actor output Schema

## `listings` (type: `string`):

View the collected car listings.

# 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 = {
    "searchMethod": "city",
    "city": "Bangalore",
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/spinny").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 = {
    "searchMethod": "city",
    "city": "Bangalore",
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/spinny").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 '{
  "searchMethod": "city",
  "city": "Bangalore",
  "maxItems": 10
}' |
apify call maximedupre/spinny --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maximedupre/spinny"
        }
    }
}
```

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/SioKhjX58tgWgACWr/builds/iuPyVHWOvwQzJ88bZ/openapi.json
