# Google Hotels Scraper — Prices, OTA Offers & Contacts (`foxlabs/google-hotels-scraper`) Actor

Hotels from Google Hotels for any destination and dates: nightly price, the offers of the booking sites Google lists (Booking.com, Expedia, official site…), room rates with free-cancellation terms, class, rating, reviews, address, phone, website and Place ID.

- **URL**: https://apify.com/foxlabs/google-hotels-scraper.md
- **Developed by:** [Berkan Kaplan](https://apify.com/foxlabs) (community)
- **Categories:** Travel, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 hotels

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Hotels Scraper — Prices, OTA Offers & Contacts

Get the hotels Google Hotels shows for any destination and dates, with **the nightly price, the offer of each booking site Google lists (Booking.com, Expedia, Hotels.com, Agoda, the hotel's own site…), room rates with free-cancellation terms, star class, guest rating and review count, third-party ratings (Tripadvisor…), address, phone, website and Google Place ID**. One row per property, with the whole price comparison nested inside it.

No Google account, no API key, no browser.

### Quick start (API)

```bash
curl -X POST "https://api.apify.com/v2/acts/foxlabs~google-hotels-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries": ["hotels in Paris"], "checkIn": "+30", "nights": 2, "currency": "EUR", "maxHotelsPerQuery": 10}'
```

### What you get

| Group | Fields |
|---|---|
| Property | `name`, `propertyType` (hotel, hostel, resort hotel, vacation rental…), `hotelClass` (stars), `hotelClassText`, `description`, `highlights`, `amenities` (vacation rentals), `thumbnailUrl` |
| Price | `pricePerNight` (Google's lead price, before taxes), `pricePerNightText`, `pricePerNightWithTaxesText`, `deal` ("16% less than usual"), `cheapestOffer` |
| Booking sites | `offers[]`: `provider`, `isOfficialSite`, `pricePerNight`, `pricePerNightWithTaxes`, `totalPrice`, `totalPriceWithTaxes`, `link` (the booking site's own URL with your dates); `offersCount` |
| Rooms | `roomRates[]`: `provider`, `room`, `features`, `freeCancellation`, `cancellation` ("Free cancellation until Nov 10"), prices |
| Reviews | `rating`, `reviewsCount`, `ratingHistogram` (reviews per star), `reviewTopics` (topic and mentions), `externalRatings[]` (Tripadvisor, Trip.com… with their review counts) |
| Contact & location | `address`, `phone`, `website`, `googlePlaceId`, `mapsFeatureId`, `latitude`, `longitude`, `countryCode`, `neighborhood`, `neighborhoodDescription`, `checkInTime`, `checkOutTime` |
| Search | `checkIn`, `checkOut`, `nights`, `adults`, `currency`, `searchRank`, `resolvedLocation`, `googleHotelsUrl`, `propertyToken`, `query`, `offersStatus`, `scrapedAt`, `error` |

Booking sites, rooms, address, phone, Place ID, third-party ratings, `highlights`, `neighborhood` and `neighborhoodDescription` come from each hotel's price comparison, read when `includeOffers` is on (the default). Some booking sites show no total including taxes: `totalPriceWithTaxes` was empty for 82 of 752 offers in run `mE7Hvz3icgWa67yZK`.

`resolvedLocation` is set on rows from a text query and says what Google searched. `type`, `name`, `knowledgeGraphId` and `mapsFeatureId` describe one place. `area` is the wider area Google placed it in, when that is a different place. Examples from the responses Google returned on 2026-09-28:

- `hotels in Lisbon` → `{ "type": "place", "name": "Lisbon", "knowledgeGraphId": "/m/04llb", "mapsFeatureId": "0xd19331a61e4f33b:0x400ebbde49036d0", "area": null }`
- `hotels near Eiffel Tower` → `{ "type": "place", "name": "Eiffel Tower", "knowledgeGraphId": null, "mapsFeatureId": "0x47e66e2964e34e2d:0x8ddca9ee380ef7e0", "area": { "name": "Paris", "knowledgeGraphId": "/m/05qtj" } }`
- `Ritz Paris` → `{ "type": "hotel", "name": "Ritz Paris", …, "area": { "name": null, "knowledgeGraphId": "/m/05qtj" } }` (Google gives the city's ID but not its name here)

It is `null` for Google Hotels links and property tokens, where nothing is searched.

#### Sample output

A real row (trimmed) from platform run `mE7Hvz3icgWa67yZK` (build 0.1.2) on 2026-09-27 (UTC), query `hotels in Paris`, 12–14 November 2026, 2 adults, EUR:

```json
{
  "name": "MOB HOUSE",
  "propertyType": "hotel",
  "hotelClass": 4,
  "rating": 4.3,
  "reviewsCount": 1130,
  "pricePerNight": 67.31,
  "cheapestOffer": { "provider": "Traveluro", "pricePerNight": 67.31, "totalPriceWithTaxes": 179.3, "isOfficialSite": false },
  "address": "70 Rue des Rosiers, 93400 Saint-Ouen-sur-Seine, France",
  "phone": "+33 1 55 28 80 80",
  "website": "https://www.mobhouse.com/",
  "googlePlaceId": "ChIJIfquhEVv5kcRwVvMuyVzegQ",
  "offersCount": 26,
  "offers": [
    { "provider": "MOB HOUSE", "isOfficialSite": true, "pricePerNight": 110.38, "pricePerNightWithTaxes": 119.85, "totalPrice": 220.75, "totalPriceWithTaxes": 239.7 },
    { "provider": "Traveluro", "isOfficialSite": false, "pricePerNight": 67.31, "pricePerNightWithTaxes": 89.65, "totalPrice": 134.62, "totalPriceWithTaxes": 179.3 },
    { "provider": "trivago DEALS", "isOfficialSite": false, "pricePerNight": 68.11, "pricePerNightWithTaxes": 90.53, "totalPrice": 136.21, "totalPriceWithTaxes": 181.06 }
  ],
  "roomRates": [
    { "provider": "Expedia.com", "room": "1 double bed", "features": ["Free cancellation until Nov 9", "2 guests", "Free Wi-Fi"], "freeCancellation": true, "cancellation": "Free cancellation until Nov 9", "pricePerNight": 108, "pricePerNightWithTaxes": 135 }
  ],
  "externalRatings": [{ "source": "Tripadvisor", "rating": 3.6, "scale": 5, "reviewsCount": 66 }],
  "checkIn": "2026-11-12",
  "checkOut": "2026-11-14",
  "nights": 2,
  "currency": "EUR"
}
```

### Input & filters

| Input | What it does | Default |
|---|---|---|
| `queries` | Destinations as you would type them into Google Hotels (`hotels in Paris`, `Istanbul`, `resorts in Bali`), hotel names (`Ritz Paris`), Google Hotels links, or property tokens (`Ch…`). A link's own dates and currency are not used; the stay and currency come from this input | — |
| `checkIn` | `YYYY-MM-DD`, or days from today such as `+30`, counted in UTC (a scheduled run always prices the stay 30 days ahead) | `+14` |
| `nights` / `checkOut` | Length of stay (1–30), or an explicit check-out date | 1 night |
| `adults` | Guests per room | 2 |
| `currency` | Currency of every price (30 currencies) | USD |
| `maxHotelsPerQuery` | Stop after this many properties per destination, up to 200 (Google pages 20 at a time). The Console form starts at 10 | 20 |
| `includeOffers` | Booking-site offers, rooms, address, phone, Place ID and third-party ratings (one extra request per hotel) | on |
| `propertyType` | `all`, `hotels` (no vacation rentals), `vacation-rentals` | all |
| `minRating`, `minHotelClass`, `maxPricePerNight` | Filters applied to the results Google returns. A filtered search reads up to 20 result pages to find enough matches | off |
| `language`, `country` | Language of descriptions and labels; the searcher's market (the booking sites shown follow it) | en, us |
| `proxyConfiguration`, `autoProxyFallback` | Proxy is not needed; the Actor switches to Apify residential proxy by itself if Google rate-limits it | off / on |

Input the form does not allow (no query, more than 30 nights, a currency code not in the list) is rejected by Apify before the run starts, with the reason. A check-in date in the past, a check-out before the check-in, or a check-out more than 30 nights after the check-in stops the run at once, with the reason in its status message.

**Each hotel once per run.** A property is delivered and charged once per run, whichever query finds it first: the same hotel given by name and by token, or returned by two searches, is one row. Later queries skip it and count it as `duplicates` in the `SOURCE_REPORT` record; a query that finds only such properties leaves a free row with `error: "skipped: …"`.

**Destination not found.** Google handles an unknown place in two ways, and the Actor delivers no hotels for either:

- It shows hotels near the searcher's own location instead, which for the Actor is the server that runs it. In platform run `ux35BUW57frK3eUr5` (build 0.1.1), "zzqx no such place 7731" returned three hotels in Ashburn (Virginia), Chambersburg (Pennsylvania) and Morgantown (West Virginia). The Actor now recognises this answer and leaves one free row whose `error` starts with `unresolved:` and names the area Google fell back to.
- It answers nothing. This happened for "hotels near Times Square" and "hotels near Colosseum", while "Times Square" and "Colosseum" alone work. The Actor then searches the place without the "hotels near" wrapper once, and records it as `searchedAs` in the `SOURCE_REPORT` record. If that finds nothing too, the row says `unresolved:` and suggests adding the city.

The query gets `status: "unresolved"` in the `SOURCE_REPORT` record.

### Example inputs (copy & paste)

Price comparison for a city, 2 nights, 40 hotels:

```json
{ "queries": ["hotels in Paris"], "checkIn": "2026-11-12", "nights": 2, "currency": "EUR", "maxHotelsPerQuery": 40 }
```

Daily rate tracking of a shortlist, always 30 days ahead (schedule it):

```json
{ "queries": ["https://www.google.com/travel/hotels/entity/ChcIk_ron8CcvN8-GgsvZy8xdnMxcjVkYhAB", "ChkI5ub93LiKvvinARoML2cvMTF4dngxM2oyEAE"], "checkIn": "+30", "nights": 1, "currency": "EUR" }
```

Upscale hotels only, fast list without booking sites:

```json
{ "queries": ["hotels in Paris"], "minRating": "4.5", "minHotelClass": "4", "maxHotelsPerQuery": 20, "includeOffers": false }
```

Local market and currency:

```json
{ "queries": ["Istanbul"], "checkIn": "+30", "currency": "TRY", "language": "tr", "country": "tr", "maxHotelsPerQuery": 20 }
```

### Use cases

- **Rate parity and revenue management:** a hotel's own-site price next to the OTA prices Google lists, per date, with the total including taxes where the booking site shows it.
- **Competitor price tracking:** schedule a destination or a shortlist of competitors with a relative check-in date.
- **Travel and OTA products:** hotel lists with lead price, rating, class and location for a destination.
- **B2B sales to hotels:** property lists with phone, address, website and Google Place ID for PMS, booking-engine and revenue-management vendors.

### Performance & throughput

Measured on the Apify platform on 2026-09-27 (UTC) with build 0.1.2 (default proxy setting, 1 GB memory):

| Run | Input | Properties | Requests | Time |
|---|---|---|---|---|
| `BEacU1AVJNrhwGyxF` | The quick-start command above (`hotels in Paris`, 10, booking sites on) | 10 | 11 | 7 s |
| `mE7Hvz3icgWa67yZK` | `hotels in Paris`, 40, 2 nights, EUR, booking sites on | 40 | 43 | 25 s |
| `HZup4nnqGQdXh7gq3` | `Istanbul`, 20, TRY, Turkish, booking sites on | 20 | 21 | 11 s |
| `lhJb1yDko1l69mw7y` | `hotels in Tokyo`, hotels only, up to ¥40,000, Japanese, booking sites on | 5 | 6 | 10 s |
| `QmK5yJBV78nnWRskm` | Two hotels by Google Hotels link and token | 2 | 2 | 5 s |
| `hejwTAF6D13NqSMxR` | `hotels in Paris`, rating 4.5+, 4-star and up, booking sites off | 20 | 7 | 21 s |
| `8ufUlcxU2d0sL9fAy` | `hotels in Paris`, 5-star, rating 4.5+, up to €900, booking sites on | 9 of 10 (20 pages read) | 29 | 67 s |

One list request returns up to 20 properties. The booking-site comparison is one more request per hotel (about 0.3 MB). None of these runs was rate-limited or needed the residential proxy.

**Memory:** 1 GB is the default. In two runs each of the 40-hotel Paris search (build 0.1.1), 512 MB took 26 s and 29 s (`36eyx1igKJE38MM71`, `4yNQdPb33tb0g1Fdt`) against 23 s and 25 s at 1 GB (`7Xg192j2JF7ZNRlao`, `uacks9nAx0Xddfq9a`), so 512 MB works about 10–15% slower. Peak memory was at most 117 MiB.

### Integrations

Use the dataset from the API, schedule the Actor in Apify Console, or connect it to Make, Zapier, n8n, Google Sheets or a webhook. Each row is self-contained, so a hotel and its whole price comparison stay together.

### Data quality

Measured on the platform runs `mE7Hvz3icgWa67yZK`, `HZup4nnqGQdXh7gq3` and `BEacU1AVJNrhwGyxF` (build 0.1.2):

- **Uniqueness:** no property appeared twice in a run (40 of 40, 20 of 20 and 10 of 10 unique `propertyToken`).
- **Prices:** every offer's total equals its nightly price × nights to the cent (1,225 of 1,225 offers; 743 exactly, the rest within a cent of rounding). `cheapestOffer` was the lowest offer in 70 of 70 rows.
- **Coverage (Paris, 40 properties, `mE7Hvz3icgWa67yZK`):**
  - Booking-site offers for 40 of 40, three or more sites for 35, about 19 sites on average.
  - Address for all 36 hotels, hostels and extended-stay hotels. The 4 vacation rentals have no address and no phone.
  - Phone 35, website 38. The hotel's own site was among the offers for 29.
  - Room rates with a free-cancellation term for 28.
- **Coverage (Istanbul, 20 properties, `HZup4nnqGQdXh7gq3`):**
  - Booking-site offers for 20 of 20, three or more sites for 14.
  - Address and phone 16 of 20; the 4 without them are vacation rentals.
  - Website 16 of 20: two hotels have none, and two vacation rentals have one. All three are present for 14.
  - Star class for 14 of the 15 hotels.
  - Room rates with a free-cancellation term for 11.
- **Search order is not fixed:** Google reorders results between requests, so two runs of the same search do not list the same properties in the same order. Treat `searchRank` as the rank in this run, not a stable position.

### Pricing

**$4 per 1,000 hotels ($0.004 per hotel), booking-site offers included.** Each delivered property is one `hotel` event. Status rows are free: a search with no results, a destination Google could not find, a hotel already delivered by an earlier query, a skipped duplicate query. Apify also charges its standard Actor Start event once per run ($0.00005 per GB of memory, so $0.00005 at the default 1 GB), including runs that deliver no hotels. Current prices are on the Pricing tab.

### FAQ

**Is `pricePerNight` the cheapest price?** It is Google's lead price for the stay. In the 0.1.2 runs it equalled the cheapest offer in most rows (median ratio 1.00). It was at most 15.2% above it (Istanbul, `HZup4nnqGQdXh7gq3`) and at most 5.2% below it (Tokyo, `lhJb1yDko1l69mw7y`). One earlier Paris row was 27% below every listed booking site (`uacks9nAx0Xddfq9a`, build 0.1.1). `cheapestOffer` gives the lowest booking-site price in `offers`.

**Why do some properties have no star class?** Google shows no class for vacation rentals and for some hotels (5 of 33 hotels in `mE7Hvz3icgWa67yZK`).

**What happens with a typo in the destination?** See "Destination not found" above: no hotels are delivered for it, and the free status row says why. On delivered rows, `resolvedLocation` shows the place Google searched, so you can check that "Paris" meant Paris, France.

**Can I search by hotel name?** Yes. When Google matches the name to one hotel (`Ritz Paris`), the Actor returns that hotel with its price comparison, the same as for its property token, and `resolvedLocation.type` is `hotel`. Google's offer list can differ between two requests: 1 and 3 offers for the Ritz within a second in run `0Ti2rI3kZ4wLOvEuS`.

**Is free cancellation always detected?** Room terms are read from Google's labels, checked in 13 languages: English, Turkish, German, French, Spanish, Italian, Dutch, Polish, Russian, Japanese, Korean, Chinese and Arabic. Portuguese answers carried no room rates in our tests. In another language the term stays in `features`, and `freeCancellation`/`cancellation` are `null`. When a rate states no cancellation term, `freeCancellation` is `null`, never `false`.

**What about amenities?** Google gives amenity names for vacation rentals, and the Actor lists the available ones in `amenities` ("Air conditioning", "Kitchen", "Free Wi-Fi"…). For hotels, the responses the Actor reads carry amenities as codes without names, so `amenities` is `null` and the Actor does not guess them. Room features (Wi-Fi, breakfast, parking) are in `roomRates[].features`.

### Troubleshooting

- **A search returns fewer hotels than `maxHotelsPerQuery`:** filters removed results (see `filteredOut` in the `SOURCE_REPORT` record; a filtered search reads up to 20 pages), earlier queries already delivered some (`duplicates`), or Google has no more pages.
- **`error` starts with `unresolved:`:** Google did not find the destination. Check the spelling, or add the city or country ("hotels near Times Square, New York"). Nothing was charged for it.
- **`error` starts with `skipped:`:** the hotel or all its results were already delivered by an earlier query in the same run.
- **`offersStatus` is `error`:** the booking-site comparison failed for that hotel; the row still has the list data.
- **No results:** every query leaves a free row with the reason in `error`, and the `SOURCE_REPORT` record in the key-value store explains each query.

### Notes, limits & legal

- The Actor reads the public Google Hotels results any visitor sees. Prices come from Google's partners and change often; keep `scrapedAt` with the data.
- Up to 200 properties per destination and 30 nights per stay.
- "Google" and "Google Hotels" are trademarks of Google LLC. This Actor is not affiliated with or endorsed by Google.

### Support

Open an issue on the Issues tab with the run ID and the query.

### Changelog

#### 0.1 — 2026-09-28

First version. See CHANGELOG.md.

# Changelog

This Actor's version history is a separate document: https://apify.com/foxlabs/google-hotels-scraper/changelog.md

# Actor input Schema

## `queries` (type: `array`):

One per line: a destination as you would type it into Google Hotels ("hotels in Paris", "Istanbul", "resorts in Bali"), a hotel's name ("Ritz Paris"), a Google Hotels link, or a Google Hotels property token (starts with Ch). Each hotel is delivered once per run. A destination Google cannot find leaves a free row with the reason instead of unrelated hotels. A link's own dates and currency are not used.

## `checkIn` (type: `string`):

Check-in date as YYYY-MM-DD, or days from today such as +30, counted in UTC (a scheduled run then always prices the stay 30 days ahead). Empty means 14 days from today.

## `nights` (type: `integer`):

Length of stay. Ignored when Check-out is set.

## `checkOut` (type: `string`):

Check-out date as YYYY-MM-DD. Overrides Nights.

## `adults` (type: `integer`):

Guests per room. Prices are for this number of adults.

## `currency` (type: `string`):

Currency of every price.

## `maxHotelsPerQuery` (type: `integer`):

Stop after this many properties for each destination (up to 200; Google pages 20 at a time). The form starts at 10 for a quick first run; an API call without this field gets 20.

## `includeOffers` (type: `boolean`):

For each hotel, read Google's price comparison: the nightly and total price of each booking site Google lists (Booking.com, Expedia, the hotel's own site…), room rates with free-cancellation terms, plus address, phone, Google Place ID and third-party ratings. One extra request per hotel.

## `propertyType` (type: `string`):

Google mixes vacation rentals into hotel results. Filters are applied to the results Google returns; a filtered search reads up to 20 result pages to find enough matches.

## `minRating` (type: `string`):

Applied to the results Google returns.

## `minHotelClass` (type: `string`):

Star class. Vacation rentals have no class and are left out when this is set.

## `maxPricePerNight` (type: `integer`):

In the chosen currency, before taxes. Applied to the results Google returns.

## `language` (type: `string`):

Language of hotel descriptions and labels.

## `country` (type: `string`):

Two-letter country of the searcher, such as us, gb, de, tr. The booking sites Google shows follow the market.

## `proxyConfiguration` (type: `object`):

Not needed for most runs. Leave off and the Actor switches to Apify residential proxy by itself if Google rate-limits it.

## `autoProxyFallback` (type: `boolean`):

On by default.

## Actor input object example

```json
{
  "queries": [
    "hotels in Paris"
  ],
  "checkIn": "+14",
  "nights": 1,
  "adults": 2,
  "currency": "USD",
  "maxHotelsPerQuery": 10,
  "includeOffers": true,
  "propertyType": "all",
  "minRating": "any",
  "minHotelClass": "any",
  "language": "en",
  "country": "us",
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "autoProxyFallback": true
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "hotels in Paris"
    ],
    "maxHotelsPerQuery": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("foxlabs/google-hotels-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "queries": ["hotels in Paris"],
    "maxHotelsPerQuery": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("foxlabs/google-hotels-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "hotels in Paris"
  ],
  "maxHotelsPerQuery": 10
}' |
apify call foxlabs/google-hotels-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,foxlabs/google-hotels-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ulahsb0OeEp3MALIa/builds/DWtbJkWw7XUxj3Klo/openapi.json
