# Changelog of Marktplaats.nl Scraper (Netherlands Classifieds) (`stone_jadex/marktplaats-nl-scraper`) Actor

- **URL**: https://apify.com/stone_jadex/marktplaats-nl-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/stone_jadex/marktplaats-nl-scraper.md

## Changelog

### Unreleased (2026-10-26)

- `OUTPUT.statusMessage` now always equals the platform status text on every path (rows, removed-only, empty, errors). One function `buildStatusMessage` builds the text for both `setStatusMessage` and OUTPUT. Previously the removed-only path wrote the old '1 listing(s) were removed…' text and the rows path wrote null (red: redlogs/status-sync.red.log; mutation dropping the OUTPUT assignment on the rows path: redlogs/status-sync.mutation.log).
- Empty result rule: the throw condition (`total === 0 && errors > 0`) was already right, but a genuinely empty search (site reports `totalResultCount: 0`) was recorded as a 'page returned no listings' error, so the run still threw. Such a page is no longer an error and is not refetched: the run ends SUCCEEDED with 0 rows, nothing charged, seed status `empty`, and status message plus `OUTPUT.statusMessage` 'No rows: no listings matched the input. Nothing was charged.' No rows with errors>0 still throws (red: redlogs/empty-search.red.log; mutation `total === 0` only: redlogs/empty-search.mutation.log).
- Run status message: `Actor.setStatusMessage` (best-effort, wrapped in try/catch) at the end of every run path: completion (`Done: N rows. Removed: R (410: a, 404: b).`), only removed (`No rows: 1 listing removed (410: 1, 404: 0). Nothing was charged.`), no results (`No rows: no listings found (E errors). Nothing was charged.`, set before the run fails), and the hard run-time-limit stop. The final `Done` log line now includes the removed counts. A throwing `setStatusMessage` never fails the run (red: redlogs/status-message.red.log; mutation: redlogs/status-message.mutation.log).
- Review 6665295 fix 3: `city` on detail rows falls back to the list row's city when the detail page has no structured ad city (e.g. location is country-only), instead of the seller-profile city. QA cases: Genemuiden x2, Harlingen x1. A structured ad city still wins (red: redlogs/review-6665295-fix3.red.log).
- Review 6665295 fix 2: HTTP 404 on a detail page is final (not retried). Detail start URL: treated as removed (counted in `OUTPUT.removedListings` and new `OUTPUT.removedBy.notFound404`, not pushed, not charged, not an error). List-to-detail: the list-only row is still delivered and charged as before (useful data), and the 404 is counted in `OUTPUT.removedBy.notFound404` only; `removedListings` keeps meaning removed/skipped (red: redlogs/review-6665295-fix2.red.log).
- Review 6665295 fix 1: a detail start URL answering HTTP 410 is no longer an error that fails the run. It is counted in `OUTPUT.removedListings` and new `OUTPUT.removedBy.gone410`, not pushed, not charged, not retried; a run whose only start URL is removed succeeds with 0 rows. New `OUTPUT.statusMessage` notice; new `.actor/output_schema.json` (red: redlogs/review-6665295-fix1.red.log).
- Test: a detail page whose first answer is empty and whose refetch answers HTTP 410 is skipped (not pushed, not charged), counted in `OUTPUT.removedListings` and not in errors. Code already behaved this way; red run is a mutation that removes the refetch 410 check (redlogs/detail-410-refetch.red-mutation.log).
- Detail page HTTP 410 (listing removed) is no longer retried or reported as a network error: the listing is skipped (not pushed, not charged), counted in new field `OUTPUT.removedListings`, and the run continues (red: redlogs/detail-410.red.log).
- robots.txt Disallow matches are counted once per request in `OUTPUT.robotsDisallowedHits` (was counted twice with the real fetcher). Tests: robots.txt 5xx keeps the crawl going; Disallow is warn + count + fetch. Test seam `options.request`. Crawl-delay, rate limit and 403/429 backoff unchanged.

### 0.1.0 — 2026-10-26

- Initial Marktplaats.nl scraper (list + optional detail) from kijiji-actor template.
- PPE draft: `listing` / `listing-detail` at $0.0006 each; no start fee (azzouzana $0.0012 ×50%).
- Cost gate draft: $0.0798 per 1000 (= $0.0006 × 1000 × 0.133). Prefer list `__NEXT_DATA__`; keep detail ratio low.
- Privacy policy A: keep published seller commerce contact; drop pure private PII; do not call Disallow'd seller-profile APIs.
- List from public `__NEXT_DATA__` → `searchRequestAndResponse.listings`; detail from `window.__CONFIG__.listing` + Product JSON-LD.
- Default input: multi-seed huis-en-inrichting, auto-s, computers-en-software, audio-tv-en-foto, telecommunicatie; maxItems 50 (cap 2000); fetchDetails false; requestDelayMs 1000; concurrency 1; memory 256 MB; proxy off; residential never default (cap 5 MB).
- robots.txt Disallow logged as residual risk in OUTPUT; Crawl-delay honoured; public `/l/`, `/q/`, `/v/` still fetched.
- KYC前: local commit + npm test only; no Store publish / no platform price / no `apify push`.
