# Amazon Inventory Checker: How Many Units Are Left, by ASIN (`amazonscrapers/amazon-inventory-checker`) Actor

Find out how many units of a product can actually be ordered right now. Reads Amazon's own quantity menu and scarcity warning, so you see 3 left, 12 left, or at least 30. Plus availability, delivery, Prime and other seller count. 19 marketplaces. You only pay for rows with a verdict.

- **URL**: https://apify.com/amazonscrapers/amazon-inventory-checker.md
- **Developed by:** [Amazon Scrapers](https://apify.com/amazonscrapers) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 products with a unit counts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Amazon inventory checker: how many units are left, by ASIN

Give it a list of products. Get back how many units of each one can actually be
ordered right now.

Not "in stock" or "out of stock", which you already knew. A number: three left,
twelve left, or at least thirty. Run it daily and the difference between
Tuesday's number and Friday's is how fast that listing is selling.

### Every field it returns

#### Price and offer

| Field | What it holds |
| --- | --- |
| `price` | Current price from Amazon's own buy box data |
| `currency` | Three-letter code, from the page itself |
| `hasUsedOffer` | Whether a used copy is offered |
| `otherSellersCount` | How many other sellers offer it |

#### Stock and delivery

| Field | What it holds |
| --- | --- |
| `inStock` | True, false, or null when Amazon does not say |
| `availability` | Amazon's own availability sentence |
| `stockLeft` | Only three left in stock, when shown |
| `deliveryInfo` | The delivery date Amazon promises |
| `isPrime` | Prime delivery on this offer |

#### Identity and catalogue

| Field | What it holds |
| --- | --- |
| `asin` | The product id |
| `title` | Full product title, shortened only past 1000 characters |
| `brand` | Brand name |
| `marketplace` | Which shop this row came from |
| `url` | The page this was read from |
| `scrapedAt` | Timestamp of the read |

#### Stock level

| Field | What it holds |
| --- | --- |
| `stockAnswer` | The verdict: an exact count, a seller order cap, or no answer **(this is what you are charged for)** |
| `sellerStockLevel` | How many units the buy box seller has left, when Amazon reveals it |
| `stockSource` | Where that number came from, so you can audit it |

### Read this before your first run

**The number stops at thirty.** Amazon's quantity menu offers at most thirty
choices, so anything above that comes back as `at-least:30` rather than a figure.
This Actor will not invent what Amazon did not show.

That sounds like a big limitation and in practice it is the opposite of one. The
useful signal is at the low end. A competitor sitting on four hundred units tells
you nothing you can act on; a competitor down to six units next Thursday tells
you exactly when their listing goes dark and yours is the only one left.

**What the number really counts.** It is the most you can put in a basket right
now, which is the smaller of two things: how many the seller has, and how many
they allow per order. Those two cannot be separated from outside, and pretending
otherwise would produce a confidently wrong figure. So the field is called
`units`, not `stock`, and this paragraph is on the page rather than buried.

**It applies to the buy box seller.** Other sellers on the same listing keep
their own stock, and that is not visible here. `otherSellersCount` tells you how
many of them there are.

**Honest note about the famous trick.** The method usually described for this,
putting 999 in a basket and reading the error, is not what this Actor does. It
was tried first: four rounds against the live site, three different routes, one
of them a full replay of Amazon's own buy box form with its security token and a
live session. Four of ten products had no such form at all and the other six
answered with an error and an empty basket. What is in here reads the quantity
menu on the page instead, which is the same underlying limit Amazon applies, and
it needs no basket at all.

### The four answers

Every row carries one of these in `stockAnswer`, or nothing.

| Answer | What it means |
| --- | --- |
| `units:7` | Seven can be ordered right now. |
| `at-least:30` | The quantity menu was full. More than thirty, exact figure unknown. |
| `out-of-stock` | Amazon says it cannot be bought. |
| empty | Amazon revealed nothing usable. Delivered anyway, never charged for. |

`stockSource` says where the number came from, so you can audit it:
`quantity-menu` for Amazon's own order limit, `scarcity-warning` for the
"Only N left in stock" line, `availability` for a plain no.

When both sources speak, the lower number wins. The menu limits what you can
order and the warning describes what is on the shelf; taking the higher of the
two would report stock that is not for sale.

### What to put in

Products, three ways, same as everywhere in this family:

- an ASIN on its own, `B09B8V1LZ3`
- a product link, `https://www.amazon.com/dp/B09B8V1LZ3`
- pasted text with an ASIN in it, `ASIN: B09B8V1LZ3`

Search terms and category links work too, through `search`, if you would rather
check the stock of whatever currently ranks for a keyword.

### Settings worth knowing about

| Setting | What it does |
| --- | --- |
| `productUrls` | The products to check. ASINs, links, or pasted text. |
| `search` | Search terms or category links, if you would rather check whatever ranks. |
| `marketplace` | Which Amazon. Nineteen available. |
| `maxItems` | Hard ceiling on products for this run. |
| `maxItemsPerList` | How many products to take from each search term or category. |
| `maxListPages` | How deep to page through a search or category. |
| `proxyConfiguration` | Which proxy to use. Datacenter by default. |
| `proxyCountry` | Which country to exit from. Empty means follow the marketplace. |
| `residentialFallback` | Switch the later attempts to residential addresses. Off by default; it costs more and, measured on this engine, it did not deliver more. |
| `maxAttempts` | How many times to retry a product Amazon refuses. |
| `lanes` | How many products to work on at once. |
| `minDelayMs` `maxDelayMs` `retryPauseMs` | The pacing. The defaults are deliberately unhurried. |

### How it works, in plain terms

It opens the product page, the same page a shopper sees, and reads two things
Amazon prints there: the quantity menu next to the buy button, and the scarcity
line that says "Only N left in stock" when a listing is running down.

The quantity menu is the interesting one. Amazon will not offer you a quantity
you cannot have, so the number of choices in that menu is the order limit itself.
A seller with five units gets a menu of five.

No basket is opened, no form is submitted, nothing is added anywhere. It is a
read of a public page, which is why it works on the same pacing and the same
retry logic as everything else in this family.

If Amazon refuses the page, it is retried from a different exit address up to
`maxAttempts` times, and once more in a second pass at the end of the run. Only
after all of that does a product come back without an answer, and free.

### What you can build with it

**Sales velocity without guessing.** Snapshot a competitor daily. Five hundred on
Monday is not visible, but twenty-two on Monday and fourteen on Friday is eight
units in four days, and that is a real number rather than a model.

**Stockout timing.** When a competitor's number starts falling and yours does
not, you know roughly when they run dry. That is the day to raise your price or
push your advertising.

**Supplier reliability.** Watch your own listings across marketplaces. A number
that drops toward zero while your own system says otherwise is a fulfilment
problem you would otherwise find from a lost buy box.

**Pre-purchase checks for arbitrage.** Before you buy a hundred units to resell,
check how thin the listing already is. A listing where the buy box seller has
three left behaves very differently from one where they have thirty.

**Scarcity as a research filter.** Combined with the bestsellers scraper, a
category full of listings sitting at `units:2` is a category with supply
problems, and supply problems are where margin lives.

### Working it into your stack

Set a schedule and run it at the same hour daily, so consecutive numbers are
comparable. Pull the dataset from the API:

```
https://api.apify.com/v2/datasets/<datasetId>/items?clean=true&format=csv
```

`sellerStockLevel` is a plain number when there is one, so a spreadsheet can
subtract yesterday from today without any parsing. `stockAnswer` is the text
version for the rows where there is no number.

### Marketplaces

Nineteen, from amazon.com to amazon.co.jp. The quantity menu is read from the
page structure rather than from any English wording, so a German or Japanese page
is read the same way.

One caveat carries over from the rest of this family: on several marketplaces
Amazon does not show a buy box to visitors it cannot place, and the quantity menu
lives inside the buy box. Where there is no buy box there is no answer, and those
rows arrive empty and free. Running twenty products on your own marketplace first
costs almost nothing and tells you immediately whether this works for you.

### Pricing

Four dollars per thousand products with an answer, plus three cents to start a
run. That is four tenths of a cent per answer.

Checking a hundred products costs forty-three cents. Watching fifty daily costs
twenty-three cents a day. You are not charged for a product where Amazon revealed
nothing, or for one that never arrived. Platform usage is included, so there is
no separate compute bill and no proxy bill.

### The rest of this family

This Actor is one of thirteen on the same engine.

- **Amazon Stock Checker** when the question is simply buyable or not, with
  delivery promises, rather than how many.
- **Amazon Listing Monitor** to be told when something changes rather than
  reading the numbers yourself.
- **Amazon Offer Checker** for how many sellers are on the listing and on what
  terms.
- **Amazon Price Tracker** for the price on the same list of ASINs.
- **Amazon Bestsellers Scraper** to build the watch list in the first place.

They share the retry engine, the pricing model and the rule about never guessing,
so what you learn on one carries to the others.

### Questions people ask

**Why do so many rows say at-least:30.** Because most listings are not running
low, which is itself the answer. The interesting rows are the ones that are not
thirty.

**Is the number the seller's real inventory.** It is the most you can order right
now. For a seller with no order cap those are the same thing; for one with a cap
it is the cap. There is no way to tell from outside, and this page says so rather
than picking the flattering interpretation.

**Why is the number sometimes empty on amazon.de.** Because Amazon sent a page
without a buy box, which it does on several marketplaces when it cannot place the
visitor. The quantity menu lives inside the buy box. Those rows cost you nothing.

**Can I get more than thirty.** Not from the page, and not from this Actor. The
menu is where Amazon stops.

**Does it add anything to a basket.** No. Nothing is added, submitted or ordered.
It reads a public page.

### What it does not collect

No review text, no reviewer names, no customer questions, no seller names. Review
text and reviewer names are personal data, and scraping personal data is almost
always a problem under European privacy law regardless of intent. Star ratings
and review counts are aggregate numbers and those are available in the sister
Actors that report them.

You can see how many sellers are on a listing. You cannot see who they are.

### Legal note

This Actor reads pages that Amazon serves publicly, at a deliberately unhurried
pace. It is not affiliated with, endorsed by, or connected to Amazon.com, Inc.
What you may do with the data it returns depends on where you are and what you
use it for, and that is your call to make.

# Actor input Schema

## `productUrls` (type: `array`):

Amazon product URLs or bare ASINs, one per line. Leave empty if you are using Search instead. Duplicates are removed so you are never charged twice.

## `search` (type: `array`):

Anything that lists products: a plain search term ("tower fan"), an Amazon search URL, a category link, or a bestsellers page. Each one is crawled and every product found is scraped. Use this when you do not know the ASINs up front.

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

Which Amazon site to read. The currency of the price follows the marketplace and the proxy country.

## `proxyCountry` (type: `string`):

Which country the requests should appear to come from. Leave empty and it follows the marketplace: amazon.de is read from Germany, amazon.co.uk from the UK. This matters more than it looks -- Amazon shows different prices, currencies and even availability depending on where you appear to be.

## `maxItems` (type: `integer`):

Hard ceiling on delivered products. 0 means no ceiling: the Actor keeps going until the lists run out or your limits stop it.

## `maxItemsPerList` (type: `integer`):

Products to take from each search term or category link. Up to 10000.

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

Datacenter proxies were enough in testing: 30 out of 30 products returned with zero blocks. They are the cheaper option and the default. Switch to residential if you start seeing blocked pages at higher volume. Running without any proxy stops after roughly 85-120 products, because Amazon closes the door on a single IP address for over an hour.

## `lanes` (type: `integer`):

How many products to read at the same time. Each lane uses its own exit address, so more lanes never means asking one address more often. Eight is the tested default and the most accurate. Sixteen finishes the same sixty products in about half the time, but measured on 2026-08-24 it returned six more products without a price, because Amazon strips the buy box sooner under pressure. Raise it when speed matters more than the last few prices.

## `maxAttempts` (type: `integer`):

How often to retry a product Amazon refuses, each time from a different exit IP. A refusal is a property of one address, not of the product, and a refused attempt costs about 4 KB. Twelve tries is cheap insurance against a run that comes back short.

## `residentialFallback` (type: `boolean`):

After half the attempts have failed, retry through residential addresses instead of datacenter ones. Measured 2026-08-26: residential transfer was 90 percent of the bill on a sixty product run ($0.150 of $0.167) while a run that never touched it delivered all sixty anyway. Leave it off unless you are losing products; turn it on when a marketplace refuses everything.

## `maxListPages` (type: `integer`):

Result pages to walk per list. Up to 100. Amazon itself stops earlier on most searches.

## `minDelayMs` (type: `integer`):

Pause between products. Measured 2026-08-23: at 1-2 seconds this returned 10 of 15 products; at 8-15 seconds it returned 12 of 15 on the same list. Pace turned out to matter more than anything else. The market leader waits about 14 seconds per product.

## `maxDelayMs` (type: `integer`):

Upper bound for the pause between products. The actual pause is random between the minimum and this value, which looks less mechanical than a fixed interval.

## `retryPauseMs` (type: `integer`):

How long to wait before trying a refused product again. Kept short because the retry already switches to a different exit IP, and waiting longer only makes the run more expensive.

## Actor input object example

```json
{
  "productUrls": [
    "B09B8V1LZ3",
    "https://www.amazon.com/dp/B0DXXYS4BJ"
  ],
  "search": [],
  "marketplace": "com",
  "maxItems": 0,
  "maxItemsPerList": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "lanes": 8,
  "maxAttempts": 12,
  "residentialFallback": false,
  "maxListPages": 5,
  "minDelayMs": 8000,
  "maxDelayMs": 15000,
  "retryPauseMs": 300
}
```

# Actor output Schema

## `products` (type: `string`):

One row per product: how many units can be ordered right now, where that number came from, and the availability around it. Products where Amazon revealed nothing are delivered and never charged for.

## `summary` (type: `string`):

Counts per outcome, exit addresses used, bytes per charged result.

# 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 = {
    "productUrls": [
        "B09B8V1LZ3",
        "https://www.amazon.com/dp/B0DXXYS4BJ"
    ],
    "search": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("amazonscrapers/amazon-inventory-checker").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 = {
    "productUrls": [
        "B09B8V1LZ3",
        "https://www.amazon.com/dp/B0DXXYS4BJ",
    ],
    "search": [],
}

# Run the Actor and wait for it to finish
run = client.actor("amazonscrapers/amazon-inventory-checker").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 '{
  "productUrls": [
    "B09B8V1LZ3",
    "https://www.amazon.com/dp/B0DXXYS4BJ"
  ],
  "search": []
}' |
apify call amazonscrapers/amazon-inventory-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,amazonscrapers/amazon-inventory-checker"
        }
    }
}

```

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/0gn9XkYHXvzp3QCWe/builds/693YJpdo2rcJDPaUl/openapi.json
