# Amazon to 1688 Sourcing Bridge: FBA Suppliers & Margins (`crawleast/amazon-fba-sourcing-bridge`) Actor

Find 1688.com suppliers for Amazon products by image search. Each row: wholesale and consign price in CNY, MOQ, factory signals and an estimated per-unit FBA margin. $0.005 per Amazon lookup, $0.008 per supplier row, $0.00005 run base fee. Failed lookups are free.

- **URL**: https://apify.com/crawleast/amazon-fba-sourcing-bridge.md
- **Developed by:** [Kyle Wang](https://apify.com/crawleast) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.60 / 1,000 1688 supplier matches

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Amazon → 1688 Sourcing Bridge (FBA)

Turn Amazon product URLs or ASINs into a **1688 supplier shortlist** — one row per supplier, with wholesale and consign prices in CNY, MOQ, factory signals, and an **estimated FBA per-unit margin** in your marketplace's currency.

Most Amazon scrapers sell listings. Most 1688 image-search Actors accept a photo. This Actor joins the two: it reads an Amazon product detail page, takes its main image, runs a reverse image search on 1688.com, and returns sourcing rows you can act on — with the Amazon FBA fulfillment fee estimated on top.

### What you get

Three flat row types in one dataset (`type` tells them apart):

| `type` | Meaning |
| --- | --- |
| `source` | One Amazon product lookup: title, main image, buy-box price, rating, review count, BSR rank, sold-by-Amazon flag, fetch status |
| `match` | One 1688 supplier offer: wholesale/consign price (CNY), MOQ, booked count, supplier city/province, years on 1688, factory flags, offer URL, estimated unit margin |
| `summary` | Per-item rollup: 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, 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 |
| --- | --- | --- | --- |
| `amazonUrls` | string\[] | — | Up to 100 product URLs (`amazon.com/dp/<ASIN>`, `/gp/product/<ASIN>`, `/gp/aw/d/<ASIN>`; query strings are fine) |
| `asins` | string\[] | — | Up to 100 bare ASINs; merged and deduplicated with `amazonUrls` |
| `imageUrls` | string\[] | — | Up to 100 direct product image URLs. Skips the Amazon lookup; no Amazon price, so margin is null |
| `marketplace` | enum | `com` | `com`, `ca`, `co.uk`, `de`, `fr`, `it`, `es`, `jp` — sets the session country, page language and margin currency |
| `maxSuppliersPerItem` | int | 10 | 1–20, in similarity order |
| `marginBasis` | enum | `fba` | `fba` subtracts the estimated FBA fulfillment fee; `plain` subtracts the 1688 cost only |
| `fbaFeeUsd` | number | — | Optional per-run fee override in USD. When set, the static estimator is bypassed |
| `proxyConfiguration` | — | — | Informational: residential proxy usage is built in |
| `maxTotalChargeUsd` | number | 2 | Hard per-run charge cap, minimum 0.04 |
| `maxRequestsPerRun` | int | 1200 | Request quota guard, 50–2000 |

You can mix URL, ASIN and image inputs in one run. Duplicates are removed by ASIN (URLs and bare ASINs together) or by exact image URL.

### Output example

```json
{
  "type": "match",
  "itemKey": "amz:B08N5WRWNW",
  "asin": "B08N5WRWNW",
  "offerId": "692120494348",
  "similarityRank": 1,
  "title1688": "源头工厂不入耳无线蓝牙耳机X15电竞游戏双模式无延迟tws蓝牙耳机",
  "priceYuan": 8.2,
  "consignPriceYuan": 7.5,
  "moq": 5,
  "bookedCount": 1200,
  "supplierName": "深圳某某科技有限公司",
  "supplierCity": "深圳",
  "supplierProvince": "广东",
  "yearsOnPlatform": 4,
  "compositeScore": 3.1,
  "isFactory": true,
  "isSuperFactory": false,
  "offerUrl": "https://detail.1688.com/offer/692120494348.html",
  "estMarginPerUnit": 2.15,
  "estMarginPct": 53.8,
  "marginBasis": "fba",
  "costBasis": "consign",
  "marginCurrency": "USD",
  "fbaFeeUsd": 3.66,
  "fbaFeeEstimated": true,
  "fbaFeeLocal": 3.66,
  "matchedBy": "image"
}
```

`estMarginPerUnit` is negative when the 1688 cost plus the FBA fee exceeds the Amazon price. Negative margins are reported as-is: a product to avoid is also an answer.

### 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 |
| `amazon-item-lookup` | $0.005 | $0.0045 | $0.004 | $0.0035 | $0.0035 | $0.0035 | Per Amazon 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, 404 or region-unavailable Amazon lookups, items stopped by budget/quota/deadline, image-conversion failures, 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 Amazon product, 10 matches | $0.00005 + $0.005 + 10 × $0.008 | **$0.08505** |
| 10 Amazon products, 10 matches each | $0.00005 + 10 × $0.005 + 100 × $0.008 | **$0.85005** |
| 10 image URLs, 10 matches each | $0.00005 + 100 × $0.008 | **$0.80005** |
| 1 Amazon product, no 1688 match | $0.00005 + $0.005 | **$0.00505** |

The default `maxTotalChargeUsd` is $2, which covers roughly 23 fully matched products 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 (1 CNY → USD/CAD/GBP/EUR/JPY) is captured at the start of the run and reported in `RUN_SUMMARY.fx` (rates, source, timestamp). No multi-currency matrix is maintained.

- Margin currency = the marketplace's currency (`.com` → USD, `.de` → EUR, `.co.jp` → JPY, …).
- Cost basis: `consignPriceYuan` when the 1688 offer exposes a dropship/consign price, otherwise `priceYuan` (`costBasis` records which).
- Revenue = the Amazon buy-box price on the product page.
- `estMarginPerUnit = buyBoxPrice − costCNY × fx(CNY→local) − fbaFeeUsd × fx(USD→local)`
- FBA fee: your `fbaFeeUsd` override wins (marked `fbaFeeEstimated: false`); otherwise the estimator classifies the item from the page's weight/dimensions and looks it up in the published 2026 US fee schedule by size tier and price band (<$10 / $10–50 / >$50), including the 2026-04-17 fuel surcharge. `fbaFeeUsd`, `fbaFeeLocal` and `fbaFeeEstimated` are written on every row.
- When no weight can be parsed — or for image-only inputs — the row **degrades to `marginBasis: "plain"`** (1688 cost only) rather than inventing a fee.

Margin estimates are **indicative, not guaranteed**. They exclude inbound shipping to Amazon, duties, payment fees, returns, referral fees and storage fees. Always verify with a sample order and Amazon's official revenue calculator.

### How it works

1. **Amazon leg** — pure HTTP (no browser) with a fresh sticky residential session per item (country = marketplace). The session is warmed with a homepage request to seed cookies, then the detail page is fetched. CAPTCHA/robot-check pages rotate the session up to two times; no challenge is ever solved and no login is used. Rotations switch to a mobile profile (mobile Safari UA + `/gp/aw/d/<asin>` path), which is how `.de` / `.co.uk` pages are still served to HTTP clients that the storefronts wall behind a "continue shopping" interstitial. A 404 is reported as `notFound`.
2. **Image conversion** — the main image is downloaded and inspected by **magic bytes**, not by file extension. Amazon's CDN serves WebP bytes from `.jpg` URLs. WebP/AVIF images are converted to real JPEG (max 800×800, quality 85) before upload.
3. **1688 leg** — the converted JPEG 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).

### Limits and honest caveats

- **Visual similarity ≠ same product or same factory.** Match rows are ordered by the platform's similarity rank. Marketing photos and lifestyle shots recall worse than clean product shots. Verify before ordering.
- **Amazon anti-bot is real.** A CAPTCHA'd item is returned as a `source` row with `fetchStatus: "blocked"` and is **not billed**. The run report counts it under `skippedBy.blocked`.
- **FBA fees are estimates based on a published 2026 US fee schedule; they are not live Amazon quotes.** Non-US marketplaces run the same USD schedule through the run-time exchange rate. Amazon reprices during the year and the schedule drifts until the next Actor build.
- **Weight/dimensions/BSR are best-effort page fields** and are often absent; `RUN_SUMMARY.fieldCoverage` reports their coverage so you know what you got. When weight is missing the row degrades to a plain (cost-only) margin.
- **`imageUrls` input has no Amazon price**, so margin fields are null. Match rows are still full price; the 1688 supplier data is the deliverable.
- **Prices vary by marketplace and session.** The buy-box price is read from the page as served to the marketplace country; currency is inferred from the marketplace.
- **Supplier names stay in Chinese** as registered on 1688. `compositeScore` and `isFactory` are raw platform signals. This Actor does not claim a supplier is "verified"; the judgment is yours.
- **Run window.** Default timeout is 1,200 seconds. The Amazon phase reserves the last ~35% of the window for the 1688 leg. Large batches can hit the deadline or budget; the run stops gracefully and reports `partial: true` with the exact reason.
- **Public data only.** No login, no cookies from you, no personal data, no buyer review text.

### Disclosure

> Finds wholesale suppliers on 1688.com for Amazon products using image search. Scrapes publicly available data without login. Not affiliated with Amazon 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 lookups are never billed.

> FBA fee and margin figures are estimates based on a published fee schedule and a single run-time exchange rate; they are indicative, not guaranteed.

### Files

- `src/main.js` — orchestration, gates, billing, completeness
- `src/amazon-client.js` — pure-HTTP Amazon leg (sticky sessions, CAPTCHA rotation)
- `src/amazon-parse.js` — pure parsers for Amazon detail HTML/JSON-LD
- `src/fba-fees.js` — static 2026 FBA fee schedule and estimator
- `src/margin.js`, `src/fx.js` — unit economics and the CNY FX snapshot
- `src/image-convert.js` — magic-byte detection and JPEG normalization
- `src/image-search.js`, `src/image-search-probe.js` — 1688 reverse image search engine
- `src/token-cache.js` — cross-run mtop token cache
- `src/billing.js` — pay-per-event ledger

# Changelog

This Actor's version history is a separate document: https://apify.com/crawleast/amazon-fba-sourcing-bridge/changelog.md

# Actor input Schema

## `amazonUrls` (type: `array`):

Public Amazon product URLs (dp or gp forms, any supported marketplace domain), up to 100 per run. Query parameters are fine. Each successfully looked-up item costs one $0.005 amazon-item-lookup event; blocked, region-unavailable and empty lookups are free. Batch items in one run to pay the $0.00005 run base fee once.

## `asins` (type: `array`):

10-character Amazon ASINs (letters and digits), up to 100 per run. Looked up on the selected marketplace. Billing is identical to amazonUrls: $0.005 per successfully looked-up ASIN, failures are free. Mix with amazonUrls and imageUrls in one run.

## `imageUrls` (type: `array`):

Public product photo URLs (jpg/png/webp/avif, about 1 MB or less), up to 100 per run. These skip the Amazon lookup entirely: no amazon-item-lookup fee, no Amazon price, so margin fields are null. Mix with amazonUrls/asins to process both kinds in one run.

## `marketplace` (type: `string`):

Which Amazon marketplace the lookups run against (applies to amazonUrls and asins). Also fixes the currency of the Amazon price and of the margin columns: com=USD, ca=CAD, co.uk=GBP, de/fr/it/es=EUR, jp=JPY. The Amazon leg uses a residential proxy in the marketplace country; the 1688 leg always uses China residential sessions.

## `maxSuppliersPerItem` (type: `integer`):

How many visually matching 1688 offers to return per item, in similarity order. Each delivered match row costs $0.008 (FREE tier); matches cut by your maxTotalChargeUsd are not charged.

## `marginBasis` (type: `string`):

Cost basis of estMarginPerUnit / estMarginPct. FBA (default) subtracts the estimated Amazon fulfillment fee on top of the 1688 unit cost; the fee is estimated from the product's tier/weight band on the product page when available. Plain subtracts only the 1688 unit cost. FBA fee estimates are approximations, not exact Amazon quotes.

## `fbaFeeUsd` (type: `number`):

Optional. Overrides the estimated FBA fulfillment fee for every Amazon-sourced item with your own USD figure (e.g. from the Amazon revenue calculator). Ignored when marginBasis is plain and for image-only items. The run-time USD→marketplace-currency rate used to convert it is reported in RUN_SUMMARY.

## `proxyConfiguration` (type: `object`):

Informational only. The Actor enforces RESIDENTIAL proxies internally: the Amazon leg uses one sticky residential session per item in the marketplace country (US by default), and the 1688 image-search leg uses China residential sessions. Datacenter proxies are known to be blocked by Amazon.

## `maxTotalChargeUsd` (type: `number`):

Hard budget cap for this run including the run base fee. When the next item cannot be delivered within the cap, the run stops gracefully, marks the remaining items in skippedBy.budget and reports trigger="budget". Minimum 0.04 (Apify platform limit).

## `maxRequestsPerRun` (type: `integer`):

Request quota guard across both legs (Amazon navigations, image downloads, 1688 uploads/searches). When exhausted, remaining items are marked skippedBy.quota and trigger="quota". The default 1,200 covers 100 items with retry headroom.

## Actor input object example

```json
{
  "amazonUrls": [
    "https://www.amazon.com/dp/B08N5WRWNW",
    "https://www.amazon.co.uk/dp/B0CXYZ1234",
    "https://www.amazon.de/gp/product/B0DEFG5678"
  ],
  "asins": [
    "B08N5WRWNW"
  ],
  "imageUrls": [
    "https://m.media-amazon.com/images/I/81zKd1fUqPL.jpg",
    "https://example.com/product-photo.jpg"
  ],
  "marketplace": "com",
  "maxSuppliersPerItem": 10,
  "marginBasis": "fba",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "maxTotalChargeUsd": 2,
  "maxRequestsPerRun": 1200
}
```

# Actor output Schema

## `results` (type: `string`):

Source rows (Amazon lookups), match rows (1688 suppliers with unit economics) and per-item summaries, in delivery order.

## `sources` (type: `string`):

The dataset filtered to source rows: title, main image, buy-box price, rating, review count, BSR and fetch status.

## `matches` (type: `string`):

The dataset filtered to match rows: 1688 offer, wholesale/consign price, MOQ, factory flags and estimated FBA/plain unit margin.

## `summaries` (type: `string`):

The dataset filtered to summary rows: match count, best margin, factory count and top margins per item.

## `runSummary` (type: `string`):

Machine-readable report: requested/delivered counts, skipped items by reason, coverage metrics, request usage, FX rates and billed amount.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "amazonUrls": [
        "https://www.amazon.com/dp/B0C1D2E3F4",
        "https://www.amazon.com/dp/B0A5B6C7D8",
        "https://www.amazon.com/dp/B09X1Y2Z3W"
    ],
    "asins": [
        "B08N5WRWNW",
        "B07FZ8S74R"
    ],
    "imageUrls": [
        "https://m.media-amazon.com/images/I/81zKd1fUqPL.jpg"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawleast/amazon-fba-sourcing-bridge").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "amazonUrls": [
        "https://www.amazon.com/dp/B0C1D2E3F4",
        "https://www.amazon.com/dp/B0A5B6C7D8",
        "https://www.amazon.com/dp/B09X1Y2Z3W",
    ],
    "asins": [
        "B08N5WRWNW",
        "B07FZ8S74R",
    ],
    "imageUrls": ["https://m.media-amazon.com/images/I/81zKd1fUqPL.jpg"],
}

# Run the Actor and wait for it to finish
run = client.actor("crawleast/amazon-fba-sourcing-bridge").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "amazonUrls": [
    "https://www.amazon.com/dp/B0C1D2E3F4",
    "https://www.amazon.com/dp/B0A5B6C7D8",
    "https://www.amazon.com/dp/B09X1Y2Z3W"
  ],
  "asins": [
    "B08N5WRWNW",
    "B07FZ8S74R"
  ],
  "imageUrls": [
    "https://m.media-amazon.com/images/I/81zKd1fUqPL.jpg"
  ]
}' |
apify call crawleast/amazon-fba-sourcing-bridge --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawleast/amazon-fba-sourcing-bridge"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ACK5pvjrebBzEaDlf/builds/X7jJmUoxkMakbzwH1/openapi.json
