Scrape ShopBack for a brand: merchant cashback rates, tiers and terms (AU, SG, MY) plus the brand's gift-card listing with its own cashback rate per denomination. With your ShopBack session it reads the live affiliate network from the click-out. Pass a domain or ShopBack URL. Pay per result.
Gift-card listings. Existing prices are unchanged; one new charge event, Gift card listing (gift-card, $0.01), starts on 13 October 2026. Input and output stay backward compatible (new fields are additive, existing fields keep their names, types and meaning).
Every target is now also checked for a ShopBack gift-card listing, in every mode, over plain HTTP. New output fields: giftCard (url, brand, groupCode, cashbackType, cashbackRate, cashbackRateMin, availability, currency, denominations, brandVerified, discoveredVia, checkedAt), giftCardCheck (found, not_found, brand_mismatch, check_failed) and shopbackPresence (merchant_only, gift_cards_only, both, not_found, unknown).
Gift-card URLs are accepted as input (/ecommerce/skugroup/<code> and /ecommerce/checkout/<code>). They used to be read as a merchant slug named "ecommerce" and came back not_on_shopback, which wrongly said that a brand such as BP has no ShopBack presence.
Gift cards are discovered from a domain or brand through ShopBack's search and confirmed on the gift-card page. The brand match is strict (a similarly named brand never matches) and the page must be served by the storefront of the run's region.
Rates are read live per denomination. cashbackRate is the highest live rate, cashbackRateMin the lowest.
Gift-card cashback is kept apart from merchant cashback: details, affiliate, shopbackUrl and listingStatus describe the merchant listing only and are never filled from a gift card. No affiliate network is inferred from a gift-card listing.
outcome semantics, the one change for consumers: a brand with a verified gift-card listing and no merchant listing is resolved (it used to be not_on_shopback); not_on_shopback now means neither a merchant listing nor a gift card was found. One exception is kept from 0.2: in affiliate mode a paused merchant (listingStatus: "temporarily_unavailable") without a gift card is still not_on_shopback, because there is no click-out to read, although its page exists (shopbackPresence: "merchant_only"). When no merchant listing was found and the gift-card check could not be completed, the row is check_failed (not billed) instead of a negative.
Billing until 13 October 2026 is unchanged: gift-card data is free and a gift-cards-only row is billed as the same Negative result event as before. From 13 October 2026 one Gift card listing event ($0.01, Silver $0.009, Gold and above $0.008) is charged per brand with a verified gift-card listing: in addition to the merchant events, and in place of the Negative result on a row without a merchant listing. The Actor switches by itself on that date.
costTelemetry.phases.giftCardMs and the run summary's giftCards and presence counters report what the check did.
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.