eBay to 1688 Sourcing Bridge: Suppliers & Margins
Pricing
from $5.60 / 1,000 1688 supplier matches
eBay to 1688 Sourcing Bridge: Suppliers & Margins
Find 1688.com suppliers for eBay items by image search. Each row: wholesale and consign price in CNY, MOQ, factory signals, soldCount and an estimated per-unit margin. $0.005 per eBay lookup, $0.008 per supplier row, $0.00005 run base fee. Failed lookups are free.
Pricing
from $5.60 / 1,000 1688 supplier matches
Rating
0.0
(0)
Developer
Kyle Wang
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
7 days ago
Last modified
Categories
Share
eBay → 1688 Sourcing Bridge
Turn eBay item URLs, item IDs or product photos into a 1688 supplier shortlist — one row per supplier, with wholesale and consign prices in CNY, MOQ, factory signals, sold counts, and an estimated per-unit margin in the listing's own price currency (USD, GBP, EUR, AUD or CAD).
Most eBay scrapers sell listings. Most 1688 image-search Actors accept a photo. This Actor joins the two: it reads a public eBay item page (/itm/{id}), takes the main image, runs a reverse image search on 1688.com, and returns sourcing rows you can act on.
What you get
Three flat row types in one dataset (type tells them apart):
type | Meaning |
|---|---|
source | One eBay lookup: title, main image, price + currency, condition, sold count, available quantity, listing type (Buy It Now / auction), Best-Offer flag, seller store name and link, fetchStatus |
match | One 1688 supplier offer: wholesale/consign price (CNY), MOQ, booked count, supplier city/province, years on 1688, factory flags, offer URL and image, relevantMatch flag, estimated unit margin |
summary | Per-item rollup: match count, relevant match count, best margin, best supplier, factory count, top 3 margins |
The run report is stored as RUN_SUMMARY in the key-value store: requested/delivered counts, skipped items by reason, field-coverage metrics (including relevantMatchRate and soldCountPresent), eBay challenge statistics, request usage, FX rates and charged amount. The completeness identity delivered.summaries + sum(skippedBy) = requested.dedupedItems is verified before exit, so items are never silently dropped.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
ebayUrls | string[] | — | Up to 100 item URLs. ebay.com/itm/{id} and ebay.com/p/{id} are both normalized to the item ID. Any of the four supported marketplaces (.com, .co.uk, .de, .com.au) is accepted; each URL carries its own marketplace. ebay.ca URLs are rejected before any request and are not charged |
itemIds | string[] | — | Up to 100 numeric item IDs (6+ digits); merged and deduplicated with ebayUrls. Bare IDs use the marketplace setting |
imageUrls | string[] | — | Up to 100 direct product image URLs. Skips the eBay lookup (free); no eBay price, so margin is null |
marketplace | enum | com | com, co.uk, de, au — used for bare item IDs. Each marketplace is fetched through a residential exit in its own country (US/GB/DE/AU). The price currency follows the listing (normally the marketplace currency: USD, GBP, EUR, AUD). ebay.ca is not supported — see the caveats |
maxItems | int | 20 | 1–100, global hard cap across the three inputs (deduplicated union, first come first served). Each delivered item costs one $0.005 ebay-item-lookup plus its supplier-match rows. The default 1024 MB is not the binding limit at the top of the range — the run window is (see Run window below). Measured: a full maxItems=100 run peaked at 457 MB of its 1024 MB. Raise the memory to 2048 MB only if you also raise maxSuppliersPerItem well above its default |
maxSuppliersPerItem | int | 10 | 1–20, in similarity order |
maxTotalChargeUsd | number | 2 | Hard per-run charge cap, minimum 0.04. With a very small cap (under ~$0.10) send only 1–2 items: lookups are billed as they complete, and a micro cap can be consumed before many supplier rows are delivered |
maxRequestsPerRun | int | 1200 | Request quota guard, 50–2000 |
You can mix all three inputs in one run. Duplicates are removed by item ID (URLs and bare IDs together) or by exact image URL. There is no keyword mode: every run is anchored to items you already know.
All inputs empty → the run exits with a validation error and zero charge.
Output example
{"type": "match","itemKey": "ebay:186933747946","itemId": "186933747946","inputKind": "ebay","offerId": "8899001","similarityRank": 1,"title1688": "宠物玩具源头工厂批发 可定制","priceYuan": 6.8,"consignPriceYuan": 9.5,"moq": 2,"bookedCount": 8200,"supplierName": "义乌市宠物用品厂","supplierCity": "金华","supplierProvince": "浙江","yearsOnPlatform": 6,"compositeScore": 87,"isFactory": true,"isSuperFactory": false,"offerUrl": "https://detail.1688.com/offer/8899001.html","offerImageUrl": "https://cbu01.alicdn.com/img/ibank/abc.jpg","estMarginPerUnit": 23.66,"estMarginPct": 94.7,"marginBasis": "consign","costBasis": "consign","marginCurrency": "USD","fxUsdCny": 7.14,"fxCnyToLocal": 0.14,"matchedBy": "image","relevantMatch": true}
estMarginPerUnit is negative when the 1688 cost exceeds the eBay price. Negative margins are reported as-is: a product to avoid is also an answer.
About relevantMatch
Image search finds visually similar products, and visual similarity is not semantics: an exact-form hit and a loosely-similar category neighbor can come back in the same list. Every match row therefore carries a relevantMatch boolean: true only when the 1688 offer title shares meaningful vocabulary with the eBay title (a static EN→CN category word map, a German-stem bridge so .de listings are not left out, or latin tokens like led/usb that pass through untranslated). Vocabulary coverage is English and German; a title in another language can only match on latin pass-through tokens, so the flag can read false on an offer that really is the same product — it is a filter aid, never a verdict, and it has never affected billing. similarityRank orders the rows but never marks them relevant — a top-ranked visual neighbor from a different category (a scene photo matching the furniture around the product) is flagged false like any other miss. Offers that are services rather than products (processing, recycling, franchise/agency listings) are always false. Noisy rows are still delivered and billed — the engine cost has already happened — but summary.relevantMatchCount and RUN_SUMMARY.fieldCoverage.relevantMatchRate count only the relevant subset, so Store-facing numbers stay honest. Filter on the flag; judge with your own eyes before ordering.
Pricing (pay-per-event)
All prices are FREE-tier list prices. Subscription tiers receive the discounts below.
| Event | FREE | BRONZE (−10%) | SILVER (−20%) | GOLD (−30%) | PLATINUM (−30%) | DIAMOND (−30%) | Charged when |
|---|---|---|---|---|---|---|---|
run-base-fee | $0.00005 | $0.00005 | $0.00005 | $0.00005 | $0.00005 | $0.00005 | Once per run, only if at least one billable row is delivered |
ebay-item-lookup | $0.005 | $0.0045 | $0.004 | $0.0035 | $0.0035 | $0.0035 | Per eBay item with fetchStatus: "ok" |
supplier-match | $0.008 | $0.0072 | $0.0064 | $0.0056 | $0.0056 | $0.0056 | Per match row actually written to the dataset |
Discounts are applied by Apify according to the subscriber's plan. There is no platform start fee.
Free: blocked, not-found and errored eBay lookups, challenge-wall items, image-conversion failures, items stopped by budget/quota/deadline, zero-match image searches, and matches cut by your budget. You pay only for rows actually delivered.
Worked examples (FREE tier):
| Order | Calculation | Total |
|---|---|---|
| 1 eBay item, 10 matches | $0.00005 + $0.005 + 10 × $0.008 | $0.08505 |
| 10 eBay items, 10 matches each (default) | $0.00005 + 10 × $0.005 + 100 × $0.008 | $0.85005 |
| 10 image URLs, 10 matches each | $0.00005 + 100 × $0.008 | $0.80005 |
| 100 eBay items × up to 20 suppliers (top cap) | $0.00005 + 100 × $0.005 + up to 2,000 × $0.008 | $16.50005 — far above the default $2 budget, so partial runs are expected; raise maxTotalChargeUsd for full batches. Note the run window also caps a single run at roughly 90 fully matched items (see Run window), so the top of the range is reached by splitting across runs |
The default maxTotalChargeUsd is $2, which covers roughly 23 fully matched items at 10 suppliers each. Raise it for larger batches; when the cap is reached the run stops gracefully and reports trigger: "budget" plus skippedBy.budget.
Margin math
One FX snapshot is captured at the start of the run and reported in RUN_SUMMARY.fx (rates, source, timestamp). Every item is computed in the currency its price is actually denominated in — normally the marketplace currency (a .co.uk item yields GBP margins, a .de item EUR), except listings that price in a foreign currency (e.g. a GBP price served on ebay.com), which keep that currency — using a single CNY→local rate per run.
- Margin currency = the currency the listing's price is denominated in (
marginCurrencyrecords it;fxCnyToLocalrecords the rate used). - Cost basis:
consignPriceYuanwhen the 1688 offer exposes a dropship/consign price, otherwisepriceYuan(costBasisandmarginBasisrecord which). - Revenue = the eBay price as served on the page. It is read from the page's own price block; the embedded JSON-LD price is a fallback only when its declared currency matches the marketplace — localized JSON-LD prices (a CN visitor seeing CNY on a US listing) are rejected this way. An explicit currency marker in the price block (a GBP price on ebay.com) wins over the marketplace default; a bare
$price with no marker inherits the marketplace currency. estMarginPerUnit = priceLocal − costCNY × fx(CNY→marginCurrency)- Direct
imageUrlsinputs have no eBay price, so their margin fields are null (marginBasis: "none").
Margin estimates are indicative, not guaranteed. They exclude inbound shipping to you, duties, payment fees, eBay seller fees and returns. Always verify with a sample order.
How it works
- eBay leg — pure HTTP (no browser) with a fresh sticky residential session per item (hyphen-free session IDs), exiting in the marketplace's own country: US for .com, GB for .co.uk, DE for .de, AU for .com.au — a geographically matched exit lowers eBay's challenge rate. The session is warmed with a homepage request to seed cookies, then
/itm/{id}is fetched with full navigation headers. eBay's splashui challenge is a passive proof-of-work page that usually auto-passes in a few seconds: on the first attempt the Actor polls the same session every 2 s for up to 15 s and continues when it clears. Interactive challenge forms (CAPTCHA, press-and-hold, sliders) are never waited for and never solved — the session rotates immediately, at most two rotations before the item is reportedblocked(free). A 404/410 isnotFound; datacenter-style 403/429/503 also rotate. All four supported marketplaces share the same leg. - Image handling — the main image URL is rewritten to eBay's
s-l1600.jpgCDN name, which forces a full-size real JPEG. The download is verified by magic bytes, not extension; buffers under 10 KB are the CDN's placeholder trap, which triggers a downgrade tos-l500.jpgand one retry. WebP images from custom URLs are converted to real JPEG before upload. - 1688 leg — the image is uploaded to 1688's image service and searched with the existing production image-search engine: per-identity quotas, residential China sessions, token cache, risk-control rotation. Card fields come straight from the search response (no extra 1688 detail calls), and each offer is immediately scored for margin and
relevantMatch.
Limits and honest caveats
- Visual similarity ≠ same product or same factory. Match rows are ordered by the platform's similarity rank. eBay product photos are typically clean object shots, so recall quality is high — but marketing composites, lifestyle shots and text-heavy designs still recall worse. Use
relevantMatch+similarityRank, then verify with your own eyes. soldCount,availableQuantity,bestOffer,listingType,sellerName/storeSlugare best-effort fields read from public detail-page structures. They are parsed language-independently (structural selectors and the page's embedded view-model JSON, never localized button text), and each field is extracted independently — one missing block can no longer null out the others. They are null (never guessed) when the page genuinely lacks the information, andRUN_SUMMARY.fieldCoverage.soldCountPresentreports the measured coverage.soldCountandavailableQuantityare both read from the quantity block's own facts, so recommended-item carousels can never leak another listing's sold count into a row.availableQuantityis what the page displays, and eBay caps that display at 10 ("More than 10 available"), so a10means "at least 10".soldCountis one of eBay buyers' core sourcing signals — treat the column as a signal, not a guarantee.- Variation listings show their cheapest variation. Before a variation is selected, eBay's price block displays the minimum across variations (a £5–£200 listing shows £5.00). When that happens the source row carries
priceIsVariationMinimum: trueandvariationPriceRange {min, max, count, variationsTotal, currency, currencyMatchesListing}— margin computed from the displayed minimum can understate the real deal price, so check the range before judging such an item. Both fields are only ever computed inside one currency: eBay sometimes serves the variation view-model converted (a .co.uk listing came back priced in USD), and comparing a displayed £5.00 with a converted $6.70 minimum once produced a flatly wrongfalse. When the page carries nothing but a converted currency the flag isnullandcurrencyMatchesListingisfalse— unknown, not negative. - eBay anti-bot is real. A challenge-blocked item is returned as a
sourcerow withfetchStatus: "blocked"and is not billed. The run report counts it underskippedBy.blockedandchallengeStatsrecords how often the passive challenge was seen, waited out, or blocked the item. skippedBy.blockedcovers both legs, and only the eBay one is free. The same counter is incremented when 1688's image search returns risk control for an item. In that case the eBay fetch had already succeeded, so the item is billed oneebay-item-lookupand produces no match rows and no summary row. To tell the two apart, count thesourcerows withfetchStatus: "blocked":skippedBy.blockedminus that number is the 1688-side count. Measured rate on the Etsy twin of this Actor: 19% of paid lookups on a 56-item run, 8% on a 39-item run — it depends on how hard 1688 is rate-limiting its image-search endpoint that day, and a smaller batch lowers it.ebay.cais not supported. The Canadian site served an interactive human-verification challenge to every automated session measured — 6/6 through a US residential exit and 4/4 through a Canadian residential exit — while .com, .co.uk, .de and .com.au delivered normally inside the same runs. Rather than advertise five marketplaces and hand back freeblockedrows on the fifth,.cais not offered: anebay.caURL is rejected before any request, is never billed, and is reported inRUN_SUMMARY.invalidInputswith reasonunsupported_marketplace_ebay_ca.- Prices vary by session and marketplace. The price is read from the page as served to a residential session in the marketplace's country, in the currency the price block itself denotes (a foreign-currency listing keeps its own currency;
priceCurrencyandmarginCurrencyrecord which). Auction items carry the current bid, not a final price. imageUrlsinput has no eBay price, so margin fields are null. Match rows are still full price; the 1688 supplier data is the deliverable.- Supplier names stay in Chinese as registered on 1688.
compositeScoreandisFactoryare raw platform signals. This Actor does not claim a supplier is "verified"; the judgment is yours. - Run window. Default timeout is 1,200 seconds, and the Actor caps its own working budget at 1,110 seconds of that (the remainder is the finish reserve) — raising the platform timeout above 1,200 s does not buy you more items. The eBay phase holds back roughly the last 35% of the window for the 1688 leg — and never more than half of it, so a short timeout shrinks the reserve instead of cancelling the eBay phase outright. So for large batches the window, not memory or budget, is usually what stops you: a measured
maxItems=100run delivered 100 source rows and 89 complete supplier shortlists, then cut the last 7 items withtrigger: "deadline"(skippedBy.deadline: 7) at a 457 MB peak. The run always stops gracefully, reportspartial: truewith the exact reason, and never bills an item that did not reach a terminal state. When the reason is the clock,RUN_SUMMARY.deadlineKindsays which of two budgets ran out, and the remedies are opposite:platform-timeoutmeans Apify really ended the run, so send a smaller batch;phase-windowmeans this Actor's own reserve closed the eBay phase while platform time was still on the clock, so raise the run timeout. Split very large jobs across runs if you need every item's shortlist. - Your report says whether its own money figures can be trusted.
RUN_SUMMARY.billing.pricingSourceisplatformwhen the prices inbilling.pricesare the ones this run was actually issued — the only case wherechargedUsdcan be reconciled line by line. If the Actor could not read its own pricing it saysplatform-read-failed, putsPRICING_READ_FAILEDinnotes, and reserves 3x per event at the budget gate so the run stops early instead of overspending: the platform charges its own price whatever the process believes, and an undelivered tail can be reported while an overcharge cannot be handed back. - Public data only. No login, no cookies from you, no personal data, no buyer review text. Seller store names and links are public storefront attributes; individual persons' names and contact details are not collected.
Disclosure
Finds wholesale suppliers on 1688.com for eBay items using image search. Scrapes publicly available data without login. Not affiliated with eBay or Alibaba. Users are responsible for complying with the applicable terms of service.
You are billed only for rows actually delivered. Failed, blocked and empty eBay lookups are never billed. A lookup whose eBay fetch succeeded is billed even if 1688's image search then returns risk control for it — see
skippedBy.blockedabove.
Image matches include both exact and loosely-similar results; use the
relevantMatchflag andsimilarityRankto filter. Margin figures are indicative estimates.
Files
src/main.js— orchestration, gates, billing, challenge statistics, completenesssrc/ebay-client.js— pure-HTTP eBay leg (sticky sessions, splashui wait + rotation, four marketplaces)src/ebay-parse.js— detail-page parser, challenge-shell detection, s-l1600 image URL handlingsrc/relevant-match.js— EN↔CN title-overlap heuristic behind therelevantMatchflag, plus the German-stem bridgesrc/margin.js,src/fx.js— multi-currency unit economics and the CNY FX snapshotsrc/image-convert.js— magic-byte detection and JPEG normalizationsrc/image-search.js,src/image-search-probe.js— 1688 reverse image search enginesrc/token-cache.js— cross-run mtop token cachesrc/billing.js— pay-per-event ledger