# Otomoto Deal Finder: Car Deal Ratings & Price Drops (`donzely/otomoto-deal-finder`) Actor

Find underpriced used cars on Otomoto.pl. Every listing is rated GREAT, GOOD, FAIR, HIGH or OVERPRICED against comparable cars (same model, year, fuel, power, mileage-adjusted), with market price, difference in PLN and daily alerts for new listings and price drops.

- **URL**: https://apify.com/donzely/otomoto-deal-finder.md
- **Developed by:** [Grzegorz Pryjma](https://apify.com/donzely) (community)
- **Categories:** Automation, E-commerce
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.50 / 1,000 rated 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

## Otomoto Deal Finder: Car Deal Ratings & Price Drops

**Find underpriced used cars on Otomoto.pl in minutes.** This Actor rates every listing against comparable cars on the market, the way CarGurus does in the US. Each car gets a deal rating (**GREAT, GOOD, FAIR, HIGH, OVERPRICED**), its estimated market price and how many złoty it is below or above the market. Run it on a schedule and it reports only new listings and price drops.

🇵🇱 *Wyszukiwarka okazji na Otomoto: każde ogłoszenie porównane z rynkiem (ten sam model, rocznik, paliwo, moc, korekta za przebieg) i ocenione jak w CarGurus, plus alerty o nowych ogłoszeniach i obniżkach cen.*

### What it does

1. Takes searches typed naturally, such as `bmw x5`, `toyota corolla 2019-2021`, `skoda octavia kombi diesel` or `mercedes klasa c 2018`, or Otomoto search URLs with your own filters. Typos like `toyta corola` are recognized.
2. Scans the newest listings, with optional filters for year, price, mileage, fuel, region and seller type.
3. For every listing it builds a market comparison from **undamaged** cars of the **same make and model, year ±1, same fuel and power ±15%**.
4. It fits a mileage- and year-adjusted price model on those comparables. A high-mileage car is compared with what a car with *that* mileage should cost, not with the average.
5. It outputs the market price, the difference in PLN and %, the deal rating, the number of comparables and a confidence level.
6. It skips ads that only look cheap: lease transfers (cesja, odstępne), monthly-installment prices, rentals, damaged cars and prices below 15% of market. Listings priced in EUR, usually cars still abroad and often net of VAT, are kept but not rated.

### Deal ratings

The difference is `(price − market price) / market price`.

| Rating | Difference |
|---|---|
| GREAT | 15% or more below market |
| GOOD | 7–15% below market |
| FAIR | within ±7% of market |
| HIGH | 7–15% above market |
| OVERPRICED | 15% or more above market |

Confidence depends on how many comparable listings were found: **high** for 30 or more, **medium** for 15–29, **low** for 8–14. With fewer than 8 the listing is not rated.

### Who is it for

- Car dealers and flippers looking for cars to buy below market
- Private buyers who want to know if a price is fair
- Analysts tracking used-car prices in Poland
- Anyone who wants a daily alert for good deals on a specific model

### Input

| Field | Description |
|---|---|
| `searches` | One car per line, e.g. `volkswagen golf 2017-2020`, `audi a4 avant diesel` |
| `startUrls` | Otomoto search URLs with your own filters |
| `yearFrom`, `yearTo`, `maxPricePln`, `maxMileageKm`, `fuel`, `region`, `sellerType` | Filters |
| `onlyDeals` | Output only GOOD and GREAT deals |
| `onlyNewSinceLastRun` | For scheduled runs: only new listings and price drops |
| `maxItems` | Maximum rated listings (you pay per rated listing) |

Example:

```json
{
  "searches": ["skoda octavia kombi diesel 2018-2021", "toyota corolla 2019-2021"],
  "maxMileageKm": 200000,
  "region": "mazowieckie",
  "onlyDeals": true,
  "maxItems": 50
}
```

### Output

```json
{
  "title": "Toyota Corolla 1.8 Hybrid Comfort",
  "url": "https://www.otomoto.pl/osobowe/oferta/...",
  "year": 2019, "mileageKm": 72000, "powerHp": 122, "fuel": "hybrid",
  "pricePln": 63900,
  "marketPricePln": 77198,
  "differencePln": -13298,
  "differencePct": -17.2,
  "dealRating": "GREAT",
  "confidence": "high",
  "comparablesCount": 94,
  "valuationMethod": "mileage- and year-adjusted regression",
  "mileageEffectPer10kKmPln": -1180,
  "comparablesSearchUrl": "https://www.otomoto.pl/osobowe?search[...]",
  "isNew": true, "previousPricePln": 66900, "priceDropPln": 3000
}
```

The **Deals overview** table shows photo, price, market price, difference and rating side by side. Export to Excel, CSV or JSON, or connect through the API, Make, Zapier or n8n.

### Daily deal alerts

Schedule the Actor daily with `onlyNewSinceLastRun` on. Each run returns only listings it has not seen before with the same searches, plus listings whose price dropped. Combine it with `onlyDeals` to get just the new bargains.

### Pricing

Pay per rated listing, no start fee. Market comparisons are cached per model, year, fuel and power, so large runs stay fast. Listings skipped as suspicious or filtered out by `onlyDeals` are not charged.

### Limits

- The market price is an estimate from asking prices on Otomoto, not transaction prices. Equipment, condition and accident history are not visible in the comparison, so always check the ad.
- Rare models may have too few comparables and stay unrated.
- Only passenger cars (osobowe) are supported.

# Actor input Schema

## `searches` (type: `array`):

One car per line, typed naturally: make, model, optional year or year range, fuel and body. Examples: "bmw x5", "toyota corolla 2019-2021", "skoda octavia kombi diesel", "mercedes klasa c 2018". You can also paste an Otomoto search URL.

## `startUrls` (type: `array`):

Otomoto search result pages with your own filters, e.g. https://www.otomoto.pl/osobowe/volkswagen/golf?search\[filter_float_year:from]=2018

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

Minimum production year (overrides years in the search text).

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

Maximum production year.

## `maxPricePln` (type: `integer`):

Only listings up to this price.

## `maxMileageKm` (type: `integer`):

Only listings up to this mileage.

## `fuel` (type: `string`):

Fuel type (overrides fuel words in the search text).

## `region` (type: `string`):

Only listings from this voivodeship.

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

Private sellers, dealers or both.

## `onlyDeals` (type: `boolean`):

Output only listings priced at least 7% below their market value.

## `includeUnrated` (type: `boolean`):

Rare cars may have too few comparable listings to rate. Turn off to drop them.

## `onlyNewSinceLastRun` (type: `boolean`):

For scheduled runs: output only listings not seen in previous runs with the same searches, plus listings whose price dropped.

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

Stop after this many rated listings (you pay per rated listing).

## `maxPagesPerSearch` (type: `integer`):

Otomoto pages (32 listings each, newest first) scanned per search.

## `minComparables` (type: `integer`):

Minimum number of comparable cars needed to rate a listing.

## `comparablePages` (type: `integer`):

Otomoto pages (32 listings each) used to build each market comparison.

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

Optional Apify Proxy.

## Actor input object example

```json
{
  "searches": [
    "toyota corolla 2019-2021"
  ],
  "sellerType": "all",
  "onlyDeals": false,
  "includeUnrated": true,
  "onlyNewSinceLastRun": false,
  "maxItems": 30,
  "maxPagesPerSearch": 5,
  "minComparables": 8,
  "comparablePages": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `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 = {
    "searches": [
        "toyota corolla 2019-2021"
    ],
    "maxItems": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("donzely/otomoto-deal-finder").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 = {
    "searches": ["toyota corolla 2019-2021"],
    "maxItems": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("donzely/otomoto-deal-finder").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 '{
  "searches": [
    "toyota corolla 2019-2021"
  ],
  "maxItems": 30
}' |
apify call donzely/otomoto-deal-finder --silent --output-dataset

```

## MCP server setup

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

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/azXRiKbbRdB0Iousq/builds/88VzLcoBJfvaBVsan/openapi.json
