BEST Agoda Scraper avatar

BEST Agoda Scraper

Pricing

from $2.00 / 1,000 results

Go to Apify Store
BEST Agoda Scraper

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

lenskii

Maintained by Community

Actor stats

2

Bookmarked

13

Total users

3

Monthly active users

4 days ago

Last modified

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)

  1. Go to agoda.com and pick a destination.
  2. Copy the URL from your browser's address bar.
  3. 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 a YYYY-MM-DD date.
  • 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: when true, 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.

FieldTypeDescription
propertyIdnumberAgoda internal property ID
namestringProperty name
propertyTypestringHotel, Homestay, Apartment, Hostel, etc.
starRatingnumber0 to 5. 0 means self-classified homestay.
addressstringArea, city, country
geo{lat, lng}Coordinates
coverImagestringFirst property image (https URL)
imageCountnumberTotal available images on Agoda
checkIn / checkOutdateThe dates this row represents
nightsnumberLength of stay
currencystringISO currency code of all prices
pricePerNightnumberCheapest nightly price, taxes included
priceTotalnumberTotal stay price, taxes included
originalPricePerNightnumber or nullCrossed-out price (pre-discount)
discountPctnumber or nullDiscount percentage
saveUpToPerNightnumber or nullSavings per night vs. crossed-out
isAvailablebooleanCan be booked for these dates
soldOutbooleanExplicitly flagged as sold out
availableRoomsnumber or nullRooms left at the cheapest rate
freeCancellationbooleanOffer allows free cancellation
cancellationTypestringRaw policy code (FreeCancellation, NonRefundable, etc.)
paymentModelstringPayNow, PayAtHotel, or PayLater
reviewScorenumber0 to 10
reviewCountnumberTotal reviews
reviewSnippetsarrayTopic-grouped review quotes
topSellingPointstringAgoda marketing badge (HighlyRated, GreatValue, etc.)
ranknumberPosition in Agoda's default sort
priceRankInCitynumber1-indexed rank by nightly price within the same city and check-in. 1 = cheapest available.
priceRankOfTotalnumberCount of available properties in the same city and check-in pool (so a consumer can print rank of total).
priceVsCityMedianPctnumberSigned percentage vs. pool median. -30 means 30% cheaper than median, +45 means 45% above.
priceCategorystringOne of cheap, below-average, average, above-average, premium (quintile bucket within the pool).
propertyUrlstringCanonical 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.

FieldTypeDescription
totalPropertiesnumberTotal properties returned in the pool.
availableCountnumberHow many had a bookable nightly price.
soldOutCountnumberHow many were sold out or had no price.
soldOutPctnumberSold-out share as a percentage (0 to 100).
priceMin, priceP25, priceMedian, priceP75, priceMaxnumberPrice distribution across available rows.
priceStddevnumberSample 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, .localeName
  • property.type (Hotel, Homestay, Apartment, etc.)
  • property.starRating, .isLuxuryHotel
  • property.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, .reviewCount
  • property.reviewBreakdown (per-dimension score for cleanliness, staff, facilities, etc.)
  • property.categoryScores (positive-mention sentiment 0 to 100, like pool: 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, .hasHostExperience
  • property.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, or unknown)

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 dates
  • cheapestDate, mostExpensiveDate
  • cheapestWindow: {checkIn, checkOut, priceTotal, savingsPctVsMedian} (cheapest contiguous N-night window. Requires flexDays > 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. priceChangePct and priceChangeVsDate come out of the box so you can wire price drop alerts in minutes.
  • Webhook-ready alerting. alertBelowPrice plus 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) and imageCount. The remaining gallery URLs are not emitted.
  • No city-name full-text search. Agoda's /search?query=X is a search box, not a canonical city page. Use a city URL (https://www.agoda.com/city/...) or a numeric cityId.
  • 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 sortBy fanout recipe above (run the same input with bestMatch, reviewScore, lowestPriceFirst, highestPriceFirst) combined with skipSeen: true to 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.