{
  "openapi": "3.0.1",
  "info": {
    "title": "Google Hotels Scraper",
    "description": "Scrape Google Hotels by place and dates: nightly price with and without taxes, rating, reviews summary, amenities, location. Every booking site's price, room rates, reviews and price calendar on demand. Export to JSON, CSV or Excel.",
    "version": "0.0",
    "x-build-id": "IyafP6H0EcRfhTpjI"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/nice_dev~google-hotels-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-nice_dev-google-hotels-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/nice_dev~google-hotels-scraper/runs": {
      "post": {
        "operationId": "runs-sync-nice_dev-google-hotels-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/nice_dev~google-hotels-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-nice_dev-google-hotels-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "location": {
            "title": "Destination",
            "maxLength": 200,
            "type": "string",
            "description": "A city, region, district or landmark, as typed in the Google Hotels search box (e.g. `Paris`, `Tuscany`, `Times Square`). Google resolves it the way its own search does; the place it settled on is in `resolvedLocation`, and a destination Google cannot find is reported in the log instead of returning hotels from somewhere else. Empty = no destination from this field."
          },
          "locations": {
            "title": "More destinations",
            "maxItems": 100,
            "uniqueItems": true,
            "type": "array",
            "description": "Several destinations in one run: one search per destination (times each search text below; destinations × search texts max 500). Added to **Destination**. Hotels found by several searches are saved once.",
            "items": {
              "type": "string",
              "maxLength": 200
            },
            "default": []
          },
          "query": {
            "title": "Search text",
            "maxLength": 200,
            "type": "string",
            "description": "Optional words sent to Google Hotels before the destination, exactly as you would type them (e.g. `boutique hotels`, `hotels near the Louvre`, `pet friendly hotels`). With a destination, the search is `<search text> <destination>`; alone, it is sent as is. Empty = hotels of the destination."
          },
          "searchQueries": {
            "title": "More search texts",
            "maxItems": 100,
            "uniqueItems": true,
            "type": "array",
            "description": "Several search texts in one run: every text is searched in every destination (3 texts × 4 destinations = 12 searches, max 500). Added to **Search text**.",
            "items": {
              "type": "string",
              "maxLength": 200
            },
            "default": []
          },
          "startUrls": {
            "title": "Google Hotels links",
            "maxItems": 1000,
            "type": "array",
            "description": "Google Hotels search links copied from the address bar (`https://www.google.com/travel/search?q=...&ts=...`): their search text, dates, guests, currency, sort and filters are kept and pagination is automatic - or single hotel links (`https://www.google.com/travel/hotels/entity/<id>`, with or without `/prices`, `/reviews`). Added to the destinations and hotels of this form: all of them run together. Max 1 000 links.",
            "default": [],
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "hotelNames": {
            "title": "Hotel names",
            "maxItems": 1000,
            "uniqueItems": true,
            "type": "array",
            "description": "Hotels named as you would type them on Google (e.g. `Hotel Plaza Athenee Paris`): each name is looked up on Google Hotels and the hotel it settles on is read, with its price for your dates. Add the city to the name to avoid a namesake elsewhere. Added to the other sources.",
            "items": {
              "type": "string",
              "maxLength": 200
            },
            "default": []
          },
          "hotelIds": {
            "title": "Hotel IDs",
            "maxItems": 5000,
            "uniqueItems": true,
            "type": "array",
            "description": "Google Hotels ids (the `entityId` of a result, e.g. `ChkIvOHd86zKwZeBARoML2cvMTF4ZHB2Njd2EAE`, the part of a hotel link after `/entity/`): each hotel is read with its price for your dates. Added to the other sources.",
            "items": {
              "type": "string",
              "maxLength": 200
            },
            "default": []
          },
          "mapArea": {
            "title": "Map area (GPS box)",
            "type": "object",
            "description": "Search the hotels inside a box drawn on the map, like moving the Google Hotels map and pressing **Update list**: `{\"south\": 48.876, \"west\": 2.326, \"north\": 48.896, \"east\": 2.356}` (decimal degrees). Used alone, it searches every hotel of the box; with a **Destination** or **Search text**, the box wins over the place named in the text. Empty = no box."
          },
          "mapAreaGrid": {
            "title": "Split the map area into a grid",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "Cut the **Map area** into N × N smaller boxes searched one by one, then merged without duplicates: Google stops a search near 800-1,000 hotels, so a big city needs a grid to reach every hotel. 1 = one search for the whole box.",
            "default": 1
          },
          "checkIn": {
            "title": "Check-in date",
            "type": "string",
            "description": "First night: a date (`2026-12-20`), or a period from the run date such as `7 days`, `2 weeks` or `3 months` - a saved task then always looks the same distance ahead. Empty = 30 days from the run date. Google Hotels shows prices up to about 330 days ahead: a later date is refused."
          },
          "checkOut": {
            "title": "Check-out date",
            "type": "string",
            "description": "Departure day, `YYYY-MM-DD`. Empty = check-in plus **Nights** (the way to keep the length of a stay whose check-in moves with the run date). Must be after the check-in date, at most 30 nights after it."
          },
          "nights": {
            "title": "Nights",
            "minimum": 1,
            "maximum": 30,
            "type": "integer",
            "description": "Length of stay, used when **Check-out date** is empty.",
            "default": 1
          },
          "adults": {
            "title": "Adults",
            "minimum": 1,
            "maximum": 6,
            "type": "integer",
            "description": "Adults for the stay, as in the Google Hotels guest picker: at most 6 guests in all (adults + children). The number of guests changes the prices.",
            "default": 2
          },
          "childrenAges": {
            "title": "Children ages",
            "maxItems": 5,
            "type": "array",
            "description": "One age (0-17) per child, e.g. `4` and `9` for two children. Empty = no children. Google prices the stay for these ages; adults + children = 6 at most.",
            "items": {
              "type": "string",
              "maxLength": 2
            },
            "default": []
          },
          "currency": {
            "title": "Currency",
            "enum": [
              "USD",
              "EUR",
              "GBP",
              "AUD",
              "CAD",
              "CHF",
              "JPY",
              "CNY",
              "HKD",
              "SGD",
              "NZD",
              "INR",
              "AED",
              "SAR",
              "QAR",
              "KWD",
              "BHD",
              "OMR",
              "JOD",
              "ILS",
              "TRY",
              "EGP",
              "MAD",
              "DZD",
              "ZAR",
              "BRL",
              "MXN",
              "ARS",
              "CLP",
              "COP",
              "PEN",
              "CRC",
              "DOP",
              "JMD",
              "BSD",
              "BMD",
              "AWG",
              "PAB",
              "CUP",
              "THB",
              "MYR",
              "IDR",
              "PHP",
              "KRW",
              "TWD",
              "VND",
              "PKR",
              "KZT",
              "AZN",
              "AMD",
              "GEL",
              "SEK",
              "NOK",
              "DKK",
              "ISK",
              "PLN",
              "CZK",
              "HUF",
              "RON",
              "BGN",
              "HRK",
              "RSD",
              "MKD",
              "BAM",
              "ALL",
              "MDL",
              "UAH",
              "BYN",
              "RUB",
              "IRR",
              "LBP",
              "XPF"
            ],
            "type": "string",
            "description": "Currency of every price (Google converts it). A search link pasted in **Google Hotels links** keeps its own currency.",
            "default": "USD"
          },
          "language": {
            "title": "Language",
            "enum": [
              "en",
              "en-GB",
              "fr",
              "de",
              "es",
              "it",
              "pt-BR",
              "pt-PT",
              "nl",
              "ja",
              "zh-CN",
              "zh-TW",
              "ko",
              "ru",
              "pl",
              "tr",
              "sv",
              "da",
              "no",
              "fi",
              "cs",
              "el",
              "hu",
              "ro",
              "uk",
              "ar",
              "he",
              "th",
              "id",
              "vi",
              "hi"
            ],
            "type": "string",
            "description": "Language of the texts Google returns (hotel type, descriptions, review topics, deal wording; amenity names come in English or French, any other language reads English). Field names and numbers do not change.",
            "default": "en"
          },
          "country": {
            "title": "Market (country)",
            "enum": [
              "us",
              "gb",
              "ca",
              "au",
              "nz",
              "ie",
              "fr",
              "de",
              "es",
              "it",
              "pt",
              "nl",
              "be",
              "ch",
              "at",
              "se",
              "no",
              "dk",
              "fi",
              "pl",
              "cz",
              "gr",
              "tr",
              "il",
              "ae",
              "sa",
              "eg",
              "ma",
              "za",
              "in",
              "jp",
              "kr",
              "cn",
              "hk",
              "tw",
              "sg",
              "my",
              "th",
              "id",
              "ph",
              "vn",
              "br",
              "mx",
              "ar",
              "cl",
              "co",
              "pe"
            ],
            "type": "string",
            "description": "Country Google Hotels serves the results for (its `gl` market). It decides how prices are shown - in the United States before taxes, in most other countries with taxes included (`priceIncludesTaxes` tells which) - and can change how many hotels Google lists: the market of the destination often gives the longest list.",
            "default": "us"
          },
          "stayType": {
            "title": "Search for",
            "enum": [
              "hotels",
              "vacation_rentals"
            ],
            "type": "string",
            "description": "`hotels` = the Hotels tab of Google Hotels (hotels, hostels, B&Bs, apartment hotels...); `vacation_rentals` = its Vacation rentals tab (apartments, houses, villas...), with bedrooms, bathrooms, beds and size on each row. Hotel names, ids and links are read whatever this is.",
            "default": "hotels"
          },
          "sortBy": {
            "title": "Sort by",
            "enum": [
              "relevance",
              "lowest_price",
              "highest_rating",
              "most_reviewed"
            ],
            "type": "string",
            "description": "Order of the hotels, as on Google Hotels. With a cap on the number of hotels, it picks which ones are kept.",
            "default": "relevance"
          },
          "maxItems": {
            "title": "Max hotels",
            "minimum": 0,
            "maximum": 100000,
            "type": "integer",
            "description": "Maximum number of hotels to save for the whole run (after deduplication and filters). 0 = no limit. Google Hotels lists up to about 800-1 000 hotels per search.",
            "default": 100
          },
          "maxItemsPerQuery": {
            "title": "Max hotels per search",
            "minimum": 0,
            "maximum": 100000,
            "type": "integer",
            "description": "Cap for EACH search (search text × destination, or search link), so that the first search cannot use up the whole **Max hotels** budget. 0 = no per-search cap.",
            "default": 0
          },
          "extractDetails": {
            "title": "Extract full hotel profile",
            "type": "boolean",
            "description": "Full address, phone number, long description, every photo with its author and the review excerpts Google shows on the hotel page. Off = search-result fields only (name, stars, price, rating, amenities, GPS, website, a few photos).",
            "default": false
          },
          "includeOffers": {
            "title": "Prices of every booking site",
            "type": "boolean",
            "description": "Add the price of the stay on every booking site Google compares for the hotel (`offers`, often 15-30 sites): site name, official hotel site or not, price per night and for the stay, before and after taxes, free cancellation and its deadline, booking link; plus Google's usual price range for the hotel (`typicalPriceLow` / `typicalPriceHigh`). Charged per site price saved.",
            "default": false
          },
          "maxOffersPerHotel": {
            "title": "Max booking sites per hotel",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Cap on the booking-site prices saved for each hotel, cheapest first. 0 = every site Google lists.",
            "default": 0
          },
          "offerProviders": {
            "title": "Only these booking sites",
            "maxItems": 50,
            "uniqueItems": true,
            "type": "array",
            "description": "Keep only the prices of these booking sites (`Booking.com`, `Expedia`, `Hotels.com`, the hotel's own site as `official`...), as Google names them; case and accents ignored. Empty = every site. Fewer sites saved = fewer `offer` events charged. It applies to `offers` only: the room rates (`roomOffers`) keep every site.",
            "items": {
              "type": "string",
              "maxLength": 200
            },
            "default": []
          },
          "includeRoomOffers": {
            "title": "Room rates (every room on every site)",
            "type": "boolean",
            "description": "Add every room rate Google lists for the stay (`roomOffers`): room type, booking site, price, free cancellation deadline. Charged per room rate saved.",
            "default": false
          },
          "maxRoomOffersPerHotel": {
            "title": "Max room rates per hotel",
            "minimum": 0,
            "maximum": 500,
            "type": "integer",
            "description": "Cap on the room rates saved for each hotel, cheapest first. 0 = every rate Google lists.",
            "default": 0
          },
          "includeReviews": {
            "title": "Include reviews",
            "type": "boolean",
            "description": "Add the guest reviews Google shows for each hotel (`reviews`): rating, date as Google writes it (`2 months ago`) and month of the stay, full text, author, source site (Google, Tripadvisor, Trip.com...), trip type, ratings for rooms / service / location, photos, and the hotel's reply. Charged per review saved. Off = only the rating, the review count, the rating breakdown and the review topics (always included).",
            "default": false
          },
          "maxReviewsPerHotel": {
            "title": "Max reviews per hotel",
            "minimum": 0,
            "maximum": 100000,
            "type": "integer",
            "description": "Cap on the reviews saved for each hotel. 0 = every review Google serves, up to about 6,000 reviews: one hotel row holds no more than that (a larger row could not be saved), whatever the number set here; the row then says reviewsIncomplete. Each review saved is charged on its own.",
            "default": 20
          },
          "reviewsSort": {
            "title": "Reviews order",
            "enum": [
              "most_relevant",
              "newest",
              "highest_rating",
              "lowest_rating"
            ],
            "type": "string",
            "description": "Order of the saved reviews: with the cap on reviews per hotel, it picks which ones are kept.",
            "default": "most_relevant"
          },
          "reviewsSource": {
            "title": "Reviews source",
            "enum": [
              "all",
              "google",
              "tripadvisor",
              "trip_com"
            ],
            "type": "string",
            "description": "Keep only the reviews from one site. `all` = every source Google gathers (Google, Tripadvisor, Trip.com...).",
            "default": "all"
          },
          "reviewsTopic": {
            "title": "Reviews topic",
            "maxLength": 100,
            "type": "string",
            "description": "Keep only the reviews about one topic, named as in the hotel's `reviewTopics` (e.g. `Breakfast`, `Location`, `Cleanliness`). Empty = every review."
          },
          "includeCalendar": {
            "title": "Price calendar",
            "type": "boolean",
            "description": "Add, day by day from the check-in date, the lowest price Google shows for a stay of **Nights** starting that day, before and after taxes (`calendar`). The days that have no price (the hotel is full, or the date is past what Google prices) are listed too, and free. Up to a year in one request per hotel. Charged per day with a price saved.",
            "default": false
          },
          "calendarDays": {
            "title": "Calendar days",
            "minimum": 1,
            "maximum": 365,
            "type": "integer",
            "description": "Number of check-in days of the price calendar, counted from the check-in date. Google prices up to about 330 days ahead: later days come without a price.",
            "default": 30
          },
          "minPrice": {
            "title": "Minimum price per night",
            "minimum": 0,
            "maximum": 1000000,
            "type": "integer",
            "description": "Keep hotels whose price per night is at least this, in **Currency**. 0 = no filter. Asked from Google Hotels.",
            "default": 0
          },
          "maxPrice": {
            "title": "Maximum price per night",
            "minimum": 0,
            "maximum": 1000000,
            "type": "integer",
            "description": "Keep hotels whose price per night is at most this, in **Currency**. 0 = no filter. Asked from Google Hotels.",
            "default": 0
          },
          "hotelClass": {
            "title": "Hotel class (stars)",
            "uniqueItems": true,
            "type": "array",
            "description": "Keep only hotels of these star classes (any of them). Asked from Google Hotels. Empty = every class, unrated places included.",
            "items": {
              "type": "string",
              "enum": [
                "2",
                "3",
                "4",
                "5"
              ],
              "enumTitles": [
                "2 stars",
                "3 stars",
                "4 stars",
                "5 stars"
              ]
            },
            "default": []
          },
          "minRating": {
            "title": "Minimum guest rating",
            "minimum": 0,
            "maximum": 5,
            "type": "number",
            "description": "Keep hotels whose guest rating (out of 5) is at least this. 0 = no filter. Google Hotels is asked for its step just below (3.5+, 4.0+ or 4.5+), then the exact rating is checked. Hotels without any review are dropped when this is set.",
            "default": 0
          },
          "minReviewCount": {
            "title": "Minimum number of reviews",
            "minimum": 0,
            "maximum": 1000000,
            "type": "integer",
            "description": "Keep hotels with at least this many reviews. 0 = no filter.",
            "default": 0
          },
          "amenities": {
            "title": "Amenities (all required)",
            "uniqueItems": true,
            "type": "array",
            "description": "Keep only hotels that have ALL the ticked amenities (Google Hotels' own amenity filters). Asked from Google Hotels. Empty = no filter. Hotels search only (see **Rental amenities** for vacation rentals).",
            "items": {
              "type": "string",
              "enum": [
                "free_wifi",
                "free_breakfast",
                "restaurant",
                "bar",
                "kid_friendly",
                "pet_friendly",
                "free_parking",
                "parking",
                "ev_charger",
                "room_service",
                "fitness_center",
                "spa",
                "pool",
                "indoor_pool",
                "outdoor_pool",
                "air_conditioning",
                "wheelchair_accessible",
                "beach_access",
                "all_inclusive"
              ],
              "enumTitles": [
                "Free Wi-Fi",
                "Free breakfast",
                "Restaurant",
                "Bar",
                "Kid-friendly",
                "Pet-friendly",
                "Free parking",
                "Parking",
                "EV charger",
                "Room service",
                "Fitness center",
                "Spa",
                "Pool",
                "Indoor pool",
                "Outdoor pool",
                "Air-conditioned",
                "Wheelchair accessible",
                "Beach access",
                "All-inclusive available"
              ]
            },
            "default": []
          },
          "propertyTypes": {
            "title": "Property types",
            "uniqueItems": true,
            "type": "array",
            "description": "Keep only these types of hotel (any of them). Asked from Google Hotels. Empty = every type. Hotels search only (see **Rental types** for vacation rentals).",
            "items": {
              "type": "string",
              "enum": [
                "boutique",
                "bed_and_breakfast",
                "spa_hotel",
                "hostel",
                "resort",
                "inn",
                "apartment_hotel",
                "motel",
                "beach_hotel",
                "other"
              ],
              "enumTitles": [
                "Boutique hotels",
                "Bed and breakfasts",
                "Spa hotels",
                "Hostels",
                "Resorts",
                "Inns",
                "Apartment hotels",
                "Motels",
                "Beach hotels",
                "Other"
              ]
            },
            "default": []
          },
          "freeCancellationOnly": {
            "title": "Free cancellation only",
            "type": "boolean",
            "description": "Keep only hotels with at least one offer that can be cancelled free of charge. Asked from Google Hotels.",
            "default": false
          },
          "specialOffersOnly": {
            "title": "Special offers only",
            "type": "boolean",
            "description": "Keep only hotels with a special offer (deal, discount) for your dates. Asked from Google Hotels.",
            "default": false
          },
          "ecoCertifiedOnly": {
            "title": "Eco-certified only",
            "type": "boolean",
            "description": "Keep only hotels with an eco-certification Google shows. Asked from Google Hotels.",
            "default": false
          },
          "brands": {
            "title": "Brands",
            "maxItems": 50,
            "uniqueItems": true,
            "type": "array",
            "description": "Keep only hotels of these brands or hotel groups, named as on Google Hotels (e.g. `Hyatt`, `Marriott`, `Accor`, `ibis`). Each name is matched against the brands Google offers for the search, then asked from Google Hotels; a name Google does not offer for a destination is reported in the log. Empty = every brand.",
            "items": {
              "type": "string",
              "maxLength": 100
            },
            "default": []
          },
          "rentalTypes": {
            "title": "Rental types",
            "uniqueItems": true,
            "type": "array",
            "description": "Vacation rentals only: keep these types of rental (any of them). Asked from Google Hotels. Empty = every type.",
            "items": {
              "type": "string",
              "enum": [
                "apartment",
                "house",
                "villa",
                "cottage",
                "other"
              ],
              "enumTitles": [
                "Apartments",
                "Houses",
                "Villas",
                "Cottages",
                "Other"
              ]
            },
            "default": []
          },
          "minBedrooms": {
            "title": "Minimum bedrooms",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Vacation rentals only: at least this many bedrooms (Google's steps, 1 to 5). 0 = no filter. Asked from Google Hotels.",
            "default": 0
          },
          "minBathrooms": {
            "title": "Minimum bathrooms",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Vacation rentals only: at least this many bathrooms (1 to 5). 0 = no filter. Asked from Google Hotels.",
            "default": 0
          },
          "rentalAmenities": {
            "title": "Rental amenities (all required)",
            "uniqueItems": true,
            "type": "array",
            "description": "Vacation rentals only: keep the rentals that have ALL the ticked amenities. Asked from Google Hotels. Empty = no filter.",
            "items": {
              "type": "string",
              "enum": [
                "wifi",
                "kitchen",
                "pool",
                "hot_tub",
                "air_conditioning",
                "fitness_center",
                "kid_friendly",
                "pet_friendly",
                "patio",
                "barbecue",
                "crib",
                "fireplace"
              ],
              "enumTitles": [
                "Wi-Fi",
                "Kitchen",
                "Pool",
                "Hot tub",
                "Air conditioning",
                "Fitness center",
                "Kid-friendly",
                "Pet-friendly",
                "Patio",
                "Barbecue grill",
                "Crib",
                "Fireplace"
              ]
            },
            "default": []
          },
          "availableOnly": {
            "title": "Hotels with a price only",
            "type": "boolean",
            "description": "Leave out the hotels Google lists without any price for your dates (sold out or no booking site). Off = they are saved with `isAvailable: false` and no price.",
            "default": false
          },
          "excludeKeywords": {
            "title": "Exclude keywords",
            "maxItems": 50,
            "uniqueItems": true,
            "type": "array",
            "description": "Drop the hotels whose name contains one of these words (case and accents ignored).",
            "items": {
              "type": "string",
              "maxLength": 100
            },
            "default": []
          },
          "excludeHotelIds": {
            "title": "Exclude hotel IDs",
            "maxItems": 5000,
            "uniqueItems": true,
            "type": "array",
            "description": "Google Hotels ids (`entityId`) to skip, even when they match the search (e.g. your own hotels).",
            "items": {
              "type": "string",
              "maxLength": 200
            },
            "default": []
          },
          "onlyNew": {
            "title": "Only new hotels",
            "type": "boolean",
            "description": "Skip the hotels that a previous run (same **Memory key**) already delivered: they are not saved and not charged, and the page of a hotel found by a search is not even opened (a hotel given by id, link or name is read before it is known as delivered). First run = everything is new. To follow prices, leave it off and schedule the task: every row carries its price and `scrapedAt`.",
            "default": false
          },
          "trackPriceChanges": {
            "title": "Price changes",
            "type": "boolean",
            "description": "Needs **Only new hotels**. A hotel already delivered under this **Memory key** comes back, whole, when its price per night has moved by at least the **Price change threshold (%)** since the run that delivered it, for the same stay (same dates, guests, currency and market): `previousPrice`, `priceChange`, `priceChangePct` and `priceChangedAt` are filled. Charged per hotel that comes back as **Price change**, on top of the hotel itself, see Pricing; a hotel whose price did not move enough is skipped and costs nothing, and a hotel with no price is never a change. Use fixed dates (for example `2026-12-20`): a relative check-in such as `14 days` moves the stay at every run, so its prices are learned again instead of compared. The first run after you tick it learns the prices and reports no change. Each search is read to its last page (1,000 hotels per search at most) because any hotel of it can change its price: a run takes longer than with **Only new hotels** alone, which stops after 20 pages with nothing new. Unticked (default) = the four columns are always null and nothing is charged.",
            "default": false
          },
          "priceChangeThreshold": {
            "title": "Price change threshold (%)",
            "minimum": 0.1,
            "maximum": 100,
            "type": "number",
            "description": "Used with **Price changes**. How far a price per night must move, up or down, from the price delivered for the hotel to come back: 3 means a price that goes from 100 to 103 or to 97. From 0.1 to 100.",
            "default": 3
          },
          "stateKey": {
            "title": "Memory key",
            "pattern": "^[a-zA-Z0-9_-]{1,64}$",
            "maxLength": 64,
            "type": "string",
            "description": "Name of the memory used by **Only new hotels**. Give each schedule / task its own key (e.g. `paris-hotels`) so that they do not share their memory. Letters, digits, `-` and `_`.",
            "default": "default"
          },
          "resetState": {
            "title": "Reset the memory",
            "type": "boolean",
            "description": "Forget everything remembered under this **Memory key** before the run: this run returns (and charges) every hotel again. Untick it afterwards.",
            "default": false
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Apify Proxy or your own proxies. Keep the default: it is included in the price. The residential Apify proxy is not available in this Actor.",
            "default": {
              "useApifyProxy": true
            }
          },
          "maxConcurrency": {
            "title": "Max concurrency",
            "minimum": 1,
            "maximum": 50,
            "type": "integer",
            "description": "Maximum number of requests processed in parallel.",
            "default": 8
          },
          "maxRequestsPerMinute": {
            "title": "Max requests per minute",
            "minimum": 10,
            "maximum": 2000,
            "type": "integer",
            "description": "Most requests to Google in any 60 seconds, all of them counted: result pages, hotel pages, review and calendar pages. A budget, not an even pace: up to this many can leave at once when the minute starts (spread them with the minimum delay below). Lower it if the log shows Google's \"unusual traffic\" page.",
            "default": 120
          },
          "minRequestIntervalMs": {
            "title": "Min delay between requests",
            "minimum": 0,
            "maximum": 60000,
            "type": "integer",
            "description": "Smallest gap between two requests, in milliseconds. Unlike the per-minute rate, this spreads the requests evenly instead of letting them go out in a burst. 0 = no gap.",
            "default": 0
          },
          "maxRequestRetries": {
            "title": "Max request retries",
            "minimum": 0,
            "maximum": 20,
            "type": "integer",
            "description": "Retries per request before it is marked as failed. Behind a proxy, a request Google turns away is also retried on a new proxy session up to 10 times without using up these retries.",
            "default": 5
          },
          "debugLog": {
            "title": "Debug log",
            "type": "boolean",
            "description": "Include debug messages in the run log.",
            "default": false
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}