# Otomoto Change Intelligence (`green_amazement/otomoto-change-intelligence`) Actor

Monitor public Otomoto search pages for new used-car listings, price drops and removed offers. Export structured changes to datasets for scheduled monitoring workflows.

- **URL**: https://apify.com/green_amazement/otomoto-change-intelligence.md
- **Developed by:** [ForgeFrame Lab](https://apify.com/green_amazement) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 source scans

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 Change Intelligence — Price Drop & Inventory Monitor

**Stop comparing the same OTOMOTO search by hand.** Track public used-car listings, asking-price changes, newly visible offers, and listings that leave your monitored result window. Export structured events to a spreadsheet, webhook, database, or AI agent.

**Start in one click with a preconfigured use case:** [BMW 3 Series price drops](https://apify.com/green_amazement/otomoto-change-intelligence/examples/bmw-3-series-price-changes), [Audi A4 competitor price monitoring](https://apify.com/green_amazement/otomoto-change-intelligence/examples/audi-a4-market-price-watch), or [Skoda Octavia new offers](https://apify.com/green_amazement/otomoto-change-intelligence/examples/skoda-octavia-new-listing-monitor).

This Actor is for **recurring change monitoring**, not just another one-off bulk scraper. Your first successful run establishes a baseline; later runs emit meaningful deltas. Listings outside a bounded result window are not necessarily sold or deleted.

### What you get

For every monitored search, the Actor keeps a persistent snapshot and emits structured events:

- `NEW_LISTING` — a listing appeared since the previous run.
- `PRICE_CHANGE` — price or currency changed, with absolute and percentage delta.
- `REMOVED_LISTING` — a listing disappeared from the monitored result set.
- `BASELINE_CREATED` — the first successful run created the baseline.

Each listing contains a stable OTOMOTO ID, URL, title, price, currency, year, mileage, fuel type, and gearbox when present on the public result card.

### Best use cases

- Dealer inventory monitoring.
- Price-drop alerts for a saved OTOMOTO search.
- Sourcing newly listed vehicles before a manual review.
- Competitive inventory monitoring.
- Daily or hourly market-segment snapshots.
- Feeding change events into Make, Zapier, n8n, webhooks, Sheets, databases, or agents.

### Quick start

Use any public OTOMOTO search/category URL:

```json
{
  "searchUrl": "https://www.otomoto.pl/osobowe/bmw/seria-3",
  "maxItems": 100,
  "maxPages": 4,
  "snapshotKey": "bmw-3-series",
  "includeCurrentSnapshot": true
}
```

#### First run

The first run stores a baseline. It emits `BASELINE_CREATED`, not hundreds of fake "new" events. With `includeCurrentSnapshot=true`, the dataset also contains `CURRENT_LISTING` rows, so users immediately see the current inventory while preparing for later price-change comparisons.

#### Later runs

Run the same input again — ideally on an Apify Schedule. The Actor compares the current public result set with the persistent baseline and emits only actual changes.

### Pricing

Pay per event, with platform usage included in event pricing.

- **Source scan:** $0.01 per successfully fetched and parsed OTOMOTO result page.
- **Detected listing change:** $0.001 for each new, removed, or price-changed listing.
- A tiny Actor-start and default dataset-item charge may also apply as displayed by Apify.

The Actor respects the run's maximum charge. It stops cleanly when the event budget is exhausted.

### Cost control

Use `maxItems` and `maxPages` as hard limits.

For a narrow saved search, start with:

```json
{
  "maxItems": 100,
  "maxPages": 4
}
```

A typical OTOMOTO result page contains dozens of cards, so change monitoring does not require fetching individual detail pages.

### Input

#### `searchUrl`

Public OTOMOTO category or filtered search URL. Individual listing pages are intentionally rejected.

#### `snapshotKey`

Optional stable identifier for the monitored search. Reuse the same value across scheduled runs.

#### `maxItems`

Maximum listings retained in the current snapshot.

#### `maxPages`

Maximum public search-result pages fetched in one run.

#### `requestDelaySeconds`

Delay between result-page requests. Minimum is 0.5 seconds.

#### `includeCurrentSnapshot`

When enabled, current listing rows are also written to the default dataset. Leave disabled when you only need changes.

### Reliability and safety

- Public search/category pages only.
- No login or OTOMOTO account required.
- No CAPTCHA bypass.
- No residential-proxy requirement in the current adapter.
- No hidden/private endpoints.
- The Actor fails loudly if the result-card structure disappears instead of silently returning an empty dataset.
- Snapshots are committed only after a successful scan, so a failed run does not overwrite the previous baseline.
- Watch history is partitioned by the authenticated Apify user, public search URL and snapshot key. Different users cannot share a comparison baseline even when they choose identical task names.
- **October 2026 baseline migration:** the new isolated storage keys intentionally do not reuse older, unpartitioned comparison records. The first run after this update establishes a fresh baseline; subsequent runs resume normal price-change detection. No legacy data is copied across accounts.
- `REMOVED_LISTING` means an offer left the currently configured, bounded search result window. It does **not** prove the vehicle sold, was removed from OTOMOTO, or became unavailable.
- The Actor stores no private seller contact details; search URLs and results must be publicly accessible.
- Output tab includes both the default dataset link and a machine-readable `OUTPUT` run summary for APIs and agent workflows.

### Recommended workflow

1. Build the OTOMOTO filters you care about in your browser.
2. Copy the resulting public search URL.
3. Run once to create the baseline.
4. Create an Apify Schedule with the same `snapshotKey`.
5. Consume only `NEW_LISTING`, `PRICE_CHANGE`, and `REMOVED_LISTING` events.

### Output example

```json
{
  "type": "PRICE_CHANGE",
  "listing": {
    "id": "6150993730",
    "url": "https://www.otomoto.pl/osobowe/oferta/example.html",
    "title": "Example vehicle",
    "price": 119900,
    "currency": "PLN",
    "year": 2022,
    "mileage_km": 42000
  },
  "previous_price": 124900,
  "previous_currency": "PLN",
  "delta": -5000,
  "delta_pct": -4.0032
}
```

### Scope

The Actor monitors the public data visible on OTOMOTO result pages. It does not claim access to private seller data or privileged OTOMOTO APIs.

# Actor input Schema

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

Paste a public OTOMOTO category or filtered search URL. Individual listing URLs are rejected.

## `snapshotKey` (type: `string`):

Optional stable key. Reuse the same value in scheduled runs to compare against the same baseline.

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

Hard cap on listings held in the current snapshot.

## `maxPages` (type: `integer`):

Each successfully parsed page triggers one Source scan event.

## `requestDelaySeconds` (type: `number`):

Polite delay between public result-page requests.

## `includeCurrentSnapshot` (type: `boolean`):

When enabled, current listing rows are also written to the default dataset.

## Actor input object example

```json
{
  "searchUrl": "https://www.otomoto.pl/osobowe",
  "maxItems": 100,
  "maxPages": 5,
  "requestDelaySeconds": 1.2,
  "includeCurrentSnapshot": false
}
```

# Actor output Schema

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

Default dataset items from the monitored public OTOMOTO search; includes baseline, additions, removals and price changes depending on run state.

## `scanSummary` (type: `string`):

First-run baseline indicator, pages and listings scanned, number of actual changes, and category counts.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("green_amazement/otomoto-change-intelligence").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("green_amazement/otomoto-change-intelligence").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 '{}' |
apify call green_amazement/otomoto-change-intelligence --silent --output-dataset

```

## MCP server setup

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

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/YGiUITjESUw8wfi5s/builds/fCgrn0EW2R7qG6bo0/openapi.json
