# Listing Status Checker - Sold, Removed & Price Changes (`amitaviv/property-listing-status-checker`) Actor

Is the listing still online? Paste ad URLs from ImmoScout24, Kleinanzeigen, Fotocasa, Vinted, SEEK or Welcome to the Jungle: get status (online, sold, reserved, removed, expired), current price and price change per URL. For CRM clean-up and price tracking. Refused checks are free.

- **URL**: https://apify.com/amitaviv/property-listing-status-checker.md
- **Developed by:** [Amit Aviv](https://apify.com/amitaviv) (community)
- **Categories:** Real estate, Automation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 listing checks

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

## Listing Status Checker: Sold, Removed & Price Changes

Paste the URLs of property listings, classified ads or job ads you already have, and get one record per URL: is it still online, sold, reserved, removed or expired, what does it cost now, and how has the price changed since you last looked. Supported: **ImmoScout24, Kleinanzeigen, Fotocasa, Vinted, SEEK and Welcome to the Jungle**. Plain HTTP, no browser: a test list of 1,130 URLs from all six sites took two and a half minutes; you pay only for checks that returned a status, and a check the site refused is reported as `unknown` and not charged.

Built for:

- **Agencies and CRM owners**: find the listings in your CRM or spreadsheet that are gone, sold or reserved, without re-scraping whole searches.
- **Price trackers and investors**: re-check a watch list daily and get the price change per listing, in money and percent.
- **Job boards and aggregators**: drop expired SEEK and Welcome to the Jungle ads from your index.

### What you get

- `status`: `online`, `reserved`, `paused`, `sold`, `expired`, `removed`, `redirected`, `notFound` or `unknown`, plus `isOnline` (true / false / null) and `statusLabel`, the site's own words ("Verkauft", "Vendu", "Expired", "archived" …).
- `saleConfirmed` for `sold`: `true` when the site's own checkout marked the item sold (Vinted), `false` when the site only labels the ad (Kleinanzeigen shows "Verkauft" on every deleted goods ad), `null` for other statuses.
- `title`, current `price` and `currency`, `priceType` (cold rent, sale, item price …), `priceText` as shown (salary text for job ads).
- `previousPrice` (the one you gave, or the one the previous run saw), `priceChanged`, `priceDelta`, `priceDeltaPercent`; on Fotocasa also `sitePriceDrop`, the site's own "price lowered by" amount.
- `previousStatus`, `statusChanged`, `previousCheckedAt` when you run the same list again (on by default).
- Dates where the site shows them: `publishedAt` (Fotocasa, SEEK, Welcome to the Jungle), `updatedAt` (Welcome to the Jungle), `expiresAt` (SEEK), `dateOnPage` / `dateOnPageText` (Kleinanzeigen: posted or renewed; Vinted: "uploaded …" as worded).
- `sellerType` (`professional` / `private`) and, for professionals, `advertiserName` when it is recognisably a business name (agency, company, shop): text after a dash (contact person or branch) is cut off ("Covivio Immobilien GmbH - Kathi Piaskowski" becomes "Covivio Immobilien GmbH", "LA CASA AGENCY - HOSTAFRANCS" becomes "LA CASA AGENCY"), and names the actor cannot tell from a person's are left `null`: personal names such as "Sara Fischer", but also some companies whose name has no legal form or trade word (e.g. "Althena"). For job ads, the employer.
- Your own `reference` and the `inputPosition` of each URL, so you can join the output back to your list.
- A run summary (`OUTPUT_SUMMARY` in the run's key-value store): checks per status and per portal, what was charged, which inputs were skipped and why, refused requests.

What it does not return: descriptions, photos, contact details, private sellers' names (unless you opt in, see Legal), anything behind a login. It does not search: you bring the URLs.

### How to use

1. Copy the listing URLs from your CRM, spreadsheet or browser.
2. Paste them into **Listing URLs**, one per line. To compare prices, add the price you last saw after the URL: `https://www.immobilienscout24.de/expose/134412431 700`. Lines copied from a spreadsheet as CSV work too: `https://www.immobilienscout24.de/expose/134412431,700,CRM-17`.
3. Press Start. Download the results from the Output tab (JSON, CSV, Excel) or read them from the API.
4. To watch a list, save the input as a task and schedule it (daily, weekly). Each run reports what changed since the previous one.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `urls` | list of text | none (give this or `listings`) | One listing per line, optionally followed by the price you last saw and your own reference, separated by a space, comma, `;` or tab. Text after the URL that is not a price is kept as your reference (the run summary warns). A URL given twice is checked once, with the price and reference from either line. URLs from other sites and search pages are skipped and listed in the run summary. Up to 50,000 per run. |
| `listings` | JSON list | empty | The same as objects, for exports: `[{ "url": "…", "previousPrice": 700, "reference": "CRM-17" }]`. |
| `compareWithPreviousRun` | yes/no | yes | Remember each listing's status and price and report changes in the next run. |
| `memoryKey` | text | empty | Runs with the same name share one memory; use different names for different lists. |
| `includePrivateSellerData` | yes/no | no | Private sellers' names, and professional account names that are a person's name (Kleinanzeigen, Fotocasa, ImmoScout24). Only with a lawful basis, see Legal. |
| `proxyConfiguration` | proxy | off | Not needed. Fotocasa is always checked through Apify Proxy (included in the price). Turning it on sends every check through Apify Proxy's datacenter addresses; residential groups are replaced by datacenter ones. |

Accepted URL forms: `immobilienscout24.de/expose/<id>`, `kleinanzeigen.de/s-anzeige/…/<id>-<cat>-<loc>`, `fotocasa.es/…/<id>/d`, `vinted.<country>/items/<id>…` on Vinted's own sites (`.fr`, `.de`, `.co.uk`, `.es`, `.it`, `.nl`, `.be`, `.pl`, `.pt`, `.at`, `.lt`, `.lu`, `.cz`, `.sk`, `.hu`, `.ro`, `.se`, `.dk`, `.fi`, `.gr`, `.hr`, `.ie`, `.si`, `.ee`, `.lv`, `.com`), `seek.com.au/job/<id>` and `seek.co.nz/job/<id>`, `welcometothejungle.com/<lang>/companies/<company>/jobs/<job>`.

```json
{
  "urls": [
    "https://www.immobilienscout24.de/expose/134412431 700 CRM-1",
    "https://www.kleinanzeigen.de/s-anzeige/abus-kinderfahrradhelm-erdbeeren-45-50cm/3539529137-217-1590",
    "https://www.fotocasa.es/es/comprar/vivienda/madrid-capital/aire-acondicionado-calefaccion-ascensor/188317693/d 685000",
    "https://www.vinted.fr/items/10350170143-jupe-nike-pro",
    "https://www.seek.com.au/job/94000123"
  ]
}
```

### Example result

From run `1BeqJ5ffbgbxtwV8y` on 2026-10-14 (the second run of an 18-URL test list that also contains the five above, with the same memory name as the run before it), unedited. The input gave 685,000 as the previous price; Fotocasa itself also shows a 10,000 drop:

```json
{
  "url": "https://www.fotocasa.es/es/comprar/vivienda/madrid-capital/aire-acondicionado-calefaccion-ascensor/188317693/d",
  "inputPosition": 7,
  "portal": "fotocasa",
  "listingId": "188317693",
  "reference": null,
  "status": "online",
  "isOnline": true,
  "statusLabel": null,
  "saleConfirmed": null,
  "previousStatus": "online",
  "statusChanged": false,
  "title": "Piso en venta",
  "price": 675000,
  "currency": "EUR",
  "priceType": "sale",
  "priceText": null,
  "previousPrice": 685000,
  "previousPriceSource": "input",
  "priceChanged": true,
  "priceDelta": -10000,
  "priceDeltaPercent": -1.46,
  "sitePriceDrop": 10000,
  "publishedAt": "2025-12-09T12:15:28.543Z",
  "updatedAt": null,
  "expiresAt": null,
  "dateOnPage": null,
  "dateOnPageText": null,
  "sellerType": "professional",
  "advertiserName": "Aproperties Real Estate Madrid",
  "finalUrl": "https://www.fotocasa.es/es/comprar/vivienda/madrid-capital/aire-acondicionado-calefaccion-ascensor/188317693/d",
  "httpStatus": 200,
  "previousCheckedAt": "2026-10-14T16:36:46.420Z",
  "checkedAt": "2026-10-14T16:36:59.148Z",
  "checkId": "fotocasa:188317693",
  "error": null
}
```

The same run, other URLs: an ImmoScout24 flat listed at 710.05 € cold rent against 700 given (`priceDelta` 10.05, `priceDeltaPercent` 1.44); a Kleinanzeigen flat at 1,522 € against 1,600 given (`priceDelta` -78, `priceDeltaPercent` -4.88); a Kleinanzeigen bike helmet the site shows as "Verkauft" (`sold`, `saleConfirmed: false`); a Kleinanzeigen flat the site now redirects to a category page (`redirected`); a SEEK ad with status "Expired"; Vinted items the site shows as "Vendu" (`sold`, `saleConfirmed: true`) with `previousPrice` taken from the run before (`previousPriceSource: "previous run"`). One of them showed "Réservé" (`reserved`) in a test earlier the same day. In an earlier test (run `hLfTpdyVGskro8rO7`), a Vinted item that had answered "not found" seven minutes before showed "Vendu", and came back with `statusChanged: true`, `previousStatus: "notFound"`.

What each status means:

| `status` | `isOnline` | Meaning | Where seen in tests |
|---|---|---|---|
| `online` | true | The listing is live. | all six sites |
| `reserved` | true | Still shown, but reserved for a buyer. | Vinted ("Réservé") |
| `paused` | false | The advertiser paused the ad. | Kleinanzeigen |
| `sold` | false | The site says sold ("Verkauft", "Vendu"). `saleConfirmed` tells a sale through the site's checkout (Vinted, `true`) from a label on a deleted ad (Kleinanzeigen, `false`). | Kleinanzeigen, Vinted |
| `expired` | false | The job ad ran out. | SEEK |
| `removed` | false | The site says deleted, deactivated or archived ("Nicht mehr verfügbar", "Verschenkt", "archived"). | Kleinanzeigen, Welcome to the Jungle |
| `redirected` | false | The site sends the URL to a search or category page instead of the listing. | Kleinanzeigen |
| `notFound` | false | The site answers "not found" (ImmoScout24, SEEK, Welcome to the Jungle and Vinted say 404 or no such id; Fotocasa redirects with `propertyNotFound`). Sites do not tell a deleted listing from an id that never existed. | all six sites |
| `unknown` | null | The site refused the request (403, 429 after retries) or could not be reached, redirected to a sign-in, consent or bot-check page or to another site, or the page could not be read; or the site kept refusing, so the URL was not tried (see Reliability). `error` says why. **Not charged.** Run the URL again later. | run `yjCezQ51k8axsztYE` (a Fotocasa page that did not arrive in time: 5 records, 4 charged); run `80O93hw5avC9hdGO3` (sites unreachable); a real Fotocasa 403 reproduced outside Apify; offline tests |

Fields the site does not provide for a listing are `null`, never missing.

### Pricing

Pay per event: you pay for checks that returned a status, not for time or memory.

| Event | Free | Bronze | Silver | Gold and above |
|---|---|---|---|---|
| Actor start (once per run, 512 MB) | $0.0036 | $0.003 | $0.0027 | $0.0024 |
| Listing check with a known status | $0.0018 | $0.0015 | $0.00135 | $0.0012 |

Worked examples (Bronze):

- 1,000 URLs, one run: 1,000 × $0.0015 + $0.003 = **$1.503**.

- A list of 200 listings checked every day for 30 days: 30 × (200 × $0.0015 + $0.003) = **$9.09**.

- 20 URLs where the site refuses 2 checks: 18 × $0.0015 + $0.003 = $0.030; the 2 come back as `unknown`.

- A URL listed twice is checked and charged once. Skipped inputs (other sites, search pages) cost nothing.

- The maximum total charge you set for a run is respected: the run checks what that pays for, stops, keeps the results and names the number of unchecked URLs in its status message (run `G8htjUIBbuEoJw4v9`: limit $0.0105 = start + 5 checks; 5 checked and charged, 13 not checked, run SUCCEEDED). A limit below the start fee plus one check fails at once (run `i4aaZkNTQcURpyrbr`).

### Reliability and failure behaviour

| What happened | Run status | Status message (real examples) |
|---|---|---|
| Checks done | Succeeded | `Checked 1130 listings: 991 online, 43 sold, 43 expired, 39 not found, 10 removed, 3 paused, 1 redirected away (gone) — 4 prices changed; 80 input entries ignored (see OUTPUT_SUMMARY)` |
| Some checks refused by a site | Succeeded | `Checked 1 listing: 1 online — 1 URL could not be checked (status "unknown", not charged: Fotocasa refused 1)` (a real Fotocasa 403 on an address it refuses, reproduced outside Apify) |
| One site keeps refusing | Succeeded | After 6 refused or failed checks in a row on one site (or 2 in a row with no success for 3 minutes), that site is given up for the run: its other URLs come back `unknown`, not tried and not charged, and the other sites finish. `… — 30 URLs could not be checked (status "unknown", not charged: Fotocasa refused 6); Fotocasa kept refusing or failing, so 24 of its URLs were not tried; try again later` (offline test) |
| Every check refused or no site reachable | **Failed**, within about 2 minutes whatever the list size | `No listing could be checked: Vinted refused every request; try again later. No checks were charged (the start fee applies).` (offline test). Live, with an unreachable proxy country: 40 URLs, both sites given up after 6 checks each, FAILED after 118 s, nothing but the start charged (run `80O93hw5avC9hdGO3`) |
| Nothing usable in the input (an empty list, or only unsupported URLs) | **Failed**, in about a second; on purpose, so a scheduled run with an empty or broken list is noticed instead of succeeding with 0 records | `Nothing to do: the input has no "urls". Add listing URLs to "urls", e.g. "https://www.immobilienscout24.de/expose/134412431". No checks were charged (the start fee applies).` |
| Maximum charge reached | Succeeded | `Checked 5 listings: 3 online, 1 sold, 1 not found — …; stopped at the maximum charge set for this run: 13 URLs not checked` |
| Run timeout close | Succeeded | `… — stopped just before the run timeout: N URLs not checked; raise the timeout` (offline test) |
| You abort the run | Aborted | `Aborted by the user after 810 charged checks` (run `1R3nUsQWLUGthPUOh`: 810 records, 810 charged) |

- Requests are retried on network errors, HTTP 429 and 5xx (3 to 6 times depending on the site, with increasing pauses); a refusal (403, 429) is retried on a new proxy address where a proxy is used.
- Results are saved every 25 checks. A run that is aborted, times out or is restarted keeps what was checked and never checks or charges the same URL twice.
- Measured on 2026-10-14 on the current build: every live test run that had URLs to check and reachable sites succeeded with no `unknown` record, and was charged exactly one check per record (9 runs, 2,091 checks, among them 1,130 URLs in one run, `GTubuwHwcAJEXrqfR`, 91 Fotocasa listings in 54 s, `LVoxuClo7p9vln0yN`, and an aborted run). One run had an `unknown` record (a Fotocasa page that did not arrive in time) and was charged for the other 4 only.

### Limits

- Speed at the default settings, measured in run `U3Fq7Av5qOcT3qwp2` (all six sites in parallel, 1,130 URLs in 178 s; 147 s in run `GTubuwHwcAJEXrqfR`): ImmoScout24 about 500 a minute, Welcome to the Jungle about 780, SEEK about 150, Kleinanzeigen about 90, Fotocasa about 60, Vinted about 20 (Vinted pages are 2 MB and the site limits request rates, so Vinted checks are paced).
- Large lists: with the default run timeout of one hour, plan for about 1,200 Vinted items, 3,600 Fotocasa listings or 5,000 Kleinanzeigen ads per run (ImmoScout24 and job ads go much faster). A run that reaches the timeout stops cleanly, keeps what it checked and names how many URLs were left; raise the timeout or split the list.
- Fotocasa pages come through Apify Proxy, usually in 2-4 s but at times in up to about 45 s; a page that does not arrive in 60 s is asked for again on another address (up to 7 times) and then reported `unknown`, free.
- A Vinted "not found" is not always final: an item that is being bought is hidden for a few minutes and then shows as sold. Seen once in testing.
- ImmoScout24 is read through the API of its mobile app; ImmoScout24 does not say whether a missing listing was sold or rented, only that it is gone.
- Kleinanzeigen calls every deleted goods ad "Verkauft" (sold), whatever the reason the advertiser deleted it; we report the site's word as `sold` with `saleConfirmed: false`.
- A site that blocks for a while (rate limit, bot protection) is given up for the rest of the run after a few refused checks, so a blocked site cannot keep the run going until its timeout; those URLs are `unknown` and free. Run them again later.
- Idealista, Leboncoin, Immowelt and other sites behind DataDome are not supported (they need a real browser, which would cost more than a check is worth).
- Some fields are site-specific (see "What you get"); job ads have no `price`, only `priceText`.
- `advertiserName` for professionals comes from a keyword filter (legal forms such as GmbH, AG, SE, S.L.; trade words such as Immobilien, inmobiliaria, Autohaus): agencies without such a word are left `null` (e.g. "Althena", "SPOT MUNICH"), and trade names that contain a person's name are kept ("Immobilien Fabian Schneider"). It is there to tell agencies apart, not as a complete company directory.
- The charged-event counters shown on a run can lag for about a minute after it ends; read them again before comparing them with the dataset.

### Watching a list: compare with the previous run

On by default. Every run remembers, per listing, the status, the price and when it was checked; the next run with the same **Memory name** fills `previousStatus`, `statusChanged`, `previousCheckedAt` and, if you gave no price in the input, `previousPrice` from it. A check that came back `unknown` leaves the old line untouched.

The memory is a key-value store named `property-listing-status-checker-memory` in your own account (one record per memory name, at most 100,000 listings, the longest unchecked forgotten first). Delete the store or change **Memory name** to start over. To be told about changes, add an integration to the scheduled task (email, Slack, webhook) and filter the dataset on `statusChanged = true` or `priceChanged = true`.

### FAQ

**Do I need a proxy?** No. Fotocasa refuses datacenter addresses outside Apify, so Fotocasa URLs always go through Apify Proxy, at no extra charge to you.

**Why is a URL skipped?** It is from another site, it is a search or category page rather than one listing, or it is a duplicate. The run summary lists each skipped entry with the reason.

**Can I run it from code?** Yes: the API, the Apify clients for JavaScript and Python, Make, Zapier, n8n. The Output tab shows the URLs.

**What happens when a site changes its pages?** The affected checks come back as `unknown` with the reason in `error`, uncharged; if nothing at all can be checked, the run fails. Please report the run id under Issues.

### Legal and responsible use

This actor reads whether a public listing is still online and its price, as any visitor can see without logging in. It does not return private persons' personal data by default: for listings of private sellers the advertiser name is `null` (`sellerType: "private"`), phone numbers and e-mail addresses written into their titles are masked, and Vinted sellers' names are never read. For professional accounts only a name that is recognisably a business is returned: text after a dash (contact person or branch) is cut off, and names the actor cannot tell from a person's are left `null`, which also leaves out some real company names. Turn on **Include private sellers' names** only if you have a lawful basis under the GDPR (or your local law) to process them, for example for your own listings.

The sites' terms of use restrict automated access; you are responsible for how you use this actor and its output: respect the sites' terms, database rights and data-protection law in your country and the country of the data, and do not use the output for unsolicited marketing to individuals. If you are unsure, ask a lawyer before you build on it.

### Changelog

- 2026-10-14 0.1: first version: ImmoScout24, Kleinanzeigen, Fotocasa, Vinted, SEEK, Welcome to the Jungle; comparison with the previous run; a site that keeps refusing is given up for the run; CSV lines; `saleConfirmed`; business names only for professionals.

### Related actors

The scrapers by the same developer for the sites this actor checks. Use one to collect listing URLs from a search, then this actor to re-check those URLs cheaply on a schedule:

- [ImmoScout24 Scraper](https://apify.com/amitaviv/immoscout24-scraper): rent and sale listings from immobilienscout24.de with cold and warm rent, size, rooms, address and coordinates.
- [Kleinanzeigen Scraper](https://apify.com/amitaviv/kleinanzeigen-scraper): ads in every category from kleinanzeigen.de, by search URL or keyword.
- [Fotocasa Scraper](https://apify.com/amitaviv/fotocasa-scraper): sale and rent listings from fotocasa.es with price per m² and price drops.
- [Vinted Scraper](https://apify.com/amitaviv/vinted-scraper): items with brand, size, condition and price from all of Vinted's country sites, with a new-items monitor.
- [SEEK Jobs Scraper](https://apify.com/amitaviv/seek-jobs-scraper): job ads from seek.com.au and seek.co.nz with salary, work type and listing date.

### Support

Open an issue on the actor's **Issues** tab with the run id.

# Actor input Schema

## `urls` (type: `array`):

One listing per line, from immobilienscout24.de (…/expose/<id>), kleinanzeigen.de (…/s-anzeige/…), fotocasa.es (…/<id>/d), vinted.fr, .de, .co.uk and Vinted's other country sites (…/items/<id>…), seek.com.au / seek.co.nz (…/job/<id>) or welcometothejungle.com (…/companies/…/jobs/…). Optionally add the price you last saw and your own reference after the URL, separated by a space, comma, ; or tab: "https://www.immobilienscout24.de/expose/134412431 700 CRM-17" (spreadsheet lines such as "<url>,700,CRM-17" work too). Text after the URL that is not a price is kept as your reference. A URL listed twice is checked once. Other sites and search pages are skipped and listed in the run summary. Up to 50,000 URLs per run. Each URL that gets a known status is one charged 'check' event; URLs the site refused come back with status unknown and are not charged. Required unless "listings" is given.

## `listings` (type: `array`):

The same as "Listing URLs" as objects, for exports from a CRM or spreadsheet: \[{ "url": "https://…", "previousPrice": 700, "reference": "CRM-17" }]. previousPrice and reference are optional.

## `compareWithPreviousRun` (type: `boolean`):

Remember each listing's status and price, and report in the next run what changed (previousStatus, statusChanged, previousPrice). Default on. A price you give in the input is used instead of the remembered one. The memory is a key-value store named property-listing-status-checker-memory in your account; delete it to start over.

## `memoryKey` (type: `string`):

Free text, e.g. "client-a-daily". Runs with the same name share one memory. Give separate lists (clients, portals, schedules) different names to keep their comparisons apart.

## `includePrivateSellerData` (type: `boolean`):

Off by default: for listings of private persons the advertiser name is left empty and phone numbers or e-mail addresses in their titles are masked (sellerType says "private"). For business accounts on Kleinanzeigen, ImmoScout24 and Fotocasa only a business name is shown, without the contact person or branch after a dash; a name that is not recognisably a business is left empty (this includes some real company names). Turn this on only if you confirm you have a lawful basis under the GDPR (or your local law) to process these names, e.g. your own listings. Vinted sellers' names are never collected.

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

Off by default. Fotocasa is always checked through Apify Proxy (it refuses other datacenter addresses). Turn on Apify Proxy here to send all checks through its datacenter addresses (Vinted checks are then paced 0.3 s apart instead of 1.2 s). Residential groups are not used: they are replaced by datacenter addresses.

## Actor input object example

```json
{
  "urls": [
    "https://www.immobilienscout24.de/expose/134412431",
    "https://www.seek.com.au/job/94000123"
  ],
  "compareWithPreviousRun": true,
  "includePrivateSellerData": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

All records as JSON, one object per listing URL. Main fields: url, portal, listingId, reference (yours), status (online, reserved, paused, sold, expired, removed, redirected, notFound or unknown), isOnline, statusLabel (the site's own words), saleConfirmed, title, price, currency, priceType, previousPrice, priceChanged, priceDelta, priceDeltaPercent, previousStatus, statusChanged, publishedAt, sellerType, advertiserName (businesses only by default), checkedAt, and error (why a status is unknown).

## `resultsCsv` (type: `string`):

All records as a CSV file, one row per listing URL.

## `summary` (type: `string`):

How many URLs were checked, per status and portal, what was charged, which inputs were ignored and why the run stopped.

# 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 = {
    "urls": [
        "https://www.immobilienscout24.de/expose/134412431",
        "https://www.seek.com.au/job/94000123"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("amitaviv/property-listing-status-checker").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 = {
    "urls": [
        "https://www.immobilienscout24.de/expose/134412431",
        "https://www.seek.com.au/job/94000123",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("amitaviv/property-listing-status-checker").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 '{
  "urls": [
    "https://www.immobilienscout24.de/expose/134412431",
    "https://www.seek.com.au/job/94000123"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call amitaviv/property-listing-status-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,amitaviv/property-listing-status-checker"
        }
    }
}
```

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/RWPT4pv2Au57R29RE/builds/ku59NbkJKQUfIR59Z/openapi.json
