# Savills Scraper \[From $1💰] | Property Listings | Prices (`ahmed_jasarevic/savills-scraper`) Actor

Extract Savills property listings worldwide with local-currency prices, tenure, EPC rating, bedrooms, size, coordinates, agent contacts, photos and floor plans. Optional detail pages add full property data for market research.

- **URL**: https://apify.com/ahmed_jasarevic/savills-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Savills Scraper — Scrape Worldwide Savills Property Listings Data

Scrape residential, luxury, new-build, farm and commercial listings from Savills' global search site into JSON — ~90 mapped fields per listing: price in local currency, tenure, EPC rating, status tags, coordinates, photos and agent contacts. Built for luxury-market analysts, cross-border investors, proptech dashboards and relocation / buyer agencies who need structured Savills listings data on a schedule.

***

### What You Can Build With Savills Property Data

- **A UK property listings database** with EPC rating data, tenure, council tax band, service charge and ground rent on every row.
- **Property price monitoring UK workflows** — `status`, `originalPrice`, `priceQualifier`, `lastUpdated`, `_scrapedAt` are your diff inputs between runs.
- **International coverage** — verified Savills pages carry Europe 13,173 listings, France 1,047, Italy 317 and a Spain desk: cross-border property investment data.
- **New homes listings data** from `/list/new-homes-for-sale/` and `/list/new-homes-to-rent/`, flagged `isNewDevelopment`, `isHelpToBuy`, `isSharedOwnership`.
- **Commercial property listings API-style feeds** — office, retail, industrial, leisure, investment and hotel paths with `isCommercial`, `isFarm`, `clearHeight`.
- **Real estate market intelligence pipelines** — lat/lng, size in sqm/sqft/acres/hectares, images, floor plans, brochures, agent phone numbers.

***

### How The Savills Scraper Works

Savills' search application (`search.savills.com`) server-renders every listing into a Next.js `__NEXT_DATA__` JSON blob. This Actor fetches those pages with plain HTTP through a CheerioCrawler — no browser, no headless Chrome — parses the blob, and maps it to one dataset item per listing. Detail pages are small JSON requests too, so runs stay fast and need no paid anti-bot service.

***

### Input Parameters

| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
| `searchUrls` | array | No (prefilled) | England sale | Full or partial URLs (`https://search.savills.com/list/property-for-sale/england`) or bare paths like `/list/property-for-sale/italy`, expanded against `search.savills.com`; a `/page/N` suffix is stripped so crawls restart at page 1. |
| `maxListings` | integer | No | `100` | Stop condition: the run ends once this many listings are collected (min 1, max 5000). Free plans cap at 10. |
| `scrapeDetailPages` | boolean | No | `false` | Also open each `/property-detail/<id>` page and merge it — adds the detail-only fields listed under Output Fields plus a complete size block. One extra request per listing, billed as one `property-detail-page` event. |
| `proxy` | object | No | `{ "useApifyProxy": false }` | Standard Apify proxy picker; select group/country in the UI — the only likely extra cost. |

**How a run stops** — no page cap; `maxListings` drives everything:

1. a listing slot is reserved when a search card is seen, so the cap is exact;
2. pagination stops at the cap, at a page with no new listings, or when the page budget `ceil(maxListings / 16) + 3` per search URL is spent — whichever comes first;
3. `maxRequestsPerCrawl` bounds the run: `search URLs × page budget + maxListings detail requests + 40`.

**Supported search URL shapes:**

```
/list/property-for-sale/<location>       e.g. england, scotland, wales, italy, france, spain, australia
/list/property-to-rent/<location>
/list/new-homes-for-sale/<location>
/list/new-homes-to-rent/<location>
/list/farms/<sub-category>/<location>
/list/commercial/property-for-sale/<type>/<location>   office, retail, industrial, leisure, investment, hotel
/list/commercial/property-to-let/<type>/<location>
/list/<location>/<region>/...            deeper paths such as england/london/london/ec3n
```

***

### Output Fields

One dataset item per listing (~90 mapped fields); two table views ship with it: **Listing overview** and **Listing table**.

- **Identity** — `listingId`, `internalId`, `externalIdFormatted`, `url`, `seoTitle`, `description`, `longDescription`, `locationNotes`, `features`
- **Price** — `price`, `displayPrice`, `originalPrice`, `priceQualifier`, `currency`, `otherFees`, `priceDisclaimer`, `yield`
- **Location** — `countryCode`, `regionOrTown`, `addressLine1`, `addressLine2`, `fullAddress`, `latitude`, `longitude`, `openHouse`
- **Type** — `propertyTypes`, `propertyTypeTag`, `propertyTypeSlug`, `marketTypes`, `isCommercial`, `isFarm`, `isNewDevelopment`, `newDevelopmentType`, `isHelpToBuy`, `isSharedOwnership`, `furnished`, `sizeDescription`
- **Status tags** — `status`, `statusCode`, `statusTag`, `isSold`, `isLet`, `isConfidential`, `isFeatured`, `launchingDate`
- **Rooms & size** — `bedrooms`/`bedroomsText`, `bathrooms`/`bathroomsText`, `receptions`/`receptionsText`, `carSpaces`/`carSpacesText`, `sizeFormatted`, `size` (`sqm`, `sqft`, `sqYd`, `acres`, `hectares`), `clearHeight`
- **Tenure / compliance** — `tenure`, `tenureTypeCode`, `leaseType`, `leaseExpiry`, `leaseRemaining`, `serviceCharge`, `groundRent`, `councilTaxBand`, `epcRating`, `energyText`
- **Agents** — `primaryAgent`, `secondaryAgent` (`name`, `phone`, `office`, `photo`, `licenceNumber`, `whatsapp`)
- **Media** — `images`, `imageCount`, `imageCaptions`, `floorPlans`, `brochureUrls`, `epcGraphUrls`, `floorPlanPdfUrl`, `videoUrl`, `video360Url`, `externalWebsiteUrl`, `agentQuote`
- **Detail-page extras** — `lastUpdated`, `fullPriceText`, `shortDisplayPrice`, `hasFloorplan`, `fluxProBrochureUrl`, `additionalAgents`, `areaGuide`, `sizeMaximum`, `saleableArea`
- **Meta** — `_source` (`search-list`, `search-list+property-detail`, `property-detail`), `_scrapedAt`

EPC rating, tenure, service charge, ground rent and council tax band are parsed from Savills' free-text `AdditionalInformation` array; status tags plus `originalPrice` and `priceQualifier` drive change detection.

***

### Example Input And Output

```json
{
  "searchUrls": [
    { "url": "https://search.savills.com/list/property-for-sale/england" },
    { "url": "/list/property-to-rent/italy" }
  ],
  "maxListings": 100,
  "scrapeDetailPages": false,
  "proxy": { "useApifyProxy": false }
}
```

```json
{
  "listingId": "GBCSRSCIS260102",
  "url": "https://search.savills.com/property-detail/GBCSRSCIS260102",
  "price": 850000,
  "displayPrice": "£850,000",
  "priceQualifier": "Guide price",
  "currency": "GBP",
  "fullAddress": "City of London, London EC3N",
  "latitude": 51.512,
  "longitude": -0.083,
  "status": "Under offer",
  "bedrooms": 2,
  "sizeFormatted": "1,179 sq ft",
  "tenure": "Share of freehold",
  "councilTaxBand": "D",
  "epcRating": "C",
  "primaryAgent": { "name": "Jane Smith", "phone": "+44 20 7000 0000", "office": "Savills City" },
  "_source": "search-list",
  "_scrapedAt": "2026-10-07T09:15:00.000Z"
}
```

***

### Build Savills Listings Data Without An Official API

There is no public Savills API — `api.savills.com` 404s every probed route, no developer portal. This Actor reads the surface Savills' own frontend consumes.

| What | Value |
|---|---|
| Host | `https://search.savills.com` |
| Search / list URL | `https://search.savills.com/list/<path>` |
| Pagination | `https://search.savills.com/list/<path>/page/<n>` |
| Property detail URL | `https://search.savills.com/property-detail/<externalPropertyId>` |
| Data blob | `<script id="__NEXT_DATA__" type="application/json">` |
| JSON path used | `props.initialReduxState.properties` (lists), `props.initialReduxState.propertyDetail.property` (details) |
| Pagination metadata | `props.initialReduxState.listPage.{currentPage,totalItems,pageMap}` + `pageMap.<n>.metaData.NextUrl` |

Marketing pages on `www.savills.com` / `www.savills.co.uk` carry no listing data; results live in a separate application whose config, published at `https://search.savills.com/js/endpoints.js`, exposes `dataEndpoint: https://livev6-searchapi.savills.com` (plus `livev6-profile`, `livev6-authentication` and `assets.savills.com`) — the fallback surface if the SSR blob ever disappears.

Instead of guessing undocumented paths on the private `livev6-searchapi` host, the SSR blob was chosen because it is:

1. **The richest source** — one 89-field object per listing (price, tenure, EPC, service charge, agent, floor plans, brochures, coordinates); no equivalent public REST shape.
2. **Authenticated and stable** — the exact payload the frontend consumes, so it cannot drift behind an internal API contract.
3. **Free** — plain HTTP via the standard Apify proxy; no paid anti-bot API for residential pages.
4. **Server-rendered** — listings sit in the first byte range; JavaScript never runs.

**Parse gotcha:** the blob can hold a literal `</script>` inside a string (descriptions embed HTML), so naive `indexOf('</script>')` truncates the JSON mid-string — the Actor slices generously and lets `JSON.parse` find the real end. `curl` also needs `--compressed`, or Savills' gzip stream arrives truncated.

***

### Complete Property Detail Pages With scrapeDetailPages

Measured against `search.savills.com` (residential, England):

- card and detail page share **86 identical fields** — price, description, agents, galleries, coordinates and `AdditionalInformation` match byte for byte, so detail never *corrects* a card value;
- detail carries **47 extra fields**, the useful ones mapped into the output (listed under Output Fields);
- `size` is completed there: the card leaves `AvailableSize` all-zero and renders only `"1,179 sq ft"`, while detail carries the numeric `Size` block with **acres, hectares, square yards and ping** — unrecoverable from card text;
- detail responses cost **60–240 ms** vs **300–900 ms** for a list page. At `maxConcurrency: 5`: 40 listings without detail pages = 3 requests in 2.7 s; the same 40 with detail pages = 43 requests in 9 s.

Because the dataset is append-only, `scrapeDetailPages: true` **defers** each row until its detail page lands, then writes it once with both sources merged; a failed detail page always falls back to search-card data.

***

### Scrape Savills At Scale: AWS WAF Limits, Rate Control And Running Cost

Savills serves `search.savills.com` behind **AWS WAF** — the `awsWafCookieDomainList` challenge returned as **HTTP 202** with a JS body instead of the page. The Actor:

- retries a 202 up to 3 times with escalating backoff **8s / 16s / 24s**;
- crawls at `maxConcurrency: 5` with `useSessionPool` and no keep-alive — 12 parallel detail requests passed untouched, but sustained single-IP volume eventually triggers the challenge;
- **stops globally the moment `maxListings` is reserved**.

Residential pages work from ordinary IPs. The WAF is **rate-based, not path-based**: a burst from one IP challenges every path, including ones that worked seconds earlier. Commercial and farm paths challenge sooner.

**Running cost:** no paid anti-bot API (Scrapfly/Zyte) is required; sustained volume may need the **Apify proxy** input with a residential group — the only likely extra cost. Code limits: `maxRequestsPerCrawl`, `maxConcurrency: 5`, `maxRequestRetries: 3`, 60s handler timeout, page budget, listing cap.

***

### Pricing, Free Tier And Pay-Per-Event Billing

| Event | Price |
|---|---|
| `result` | $0.0009 (FREE), stepping down to $0.0008 |
| `Details` | $0.0009 → $0.0008 |
| `Actor Start` | $0.00005 per run |

Free plans are capped at **10 listings** (`APIFY_USER_IS_PAYING` gate); paid plans run up to `maxListings`.

Detail work is billed as `property-detail-page`, once per detail page fetched — **only with `scrapeDetailPages: true`**:

- billed whether the page merges or falls back to search-card data;
- nothing is billed with `scrapeDetailPages: false`, and on a non-pay-per-event Actor `Actor.charge()` is a documented no-op;
- the charge lands the moment the page is fetched (never batched); at the spending limit the crawl stops via `crawler.autoscaledPool.abort()` and held rows flush as search-card rows;
- on `aborting`, waiting rows are pushed inside the 30-second window.

Define the event in Monetization (Console → Actor → Monetization → pricing) with a price and discount tiers — undefined events are free. Test locally with `ACTOR_TEST_PAY_PER_EVENT=true ACTOR_USE_CHARGING_LOG_DATASET=true apify run` (charges log to `storage/datasets/charging_log`).

***

### Savills vs Rightmove vs Zoopla: Which Source For UK Property Listings

Savills is an **agency** site — its own instructions with agency-level depth (EPC, tenure, service charge, agent, brochures) but only Savills stock. Rightmove, Zoopla and OnTheMarket are **portals** with far broader UK volume and normalised records. Claims are from each actor's Store page:

| Actor | Store-page claim |
|---|---|
| [epctex/rightmove-scraper](https://apify.com/epctex/rightmove-scraper) | 4.98★, 167 users, 51 fields, $0.40/1,000 properties |
| [tri_angle/fast-zoopla-properties-scraper](https://apify.com/tri_angle/fast-zoopla-properties-scraper) | Apify-published, 4.85★, 194 users, $0.001/result |
| [one-api/zoopla-property-scraper](https://apify.com/one-api/zoopla-property-scraper) | sold-price history, sale/rent estimates, tenure, $0.003/result |
| [fatihtahta/onthemarket-scraper](https://apify.com/fatihtahta/onthemarket-scraper) | $1.99 per 1,000 results |

Direct Savills rivals: `stealth_mode/savills-property-search-scraper` (130+ fields, bulk URLs), `shahidirfan/savills-property-scraper` (commercial, ~33 fields), `nocodeventure/savills-property-scraper` (UK detail mode), `rigelbytes/savills-scraper` ($2/1,000). Land registry alternative for transactions: GOV.UK Land Registry API, Homedata, Propalt. Southern Europe: `igolaizola/idealista-scraper` (2,422 users), `memo23/idealista-scraper` (80+ fields). Unified UK: `jungle_synthesizer/rightmove-zoopla-onthemarket-uk-scraper` ($0.001/record).

***

### Run Savills Scraper From The Apify API, Console Or Schedule

Start runs from the Console (fill the four fields, press Start) or through the API:

```bash
curl -X POST https://api.apify.com/v2/acts/YcKKGzgNPHHgwny0O/runs \
  -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
  -d '{"searchUrls":[{"url":"https://search.savills.com/list/property-for-sale/england"}]}'
```

Then poll `GET /v2/actor-runs/<runId>` and read rows from `GET /v2/datasets/<datasetId>/items?format=json`.

### Integrations & Automation

- **Webhooks** — fire on `actor.succeeded` / `actor.failed` to push rows into a warehouse, Google Sheets or Slack.
- **Zapier / Make** — supported by Apify, so a new dataset item can become a CRM record or deal-alert email without code.
- **Schedules** — run **daily** (price cuts, sales alerts) or **weekly** (dashboards), e.g. cron `0 6 * * *`; keep `maxListings` stable so dataset diffs stay meaningful.

***

### Related Actors

- [savills-property-search-scraper](https://apify.com/stealth_mode/savills-property-search-scraper)
- [savills-property-scraper](https://apify.com/nocodeventure/savills-property-scraper)
- [rightmove-scraper](https://apify.com/epctex/rightmove-scraper)
- [fast-zoopla-properties-scraper](https://apify.com/tri_angle/fast-zoopla-properties-scraper)
- [onthemarket-scraper](https://apify.com/fatihtahta/onthemarket-scraper)

***

### FAQ

#### Is there an official Savills API?

No. `api.savills.com` 404s every probed route and there is no developer portal; this Actor reads the public server-rendered `__NEXT_DATA__` payload from `search.savills.com` instead.

#### What's the best way to scrape Savills listings programmatically?

Fetch `/list/<path>` over plain HTTP, extract the `<script id="__NEXT_DATA__">` blob and read `props.initialReduxState.properties` — an 89-field object per row, no JavaScript. That is this Actor's approach.

#### Savills vs Rightmove vs Zoopla — which should I scrape for UK coverage?

Savills gives agency-level depth on prime, new-build, farm and commercial stock; the portals give raw volume across many agencies. Many teams run both, or a unified cross-portal actor.

#### How can I get UK property listings data via API?

Homedata, Propalt or the GOV.UK Land Registry API (price-paid transactions), or actors like this one via the Apify API. As a land registry alternative, Homodata layers transactions with listings and EPC.

#### How do I monitor UK property price changes automatically?

Schedule daily or weekly, hold `maxListings` constant and diff datasets on `listingId`; webhooks alert you when a run finishes.

#### What are the alternatives to Savills Scraper?

`stealth_mode/savills-property-search-scraper` (130+ fields), `nocodeventure/savills-property-scraper` (UK detail mode), `rigelbytes/savills-scraper` ($2/1,000), plus the Rightmove, Zoopla, OnTheMarket and Idealista scrapers.

***

### SEO Keywords

savills scraper, savills api, savills listings data, savills property data, savills property scraper, savills alternative, uk property listings database, uk property data, luxury property market data, property price monitoring uk, new homes listings data, commercial property listings api, cross-border property investment data, real estate market intelligence, epc rating data, property tenure data, land registry alternative, savills vs rightmove, rightmove scraper, zoopla scraper, onthemarket scraper, knight frank scraper, savills france property listings, savills italy property listings, savills spain property listings

### For AI Agents & LLM Apps

**Purpose:** fetch Savills search pages → one JSON dataset row per listing, ~90 fields: price + local currency, tenure, EPC, status, size, coordinates, agent contacts, media.

Minimal input:

```json
{ "searchUrls": [{ "url": "https://search.savills.com/list/property-for-sale/england" }] }
```

Variant with detail pages:

```json
{ "searchUrls": [{ "url": "https://search.savills.com/list/property-for-sale/england" }], "maxListings": 50, "scrapeDetailPages": true }
```

Output fields: listingId, internalId, externalIdFormatted, url, seoTitle, description, longDescription, locationNotes, features, price, displayPrice, originalPrice, priceQualifier, currency, otherFees, priceDisclaimer, yield, countryCode, regionOrTown, addressLine1, addressLine2, fullAddress, latitude, longitude, openHouse, propertyTypes, propertyTypeTag, propertyTypeSlug, marketTypes, isCommercial, isFarm, isNewDevelopment, newDevelopmentType, isHelpToBuy, isSharedOwnership, furnished, sizeDescription, status, statusCode, statusTag, isSold, isLet, isConfidential, isFeatured, launchingDate, bedrooms, bedroomsText, bathrooms, bathroomsText, receptions, receptionsText, carSpaces, carSpacesText, sizeFormatted, size, clearHeight, tenure, tenureTypeCode, leaseType, leaseExpiry, leaseRemaining, serviceCharge, groundRent, councilTaxBand, epcRating, energyText, primaryAgent, secondaryAgent, images, imageCount, imageCaptions, floorPlans, brochureUrls, epcGraphUrls, floorPlanPdfUrl, videoUrl, video360Url, externalWebsiteUrl, agentQuote, lastUpdated, fullPriceText, shortDisplayPrice, hasFloorplan, fluxProBrochureUrl, additionalAgents, areaGuide, sizeMaximum, saleableArea, \_source, \_scrapedAt.

Behaviors an agent should know:

- `maxListings` is the only stop condition (default 100, max 5000); free plans cap at 10 listings regardless of input.
- `scrapeDetailPages` defaults to `false`; bare paths expand to `search.savills.com` and `/page/N` is stripped so pagination restarts at page 1.
- With detail pages on, a row is withheld until its detail page lands; failures fall back to search-card data and are still written (`_source` records the source).
- Detail charges land on fetch even on fallback; the spending limit calls `crawler.autoscaledPool.abort()` and pending rows flush as search-card rows (on `aborting`, within 30 s).
- A 202 WAF challenge is retried 3 times (8s/16s/24s) at `maxConcurrency: 5`; commercial and farm paths challenge sooner.

Billing: pay-per-event — `result` ($0.0009 FREE → $0.0008), `Details` ($0.0009 → $0.0008), `Actor Start` ($0.00005/run); `property-detail-page` fires once per fetched detail page.

### Legal & Compliance Disclaimer

This Actor is an independent project and is **not affiliated with, endorsed by or sponsored by** Savills plc or any Savills group company.

It accesses only publicly served pages on `search.savills.com` — server-rendered HTML any ordinary browser receives; no login, no authentication bypass, no paid anti-bot bypass.

`search.savills.com/robots.txt` allows `/` for generic crawlers and disallows `/contact/`, `/forms/` and `/_inc/` (plus `Crawl-Delay: 5` for named bots like ClaudeBot, Bingbot, AhrefsBot) — this Actor requests only listing paths. Output is for personal, non-commercial use in respect of Savills' terms; you are responsible for compliance with those terms and with applicable data-protection law (GDPR/CCPA where relevant).

The dataset includes agent names and phone numbers — public business contact details published on listing pages — which must not be used for unsolicited commercial outreach in violation of applicable law.

# Actor input Schema

## `searchUrls` (type: `array`):

Full or partial Savills search URLs to scrape, e.g. 'https://search.savills.com/list/property-for-sale/england' or just '/list/property-for-sale/italy'. Supported path shapes: '/list/property-for-sale/<location>', '/list/property-to-rent/<location>', '/list/new-homes-for-sale/<location>', '/list/new-homes-to-rent/<location>', '/list/farms/<sub>/<location>', '/list/commercial/property-for-sale/<type>/<location>'.

## `maxListings` (type: `integer`):

Stop condition: the run ends as soon as this many listings are collected. Search pages are followed until the number is reached (no separate page cap). Free users are additionally capped at 10.

## `scrapeDetailPages` (type: `boolean`):

When true, each listing is also opened on its /property-detail/<id> page and that page is merged into the row. Adds detail-only values (lastUpdated, fullPriceText, shortDisplayPrice, hasFloorplan, fluxProBrochureUrl, additionalAgents, areaGuide, sizeMaximum, saleableArea) and a complete size block. Rows are emitted only once their detail page is fetched. Costs one extra request per listing and, on pay-per-event pricing, bills one 'property-detail-page' event per detail page fetched.

## `proxy` (type: `object`):

Select proxies to be used by your crawler.

## Actor input object example

```json
{
  "searchUrls": [
    {
      "url": "https://search.savills.com/list/property-for-sale/england"
    }
  ],
  "maxListings": 100,
  "scrapeDetailPages": false,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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 = {
    "searchUrls": [
        {
            "url": "https://search.savills.com/list/property-for-sale/england"
        }
    ],
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/savills-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 = {
    "searchUrls": [{ "url": "https://search.savills.com/list/property-for-sale/england" }],
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/savills-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 '{
  "searchUrls": [
    {
      "url": "https://search.savills.com/list/property-for-sale/england"
    }
  ],
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/savills-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ahmed_jasarevic/savills-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/YcKKGzgNPHHgwny0O/builds/u638016SWa2mNhcH2/openapi.json
