GrabFood Restaurant Scraper at a glance
GrabFood Restaurant Scraper is a ready-to-run Apify actor from abotapi for collecting ecommerce data. Its documented output includes id, name, chain, cuisine and rating, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $1.80 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify.
- Runs on
- Apify cloud: console, API, schedules and integrations
- Data type
- Ecommerce, Developer Tools, Automation
- Pricing
- $1.80 per 1,000 results (Free plan), from $1.00 on paid plans
- Output
- Documented below · JSON, CSV, Excel
- Inputs
- 24 options
Scrape GrabFood restaurants across Southeast Asia, including SG, MY, TH, VN, PH, ID, KH, and MM. Search by keyword or URL and extract 45+ fields: restaurant name, address, GPS, cuisine, ratings, reviews, promos, delivery time, fees, opening hours, and full menus with item prices and images.
What GrabFood Restaurant Scraper: Menus, Ratings & Delivery Data can do
- Two ways to find restaurants. Search by keyword inside a region, or paste ready made GrabFood restaurant pages and listing pages directly.
- Full menu on demand. Turn on menu extraction and get every category and item, with description, price, discounted price, takeaway price, image and modifier group count.
- 8 regions, one actor. Singapore, Malaysia, Thailand, Vietnam, Philippines, Indonesia, Cambodia and Myanmar, each with prices in its own local currency.
- Delivery detail that matters for ordering. Delivery time, delivery fee (with any discount applied), delivery options such as delivery, takeaway or dine in, and distance from the search point.
- Structured promotions. Promo labels come through as readable text, for example "S$5.00 off", not just a yes or no flag.
- Filters and sorting built in. Keep only restaurants matching a cuisine tag, a minimum rating or a minimum review count, then sort by rating, review count, distance or delivery time.
Choose what to collect
These inputs let you configure GrabFood Restaurant Scraper: Menus, Ratings & Delivery Data. Open the actor on Apify to enter your values and review the current options.
| Input | What it controls |
|---|---|
modestring · required | Pick how to find restaurants. Search runs keyword queries in one region. URL mode pastes ready-made GrabFood links (a single restaurant page or a restaurants listing page). |
regionstring | GrabFood country to search. Results and prices are for that country's stores. |
languagestring | Language of restaurant and menu text and of the grabUrl links, where GrabFood offers it for the selected country: Thailand (en, th), Vietnam (en, vn), Indonesia (en, id). Other countries are English only; an unsupported choice falls back to the country default. |
deliveryLatitudenumber | Optional delivery point. Supply both latitude and longitude. Used in search, recommended listings and restaurant detail requests. Leave both blank to use the country default point. Does not confirm checkout eligibility. |
deliveryLongitudenumber | Optional delivery point. Supply both latitude and longitude. Used in search, recommended listings and restaurant detail requests. Leave both blank to use the country default point. Does not confirm checkout eligibility. |
searchQueriesarray | Keywords to search within the selected region (e.g. "ramen", "pizza", "bubble tea"). Leave empty to search the default keyword (ramen); to browse a region's recommended feed use URL mode with a listing URL that has no search term. Only applies in Search mode. |
startUrlsarray | Ready-made GrabFood URLs. Supported: a restaurant page (https://food.grab.com///restaurant//, the language segment is optional), a restaurants listing page (https://food.grab.com///restaurants?search=, or without a keyword for the recommended feed) and a country home page (treated as the recommended feed). A page= parameter is not honoured and a sortBy= parameter is ignored (use the Sort by input); chain pages and city cuisine/dish collections are skipped with a warning. Only applies in URL mode. |
Show 17 more inputs
| Input | What it controls |
|---|---|
cuisineFilterarray | Keep only restaurants whose cuisine tags contain any of these terms (e.g. burger, sushi, halal, western, vegetarian). Case-insensitive substring match. Leave empty to include all. |
minRatinginteger | Minimum star rating (0-5). Restaurants below this are skipped. Leave empty for no minimum. |
minReviewsinteger | Minimum number of ratings a restaurant must have to be included. Leave empty or 0 for no minimum. |
sortBystring | Order of restaurants in the output. Default keeps GrabFood's own ranking; the other options re-order the collected results client-side. |
fetchMenuboolean | When ON, each restaurant is enriched with its full menu (categories, items, prices, images) and full address. Turn off for faster listing-only runs. |
includeRatingsboolean | When ON, the rating score and review count are populated on every record. Turn off if you don't need any rating data. |
maxItemsinteger | Hard cap on total restaurants for the whole run. This is the main limit. Leave empty or 0 for unlimited (the run then stops at Max pages). |
maxPagesinteger | No page limit by default, the run stops at Max restaurants. Set a number only to also cap how many listing pages are walked per search. Whatever you set, a single run never walks beyond what the 1,000-restaurant hard stop needs. |
resumeFromRunIdstring | Paste a previous run ID or dataset ID to continue a large pull of restaurants without returning or charging for restaurants already collected there. Use this after an interrupted run, or when continuing a large crawl in another run. For recurring daily monitoring of the same search, use Incremental mode below instead. |
incrementalModeboolean | Turn this on for daily or recurring monitoring. The first run returns all matching restaurants as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED restaurants. A restaurant is UPDATED when any output field changes (rating, votes, promo labels, open status, delivery time and fee, menu categories/items with prices and availability, opening hours, announcements, photos) except scrapedAt and any fields you list in Ignore fields below; changedFields names what moved. EXPIRED is only emitted after a complete scan. Turn on "Emit unchanged" or "Emit expired" only when you also want those restaurants returned (and billed). State is kept separately for each mode/region/search/URL and detail/filter setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above. |
stateKeystring | Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the mode/region/search/URL and detail/filter settings, different searches then never mix state with each other. |
emitUnchangedboolean | Off by default. Turn on to also return restaurants that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want the full snapshot every run. |
emitExpiredboolean | Off by default. Turn on to also return restaurants that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search, not when Max restaurants capped it or when Resume was used. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking. |
ignoreFieldsForChangesarray | Optional. Field names that must NOT make a restaurant count as UPDATED, e.g. announcements, photoHref, openHours. Use a dotted path for nested fields (menu.items.price drops price from every menu item; arrays are transparent) or .name to ignore a name at any depth (.photoHref). Ignored fields still appear in the output; they are only left out of the comparison and changedFields. Already excluded automatically: scrapedAt. |
mcpConnectorsarray | Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON, the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com). |
notionParentPageUrlstring | URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors. |
maxNotifyListingsinteger | Cap on items written to each connector per run. Does not affect the dataset. |
Fields in the output
The documented dataset includes the fields below. Availability can depend on the source page and selected mode.
idIDnameNamechainNameChaincuisineCuisineratingRatingvoteCountReviewspriceTagPrice tieraddressAddressfullAddressFull addresscityCitycountryCodeCountrylatitudeLatShow 44 more fields
longitudeLngisOpenOpenestimatedDeliveryTimeETA (min)estimatedDeliveryTimeRangeETA rangedistanceInKmDistance kmhasPromoPromopromoLabelsPromo labelsdeliveryOptionsDelivery optionsmenuCategoryCountMenu catsmenuItemCountMenu itemsbranchNameBranchdeliveryFeeDelivery feecurrencyCurrencyopenHoursOpening hoursphotoHrefPhoto (image)menuMenu (categories and items)orderValueLimitOrder value limitannouncementsAnnouncementssourceQuerySource querysourceUrlSource URL (link)grabUrlGrabFood URL (link)regionRegionscrapedAtScrapedchangeTypeChange type (incremental mode)changedFieldsChanged fields (incremental mode)firstSeenAtFirst seen (incremental mode)lastSeenAtLast seen (incremental mode)deliveryContextDelivery point and statusmenuObservedAtMenu observed atdescriptionItem descriptionavailableAvailable (boolean)pricePrice (minor units) (number)discountedPriceDiscounted price (minor units) (number)takeawayPriceTakeaway price (minor units) (number)imageUrlImage (link)modifierGroupCountOption groups (number)isOnSpecialOn special (boolean)savingsAmountSavings (minor units) (number)discountPercentDiscount % (number)currencyCodecurrencyCodecurrencyExponentCurrency decimal placespriceInCurrencyUnitsPrice (currency units)priceDisplaypriceDisplaydiscountedPriceDisplaydiscountedPriceDisplayExample output
An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.
{
"id": "SGDD00000",
"name": "Sample Burger Place",
"chainName": "Sample Burger",
"branchName": "Downtown",
"description": "Sample restaurant blurb",
"cuisine": [
"Burger",
"Fast Food",
"Halal"
],
"address": "Sample Burger Place - Downtown",
"fullAddress": "1 Sample Street, #01-01",
"street": "Sample Street",
"suburb": "Downtown",
"postcode": "000000",
"city": "Singapore",
"countryCode": "SG",
"rating": 4.3,
"voteCount": 1200,
"priceTag": 2,
"isOpen": true,
"estimatedDeliveryTime": 35,
"estimatedDeliveryTimeRange": "From 35 mins",
"distanceInKm": 1.34,
"hasPromo": true,
"promoLabels": [
"S$5.00 off"
],
"deliveryOptions": "DELIVERY_TAKEAWAY_DINEIN",
"deliveryFee": {
"currencyCode": "SGD",
"currencySymbol": "S$",
"price": 200,
"priceDisplay": "S$2.00",
"discountedPrice": 0,
"hasDiscountedPrice": true
},
"currency": {
"code": "SGD",
"symbol": "S$",
"exponent": 2
},
"openHours": {
"mon": "10:00-22:00",
"tue": "10:00-22:00",
"displayedHours": "Daily 10:00-22:00"
},
"photoHref": "https://food.grab.com/sample/photo.jpg",
"grabUrl": "https://food.grab.com/sg/en/restaurant/sample-burger-place/SGDD00000",
"menuCategoryCount": 12,
"menuItemCount": 86,
"menu": [
{
"name": "Burgers",
"available": true,
"itemCount": 1,
"items": [
{
"id": "ITEM0001",
"name": "Classic Cheeseburger",
"description": "Beef patty, cheddar, lettuce, house sauce",
"available": true,
"price": 890,
"discountedPrice": 690,
"takeawayPrice": 850,
"imageUrl": "https://food.grab.com/sample/burger.jpg",
"modifierGroupCount": 2,
"isOnSpecial": true,
"savingsAmount": 200,
"discountPercent": 22
}
]
}
],
"orderValueLimit": 1500,
"announcements": [
"Public holiday hours apply"
],
"region": "SG",
"scrapedAt": "2026-01-01T00:00:00.000Z"
}Ways to use this data
- Delivery aggregation and comparison apps: pull live menus, prices and delivery fees to compare against other platforms.
- Market and competitor research: track promotions, price tiers and ratings across cuisines, chains and cities.
- Menu and pricing analytics: build a historical menu and price dataset for a chain across countries.
- Local lead generation: find restaurants by cuisine, rating or review count to build outreach or partnership lists.
- Daily monitoring: watch a search or a list of restaurants for new promotions, rating changes or menu updates.
Before you run
Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.
Questions about this actor
What data does GrabFood Restaurant Scraper return?
The documented output for GrabFood Restaurant Scraper includes id, name, chain, cuisine, rating, reviews, price tier and address. Availability of each field depends on the source page and the selected mode.
How much does GrabFood Restaurant Scraper cost?
It costs $1.80 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.
Is an evaluation run free?
Starting a run incurs the Actor Start charge even if no restaurants are returned. Restaurant result and Menu enrichment charges apply to delivered results as described above; credits are not a zero-charge guarantee. Check the Pricing tab and the run's memory setting before starting. A separately shared static evaluation sample requires no actor run, subscription or purchase, and grants no additional content-use rights.
Does the menu include availability or sold-out status?
With Fetch full menu on, menu[].items[].available and the category's available field are included when GrabFood supplies a boolean value. true means available and false means unavailable in that response; unavailable does not necessarily mean sold out. A null or omitted flag means unknown, and an item missing from the menu is not proof that it is sold out. Availability reflects the selected location and time, rather than a guaranteed inventory count.
How do I target one Indonesian outlet?
Search in region ID uses a central Jakarta delivery location unless both delivery coordinates are supplied. A keyword containing another city or branch name can still return nearby alternatives. Use URL mode with that outlet's restaurant URL to target a specific branch.
Can I get only new or changed restaurants on a schedule?
Yes. Schedule the actor from the Schedules tab with the same search or URLs and turn on Incremental mode. Each run then returns only NEW, UPDATED and REAPPEARED restaurants; unchanged ones are skipped and not billed unless Emit unchanged is on.
