Scrape any 1688 category from one English keyword: English titles, MOQ price ladders, landed cost, dropship scores, compliance hints. Or watch a shortlist of offers for price drops and stock changes — daily snapshots, alerts, weekly trend report. Failed runs are never charged.
Full release history lives in git commit messages (git log --oneline); this file records release-visible changes from 0.1.17 onward.
0.1.31 (2026-10-20)
Bugfix release for two defects proven on 0.1.30; prices and limits unchanged.
Migration idempotency (defect B): after a platform migration the replacement process used to re-deliver and re-charge every offer from scratch (canary run charged 28 search + 28 detail events for 8 unique offers). The run's default KV now keeps a DELIVERY_STATE ledger: delivered offerIds re-seed the global dedup set, already-charged amounts re-scope the billing plan, and the run base fee is collected at most once per run even across processes. A replacement process whose contract is already fully delivered closes out with zero scraping, zero pushes and zero charges (SUMMARY.resumedAfterMigration).
Genuine no-result keywords no longer fail (defect A): 1688 pads the result counter with fuzzy-match recommendations (a gibberish keyword returned found=60, offers=0), which the old found===0 gate mislabeled as a search failure and escalated to the full anti-bot fallback ladder, ending FAILED. A well-formed empty response with found <= 100 is now classified as a business NO_MATCH — the run ends SUCCEEDED with errorCode=NO_MATCH after a single search request. Real risk-control interception (RGV587/x5sec/TMD) keeps failing the run. Classification rules are documented in docs/failure-semantics.md.
0.1.30 (2026-10-17)
Keyword search and product details now run first on browser-free HTTP identities: each identity is one sticky residential session whose cookies and mtop token are obtained over plain HTTP. Search uses mobile request headers, details use desktop headers, and an identity that hits risk control is replaced immediately (per-identity call quotas, three consecutive dead identities switch that tier off for the run). The browser mint is no longer started at run start; it starts only when a fallback needs it.
The previous browser-backed chain (in-page mtop, minted-jar HTTP, HTML ladder, browser search, browser detail groups) remains the fallback for whatever the HTTP tier cannot serve. A recent pool-health lock now skips only the browser detail fallback instead of downgrading the whole run to cards.
Fresh-identity recovery and the browser search fallback are allowed once per user keyword (0.1.29 allowed them once per run, which starved later keywords in multi-keyword runs). SUMMARY adds httpIdentity counters and searchVia: mtop_identity. PRODUCT_HTTP_IDENTITY=off restores the browser-first behaviour.
Includes the 0.1.29 candidate changes below. Event prices and limits are unchanged.
0.1.29 (candidate only, 2026-10-17)
Never selected as the public default build; superseded by 0.1.30.
Keyword detail searches start a fresh bootstrap rather than repeatedly checking the minter's rejected shared jar. Product token writes use an isolated record key; monitoring and direct-offer entry points retain cache reuse.
An in-flight bootstrap is not replaced by a competing lazy bootstrap. The first search wait covers the bootstrap's existing 60-second bound, and retries of dead tokens bypass the rejected cache.
Fresh full-chain recovery and browser search fallback each have a single run-wide allowance. Two blocked search results stop further synonymous queries. SUMMARY.searchGuard exposes the network/time cost estimate, admission limit and stop reason; this estimate is not an exact platform bill or a mid-request hard limit.
Collected rows are checkpointed in PENDING_RESULTS after offer batches and on persistState. Final delivery retains global sorting and factual event settlement; checkpoints are not billing receipts or automatic resume states.
A risk-control or infrastructure zero-delivery run now ends FAILED, while genuine NO_MATCH and empty-input runs remain uncharged.
The input form exposes optional direct offerIds without rejecting existing numeric IDs. SEO title uses Product Scraper, Wholesale Prices, MOQ and Price Monitor together. Event prices and the 200-product input limit are unchanged.
0.1.28 (2026-10-17)
Docs only; code identical to 0.1.27, prices unchanged.
Corrected the keyword claim. README and the keyword field said every English keyword is "translated to Chinese search terms internally"; in fact only pet-supply keywords are mapped (the built-in dictionary is pet-only), and every other English keyword is sent to 1688.com as typed, where 1688's own search matches it (e.g. phone case and stainless steel tumbler return relevant results in cloud runs on 2026-10-07/08). The copy now says exactly that.
Titles are described as machine-translated (free translation API chain with a dictionary fallback, as the Translation honesty rule already stated) instead of "AI-translated"; the dataset schema says titleEn is empty when no clean translation exists.
Removed the link to the retired 1688 Pet Supplies Scraper and merged the two "For AI agents" sections into one.
Local actor.json now mirrors the live Store description and SEO fields (push never syncs them).
0.1.27 (2026-10-07)
Corrected exact-budget accounting: eventChargeLimitReached=true is not an invariant violation when the requested count was fully charged; it only means later charges of that event are blocked.
Includes the complete 0.1.26 candidate repair below; 0.1.26 was never selected as the public default build.
0.1.26 (candidate only, 2026-10-07)
Corrected SDK atomic-push accounting: Actor.pushData(items, eventName) can return an aggregate chargedCount spanning the explicit event and the platform dataset event. Delivery accounting now uses the explicit event's ChargingManager.getChargedEventCount() delta, so SUMMARY, pushed-prefix selection and platform reconciliation cannot double-count rows.
Includes the complete 0.1.25 candidate repair below; 0.1.25 was never selected as the public default build.
0.1.25 (candidate only, 2026-10-07)
Budget and delivery safety repair without a price change: current subscription-tier event prices and the platform run cap are read from ChargingManager; the effective cap is the lower of input/platform limits; detail and run-base-fee are reserved; and product/monitor rows use the SDK atomic pushData(rows, eventName) path (budget limit → push prefix → charge). Detail/base settle only after a successful row push, factual ChargeResult counts drive the ledger, and terminal retries are single-flight so one batch is not pushed or charged twice.
Small includeDetails=true requests now auto-downgrade to card-only before proxy/browser startup instead of returning DETAILS_MIN_20. SUMMARY discloses requested/effective/actual delivery shape and reason.
Cloud warm-cache hits now pass one browser-channel signed canary gate before reuse. Rejections close once, never clear shared KV, and fall through to self-mint; raw acceptance and later business success are reported separately.
Search zero outcomes now distinguish NO_MATCH, RISK_CONTROL_ZERO, and infrastructure failures. Only risk-control zero receives one fresh-identity retry.
SUMMARY now includes deliveryShape, tokenPath, billingPlan, factual charged counts, errorBuckets, platform-count reconciliation and costGuard.freeRows=0.
Event prices are unchanged.
0.1.24 (2026-09-16)
Listing copy changes from this release remain below.
Store title/description/SEO rewritten around what buyers actually search for: the title leads with 1688 Scraper — Product & Supplier Search, MOQ & Landed Cost instead of a brand-style name plus a price tag. meta.description (145 chars) and store-copy.md (300-char Store description) are kept byte-identical to each other so the three disclosure surfaces cannot drift.
New README FAQ section answering the long-tail questions buyers arrive with: no 1688 account or Chinese needed, how to search in English, how to find factories, why 20 items is the enrichment minimum, what dropshipReadyScore and the landed-cost estimate actually mean, and that failed or zero-result runs cost $0.
Cheaper starter prefill: the input form now proposes phone case / 30 items instead of led strip lights / 40, so a first trial lands near $0.25. maxItems.default stays 40 — API callers who omit the field are unaffected.
One-click Task list expanded to 11 entries, leading with the new keyword-matrix tasks (wholesale search, supplier lookup, MOQ & price-range scan, US landed cost, dropship readiness, shortlist price monitor). The price-range task is the first one to exercise priceMin/priceMax.
Cross-Actor CTA to the TikTok Shop Scraper in the sourcing-toolkit section.
Buyer-facing copy no longer names competitors — the comparison table describes capability differences instead, and a source comment lost its competitor reference.
meta.categories realigned to ["ECOMMERCE","AGENTS"] to match the live Store listing. The local file declared only ECOMMERCE, so a future push would have silently dropped the AI-agents category placement.
0.1.20 (2026-09-05)
Fix (P1-4 fallout, found by the R2M-7b-equivalent run): the dataset schema rejected card-level rows whose detail response carries no weight module — weightKg: null failed "type": "number" (forensics run RPahJyL8ctKR7pvul: 2 of 3 delivered rows 400-rejected, run FAILED with 0 items; keyword card-only never tripped it only because the search-card parser omits the key entirely, while the offerIds card-only path always materialises weightKg: null). A full all-null schema audit surfaced three more fields with the same code-contract-vs-schema mismatch and they are fixed together: price.min (extractPriceFromContext ships {min:null,…} when no price module; price.max already allowed null — the original author covered max but missed min), salesTotal (parseTransactionCount returns null for listings without a transaction count) and quantityPrices[].minQuantity (tiers whose beginAmount is null are kept). All four now accept null; wrong types (strings) are still rejected. Pinned by tests/task273-schema-null-tolerance.test.js (N1–N8) using the real ajv validator.
Ops: data-safety.js flush failures now log the platform's invalidItems payload (bounded JSON dump) so future schema rejections are diagnosable from the run log without a forensics build.
0.1.18 (2026-09-05)
Fix (P1-4, 方案 A): offerIds + includeDetails=false no longer silently delivers 0 products (run ui0FeqEeUkejFXArA). The combination now means CARD-LEVEL delivery — every offerId goes through the mtop-primary transport (fetchDetailsParallel) and is delivered at card level only (no detail enrichment, no description images), billed search-item × N + run-base-fee exactly like the keyword card-only path (5 IDs ≈ $0.035). Offers the transport cannot resolve are honestly absent and never billed; SUMMARY.detailStatus reports card_only.
Fix (P1-1): card-level paths with no search phase (Price Monitoring snapshots and the new offerIds card-only path) now seed the cached minter jar into a live warm page (Crawler1688.seedWarmCardPage) BEFORE the batch fetch — previously a settled cache-hit token stayed page-less, so fetchDetailsParallel skipped tier-1 (warm-page probe) and tier-1.5 (retained reuse) and fell straight to tier-2 fresh mtopdet* sessions (R2M-1: 3/3 RGV587, Cliff breaker TRIPPED, while the SAME token seeded by the keyword search tier delivered 20/20 — R2M-6b). A teardown leak guard (releaseSearchFallbackBrowser) closes any unconsumed seeded page on both paths.
0.1.17 (2026-09-04)
Docs (P1-2 semantic clarification): the README input table now documents the offerIds direct-fetch path and states explicitly that includeDetails=true (details enrichment) requires maxItems ≥ 20 — smaller batches fall to the DETAILS_MIN_20 guard (honest refusal, $0 charged); use includeDetails=false for small card-only lookups — and that Price Monitoring (watchlistOfferIds) is a separate mode not subject to that guard (any watchlist size 1–200). The wall itself is unchanged: it is the 0.1.7 economic red line (detail enrichment breaks even only at batch scale).