meesho-scraper-api
v0.0.1
Published
Meesho scraper API client: sitemap discovery plus catalog, price and supplier data from Meesho product pages via ScrapingBee.
Downloads
147
Maintainers
Readme
meesho-scraper-api
Meesho catalogue data for Node. Discovery through the sitemap, extraction from two sources, and both of Meesho's failure modes handled.
npm install meesho-scraper-apiNode 16 or newer. One dependency, axios.
const { MeeshoScraper, Blocked, ProductGone } = require('meesho-scraper-api');
const bee = new MeeshoScraper(process.env.SCRAPINGBEE_API_KEY);Key with 1,000 free credits: scrapingbee.com.
Run live on 2026-09-10. The three surprises below all cost credits to find.
"How do I get a list of products?"
Not from search. That is the whole shape of this target.
const shards = await bee.sitemapShards();
shards.length; // 506
shards[0]; // { loc: 'https://www.meesho.com/sitemap/pdp/7.xml', lastmod: '2026-09-08' }
const urls = await bee.shardProducts(shards[0].loc);
urls.length; // 7044506 shards at roughly 7,000 URLs each puts the public catalogue somewhere around three and a half million pages. pdp stands for product detail page.
Reach for lastmod. It is your change signal, so a nightly crawl can skip shards that have not moved, and since the API caches nothing, every refetch is billed again.
Note that requesting meesho.com/sitemap.xml directly does not work. Akamai answers:
HTTP 403
Access Denied
You don't have permission to access "http://www.meesho.com/sitemap.xml" on this server.Through the API it comes back fine.
"Why does search return nothing?"
Because the listing grid never arrives. Tested at two price points before the sitemap route was picked:
| Attempt | Configuration | Credits | Result |
|---|---|---|---|
| Cheap | auto mode | 25 | HTTP 200, products: [], productsCount: 0 |
| Full browser | render_js + premium_proxy + wait=8000 | 25 | HTTP 200, 155 KB rendered, still empty, zero product links in the DOM |
Meesho pulls its grid from an internal endpoint after mount, and it reaches neither the delivered payload nor the rendered markup in any reasonable wait. Paying for a browser buys nothing here. The payload even sets hasNextPage: true, so it looks like a working paginator on an empty page.
"I have a URL. Give me the product."
const item = await bee.product('https://www.meesho.com/madhubani-print-saree/p/1nnri7');
item.name; // 'MADHUBANI PRINT SAREE'
item.price; // 420
item.currency; // 'INR'
item.availability; // 'InStock'
item.supplier; // 'MS Shila pal'
item.handle; // 'MSShilapal'
item.is_ad_product; // false
item.mall_verified; // false
item.images.length; // 4Prices are plain integers, not strings, and the currency is stated rather than inferred.
supplier is a person, not a brand. Meesho is a reseller marketplace, so the field that would normally hold a manufacturer holds whoever listed the item. handle is that seller's store handle, which is how you go find their other listings.
The client merges two independent sources on the page:
- The
Productstructured data givesname,sku,mpn,images,supplier,price,currency,availabilityandreviews. - The application state gives
is_ad_product,mall_verified,handle,valid,in_stockandstate_price, none of which appear in the structured data.
Because both carry a price, you get a free consistency check:
item.price === item.state_price; // trueis_ad_product and mall_verified are the two to build on. They are how you narrow a crawl to organic, verified listings rather than treating every row the same.
"I want the spec attributes"
The description field is not prose, it is attribute lines, so it parses cleanly:
item.attributes;
// { Name: 'MADHUBANI PRINT SAREE',
// 'Saree Fabric': 'Cotton Silk',
// Blouse: 'Separate Blouse Piece',
// Pattern: 'Printed',
// 'Net Quantity (N)': 'Single',
// 'Country of Origin': 'India' }"I want to walk categories"
item.category_path.map((c) => c.name).join(' > ');
// 'Home > Women > Women Ethnic Wear > Sarees > MADHUBANI PRINT SAREE'Every level carries its own /pl/<id> listing URL, so you can walk the taxonomy without going near search.
"I want bigger images"
MeeshoScraper.imageAtWidth(item.images[0], 1024);
// 'https://images.meesho.com/images/products/100206079/liprw_512.avif?width=1024'Free, no request. Catalogue images are AVIF with a resizable width parameter.
"Some sitemap URLs fail"
They are delisted products, and they answer HTTP 410 GONE, forwarded untouched because 410 is one of the few statuses the API does not rewrite. The very first URL in shard 0 is one of them. A naive loop throws and dies partway through 7,044 URLs.
const batch = await bee.products(urls.slice(0, 20));
batch.items.length; // live products
batch.gone; // URLs that answered 404 or 410Nothing is billed for a 410.
"Every field is null but the request succeeded"
This is the expensive one. Meesho serves an Akamai bot challenge on roughly three requests in eight, with HTTP 200, and the full 75 credits are charged because as far as the API is concerned the fetch worked. Eight consecutive calls to one product URL, nothing changed between them:
| Attempt | Body | Result | |---|---|---| | 1 | 2,708 bytes | challenge | | 2 | 293,588 bytes | data | | 3 | 155,158 bytes | data | | 4 | 293,602 bytes | data | | 5 | 2,708 bytes | challenge | | 6 | 191,403 bytes | data | | 7 | 2,708 bytes | challenge | | 8 | 22,917 bytes | data |
Five good, three challenged, 600 credits for eight fetches of one page.
The challenge body carries an Akamai sensor script and a sec-if-cpt-container element, with no title, no structured data and no __NEXT_DATA__. Parse it blind and every field reads null while your logs say success.
Do not test on body size. Good responses ranged from 22,917 to 293,602 bytes, so any threshold you pick misfires at one end. Test on content:
if (
body.includes('sec-if-cpt-container') ||
(!body.includes('__NEXT_DATA__') && !body.includes('<loc>'))
) {
throw new Blocked(url, body.length);
}__NEXT_DATA__ is on every page, <loc> on every sitemap, neither is in the challenge.
The client retries this for you, three attempts with a growing backoff, and throws Blocked only when every attempt is challenged. Budget for it: a product page averages about 120 credits rather than 75, so a 250,000 credit plan covers roughly 2,000 products a month, not 3,300.
Cost
await bee.product(url);
bee.lastCost; // 75
await bee.usage(); // free| Call | Credits | |---|---| | Sitemap index | 75 | | A shard | 75 | | Product page, or a challenge on one | 75 | | Delisted product | 0 | | Search page | 25, and useless |
Everything worth having sits on the stealth rung. Auto mode still helps, because it bills only the rung that succeeded and nothing when all of them fail.
Scope
Public catalogue, product and category pages. Supplier dashboards, buyer accounts and order data need a signed in session, and scraping under login credentials is prohibited by ScrapingBee's terms of service. Supplier names here belong to individual sellers, so treat them as personal data where that applies.
Elsewhere
Other marketplaces: Flipkart API, Myntra API, IndiaMART API, Amazon search API, Walmart price API, Walmart inventory API, eBay scraper, Etsy API, AliExpress API, Alibaba API, Shopee API, Target API.
Features: data extraction, AI web scraping, markdown scraper, n8n integration.
Standards in play: the sitemap protocol and schema.org Product. Discovery walkthrough: github.com/ScrapingBee/meesho-scraper-api.
License
MIT
