Klook Car Rentals Scraper
Under maintenancePricing
from $7.80 / 1,000 car rental search chargeds
Klook Car Rentals Scraper
Under maintenanceGet real car rental search results — a niche no other Klook scraper covers from Klook. Talks directly to Klook's own mobile app API, no login needed. Split from the mature, published klook-all-in-one-api for a focused, single-purpose workflow.
What does Klook Car Rentals Scraper do?
Klook Car Rentals Scraper runs real car rental search on Klook — real bookable cars with real suppliers and prices — plus the location-resolution endpoints the real app requires before it will search: countries/cities available, real pickup/drop-off locations for a city, and free-text location lookup.
It talks directly to the same internal API the official Klook Android app uses, reverse-engineered by disassembling the app's native request-signing library and validated against live traffic captured from a real device. No Klook account, no API key. This is the car-rentals slice of Klook All-in-One API, split out as its own focused Actor.
Why use Klook Car Rentals Scraper?
- A real search-then-poll flow, not a stub — the app itself kicks off an async search (returns a job id) then polls for results repeatedly (confirmed live by the parent Actor: ~10 polls before real results appear); this Actor does that polling server-side so callers get one clean response with real results
- A genuinely separate subsystem — confirmed live by the parent Actor to use the exact same signing scheme as the activities API, but talking to a completely different backend (
transfercarrentalapisrv) - Real, working pagination — confirmed live by the parent Actor: distinct
pagevalues return distinct car ids - No account needed — every mode works fully anonymously
How it connects to the parent
This Actor is a narrow, batch-run spin-off of klook-all-in-one-api (an always-on Standby REST API exposing every Klook endpoint). It reuses the parent's exact, proven request-signing logic (klook-client.ts, copied verbatim, including the same GET/POST signed-request machinery) but only wraps /transport/car-rentals/countries, /transport/car-rentals/locations, /transport/car-rentals/search-locations, and /transport/car-rentals/search, and runs as a normal input-in/dataset-out Actor instead of a Standby API.
The real two-step flow
The app itself resolves a typed pickup location to a full location object (country code, IATA-style location code, poi id/name, lng/lat) before it will call search at all — a free-text string alone isn't enough. This Actor mirrors that exactly via mode:
- Run with
mode: "resolveByCity"(given acityIdfrommode: "listCountries") ormode: "resolveBySearch"(given free text like"Osaka") to get real location fields. - Run again with
mode: "search", plugging the resolvedcountry_code/iata_code/poi_id/poi_name/lng,latinto the flatpickup*input fields.
Input
| Field | Type | Description |
|---|---|---|
mode | string | listCountries | resolveByCity | resolveBySearch | search (default) |
cityId | string | Required for resolveByCity. From listCountries. |
searchWord / sourceCountryCode | string | Required for resolveBySearch (sourceCountryCode default GB). |
pickupCountryCode / pickupLocationCode / pickupLocationId / pickupLocationName / pickupCityId / pickupCityName / pickupLngLat / pickupDateTime | string | Required for search — resolved via step 1 above. |
return* (same shape as pickup*) | string | Optional for search — omit all to return to the pickup location. |
age / licenseCountryCode | integer / string | Driver age (default 30), license country (default GB). |
page / pageSize / maxPolls | integer | Result page (default 1), results per page (default 10), internal poll cap (default 8). |
currency | string | ISO code, default GBP |
Example (step 1, resolve):
{ "mode": "resolveByCity", "cityId": "28" }
Example (step 2, search):
{"mode": "search","pickupCountryCode": "JP","pickupLocationCode": "HND","pickupLocationId": "50036510","pickupLocationName": "Tokyo Haneda International Airport","pickupCityId": "28","pickupCityName": "Tokyo","pickupLngLat": "139.7783379,35.5495626","pickupDateTime": "2026-09-15 10:00","returnDateTime": "2026-09-18 10:00"}
Output
One row per call. Real example (from the parent Actor's own live-confirmed capture of a Tokyo Haneda search, trimmed):
{"mode": "search","data": {"success": true,"results": {"result": {"car_count": 214,"car_card_list": [{"car_brand_name": "Toyota","car_name": "Vitz","car_group_type": "Compact car","seat": 5,"luggage": 2}]}}}}
Known limitations
- Requires Apify's RESIDENTIAL proxy group. Klook's edge blocks non-residential IPs with a DataDome bot-challenge page — confirmed directly from this development sandbox (a request byte-for-byte identical to a working one, sent without the proxy, came back as a DataDome JS-challenge HTML page, not JSON). All outbound requests route through
Actor.createProxyConfiguration({ groups: ['RESIDENTIAL'] }). - Local dev smoke testing outside the Apify platform needs "Proxy external access" enabled on the account. This Actor's code was verified to be a byte-for-byte match against the parent's already-published, working
klook-client.ts, and the local smoke test run during development failed exactly at the proxy-URL-acquisition step (ProxyConfiguration: The "Proxy external access" feature isn't enabled for your account) — before any request to Klook was even attempted. That's an account-tier restriction on pulling a proxy URL from outside a real platform Actor run, not a defect in this code; once deployed and actually run on Apify's platform, proxy access works through the normal SDK path. mode=searchre-runs the full search-then-poll flow for everypage. There is no way to page an already-completed search without starting a new one — each call is a genuinely fresh search, which costs more time/compute than the other modes.- This is an unofficial, reverse-engineered integration, not affiliated with or endorsed by Klook Travel Technology Limited.
Pricing
Pay per event. Charged $0.012 per car-rental-search (FREE tier) — one event per row pushed to the dataset. See the Actor's Pricing tab for rates across all tiers.