# Changelog of Logic-Immo Scraper 🇫🇷 Téléphones + Particulier/Agence (`tagadanar/french-real-estate-logicimmo`) Actor

- **URL**: https://apify.com/tagadanar/french-real-estate-logicimmo/changelog.md
- **Full Actor documentation**: https://apify.com/tagadanar/french-real-estate-logicimmo.md

## Changelog

### 2026-08-29

- A long run no longer dies on the clock. The actor now reads the run's own
  timeout, reserves the end of it for delivery, and stops crawling in time, so
  the listings it already collected are charged, pushed and reported instead of
  disappearing with a timed-out run. The browser fallback — the expensive rung
  used for search URLs Logic-Immo blocks — is the main offender: with its
  shipped retry and timeout settings, one blocked URL could occupy more than a
  whole run. Its retries and timeouts are now computed from the time left, and
  it is skipped entirely when there is not enough left to load a page.
- The HTTP path's retries and per-request timeout shrink as the deadline
  approaches, so one slow page can no longer eat minutes a run does not have.
- Every run now ends with a status message that says what actually happened: a
  run stopped by the time limit says so and how to fix it, a run blocked by
  Logic-Immo's anti-bot wall says that, and "your search has no results" is only
  ever said after Logic-Immo served a results list we read that was genuinely
  empty. Runs used to finish with no message on most paths.
- **Max pages per search URL** is now an input (default 40, 25 listings per
  page). It was a fixed constant in the code, invisible and unchangeable,
  despite being the single biggest driver of how long a run takes.
- Honest limit in the input form: Max listings now caps at 1,050 — what a run
  actually delivers within the default one-hour run timeout. It advertised
  5,000. Search URLs are capped at 25 per run for the same reason.

### 2026-08-09 (pre-push review fixes)

- **A network blip no longer fails the whole run.** Three consecutive transport
  errors on one search URL (proxy connect / ECONNRESET — routine on residential)
  used to throw out of `crawlSearchUrl`, which runs at module top level with no
  try/catch: the run exited FAILED, the remaining URLs were never crawled, the
  browser fallback was never reached and `Actor.exit()` never ran. The fetch
  layer now reports a dead rung as walled so the ladder escalates, and every
  per-URL crawl is additionally wrapped so a URL that breaks degrades to the
  browser rung instead of killing the run.
- **An empty search no longer pays for a Chromium run.** Zero listings on page 1
  was treated as `walled`, so an over-filtered or genuinely empty search
  escalated to the browser to fetch the same zero rows. `parseListPage()` now
  reports whether the page carried a SERP payload at all: payload present and
  empty is a legitimate result, payload missing is still a soft wall.
- **The browser fallback is now budgeted** — at most **20 %** of a run's billed
  listings, because the Chromium rung costs $1.214 per 1,000 against $0.0328 for
  the HTTP rung. Derivation and the price coupling are in
  `src/browser-budget.js`; when the budget trips the actor stops escalating,
  ships what it has and says so in the run's status message.
- `maxMemoryMbytes` set to **2048**, matching the actor's current live default,
  so this push does not clamp running jobs down while a Chromium fallback rung is
  being introduced.

### 2026-08-09 (later) — Playwright → impit HTTP

- **No more browser on the normal path.** `src/fetch.js` fetches
  `/classified-search?page=N` with impit and `parseListPage()` reads the
  server-rendered `__UFRN_FETCHER__` payload straight out of the body. Measured
  the same day from a FR residential IP: 6 consecutive pages, 25 classifieds
  each, 75 unique ids over p1–p3, ~128 KB gzip per page against ~3.1 MB of
  browser transfer for the same listings.
- **No datacenter rung, and that is a measurement, not a guess.** 403 with a
  777-byte DataDome block from AS16276 on pages 1–6, browsers `firefox` and
  `chrome`, `ignoreTlsErrors` on and off — 16 probes, 16 walls.
- **Proxy ladder** (`residential-FR → Chromium + residential-FR`) with every
  rung's availability logged and no silent `catch` around
  `createProxyConfiguration`. The old browser path survives verbatim in
  `src/browser.js` as the last rung. Progress survives an escalation: a wall on
  page 30 resumes at page 30.
- **Guardrails:** `maxMemoryMbytes: 1024` added, default run memory 2048 → 512,
  Dockerfile no longer passes `--omit=optional` (it would strip impit's native
  binary).
- Projected cost per 1,000 listings: **$0.050**, against $1.214 measured on the
  browser path. Modelled from measured page weights — one platform run still has
  to confirm it.

### 2026-08-09 (prepared, not shipped — awaiting review)

- We-pay & positioning review completed: stays user-pays (⅓-rule flip gate:
  Gold $1.4 / measured cost $1.21 = 1.2× vs 3.0× required). Full report at
  `research/we-pay-review-2026-08-09/french-real-estate-logicimmo.md`.
- README: added an "annonces immobilières" job-phrase mention and a bullet on
  phone/description/photos shipping on the base price with no paid detail-page
  pass (evidence: the only direct Logic-Immo rival's own listing describes an
  "optional detail-page pass" for full descriptions/photos).
- `.actor/actor.json` description: added "immobilières" for phrase relevance.
  Not live yet — the Store card description is build-sourced and only changes
  on the next `apify push`.
- Proposed Console SEO fields (seoTitle/seoDescription) staged at
  `actors/tools/cfg-french-real-estate-logicimmo.json`, not applied.

### 2026-07-12

- Invalid input no longer fails the run. The run now finishes cleanly with a clear explanation in its status message, so a typo or an empty list is easy to spot and fix.
- List inputs now accept datasets piped straight from another scraper: entries
  that are objects are read through their usual key names (url/link,
  query/keyword/title, name/company and similar) instead of being rejected.

### 2026-07-11

- Billing: on paid runs every row is billed before it is written, and a run
  now stops visibly if billing fails instead of continuing unbilled.

### 2026-07-09

- Input is now tolerant of common shapes that previously failed the run: a bare
  string / bare object / delimited string for searchUrls is coerced into a list
  instead of erroring. Empty input still errors.

### 2026-07-06

- Simplified input: pagination depth is now handled automatically (technical field removed).

### 2026-07-05

- Published on Apify Store.

### 2026-07-04

- Initial release.
- Logic-Immo sale & rental listings with the advertiser's PHONE NUMBER on every ad.
- Agency / builder / private-owner flag, €/m², surface, rooms, land and photos.
