# Walmart Product Scraper (`usestring/walmart-products`) Actor

Reads Walmart.com product pages by item ID or /ip/ URL and returns one row per item: numeric price, was-price, brand, star rating, review count, availability status, the marketplace seller behind the buy box and the main image. Values come from Walmart's own item record, not display strings.

- **URL**: https://apify.com/usestring/walmart-products.md
- **Developed by:** [String](https://apify.com/usestring) (community)
- **Categories:** E-commerce, Business
- **Features:** Limited permissions
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

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

### What does Walmart Product Scraper do?

It reads Walmart.com product pages by item ID or product URL and returns one row per item: a
**numeric** `price`, a `wasPrice` when the item is genuinely marked down, `brand`, `rating`,
`reviewCount`, Walmart's own `availability` status, the `sellerName` behind the buy box, the main
image and the canonical product URL.

Every value comes out of the item record Walmart server-renders into its own page data, which is the
same object the storefront draws from. That is why prices, ratings and stock arrive as typed values
instead of display strings someone has to clean up later, and why a `null` here means Walmart's
record genuinely has no value rather than that a selector missed.

- One row per item, up to 300 items per run.
- A bare item ID and the full `/ip/` URL resolve to the same page and are fetched once, so a mixed
  list is never billed twice for one item.
- A URL that is not a Walmart item page — a `/browse/` shelf, a seller storefront, another host
  entirely — is rejected before it costs a fetch.
- Third-party marketplace sellers are named, not flattened into "Walmart".
- No account, API key or cookies. This is the page a logged-out shopper sees, at a median of about
  3.3 seconds per product in our own measurements.

### What data does it extract?

| Field | Type | Description |
| --- | --- | --- |
| `itemId` | string | Walmart's US item ID, taken from the record itself. Stable, and the right key to join on |
| `title` | string | Product name as Walmart states it |
| `brand` | string | Brand from the item record, not parsed out of the title |
| `price` | number | `2.36`, not `"$2.36"` |
| `priceText` | string | Walmart's own formatted price string, e.g. `$2.36` |
| `wasPrice` | number | The pre-markdown price, reported only while it genuinely exceeds `price` |
| `currency` | string | `USD` |
| `rating` | number | Average stars out of 5 |
| `reviewCount` | number | Number of reviews on the item |
| `availability` | string | Walmart's own status, e.g. `IN_STOCK`, `OUT_OF_STOCK`. `UNKNOWN` when the record states none |
| `sellerName` | string | The storefront the shopper sees: `Walmart.com` for Walmart's own inventory, otherwise the marketplace seller |
| `imageUrl` | string | The item's primary image |
| `productUrl` | string | Walmart's canonical URL for the item |
| `sourceUrl` | string | The URL that was fetched |
| `collectedAt` | string | ISO timestamp stamped once per run |

#### About `wasPrice`

A was-price stays on Walmart's record after a promotion ends, so taking it at face value invents
discounts that expired weeks ago. This Actor reports `wasPrice` only when it actually exceeds what
the item sells for today; a stale one comes back `null`. If you are building rollback detection, the
presence of `wasPrice` is the signal — you do not need to compare it against yesterday's price
yourself.

#### About `sellerName`

Walmart's record holds two names for a seller. `sellerDisplayName` is the storefront the buyer sees
("AnkerDirect"); `sellerName` is the legal entity behind it, which for a marketplace seller is often
an untransliterated company name. This Actor reports the display name, falling back to the legal one
when the display name is absent. Walmart's own items carry `Walmart.com` in both.

### Why scrape Walmart products?

- **Rollback and price monitoring.** Numeric `price` plus a trustworthy `wasPrice` is enough to spot
  a real markdown without maintaining your own price history first.
- **Buy-box seller intelligence.** `sellerName` tells you whether Walmart is selling an item itself
  or a marketplace seller holds it — a different competitive situation, and one you cannot infer
  from price alone.
- **Stock checks before sourcing.** `availability` comes from the record rather than from a rendered
  badge, so an out-of-stock item reads as out of stock and not as a missing element.
- **Catalogue enrichment.** Brand, rating, review count and a canonical URL for a list of item IDs
  you already keep.
- **Cross-retailer comparison.** Pair it with the Amazon and Home Depot Actors to put the same
  product's price side by side across three retailers.

### How to use it

1. Open the Actor and click **Try for free**.
2. Fill **Item IDs or URLs** with numeric Walmart item IDs, full `walmart.com/ip/…` URLs, or a mix
   of both.
3. Set **Maximum results** if you want a ceiling on the dataset, and leave **Concurrency** alone
   unless you have a reason — Walmart is fetched gently by default.
4. Run it, then export the dataset as JSON, CSV, Excel or XML, or read it over the API.
5. Check the `SUMMARY` record in the run's key-value store for anything that failed and why.

### Input

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `products` | array of strings | required | Walmart item IDs or full walmart.com product URLs, 1 to 300 per run |
| `maxItems` | integer | `1000` | Ceiling on dataset rows, 1 to 50,000 |
| `concurrency` | integer | `2` | Items fetched in parallel, 1 to 5 |

```json
{
  "products": [
    "10450114",
    "https://www.walmart.com/ip/Great-Value-Whole-Vitamin-D-Milk-Gallon/10450114",
    "https://www.walmart.com/ip/23849912"
  ],
  "maxItems": 1000,
  "concurrency": 2
}
```

**A Walmart item is addressed by its numeric item ID**, which is the last path segment of an `/ip/`
URL: `walmart.com/ip/Great-Value-Whole-Vitamin-D-Milk-Gallon/10450114` is item `10450114`. The slug
in the middle is decoration and Walmart serves the item under the bare ID just as well. Both forms
collapse to one URL before fetching, so the example above is two fetches and two rows, not three.

Anything that does not resolve to a numeric item ID is rejected up front and reported under
`failures` with the value you passed. That covers `/browse/` shelves, seller storefronts, search
URLs and any other host, and none of them cost a fetch.

### Output

One row per item. This is the shape rather than a captured run:

```json
[
  {
    "itemId": "10450114",
    "title": "Great Value Whole Vitamin D Milk, Gallon, 128 fl oz",
    "brand": "Great Value",
    "price": 2.36,
    "priceText": "$2.36",
    "wasPrice": null,
    "currency": "USD",
    "rating": 4.4,
    "reviewCount": 6132,
    "availability": "IN_STOCK",
    "sellerName": "Walmart.com",
    "imageUrl": "https://i5.walmartimages.com/seo/Great-Value-Whole-Milk-Gallon_a1f2.jpeg",
    "productUrl": "https://www.walmart.com/ip/Great-Value-Whole-Vitamin-D-Milk-Gallon/10450114",
    "sourceUrl": "https://www.walmart.com/ip/10450114",
    "collectedAt": "2026-08-20T09:14:02.881Z"
  },
  {
    "itemId": "23849912",
    "title": "Anker Soundcore Life Q30 Hybrid Active Noise Cancelling Headphones",
    "brand": "Anker",
    "price": 59.99,
    "priceText": "$59.99",
    "wasPrice": 79.99,
    "currency": "USD",
    "rating": 4.6,
    "reviewCount": 1874,
    "availability": "OUT_OF_STOCK",
    "sellerName": "AnkerDirect",
    "imageUrl": "https://i5.walmartimages.com/seo/Anker-Soundcore-Life-Q30_8c31.jpeg",
    "productUrl": "https://www.walmart.com/ip/Anker-Soundcore-Life-Q30/23849912",
    "sourceUrl": "https://www.walmart.com/ip/23849912",
    "collectedAt": "2026-08-20T09:14:02.881Z"
  }
]
```

### Geography and currency

Walmart.com is the US storefront, and that is the whole geographic story here: `currency` is `USD`
on every row, and there is no country, store or ZIP input to set. Prices and stock are the national
online values the item page shows a visitor who has not chosen a store, which is the right basis for
comparing items against each other over time.

If you need per-store local pricing, that is a different retailer's model — the [Home Depot Product
Scraper](https://apify.com/usestring/homedepot-products) takes a store number and resolves price and
inventory against it. For non-US storefronts of other retailers, the [Amazon Product
Scraper](https://apify.com/usestring/amazon-products) covers seven countries.

### How much does it cost?

Pay-per-event: you are charged per result row written to the dataset. A row is written only when it
can be charged, so hitting your spend limit stops the writing rather than delivering unbilled rows.
The current per-row figure sits on the Actor's Store page.

Runs started from an Apify **free plan** stop at **250 requests and 250 results** and say so in the
run's status message. Any paid plan runs the full input and the `maxItems` you set.

The limit exists because this Actor fetches through our own scraping infrastructure, which Apify
does not cover for free-plan runs. It binds on requests as well as rows, so a long item list cannot
spend fetches on rows the run will never return.

### Using it with the Apify API

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('usestring/walmart-products').call({
  products: ['10450114', 'https://www.walmart.com/ip/23849912'],
  maxItems: 300
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
const markdowns = items.filter((item) => item.wasPrice !== null);
console.log(`${markdowns.length} of ${items.length} items are on rollback`);
```

The Python client and the plain REST API reach the same run, and a schedule will take the price
snapshot for you every morning.

### Limitations

Product pages on walmart.com (US) only, and only for items you name. No review text, no variant
matrices, no specification tables, no per-store shelf inventory and no full offer list behind the
buy box. There is no search or category crawling here — the Actor never spends a fetch on a page you
did not ask for. Values reflect what Walmart's record said at `collectedAt`.

### Related actors

- [Home Depot Product Scraper](https://apify.com/usestring/homedepot-products) — the same product
  fields for home improvement, with local price and stock per store number.
- [Amazon Product Scraper](https://apify.com/usestring/amazon-products) — the matching lookup on
  Amazon, across seven marketplaces.
- [Amazon Search Scraper](https://apify.com/usestring/amazon-search) — keyword discovery when you do
  not yet know which products to price.
- [Amazon Bestsellers Scraper](https://apify.com/usestring/amazon-bestsellers) — category rankings,
  useful for building a comparison set worth checking on Walmart.
- [Etsy Listings Scraper](https://apify.com/usestring/etsy-listings) — listing-level data on the
  handmade marketplace.

### FAQ

**What is a Walmart item ID and where do I find it?**
The numeric identifier at the end of a Walmart product URL — `10450114` in
`walmart.com/ip/Great-Value-Whole-Vitamin-D-Milk-Gallon/10450114`. Pass it bare or pass the whole
URL; both work, and both cost one fetch.

**Can it search Walmart or crawl a category?**
No. You supply the items. That is a deliberate boundary: an Actor that crawled would spend your
budget on pages you never asked for.

**Does it return third-party marketplace sellers?**
Yes. `sellerName` carries the storefront shown on the item, so you can tell Walmart's own inventory
from a marketplace seller's.

**Why is `wasPrice` null on an item that shows a strikethrough price?**
Because the recorded was-price was not higher than the current price when the run happened. Walmart
leaves stale was-prices on the record after a promotion ends, and reporting one as a discount would
be wrong.

**How many rows does one item produce?**
One. One page fetched, one row emitted.

**What happens to an item ID that no longer exists?**
It is recorded under `failures` in the run's `SUMMARY` record, with Walmart's own error reason where
the page gives one, and the rest of the batch still returns. A run in which every item failed exits
as a failed run rather than as an empty success.

**Do I need proxies?**
No. Fetching and anti-bot handling happen on our side; there is nothing to configure.

### Feedback

If a field looks wrong or you need one that is not here, open an issue from the Actor's Store page
and include the item ID. One ID is usually enough to reproduce the problem.

# Actor input Schema

## `products` (type: `array`):

Walmart item IDs or full product URLs.

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

Global cap on dataset items. Runs started from an Apify free plan stop at 250 requests and 250 results; any paid plan runs the full amount.

## `concurrency` (type: `integer`):

Targets fetched in parallel.

## Actor input object example

```json
{
  "products": [
    "10450114"
  ],
  "maxItems": 1000,
  "concurrency": 2
}
```

# Actor output Schema

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

Reads Walmart.com product pages by item ID or /ip/ URL and returns one row per item: numeric price, was-price, brand, star rating, review count, availability status, the marketplace seller behind the buy box and the main image. Values come from Walmart's own item record, not display strings.

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

Item count, failure count and every target that failed, with its error.

# 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 = {
    "products": [
        "10450114"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("usestring/walmart-products").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 = { "products": ["10450114"] }

# Run the Actor and wait for it to finish
run = client.actor("usestring/walmart-products").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 '{
  "products": [
    "10450114"
  ]
}' |
apify call usestring/walmart-products --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,usestring/walmart-products"
        }
    }
}
```

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/Bpyynimud873IVgoS/builds/d5H1SezXb5ZG0lgKI/openapi.json
