BEST Agoda Scraper
Pricing
from $2.00 / 1,000 results
BEST Agoda Scraper
Every row gives you: name, stars, review score, nightly price (tax-inclusive), availability, cover image, address, geo. Two modes. Search a city for every hotel + homestay, or monitor specific properties across dates with price-change deltas and next-available on sold-out. Covers Agoda Homes.
Pricing
from $2.00 / 1,000 results
Rating
0.0
(0)
Developer
lenskii
Actor stats
2
Bookmarked
13
Total users
3
Monthly active users
4 days ago
Last modified
Categories
Share
Two ways to use it:
- Search a destination. Paste an Agoda city URL and get every hotel and homestay in that city, with prices, availability, reviews, and free cancellation flags.
- Monitor specific properties. Paste property URLs and get detailed per-property intel (amenities, host info, review themes, location scores) across any date range.
Covers both regular hotels and private-host Agoda Homes. Flat $2 per 1,000 rows. No tiers, no subscription, no minimums.
Quick start
Option A: search a whole city (most common)
- Go to agoda.com and pick a destination.
- Copy the URL from your browser's address bar.
- Paste it into
searchDestinations:
{"searchDestinations": ["https://www.agoda.com/city/singapore-sg.html"],"dateMatrix": {"startFrom": "today","scanDays": 7,"lengthOfStay": 2,"stride": 1},"adults": 2,"currency": "USD","searchMaxResults": 200}
You get about 200 properties times 7 check-in dates, so around 1,400 rows covering the next week.
Option B: monitor specific properties
Use this when you already know the properties you want to track (for example, hourly price monitoring):
{"propertyUrls": ["https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html"],"dateMatrix": {"startFrom": "2026-05-01","scanDays": 30,"lengthOfStay": 1,"stride": 7},"currency": "USD"}
Dates and guests
Control what gets scanned via dateMatrix:
startFrom:"today"or aYYYY-MM-DDdate.scanDays: how many consecutive check-in dates.lengthOfStay: nights per booking.stride: step between check-ins. 1 means daily, 7 means weekly snapshots.
Examples:
{scanDays: 14, stride: 1, lengthOfStay: 2}gives 14 rows per property, next two weeks, 2-night stays.{scanDays: 90, stride: 7, lengthOfStay: 1}gives 13 weekly price points over the next quarter.
adults, rooms, children shape occupancy. Agoda hides rooms that can't fit the party.
Discovering every hotel in a city (sortBy + skipSeen)
Agoda caps the number of unique properties you can see under any single sort order at roughly 650-1,000 per city. To uncover the long tail, run the same destination under all four sorts back-to-back and dedup between runs. This typically surfaces 1.5-2× more unique inventory than a single sort.
The actor has both pieces built in:
sortBy:"Recommended"(default),"PriceAsc","PriceDesc", or"ReviewScore".skipSeen: whentrue, the actor remembers every propertyId it already returned for each city (in a private per-account store) and silently drops duplicates before they hit the dataset — so you never pay twice for the same hotel.
Recipe for full-city coverage:
// Run 1: Recommended sort with skipSeen on — captures the bulk.{"searchDestinations": ["https://www.agoda.com/city/singapore-sg.html"],"dateMatrix": { "startFrom": "today", "scanDays": 7, "lengthOfStay": 1 },"searchMaxResults": 1000,"sortBy": "Recommended","skipSeen": true}// Runs 2-4: change sortBy to PriceAsc, then PriceDesc, then ReviewScore.// Runs 2-4 only emit rows you haven't already seen — no double charge.
You can also pass skipPropertyIds: [123, 456, ...] directly if you maintain your own dedup list in an external database.
Sold-out dates — find the nearest available (findNextAvailable)
Set findNextAvailable: true to annotate sold-out rows with the nearest available dates in your scan. Works for both search and monitor modes. Zero extra cost — reuses data already fetched in the same run.
On a sold-out row, these fields populate:
nextAvailableBefore:{ checkIn, checkOut, nights, priceNightly, daysOffset }— the nearest bookable check-in before the sold-out date (-1, -2, or -3 days).nextAvailableAfter: same shape, but for +1/+2/+3 days.nextAvailableCoverage(search rows only): on sold-out rows where no neighbor was found in the scan, this object tells you why and gives you a drop-in monitor-mode input block you can use to re-run with guaranteed coverage for that one property.
Your scanDays window has to actually cover the ± 3-day neighborhood for annotations to appear. Scanning a single sold-out date in isolation gives you nothing to compare against.
Great for "is the trip shiftable?" answers: if Monday is sold out but Sunday and Tuesday are open, the row tells you.
Output fields (search mode)
Every row represents one property for one check-in date.
| Field | Type | Description |
|---|---|---|
propertyId | number | Agoda internal property ID |
name | string | Property name |
propertyType | string | Hotel, Homestay, Apartment, Hostel, etc. |
starRating | number | 0 to 5. 0 means self-classified homestay. |
address | string | Area, city, country |
geo | {lat, lng} | Coordinates |
coverImage | string | First property image (https URL) |
imageCount | number | Total available images on Agoda |
checkIn / checkOut | date | The dates this row represents |
nights | number | Length of stay |
currency | string | ISO currency code of all prices |
pricePerNight | number | Cheapest nightly price, taxes included |
priceTotal | number | Total stay price, taxes included |
originalPricePerNight | number or null | Crossed-out price (pre-discount) |
discountPct | number or null | Discount percentage |
saveUpToPerNight | number or null | Savings per night vs. crossed-out |
isAvailable | boolean | Can be booked for these dates |
soldOut | boolean | Explicitly flagged as sold out |
availableRooms | number or null | Rooms left at the cheapest rate |
freeCancellation | boolean | Offer allows free cancellation |
cancellationType | string | Raw policy code (FreeCancellation, NonRefundable, etc.) |
paymentModel | string | PayNow, PayAtHotel, or PayLater |
reviewScore | number | 0 to 10 |
reviewCount | number | Total reviews |
reviewSnippets | array | Topic-grouped review quotes |
topSellingPoint | string | Agoda marketing badge (HighlyRated, GreatValue, etc.) |
rank | number | Position in Agoda's default sort |
priceRankInCity | number | 1-indexed rank by nightly price within the same city and check-in. 1 = cheapest available. |
priceRankOfTotal | number | Count of available properties in the same city and check-in pool (so a consumer can print rank of total). |
priceVsCityMedianPct | number | Signed percentage vs. pool median. -30 means 30% cheaper than median, +45 means 45% above. |
priceCategory | string | One of cheap, below-average, average, above-average, premium (quintile bucket within the pool). |
propertyUrl | string | Canonical agoda.com URL |
Note on images: every row includes coverImage (the first photo) and imageCount (how many photos Agoda has). The full photo gallery is not emitted.
City day summary rows
Once per (cityId, checkIn) pool, a row of kind city-day-summary is emitted alongside the property rows. Use it to see what the whole market looks like at a glance without aggregating client-side.
| Field | Type | Description |
|---|---|---|
totalProperties | number | Total properties returned in the pool. |
availableCount | number | How many had a bookable nightly price. |
soldOutCount | number | How many were sold out or had no price. |
soldOutPct | number | Sold-out share as a percentage (0 to 100). |
priceMin, priceP25, priceMedian, priceP75, priceMax | number | Price distribution across available rows. |
priceStddev | number | Sample standard deviation of nightly prices. |
Sample row
{"type": "search-result","scrapedAt": "2026-04-16T08:30:00.000Z","cityId": 4064,"checkIn": "2026-04-20","checkOut": "2026-04-22","nights": 2,"currency": "USD","propertyId": 8435201,"name": "Marina Bay Sands","propertyType": "Hotel","starRating": 5,"reviewScore": 9.1,"reviewCount": 847,"address": "Marina Bay, Singapore","geo": { "lat": 1.2838, "lng": 103.8591 },"pricePerNight": 84.5,"priceTotal": 169.0,"originalPricePerNight": 120.0,"discountPct": 30,"isAvailable": true,"soldOut": false,"availableRooms": 3,"freeCancellation": true,"cancellationType": "FreeCancellation","paymentModel": "PayLater","reviewSnippets": [{ "topic": "Location", "snippets": ["Walking distance to the waterfront"] },{ "topic": "Staff", "snippets": ["Front desk was super helpful"] }],"topSellingPoint": "HighlyRated","rank": 4,"priceRankInCity": 12,"priceRankOfTotal": 200,"priceVsCityMedianPct": -18,"priceCategory": "below-average","propertyUrl": "https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html"}
Output fields (monitor mode)
When you use propertyUrls, each row is a full quote with nested property intel. Fields are grouped by what they answer.
Identity and type
property.name,.defaultName,.localeNameproperty.type(Hotel, Homestay, Apartment, etc.)property.starRating,.isLuxuryHotelproperty.propertyUrl,.matterportUrl(3D walkthrough if the property has one)
Description and content
property.description(full property description)property.coverImage,.imageCount(first photo plus total photo count)property.remarks(renovation notes, for example"Renovated 2024")
Location
property.address,.neighborhood,.geo: {lat, lng}property.landmarks(nearby places with distance in km)property.walkablePlaces: {totalCount, topPlaces[]}(categorized walking-distance attractions, e.g. "356 places in walking distance")property.transit[](airports and stations with drive duration in minutes, distance, and category)property.locationSubscore: {airportScore, poiScore, transportationScore}(per-dimension 0 to 10 location score)
Reviews
property.rating,.reviewCountproperty.reviewBreakdown(per-dimension score for cleanliness, staff, facilities, etc.)property.categoryScores(positive-mention sentiment 0 to 100, likepool: 98,cleanliness: 96,breakfast: 94)property.reviews[](recent review texts with reviewer country and traveller type)property.reviewThemes[](tags like "Great location", "Clean")property.trendingScore: {past14DaysUplift, past30DaysUplift}(is the review score rising or falling)property.aiReviewSummary: {positive, negative}(Agoda's AI-generated pros and cons paragraph)
Booking logistics
property.checkInTime,.checkOutTime(for example"02:00 PM","12:00 PM")property.houseRules[](reception hours, photo ID requirements, etc.)property.policies({stayFreeAgeMin, stayFreeAgeMax, childPolicy, adult, extraBed, additional})property.isInfantCotAvailable,.hasHostExperienceproperty.awards: {goldCircleYear, advanceGuarantee}(Agoda's internal loyalty recognition)
Homes-specific (null for hotels)
property.hostName,.hostSuperhost,.hostResponseTime,.hostResponseRate
Amenities
property.amenities[](all available amenities, typically 100 to 270 per property)
Pricing (the reason you're scraping)
quote.cheapest(cheapest offer with price, cancellation, payment, mealPlan)quote.offers[](every room offer for the dates: room type, bedding, deals)quote.urgency(only-X-left, viewing-now, booked-recently signals)quote.availability(available,sold-out,last-room, orunknown)
Engagement signals
property.todayBookingCount(parsed from Agoda's "Booked 23 times today" badge)
Price change (cross-run)
priceChangeAbs,priceChangePct,priceChangeVsDate(compares against the last price scraped for the same(property, check-in)within 14 days. Good for price drop alerts.)
Per-run summary (one per property)
In addition to per-date quotes, each property gets a summary row with:
priceStats: {min, max, mean, median, stddev, count}across all scanned datescheapestDate,mostExpensiveDatecheapestWindow: {checkIn, checkOut, priceTotal, savingsPctVsMedian}(cheapest contiguous N-night window. RequiresflexDays > 0.)occupancyPct,availableDates[],soldOutDates[]
Price drop webhook alerts
Set alertBelowPrice: <number>. Any available row whose nightly price falls below that threshold is written to two keys in the run's key-value store:
HAS_PRICE_ALERTS(boolean). Single flag to gate a webhook on.PRICE_ALERTS(array). Full payload per alert (propertySlug,checkIn,checkOut,priceNightly,threshold,savingsVsThresholdPct,priceChangePct).
Wire an Apify "Actor run succeeded" webhook with a condition on the KV record. The webhook fires only when prices actually drop.
Typical recipe for an hourly price drop monitor:
{"propertyUrls": ["https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html"],"dateMatrix": { "startFrom": "today", "scanDays": 14, "lengthOfStay": 1 },"currency": "SGD","changedOnly": true,"alertBelowPrice": 400}
Schedule this hourly. The count of alerts per run is in run-report.totals.priceAlerts.
Pricing
Flat $2 per 1,000 rows. Pay per result. No subscription, no minimums.
Example costs:
- Search a city: 200 properties times 14 dates = 2,800 rows. Cost: $5.60.
- Daily price monitor: 10 hotels times 60 dates = 600 rows per day. Cost: $1.20 per day, or about $36 per month.
Benefits
- Works on Agoda Homes and regular hotels in one actor. Same input, same output schema. You don't run two scrapers.
- Cross-run price deltas built in.
priceChangePctandpriceChangeVsDatecome out of the box so you can wire price drop alerts in minutes. - Webhook-ready alerting.
alertBelowPriceplus an Apify webhook gives you a no-code price drop notifier. - Full property intel per row in monitor mode. Amenities, reviews, location scores, AI review summary, host info, and policies, without extra calls.
- Date matrix input. Scan a week, a month, or a quarter in one run.
- Flat pricing. $2 per 1,000 rows, period. No tiers to pick between.
Limitations
- No full image gallery. Each row carries
coverImage(the first photo) andimageCount. The remaining gallery URLs are not emitted. - No city-name full-text search. Agoda's
/search?query=Xis a search box, not a canonical city page. Use a city URL (https://www.agoda.com/city/...) or a numericcityId. - Monitor-mode currency. Quote/summary rows are reliably priced in USD, EUR, GBP, AUD, JPY, THB, MYR, PHP, IDR, VND, and HKD. Other currencies may fall back to the property's native currency — safest bet is to pick a major currency and let Agoda convert.
- ~650–1000 unique properties per sort, per city. Agoda paginates any single sort to a ceiling. Use the
sortByfanout recipe above (run the same input withbestMatch,reviewScore,lowestPriceFirst,highestPriceFirst) combined withskipSeen: trueto dedup across runs and cover 1.5–2× more of the city.
FAQ
Does it work for Agoda Homes (private-host listings)? Yes. Both modes handle Agoda Homes. The output schema is the same as for regular hotels.
Can I search by city name like "Bangkok"?
No. Agoda's /search?query=X is a full-text search, not a city page. Paste the city URL (https://www.agoda.com/city/...) or the numeric cityId.
What's the difference between searchDestinations and propertyUrls?
Use searchDestinations to discover properties in a city. Use propertyUrls to monitor specific properties you already know.
What currencies are supported? Any ISO code Agoda displays. USD, EUR, SGD, GBP, THB, JPY, AUD, VND, HKD, and more. Agoda does the conversion.
Which proxy does it use? Datacenter proxy by default for the price monitoring API calls (cheaper, and validated byte-identical to residential on the endpoints we use). The initial property discovery page load uses residential, because Agoda gates datacenter IPs on that page. The default config works out of the box. You don't need to change anything.
Can I turn off the datacenter proxy path?
Yes. Set apiProxyDatacenter: false to route everything through residential. This is slower and more expensive. Only useful if you need geo-accurate local pricing on every date cell, which is rare.
Do I get the full image gallery?
No. Every row includes coverImage (the first photo) and imageCount. The full gallery of photo URLs is not emitted.
Need a custom scraper?
Reach out if you need a different site scraped, extra fields added, or a private actor for your team. Clean schemas, reliable proxies, straightforward pricing.