OPTIMA Hotel Rate Scraper avatar

OPTIMA Hotel Rate Scraper

Pricing

from $3.00 / 1,000 date scanneds

Go to Apify Store
OPTIMA Hotel Rate Scraper

OPTIMA Hotel Rate Scraper

Captures direct-booking prices from any hotel or ryokan running the OPTIMA booking engine (*.reservation.jp): selling price, pre-discount price, discount rate, member price and remaining rooms for every room x plan x future check-in date, including sold-out dates.

Pricing

from $3.00 / 1,000 date scanneds

Rating

0.0

(0)

Developer

COBOCUS

COBOCUS

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

7 days ago

Last modified

Share

Track the price a guest actually sees on a hotel's own booking site — every room, every plan, every future date.

What does OPTIMA Hotel Rate Scraper do?

This Actor extracts direct-booking rates from any hotel or ryokan running the OPTIMA booking engine (booking sites on *.reservation.jp, by SYS.inc) — around 2,500 properties across Japan. Give it a property's booking-site URL and a date range, and it returns one row per room × plan × check-in date, with the selling price, the member price, the pre-discount price, the discount, the remaining-room count, the meal arrangement and the cancellation policy.

It reads only the public booking pages every visitor sees — no login, no account, no API key, and no access to the property's admin console. It does not book, hold, or cancel anything.

Why use OPTIMA Hotel Rate Scraper?

A property's own booking engine is the one channel where it controls the price outright, and it is the channel that no OTA scraper and no channel-manager API reports back. Without it you can measure your OTA prices but not the number you are measuring them against.

  • Rate-parity monitoring. Compare your direct price against the same room and date on Booking.com, Expedia, or a Japanese OTA, and see the days where parity actually broke.
  • Competitive rate shopping. Track a competitor's published direct rate daily, room type by room type, instead of guessing from a single headline "from ¥X" figure.
  • Demand and pickup analysis. Run it on a schedule and the dataset becomes a time series of check-in date × capture date — the shape you need to see how far out a date fills and how price moved as it did.
  • Sell-out tracking. Rooms the property cannot sell on a date are recorded explicitly, not dropped, so a gap in your data always means "not collected", never "sold out".
  • Member-rate visibility. Where a property publishes a members-only price next to the public one, both are captured separately, so a member discount is never mistaken for a public one.

On the Apify platform you also get scheduling, the API, webhooks, proxy rotation, monitoring, and export to JSON, CSV, Excel, XML or HTML — plus integrations with Google Sheets, Slack, Zapier, Make and others.

What data can OPTIMA Hotel Rate Scraper extract?

One row per room × plan × check-in date. The fields a rate analyst actually reaches for:

FieldTypeDescription
checkInDate / checkOutDatestringStay dates, YYYY-MM-DD. Check-out is derived from the number of nights.
capturedAtstringISO 8601 timestamp of the scrape — the second axis of the time series.
leadTimeDaysnumberDays between capture and check-in. The core input for pickup and lead-time curves.
propertyName / propertyIdstringFacility name and OPTIMA facility id.
roomName / roomIdstringRoom type.
roomAttributesstring[]Smoking policy, size, capacity, bed configuration, Wi-Fi — as the page lists them.
planName / planIdstringRate plan.
planTagsstring[]Badges shown on the plan, e.g. 朝食付 (breakfast included).
availabilityboolean | nulltrue bookable, false confirmed not bookable, null not collected. Never conflated.
soldOutReasonstringThe page's own wording when nothing is bookable.
remainingRoomCountnumber | nullRooms left, when the property publishes the count.
sellingPricenumberWhat a guest booking now is charged for the whole stay, tax and fees included.
originalPricenumberPrice before the property's discount.
discountAmountnumberoriginalPrice − sellingPrice.
discountType / discountValuestring / numberThe discount OPTIMA applied, and its configured magnitude (e.g. 10 for 10%).
memberPrice / memberPriceLabelnumber / stringMembers-only price, where the property publishes one next to the public total.
memberOnlybooleanThe plan itself is bookable by members only.
mealPlanstringMeal arrangement, e.g. 朝食, 朝食・夕食.
paymentMethodsstringe.g. 現地払い・Web決済 (pay at hotel / pay online).
checkInTimeFrom / checkOutTimeUntilstringPlan's check-in window and check-out time.
pointAmountnumberLoyalty points the booking grants.
minStayNightsnumberMinimum nights the plan can be booked for.
cancelPolicyRulesJsonstringThe plan's cancellation fee ladder and no-show rule, as JSON.
taxNotestringTax/fee wording shown beside the price.
validationFlagsstring[]Data-quality flags. Empty on a clean row.

currency, adults, children, childBands, rooms, nights, dayUse, propertyHost, hotelCode and sourceUrl are also on every row.

Pricing data definitions

OPTIMA reports two prices per plan: the price before whatever discount the property configured, and the price after it. What that discount is differs by property, so this Actor separates the two cases rather than reporting both as the same thing:

  • No member price published. sellingPrice is the discounted price, originalPrice is the price before the discount, and discountAmount is the difference — a discount every visitor gets.
  • A member price published next to the public total. The discount is conditional on signing in. sellingPrice stays the public total (what someone booking right now, not signed in, pays), memberPrice carries the members-only figure, and discountAmount is therefore 0. discountType / discountValue still describe the member discount.

sellingPrice always answers the same question — what is a guest charged if they book this now? — regardless of which case a property falls into.

How to scrape OPTIMA direct-booking rates

  1. Open the property's official website and click through to its booking engine. You are in the right place when the address is a *.reservation.jp host, for example https://go-botanicalpoolclub.reservation.jp/ja/hotels/bpc/searchInput.
  2. Copy that URL — any page of the booking site works, including the search form. Paste it into Property URLs. Add more URLs to track several properties in one run.
  3. Set Months ahead (default 6) to choose how far forward to scan, or set Start date and End date for an explicit range.
  4. Set Adults, Rooms and Nights to the occupancy you want priced. This matters: a property that cannot host that many adults in any room returns nothing for every date.
  5. Click Start. Watch the log — it prints the property name and facility id as soon as each URL resolves.
  6. When the run finishes, open the Dataset tab to browse or export the rows, and the Storage → Key-value store → OUTPUT record for the run's own health report.
  7. To build a time series, open the Schedules tab and run it daily. Set Run summary dataset name first (see Tips).

How much will it cost?

This Actor uses pay per event, with two charges, because the work has two parts.

EventPriceCharged
Date scanned$0.003Once per property × check-in date — one request, however heavy the page
Room × plan row$0.0002Each row written: one room × plan on one date
Property processed$0.01Once per property URL
Actor start$0.006 per GBOnce per run per GB of memory — $0.012 at this Actor's 2 GB default

The floor is arithmetic you can do before you start: properties × days × $0.003, so about $0.55 for a single property scanned six months ahead (181 dates). Above that you pay for the rows you actually receive, and that varies a great deal between properties — measured on two real six-month runs, one returned 24.6 room × plan rows per date and the other 86.7:

PropertyRows/dateTotal for a six-month scan
Small, few plans per day24.6$1.45
Larger, many plan variants86.7$3.70

Under the flat $0.015 per date this Actor was first priced at, both paid $2.74 — the small property was subsidising the large one. Now neither does.

Two things are not charged: a date that could not be collected at all, and a date whose page came back with the wrong checkin_date (OPTIMA answers a past date with today's inventory; this Actor detects that and marks the date availability: null rather than inventing a night). Neither the date nor its rows are billed in those cases.

Input

Only Property URLs is required; every other field has a sensible default. See the Input tab for the full list. The fields worth knowing about:

  • Months ahead — how far forward to scan from today (Japan time). Ignored when both Start date and End date are given.
  • Adults / Rooms / Nights — the occupancy priced. Prices are for the whole stay, not per night.
  • Children – bands 1-5 — OPTIMA splits children into five age/meal bands whose labels each property configures itself (typically from elementary-school age down to infants needing neither meal nor bedding). Band 1 is the oldest.
  • Include sold-out dates — on by default. Leave it on unless you only want bookable rows.
  • Day-use plans — search day-use instead of overnight stays. Most properties offer none.
  • Proxy configuration — Apify Proxy on the datacenter pool by default; see Tips.

Output

Every row is one room × plan × check-in date. Export from the Dataset tab as JSON, CSV, Excel, XML or HTML, or fetch it from the API.

A bookable plan at a property with no member pricing:

{
"source": "optima",
"propertyId": "10002664",
"propertyName": "BOTANICAL POOL CLUB",
"checkInDate": "2026-12-07",
"checkOutDate": "2026-12-08",
"nights": 1,
"leadTimeDays": 74,
"adults": 2,
"rooms": 1,
"availability": true,
"remainingRoomCount": 2,
"roomId": "10030723",
"roomName": "POOL CLUB ROOM",
"planId": "10179534",
"planName": "【秋冬限定】朝食STANDARD PLAN|温水プールとオールインクルーシブで過ごす、冬のリトリート",
"mealPlan": "朝食",
"paymentMethods": "現地払い・Web決済",
"checkInTimeFrom": "15:00",
"checkOutTimeUntil": "11:00",
"currency": "JPY",
"sellingPrice": 56160,
"originalPrice": 56160,
"discountAmount": 0,
"memberPrice": null,
"minStayNights": 1,
"capturedAt": "2026-09-24T08:25:02.183Z",
"validationFlags": []
}

A plan at a property that publishes a members-only price:

{
"propertyName": "オーセントホテル小樽",
"checkInDate": "2026-12-05",
"roomName": "スタンダードツイン(2名様利用)",
"availability": true,
"sellingPrice": 66000,
"originalPrice": 66000,
"discountAmount": 0,
"discountType": "1",
"discountValue": 10,
"memberPrice": 59400,
"memberPriceLabel": "会員価格",
"taxNote": "税・サービス料込",
"currency": "JPY"
}

A room the property cannot sell on that date:

{
"propertyName": "BOTANICAL POOL CLUB",
"checkInDate": "2026-12-05",
"roomId": "10030724",
"roomName": "POOL CLUB ROOM(TWIN)",
"availability": false,
"soldOutReason": "空室なし",
"sellingPrice": null
}

The run summary

Every run also writes one small JSON object to the key-value store as OUTPUT: dates requested versus collected, anything left uncollected, the date range actually present in the data, HTTP errors by status, and a single complete boolean. On a schedule, read that instead of re-reading thousands of rate rows to find out whether last night's run worked.

Tips and advanced options

  • Set a run summary dataset name before scheduling. Each run then appends its summary as one row to that named dataset, so consecutive days form a single table you can scan for a complete: false. Named datasets are not subject to storage retention, so the history survives even after the underlying runs expire.
  • availability: null is not sold out. It means the date was not collected — the request failed, or the site served a different date than the one asked for. Filter it out of price analysis, but treat a run that produces many of them as a run to re-check.
  • Past dates cannot be scraped. OPTIMA answers a request for a past check-in date with today's availability. The Actor detects the substitution and writes availability: null with a DATE_MISMATCH flag rather than recording a night that was never observed.
  • Match the occupancy to the property. Asking for 4 adults at a property whose rooms hold 2 returns "no rooms" on every date. If a whole scan comes back sold out, check Adults and Rooms first.
  • Leave the proxy off unless you need it. It is off by default, which is deliberate. OPTIMA is a property's own booking engine with no anti-bot measures, and it serves 0.7–2.5 MB of uncompressed HTML per check-in date. Measured on the Apify platform, same property and same seven dates: 211 seconds through the shared datacenter proxy against 10.2 seconds without it, identical data and zero errors either way. Turn a proxy on if a property ever starts blocking you — nothing else about the run changes.
  • Raising Max concurrency rarely helps. The run is bounded by the size of the pages, not by the number of requests. The default of 5 completes a six-month single-property scan in about a minute.
  • A ROOM_LIST_TRUNCATED flag means the property paginates its room list and this run saw only the first page. It has not been seen on any property to date; report it via the Issues tab if you hit it.

FAQ

Does this need a login or an account with the property? No. It reads only the public booking pages, exactly as an anonymous visitor sees them.

Why is discountAmount zero when the page clearly shows a discount? Because that discount requires signing in as a member. Look at memberPrice — see "Pricing data definitions" above.

Can it scrape several properties at once? Yes. Add as many booking-site URLs as you like; they are scanned in the same run and each row carries its own property id.

Does it work on a property's group site? Yes. Both OPTIMA site shapes are supported: group sites with a /hotels/<code>/ segment, and single-property sites without one. Paste the URL you land on when you click "book" on the property's own website.

Which languages does it return? Whatever the URL you paste asks for. A /ja/ URL returns Japanese room and plan names; /en/ returns the property's English copy where it has any.

Why did a date come back with no rooms? Either the property is genuinely sold out, the date is past the end of its booking window, or it does not offer that occupancy. OPTIMA uses one message for all three, and it is preserved verbatim in soldOutReason.

Ethical scraping, and your responsibilities

This Actor collects only publicly available information — the room, plan and price data any visitor sees on a property's public booking pages. It collects no personal data, no guest information, and nothing behind a login, and it makes no booking, modification or cancellation.

It is still your responsibility to use the data lawfully. Review the target property's terms of use, keep your request volume reasonable (the defaults are deliberately conservative), and make sure your use has a legitimate basis under the law that applies to you — including the GDPR if you are in the EU or handling EU data. If you plan to republish or commercially redistribute what you collect, take legal advice first. Apify's ethical web scraping guide is a good starting point.

Support

Found a bug, a property this Actor cannot read, or a field you need? Open an issue on the Issues tab of this Actor and include the property URL and the dates you ran. Booking sites change; issues get fixed.