Skip to content

ChocoData-com/walmart-relatedqueries-scraper

Repository files navigation

Walmart Related Queries Scraper

Walmart Related Queries Scraper

Walmart Related Queries Scraper for extracting keyword suggestions, related search terms and a search URL for each, from Walmart.com. This repo has a free Walmart related-queries script you can run right now, and a Walmart keyword data API that returns real structured JSON.

Last updated: 2026-07-20. Working against Walmart.com as of July 2026, and re-verified whenever Walmart changes their markup.

The uncut responses behind every block on this page are committed in walmart_relatedqueries_api_data/, captured 2026-07-20, and each block states what was trimmed. Every code example calls the API and is runnable from walmart_relatedqueries_api_codes/.

This repo covers one endpoint in depth. For Walmart product listings, prices, specifications and reviews, see the Walmart Scraper.

pip install requests
export CHOCODATA_API_KEY="your_key"     # free: 1,000 requests, one-time, no card
python walmart_relatedqueries_api_codes/related_queries.py "laptop"

Those three lines return this, live from Walmart.com (related_queries cut to 2 of 10; each object is complete, both fields verbatim, and the full sample is uncut):

{
  "query": "laptop",
  "related_queries": [
    { "query": "hp laptop", "url": "https://www.walmart.com/search?q=hp%20laptop&searchMethod=relatedSearch" },
    { "query": "macbook", "url": "https://www.walmart.com/search?q=macbook&searchMethod=relatedSearch" }
  ]
}

...and the same call across eight seed keywords:

Retrieved Walmart related query data

That is the whole point of this repo. The rest of this page is the free script, the wall it hits, and the endpoint with its parameters and response.


Contents


Free Walmart Related Queries Scraper

Walmart server-renders its "related searches" pills into a __NEXT_DATA__ JSON blob inside the search-results HTML, so parsing them needs no headless browser and no JavaScript rendering. The whole job is getting the HTML. Here is the plain-client version, no key and no cost:

python free_scraper/walmart_relatedqueries_free_scraper.py "laptop"

Source: free_scraper/walmart_relatedqueries_free_scraper.py. It fetches /search?q=<query>, finds the __NEXT_DATA__ script, and reads props.pageProps.initialData.searchResult.relatedSearch, taking each pill's title and absolute-ising its relative url. It parses first and only reports a block when the blob is genuinely absent.

After running the command, your terminal should look something like this:

Free Walmart related queries scraper hitting the Robot or human wall

Walmart refused the request. The next section is why.

Avoid getting blocked when scraping Walmart search

We ran exactly that script against Walmart.com while writing this README, 8 times, varying the query each time. All 8 returned the same thing: an HTTP 200 carrying a bot-check interstitial, before a single suggestion was parsed. Every run is recorded in free_scraper_survey.json.

Here is the raw evidence behind that message:

What we measured Value
HTTP status 200 (8 of 8 attempts, 8 different queries)
Response size 15,195 bytes
<title> Robot or human?
__NEXT_DATA__ blob in the HTML absent
related-search block absent (0 queries parsed)

Free scraper blocked vs Chocodata API parsed

Read the first two rows together. The status is 200, not 403 and not 429, and the body is a 15 KB page titled "Robot or human?" with no data blob in it. A scraper that checks r.status_code == 200 and then parses declares success and finds nothing, because the failure is in the body, not the status line. Whatever produced that page happens before your parser runs.

Everything else about this surface follows:

What bites you Why What it costs you
The block returns HTTP 200 The bot check is served as a normal 200 with a Robot or human? body, not a 403. A status-code health check passes while every scrape comes back empty. You have to inspect the body.
The data path is the blocked path The related-search pills only exist on the server-rendered search page, and that page is the one this client was refused on across 8 of 8 attempts. There is no cheaper page that carries the same block to smoke-test against.
The count is not fixed Real queries returned 10 suggestions on every product seed sampled; a seed Walmart has no related block for returns an empty list, not an error. Read len(related_queries). Treating 0 as a failure throws away a valid answer; assuming a fixed 10 indexes past the end on the empty ones.
The suggestions are behavioural, not semantic laptop returns printer and ipad; 4k gaming monitor 240hz returns 4k tv and gaming headset. They are Walmart's own co-search associations, not synonyms of the seed. Excellent for discovering shopper demand, wrong as a category taxonomy.
A good request can still 502 Walmart's bot check is intermittent: the same seed that works can be refused on the next call and served on the one after. Build a retry in. One refusal is not a dead query, and a pipeline that gives up on the first 502 loses rows it would have got on a retry.
The __NEXT_DATA__ path moves Walmart renames the keys inside the blob periodically, and the pills are one path change away from returning nothing. Ongoing maintenance, plus alerting smart enough to tell "empty" from "broken".

Worth knowing before you go shopping for a free alternative: a plain HTTP client fetching /search is the shape of request that got refused here, and it is the shape most free Walmart scrapers use, so check a repo's own recent output rather than its README. Several of the popular ones are wrappers that require a paid vendor's API key, which is worth checking for before you clone.


Using the Chocodata Walmart Related Queries Scraper API

The managed option, and the one this repo is built around. The Chocodata Walmart Related Queries Scraper API returns Walmart's own related search terms as parsed JSON for Walmart keyword data extraction at scale, with a ~99% success rate against the block and no proxy management. Getting parsed JSON out instead of a 15 KB "Robot or human?" page is the entire product, and it is the part we run so you do not have to. Free for the first 1,000 requests.


Walmart Related Queries Scraper API reference

Below is the Walmart Related Queries Scraper API reference to get you started: authentication, the parameters, errors and rate limits, then the endpoint with its response.

Quickstart

curl "https://api.chocodata.com/api/v1/walmart/relatedqueries?api_key=YOUR_KEY&query=laptop"
import requests

r = requests.get(
    "https://api.chocodata.com/api/v1/walmart/relatedqueries",
    params={"api_key": "YOUR_KEY", "query": "laptop"},
    timeout=90,
)
print([t["query"] for t in r.json()["related_queries"]])
# ['hp laptop', 'macbook', 'laptop computers under $200', 'gaming laptop', 'ipad', ...]

After running the command, your terminal should look something like this:

Running the Walmart Related Queries Scraper API

Get a key at chocodata.com (1,000 requests, one-time, no card).

Authentication

Pass api_key as a query parameter on every request. That is the whole auth model. There is no header form and no OAuth step.

Parameters

Param Type Required Default Description
api_key string yes - Your Chocodata API key.
query string yes - Seed keyword. The parameter is named query: q and url are not accepted and return 400. The canonical /search?q=<query> page is built from it.

Each request costs 5 credits (= 1 request). Responses are billed only on success (2xx).

Errors

Nothing below is billed: you are only charged on a 2xx.

Status error code Meaning Billed What to do
400 invalid_params query is missing or the wrong type. The body names the offending path. no Fix the query string. Use query, not q or url.
401 INVALID_API_KEY Key missing, unrecognised, or revoked. no Check api_key. Get one at chocodata.com.
402 INSUFFICIENT_CREDITS Balance exhausted. no Top up or upgrade at chocodata.com.
429 RATE_LIMITED Over the rate limit or your plan's concurrency. no Back off and retry; see Rate limits.
502 target_unreachable Walmart refused every attempt for this request. retryable: true. no Retry after a few seconds. This is the same refusal the free scraper in this repo met on 8 of 8 attempts on 2026-07-20.

Two response shapes exist: auth and billing errors nest under error.code (uppercase), while scrape-layer errors are flat with a lowercase error string plus retryable.

A bad key, verbatim:

curl "https://api.chocodata.com/api/v1/walmart/relatedqueries?api_key=totally_invalid_key_123&query=laptop"
{"error":{"code":"INVALID_API_KEY","message":"Api key not recognised."}}

Calling it with no query, verbatim. Note that it names the parameter, which is the fastest way to confirm the endpoint takes query and not q:

curl "https://api.chocodata.com/api/v1/walmart/relatedqueries?api_key=YOUR_KEY"
{"error":"invalid_params","issues":[{"code":"invalid_type","expected":"string","received":"undefined","path":["query"],"message":"Required"}]}

The scripts in this repo turn each documented status into an actionable message, so a typo'd key does not hand you a stack trace:

Walmart Related Queries Scraper API error handling

Build the retry in. A 502 here is retryable and uncharged, and it does happen, because Walmart's bot check is intermittent. Both scripts in this repo retry once after 8 seconds before giving up on a request, and that is the pattern to copy.

Rate limits and concurrency

Two limits apply at once, and the one that binds first is usually the rate limit, not the concurrency cap.

Rate limit: 120 requests per 60 seconds, per key (sliding window). That is a hard ceiling of 2 requests/second sustained, whatever your plan.

Concurrency: how many requests you may have in flight at once, which varies by plan:

Plan Concurrent requests
Free 10
Vibe 30
Pro 50
Custom 100 to 500+

Exceed either and you get 429, not a queue. Every request is a synchronous GET: there is no webhook, callback, or async job to poll. The examples use timeout=90 because a request that runs into the block and is re-attempted takes longer than the median suggests.

Size against the rate limit rather than the concurrency figure. A breadth-first expansion of one seed is 1 call at depth 1, 10 at depth 2 and up to 100 at depth 3, so about 111 calls at the ceiling, roughly a minute of rate-limited pulling. In practice it is fewer, because the graph loops back on itself and already-seen terms are not re-fetched. Keep your pool at or under your plan's concurrency and pace it to the rate limit:

from concurrent.futures import ThreadPoolExecutor
import requests

def one(q):
    r = requests.get("https://api.chocodata.com/api/v1/walmart/relatedqueries",
                     params={"api_key": KEY, "query": q}, timeout=90)
    return q, [t["query"] for t in r.json().get("related_queries", [])] if r.ok else []

seeds = ["laptop", "coffee maker", "air fryer", "headphones", "mattress"]
with ThreadPoolExecutor(max_workers=10) as pool:   # <= your plan's concurrency
    for q, terms in pool.map(one, seeds):
        print(q, terms)

Related queries: Walmart keyword suggestions and search URLs

Walmart's own related-search suggestions for a seed keyword, each with the search URL it points at. This is keyword research straight from the retailer's internal query graph: it reflects what shoppers actually type on Walmart rather than what a keyword tool models.

Param Type Required Default Description
query string yes - Seed keyword. Named query, not q or url.
curl "https://api.chocodata.com/api/v1/walmart/relatedqueries?api_key=YOUR_KEY&query=laptop"

Real response. Complete and verbatim, all 10 suggestions, both fields on each (full sample):

{
  "query": "laptop",
  "related_queries": [
    { "query": "hp laptop", "url": "https://www.walmart.com/search?q=hp%20laptop&searchMethod=relatedSearch" },
    { "query": "macbook", "url": "https://www.walmart.com/search?q=macbook&searchMethod=relatedSearch" },
    { "query": "laptop computers under $200", "url": "https://www.walmart.com/search?q=laptop%20computers%20under%20%24200&searchMethod=relatedSearch" },
    { "query": "gaming laptop", "url": "https://www.walmart.com/search?q=gaming%20laptop&searchMethod=relatedSearch" },
    { "query": "ipad", "url": "https://www.walmart.com/search?q=ipad&searchMethod=relatedSearch" },
    { "query": "chromebook", "url": "https://www.walmart.com/search?q=chromebook&searchMethod=relatedSearch" },
    { "query": "laptop apple", "url": "https://www.walmart.com/search?q=laptop%20apple&searchMethod=relatedSearch" },
    { "query": "printer", "url": "https://www.walmart.com/search?q=printer&searchMethod=relatedSearch" },
    { "query": "laptop touchscreen", "url": "https://www.walmart.com/search?q=laptop%20touchscreen&searchMethod=relatedSearch" },
    { "query": "lenovo laptop", "url": "https://www.walmart.com/search?q=lenovo%20laptop&searchMethod=relatedSearch" }
  ]
}

url is the field that makes this more than a word list: every suggestion arrives with the Walmart search URL that resolves it, carrying searchMethod=relatedSearch, so you can feed it straight into a Walmart product scraper without rebuilding query strings.

Note printer and ipad coming back for laptop. These are Walmart's behavioural co-search associations, not synonyms, which is exactly why they are useful for demand discovery: 4k gaming monitor 240hz surfaces 4k tv and gaming headset, and even a hyper-specific long-tail seed returns a full block of 10 (long-tail sample).

Read len(related_queries) rather than assuming a fixed count. Every real product query in the survey captured on 2026-07-20 returned 10. A seed Walmart ships no related-search block for returns an empty list rather than an error, so a nonsense query comes back {"query": "...", "related_queries": []} with a 200 (empty sample). There is no page parameter: Walmart renders one related block per search, so this is a seed expander rather than a keyword database. To go wider, expand the terms it returns, which is what the next section does.

Runnable: walmart_relatedqueries_api_codes/related_queries.py


Build a Walmart keyword list from one seed

Expanding a seed through Walmart's own query graph is the main reason people scrape related queries, so that use case is in the repo end to end rather than as a snippet. keyword_expander.py walks the graph breadth-first, dedupes as it goes, retries a 502 once, and writes the result to CSV:

python walmart_relatedqueries_api_codes/keyword_expander.py "laptop" --depth 2

Expanding one Walmart seed keyword into a keyword list

That is a real run: 77 unique keywords from 11 API calls. Note the shape of it. Depth 2 could have produced 100 new terms and produced 66, because the graph loops back on itself (hp laptop and macbook both return laptop). Expansion saturates quickly inside a category, which is useful to know before you budget for depth 3: you get diminishing new terms per call, so the way to widen the net is more seeds rather than more depth.

The CSV carries keyword, parent, depth, url, so the parent column gives you the path back to the seed and url gives you a ready-made Walmart search URL per row.


Measured latency

Real end-to-end wall-clock, measured from a laptop against the live API on 2026-07-20. This includes the upstream fetch, the block handling, and the parse:

Endpoint Median Range n
/walmart/relatedqueries 5.1s 3.4 to 8.0s 6

Read the range, not just the median: the slowest call in that set took more than twice the fastest. A request that runs into Walmart's refusal is re-attempted upstream until it comes back with real data, which is where the tail comes from, and absorbing that silently is the thing you are actually buying. The free script in this repo hits the same wall and simply stops. Small sample (n=6); reproduce it yourself with the scripts here.


License

MIT. See LICENSE.