Lotus's Scraper: Thailand Grocery Prices & Member Prices avatar

Lotus's Scraper: Thailand Grocery Prices & Member Prices

Pricing

$1.50 / 1,000 products

Go to Apify Store
Lotus's Scraper: Thailand Grocery Prices & Member Prices

Lotus's Scraper: Thailand Grocery Prices & Member Prices

Scrape lotuss.com (ex-Tesco Lotus) categories: price in THB, crossed-out regular price, member price, price per kg, stock, brand, every promotion incl. Buy More Save More tiers. Pay per result.

Pricing

$1.50 / 1,000 products

Rating

0.0

(0)

Developer

Hexagone Data

Hexagone Data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Lotus's Scraper — Thai Grocery Prices, Member Prices & Promotions

Collect product prices from lotuss.com, the online shop of Lotus's (formerly Tesco Lotus), one of Thailand's largest retailers. Paste category URLs and get one record per product with its brand, category, price in Thai baht, crossed-out regular price, member price, per-kilogram pricing for products sold by weight, and every promotion of the product page, including "Buy More Save More" tier prices.

Use dated exports to track an assortment, compare prices across categories, or monitor promotions over time.

Try it with 20 products

  1. Paste a category URL into Category URLs, for example https://www.lotuss.com/en/category/chicken.
  2. Set Maximum number of products to 20.
  3. Start the Actor and open its dataset.
  4. Read Run summary before exporting JSON, CSV or Excel: it says, per URL, what was listed, delivered or skipped, and why.

For the Apify API, a valid input for the steps above is:

{
"startUrls": [{"url": "https://www.lotuss.com/en/category/chicken"}],
"maxItems": 20
}

The form's prefill is 20 products, the schema default is 1,000. Set maxItems explicitly in API calls; 0 removes the product-count limit.

What to paste

InputWhat you get
A category page, e.g. https://www.lotuss.com/en/category/milk-and-beverages-1Products exposed by the traversed category listings and their subcategory listings, each product once.
A full category path, e.g. https://www.lotuss.com/en/category/meat/poultryThe same, for a category whose short name is shared by several categories.

Some short names are used by several categories (in the category tree of 25 October 2026, 77 names were shared by 209 categories, e.g. poultry exists under MEAT and under CP). Such a URL is rejected with the exact full paths to paste instead; the Actor never guesses. Product pages, search pages and other sites are rejected with a reason and never block the other URLs. Thai (/th/) category URLs are accepted; product names and categories are returned in English.

Why subcategories are read too

On this site a category's own listing can miss products of its subcategories. Measured on 25 October 2026: the WATER AND BEVERAGES listing showed 1,954 products while its 10 subcategories held 2,431 distinct products (477 missing from the parent listing, e.g. 150 of 190 in BIRD NEST AND CHICKEN ESSENCE). The Actor therefore lists every category of the subtree and delivers the union, deduplicated by product code. The run summary reports, per URL, how many products the start category listed itself and how many came only from its subcategories.

Prices: what they mean

  • price is the price shown to a signed-out visitor, with no store selected (the website's own seller). It is per kilogram when priceUnit is "kg" (products sold by weight), per item otherwise.
  • regularPrice is the normal price. When it is higher than price, the page shows it crossed out: that is a public discount.
  • memberPrice is the price shown as "Get this for ฿X as a member." — reserved to Lotus's members. It is null when the product has none. The matching promotion appears in promotions with ruleType SAME_PRODUCT_GET_DISCOUNT and no text.
  • estimatedPackWeight (weight products only) is the default weight the page uses for its estimate: the page shows "1.00Kg/฿78.00" for a product at ฿78.00/Kg with an estimated pack weight of 1.
  • "Buy More Save More" products carry their tier prices in promotions[].tiers, e.g. [{"from": 1, "to": 4, "price": 78}, {"from": 5, "to": null, "price": 72}] (per kg for weight products).

priceContext repeats this context in every record. These are not the prices of a store you chose, and not a national average.

Output

FieldMeaning
skuLotus's product code.
nameProduct name as the site returns it (the product page title).
brand, category, breadcrumbBrand and category as shown on the product page ("Brand: CP", "Category: CHICKEN"); breadcrumb is the page's category path joined by " > ". The brand can be the site's own value NO BRAND.
price, regularPrice, memberPrice, currencyPrices in Thai baht, currency is always THB. See the price section.
priceUnit, estimatedPackWeightkg or each; default pack weight for weight products.
promotionsEvery promotion of the product, in the order the product page shows them: text (the offer, e.g. "Buy 2 for 111.0 Baht"), condition (the second line some offers show, e.g. "Please add only buying quantity, free item will be adding to cart automatically", else null), ruleType (site code: bxf, bxgx, BUY_X_TO_PRICE_GET_POINT, BUY_X_GET_DISCOUNT_TIER, SAME_PRODUCT_GET_DISCOUNT…), tiers (tier prices or null). [] when the product has none.
firstPromotionText, firstPromotionCondition, firstPromotionRuleTypeThe same three values of promotions[0], for spreadsheets. They always come from the same promotion.
stockStatusThe site's stock flag as returned (IN_STOCK on all 4,204 products measured on 25 October 2026): it does not prove that a store has the product on its shelf.
url, imageUrlProduct page and main image.
priceContext, sourceUrl, scrapedAtPrice context, the start URL that delivered the product, and the time its product page data was read.
dataIssuesFields delivered as null because the site sent an unexpected value. Normally empty.

A value the site does not give is null, never an invented 0, false or empty text. promotions is a list of objects: account for it when choosing spreadsheet columns, or use the firstPromotion… fields.

Output example

Built by the Actor from the Lotus's API response captured on 25 October 2026 (offline replay); it shows the format, not today's price.

{
"sku": "75589353",
"name": "CP FROZEN CHICKEN BL LEG SCRAP MEAT KG",
"brand": "CP",
"category": "CHICKEN",
"breadcrumb": "MEAT > POULTRY > CHICKEN",
"price": 78.0,
"regularPrice": 78.0,
"memberPrice": null,
"priceUnit": "kg",
"estimatedPackWeight": 1.0,
"currency": "THB",
"promotions": [
{
"text": "Buy More Save More",
"condition": null,
"ruleType": "BUY_X_GET_DISCOUNT_TIER",
"tiers": [
{"from": 1.0, "to": 4.0, "price": 78.0},
{"from": 5.0, "to": null, "price": 72.0}
]
}
],
"firstPromotionText": "Buy More Save More",
"firstPromotionCondition": null,
"firstPromotionRuleType": "BUY_X_GET_DISCOUNT_TIER",
"stockStatus": "IN_STOCK",
"url": "https://www.lotuss.com/en/product/75589353",
"imageUrl": "https://o2o-static.lotuss.com/products/107486/75589353.jpg",
"priceContext": {"sellerId": 3, "storeSelected": false, "signedIn": false, "language": "en"},
"sourceUrl": "https://www.lotuss.com/en/category/meat",
"scrapedAt": "2026-10-25T18:40:00Z",
"dataIssues": []
}

Run summary and statuses

Open Run summary (the SUMMARY record of the run's key-value store; the OUTPUT record holds the same as JSON). For each URL it shows a status, the number of distinct products listed and delivered, and every warning with its count.

  • done: every listing of the category and its subcategories was read to its end.
  • stopped_at_limit / not_processed: your maxItems or maximum charge was reached first.
  • no_products: the category and its subcategories list nothing. The site's API answers an empty list in the same way for an empty category, a wrong URL or a site outage, so each such URL gets a NO_PRODUCTS warning. If no start URL delivers any product, the run ends as failed with the message "the category is empty, the URL is wrong or the site is down"; an empty URL next to URLs that deliver products does not fail the run.
  • partial_collection: products may be missing (a listing page failed, a page repeated an earlier one, an empty page was followed by more products, a listed product had no urlKey and was not delivered by another listing of the same URL, product pages could not be read…). The run ends as failed so it is never mistaken for a complete export; the dataset keeps what was delivered, and resurrecting the run retries the incomplete URLs without delivering anything twice.
  • failed: the URL delivered no product because its product pages could not be read (or the category tree could not be read); the run ends as failed.

Product pages that cannot be read. A product page that fails (HTTP error after retries), or that answers something other than this product's data (an error code inside a normal answer, an HTML page instead of data, or another product's data), is counted per URL (DETAIL_FAILED or PRODUCT_UNREADABLE, with an example). The product is not delivered and not charged, and the URL becomes partial_collection. When at least 10 such failures in a row are seen at the end of a batch of product pages (batches of up to 20), the URL is abandoned (DETAIL_BLOCKED). If the URL delivered no product at all because of these failures, it is failed instead of partial_collection. A single field with an unexpected value does not count here: the product is delivered with that field as null and its name in dataIssues.

  • invalid_url, category_not_found, ambiguous_category: the URL was not collected; the detail says why.

The site announces no product count, so completeness is checked against the end of each listing and against the start category's own listing.

Products whose page answers "not found". A product withdrawn between the listing and its product page is rare. Per URL, up to 2 such products, or up to 1 % of the product pages requested, are reported as a warning (PRODUCT_NOT_FOUND) and the URL can still be done. Above both limits the URL is partial_collection (DETAIL_NOT_FOUND_RATE): that many "not found" answers point to an access or site problem, not to withdrawn products. If more than half of the first 50 or more product pages answer "not found", the URL is abandoned: failed if it delivered no product, otherwise partial_collection. These products are never delivered and never charged.

Pricing

$1.50 per 1,000 delivered products ($0.03 for 20). Each product delivered to the dataset is one charged result; products skipped or not delivered are not charged. Set a maximum product count or a maximum charge for your run: when the charge limit is reached, the run stops cleanly and reports it.

Limits

  • Prices are the website's signed-out prices without a selected store; member and loyalty-card offers are reported as such, never as the public price.
  • One extra request per delivered product reads its product page data (brand, category and tier prices exist only there), four at a time; large categories take accordingly longer than the listing alone.
  • stockStatus is the site's flag, not a store inventory.

Support

For a reproducible problem, open an issue with the category URL, the run ID and the expected result. Never include API tokens. Retailer changes can affect collection: check the run summary before using the results.

Lotus's is a trademark of its owner. This Actor is not affiliated with, endorsed by or sponsored by Lotus's or CP Axtra.

Coverage checks cannot prove catalogue completeness: Lotus’s exposes no authoritative total. A short listing, or a truncation shared by a parent and its children, may remain undetectable.

After migration, previousAttempts retains the request and failure counters of the interrupted attempt of each URL (kept per URL, even when another unfinished URL is collected again first); previousAttemptCounters aggregates them separately from the current traversal. A RESUMED_ATTEMPT warning, with the earlier warnings as PREVIOUS_…, is added only when the interrupted attempt had failures or warnings; an ordinary migration without incident leaves no warning. requests includes checkpointed earlier requests. Requests made after the last durable checkpoint may be lost in a hard crash. Delivered products and field-issue counts are always rebuilt from the dataset.