# Changelog of ShopBack Scraper - Cashback Rates, Affiliates (`automation_craft/affiliate-network-detector`) Actor

- **URL**: https://apify.com/automation\_craft/affiliate-network-detector/changelog.md
- **Full Actor documentation**: https://apify.com/automation\_craft/affiliate-network-detector.md

## Changelog

### 0.2.0 (2026-09-10, live on the Store 2026-09-11)

Backend cost work. No price changes; input and output stay backward compatible (new fields are additive).

- Negatives are settled over plain HTTP (direct, then datacenter proxy): 404, redirect to a category page, and ShopBack's "Temporarily unavailable" page no longer open a browser or touch residential proxy.
- New `listingStatus` field: `active` | `temporarily_unavailable` | `delisted` | `not_found`. Paused merchants used to be reported as `auth_expired` after four full browser attempts; they are now `not_on_shopback` + `temporarily_unavailable` with `shopbackUrl` filled.
- Affiliate click-out over HTTP: the merchant page (logged in, residential IP in the session's region) exposes the merchant's `/sboc/redirects/...` interstitial, whose server render carries the network deeplink. Two small requests replace a browser session. The browser path is kept as the fallback for anything that is not a clean positive.
- Browser fallback: loads the merchant page once (it used to load it twice), does not wait for the window `load` event, and by default blocks images, fonts and every non-ShopBack script (`trafficFilter`).
- `auth_expired` is only declared after the page had a chance to hydrate, confirmed once on a fresh residential IP, and then short-circuits the rest of the run instead of loading every remaining target.
- Retries for the affiliate click-out stay on residential IPs in the session's region; escalating to datacenter/direct IPs could never fix a logged-out page.
- Keep-alive stores a pruned cookie jar (one cookie per name, expired ones dropped), re-injects the freshest jar on retries, and writes back only when its access token is at least as new as the stored one (parallel runs can no longer overwrite a fresher session with a stale one).
- A per-run canary fetch of a known merchant proves the page classifier before any HTTP negative is trusted; if ShopBack changes its page format, negatives fall back to the browser instead of becoming false `not_on_shopback` rows.
- `costTelemetry` now reports per-phase timings, per-tier bytes, attempts and the method used; the run log ends with a summary.
- `forceBrowser` now means what it says (browser for every target). `trafficFilter` input added.
- Failed checks are never negatives and never results: if the search page or a candidate page cannot be fetched in the browser path (or a logged-in page cannot be served because no residential proxy is available), the target is retried and finally reported as `outcome: "check_failed"` with `error` set, unbilled. Previously such targets came back as `not_on_shopback` or as a billed `click_out_failed`.
- A session cookie that has a still-valid access token but no `sbrefresh` is used for the click-out while it lasts (and not persisted); only a session with neither is reported `auth_expired` up front. A ShopBack URL that redirects to a different merchant is resolved through the brand search, or reported as `check_failed` when no brand is given. Name confirmation is word-based ("Cue Clothing Co" confirms "Cue"; "Rescue" does not).
- The evidence chain of a `network_identified` result keeps every redirect hop observed on the way to the merchant page (a renamed listing reads old slug, new slug, interstitial, network). A failed load of an already-known listing is retried; an empty details skeleton is never reported or billed as page details.
- The HTTP click-out fetches the merchant page without following redirects (each hop is recorded as evidence, a redirect off ShopBack is an error); every landing page must be on the regional ShopBack host; a redirect to a login/maintenance/error page is inconclusive; the search page's "No result" message must name the requested keyword.
- In the browser path an error page, or a non-merchant page served at the requested slug, is a failed check (retried, then `check_failed`), never `delisted`; only a redirect away from the requested slug to a home/category page is `delisted`. A ShopBack URL that redirects to another merchant is accepted only when every word of the requested slug or brand appears in the landing title.
- The HTTP click-out only proceeds when the search route and the classifier canary are genuinely what they claim to be (final URL still on `/search`, canary page served at its own slug with its own title); a `both`-mode run whose session is known dead bills `page-details` only; `maxConcurrency` also bounds the parallel HTTP click-outs; a breaker tripped on an old token reopens when a page refreshes the session.
- Paused merchants in `details`/`both` mode keep their page details: `outcome: "resolved"`, `listingStatus: "temporarily_unavailable"`, `affiliate: null` (no click-out exists), billed as `page-details` only. In `affiliate` mode they are `not_on_shopback` + `temporarily_unavailable`.
- Failed affiliate attempts are billed on the proxy tier they actually ran on (they used to be billed as `affiliate-direct` even after residential attempts); `page-details` is charged only when details were delivered.
- One shared cookie jar per run for the HTTP click-out, so a rotated token is used by every following target; the interstitial is fetched without following redirects so any redirect hop is recorded as evidence.
- A ShopBack session with no refresh token no longer spends residential traffic: affiliate targets are reported `auth_expired` straight after the cheap listing check.
