GrabFood Scraper — Restaurants & Menus in Southeast Asia avatar

GrabFood Scraper — Restaurants & Menus in Southeast Asia

Pricing

from $2.00 / 1,000 restaurant scrapeds

Go to Apify Store
GrabFood Scraper — Restaurants & Menus in Southeast Asia

GrabFood Scraper — Restaurants & Menus in Southeast Asia

Scrape GrabFood restaurants in Singapore, Malaysia, the Philippines, Vietnam and Indonesia: cuisines, ratings, delivery fees, addresses and optional menu prices. Pay per result.

Pricing

from $2.00 / 1,000 restaurant scrapeds

Rating

0.0

(0)

Developer

Polyglot Data

Polyglot Data

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

5 days ago

Last modified

Categories

Share

Extract restaurant and menu data from GrabFood in five Southeast Asian markets: Singapore 🇸🇬, Malaysia 🇲🇾, Philippines 🇵🇭, Vietnam 🇻🇳 and Indonesia 🇮🇩.

Get restaurant names, cuisines, ratings, delivery fees and times, addresses, opening hours and, optionally, the full menu with item prices, for any point on the map or for a list of restaurant URLs. The output is flat, clean JSON that you can export to Excel, CSV or Google Sheets, or pull from the API.


✅ Why this scraper

  • Works where HTTP-only scrapers fail. GrabFood's data API only answers to a guest session created by the site's own JavaScript. This actor opens GrabFood in a real browser, gets that guest session (no login), and calls the same API from inside the page.
  • Polite by default. It waits 2 seconds between API calls, following the Crawl-delay in GrabFood's robots.txt.
  • Pay per result. You pay only for restaurants actually saved to the dataset. Error items and failed pages are not charged.
  • Clean numbers. Prices are converted from GrabFood's minor units into normal numbers (for example "S$6.50" becomes 6.5), currencies are ISO codes (SGD, MYR, THB, PHP, VND, IDR), and missing values are null, never empty strings.
  • Five countries, one schema. The same fields come back from every country.

📦 What data you get

Fast = from search results. Detail = added with Include restaurant details. Menu = added with Include full menu with prices.

FieldTypeFastDetailMenuDescription
urlstring✅✅✅GrabFood restaurant page
restaurantIdstring✅✅✅GrabFood merchant ID
namestring✅✅✅Restaurant name
chainNamestring✅✅✅Chain name, if any
branchNamestring✅✅✅Branch name
cuisinestring[]✅✅✅Cuisine tags
ratingnumber✅✅✅Average rating
reviewCountinteger✅✅✅Number of ratings
isOpenboolean✅——Open for delivery right now
openingHoursobject—✅✅Hours by day (mon … sun) plus displayedHours
hasPromoboolean✅——Has an active promotion
promoLabelsstring[]✅——Promotion labels shown on the card
deliveryFeenumber✅——Delivery fee in major units
currencystring✅✅✅ISO 4217 code
estimatedDeliveryMinutesinteger✅——Estimated delivery time
deliveryTimeRangestring✅——Delivery time as shown, e.g. 20-30 min
distanceKmnumber✅——Distance from the search point
addressstring—✅✅Full address
citystring—✅✅City
postcodestring—✅✅Postal code
imageUrlstring✅✅✅Main photo
menuItemCountinteger—✅✅Total menu items
menuobject[]——✅Menu items with prices (see below)
searchLocationstring✅✅✅The lat,lng point the search used
countrystring✅✅✅sg, my, ph, vn or id
scrapedAtstring✅✅✅UTC timestamp of the scrape

Each menu item in menu has category, name, description, price, discountedPrice, discountPct, available and imageUrl.


⬆️ Output examples

All names and IDs below are fictional. The numbers are plausible examples, not real GrabFood data.

1. Fast mode item (search results)

{
"url": "https://food.grab.com/sg/en/restaurant/online-delivery/2-EXAMPLE01",
"restaurantId": "2-EXAMPLE01",
"name": "Example Chicken Rice — Orchard",
"chainName": null,
"branchName": "Orchard",
"cuisine": ["Chinese", "Local"],
"rating": 4.6,
"reviewCount": 812,
"isOpen": true,
"openingHours": null,
"hasPromo": true,
"promoLabels": ["20% off up to S$5"],
"deliveryFee": 1.8,
"currency": "SGD",
"estimatedDeliveryMinutes": 25,
"deliveryTimeRange": "20-30 min",
"distanceKm": 1.2,
"address": null,
"city": null,
"postcode": null,
"imageUrl": "https://example.com/photos/example-chicken-rice.jpg",
"menuItemCount": null,
"menu": null,
"searchLocation": "1.3048,103.8318",
"country": "sg",
"scrapedAt": "2026-10-09T08:30:00.000Z"
}

2. Detail item (with opening hours and address)

This record came from a search, so the fast fields are still filled. The detail fields add the address, hours and menu size.

{
"url": "https://food.grab.com/sg/en/restaurant/online-delivery/2-EXAMPLE01",
"restaurantId": "2-EXAMPLE01",
"name": "Example Chicken Rice — Orchard",
"chainName": null,
"branchName": "Orchard",
"cuisine": ["Chinese", "Local"],
"rating": 4.6,
"reviewCount": 812,
"isOpen": true,
"openingHours": {
"sun": "10:00-21:30",
"mon": "10:00-21:30",
"tue": "10:00-21:30",
"wed": "10:00-21:30",
"thu": "10:00-21:30",
"fri": "10:00-22:00",
"sat": "10:00-22:00",
"displayedHours": "Daily 10:00 AM - 10:00 PM"
},
"hasPromo": true,
"promoLabels": ["20% off up to S$5"],
"deliveryFee": 1.8,
"currency": "SGD",
"estimatedDeliveryMinutes": 25,
"deliveryTimeRange": "20-30 min",
"distanceKm": 1.2,
"address": "1 Example Street, #01-01, Singapore",
"city": "Singapore",
"postcode": "238000",
"imageUrl": "https://example.com/photos/example-chicken-rice.jpg",
"menuItemCount": 24,
"menu": null,
"searchLocation": "1.3048,103.8318",
"country": "sg",
"scrapedAt": "2026-10-09T08:31:12.000Z"
}

3. Menu snippet (two of the 24 items)

With Include full menu with prices on, menu holds every item. This snippet shows two of them. Each price is in major units (6.5 means S$6.50).

{
"name": "Example Chicken Rice — Orchard",
"menuItemCount": 24,
"menu": [
{
"category": "Chicken Rice",
"name": "Example Roasted Chicken Rice",
"description": "Half chicken, rice and chili sauce",
"price": 6.5,
"discountedPrice": null,
"discountPct": null,
"available": true,
"imageUrl": "https://example.com/photos/item-1.jpg"
},
{
"category": "Sides",
"name": "Example Braised Egg",
"description": null,
"price": 1.2,
"discountedPrice": 1.0,
"discountPct": 17,
"available": true,
"imageUrl": null
}
]
}

🚀 How to use

  1. Pick a Country.
  2. Choose where to search. Either leave Search point empty to use the city center, or enter a lat,lng.
  3. Add Search terms (dish, cuisine or restaurant name), or leave them empty to get every restaurant near the point.
  4. Set Max items, turn on the detail or menu options you need, then click Start.

How to scrape restaurants near a location

Leave the search terms empty and set a point. Every restaurant near it comes back in fast mode.

{
"country": "sg",
"latlng": "1.3048,103.8318",
"maxItems": 200
}

For Jakarta, use "country": "id" and "latlng": "-6.2088,106.8456". Leave latlng out to use the city center.

How to search for a dish or cuisine

Each search term runs as its own search around the point, one after another. Items are saved in that order.

{
"country": "my",
"searchTerms": ["nasi lemak", "satay"],
"latlng": "3.1478,101.6953",
"maxItems": 100
}

How to get full menus and prices

Turn on Include full menu with prices. It also turns on restaurant details, so you get the address and hours too.

{
"country": "sg",
"startUrls": [
{ "url": "https://food.grab.com/sg/en/restaurant/example-chicken-rice-orchard/2-EXAMPLE01" }
],
"includeMenu": true,
"maxItems": 1
}

Start URLs are always opened in detail mode, so they return address, openingHours and menuItemCount without the fast-only fields (isOpen, deliveryFee, distanceKm, hasPromo).

Input fields

FieldTypeDefaultDescription
countrysg / my / ph / vn / idsgMarket to search. Also sets the default city center.
latlngstringcity centerCustom search point as lat,lng.
searchTermsstring[][]Dish, cuisine or restaurant name. Empty = all restaurants near the point.
startUrlsrequest list[]GrabFood restaurant URLs. Each is opened in detail mode.
maxItemsinteger100Maximum number of restaurants to save. Error items do not count.
includeDetailsbooleanfalseOpen each restaurant for address, opening hours and menu size.
includeMenubooleanfalseAlso return the full menu with item prices. Implies includeDetails.
proxyConfigurationproxy objectApify residentialResidential proxy is recommended. The proxy country is set from country.
debugbooleanfalseAdds _debug diagnostic items to the dataset. For troubleshooting.

⚡ Modes

Fast (default)DetailsDetails + Menu
Turn onnothing extraincludeDetailsincludeMenu
DataSearch-level fields+ address, city, postcode, opening hours, menu size+ every menu item with prices
Requests per restaurantNone extra; one search call returns up to 32 restaurantsOne extra request per restaurantOne extra request per restaurant (same request as Details)
SpeedFastestSlower: at least 2 s per restaurant because of the crawl delaySame as Details; the menu is in the same response
Per-result feerestaurant eventrestaurant eventrestaurant + menu events
Platform usage, measured Oct 2026 (Singapore)≈ $0.05 per 1,000 restaurants≈ $0.90 per 1,000 restaurants≈ $0.90 per 1,000 restaurants

A run always starts one browser, so very small runs cost a little more per restaurant.


⚠️ Error items

If an input produces no restaurants, the actor does not fail silently. It saves an error item to the dataset that says why. Error items have an error code and a note.

CodeMeaning
NO_RESULTSThe search returned no restaurants near the point. Try a bigger area, another term or another point.
RESTAURANT_NOT_FOUNDA start URL did not match a GrabFood restaurant. Check the URL.
INVALID_LOCATIONlatlng could not be read. Use lat,lng, for example 1.3048,103.8318. The run stops after this item.
BLOCKEDGrabFood refused the page after all retries (up to 4 retries per page). Try again later, or check the proxy settings.

Example error item (no results for a search):

{
"input": "durian pizza",
"searchLocation": "1.3048,103.8318",
"error": "NO_RESULTS",
"note": "GrabFood returned no restaurants for this search near the location."
}

Error items are not charged.


🎯 Use cases

  • Market research: count restaurants, cuisines and average ratings by area and see where the market is crowded.
  • Competitor menu pricing: compare item prices and discounts across the restaurants that compete with you.
  • Promo tracking: watch hasPromo and promoLabels over time to see which restaurants run discounts and when.
  • B2B lead lists for suppliers: build a list of restaurant names and addresses (restaurant data only) for food suppliers or equipment sellers.
  • Expansion and white-space analysis: run the same cuisine search across several points to find areas with few options.

🔌 Integrations, API & MCP

  • Schedules: run it daily or hourly from the Schedules tab to track changes.
  • Webhooks, Make, Zapier, n8n, Google Sheets: send results anywhere when a run finishes.
  • API: start a run and get the items in one call:
curl -X POST "https://api.apify.com/v2/acts/Polyglot-Data~grabfood-scraper/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"country":"sg","searchTerms":["chicken rice"],"latlng":"1.3048,103.8318","maxItems":50}'

Use with AI agents (MCP). The Apify MCP server lets Claude, ChatGPT and other MCP clients call this actor directly. Ask your assistant to "find chicken rice restaurants near Orchard Road in Singapore", and it runs the actor and reads back the dataset.


💰 Pricing

Pay per result. You pay a small fixed price for each restaurant saved to the dataset (restaurant event), and a second small fee only for restaurants returned with their full menu (menu event, only when includeMenu is on). See the Pricing tab for current prices. Platform usage is on top (see the Modes table). There is no monthly rental. Error items and failed pages are never charged, and the actor stops when your run's maximum charge is reached. A test run with maxItems: 20 costs little.


❓ FAQ

Which countries are supported? Singapore, Malaysia, the Philippines, Vietnam and Indonesia, through the matching food.grab.com site. Thailand is not supported because GrabFood does not offer web ordering there.

Do I need my own proxies? No. The default is Apify residential proxy, and the proxy country follows the Country you pick. Keep it on residential.

Why does it use a browser? GrabFood's data API only answers to a guest session that the site's own JavaScript creates. The actor opens the page in a real browser to get that session (no login), then calls the same API from inside the page.

How fresh is the data? Every run reads GrabFood live when it starts. Results reflect the restaurant data at that moment.

Can I scrape a whole city? Yes. Raise Max items, or run several points across the city and merge the datasets. Each run covers the results around one point.

Why are some fields null? Three common reasons: the field is only in fast mode or only in detail mode (see the field table); a start URL skips the search, so fast-only fields such as isOpen and deliveryFee are null; or GrabFood did not publish that value for the restaurant.

Something broke, or a field is missing. Open an issue in the Issues tab with the input you used and, if you can, the error item. Issues are answered quickly.


This actor collects only publicly visible restaurant and menu information: names, addresses, cuisines, ratings, opening hours, delivery information and menu prices. It does not collect personal data, customer names or customer reviews. You are responsible for making sure your use complies with GrabFood's terms of service and with the laws that apply to you.