# URA Singapore Property Data Scraper (`rl1987/ura-property-data`) Actor

Fetches project summaries, sale transaction history, and rental history from URA's PMI Mobile property data service, by project name, street, district, or full island-wide crawl.

- **URL**: https://apify.com/rl1987/ura-property-data.md
- **Developed by:** [R.L.](https://apify.com/rl1987) (community)
- **Categories:** Real estate
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 output rows

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### What does URA Singapore Property Data Scraper do?

This Actor pulls live private residential property market data straight from the same backend that powers URA's official [PMI Mobile app](https://www.ura.gov.sg/property-market-information) — project sale price/rental summaries, unit-level sale transaction history, and quarterly rental statistics — for any project in Singapore, any street, an entire URA planning district, or the whole island at once. Run it manually, on a schedule, or trigger it from the Apify API to keep a property-market dataset continuously up to date.

### Why use URA Singapore Property Data Scraper?

- **Market research & investment analysis** — track price/rental trends for specific projects or districts over time.
- **Portfolio monitoring** — watch transaction and rental activity for buildings you own or manage.
- **Real estate proptech & data products** — feed structured Singapore property data into dashboards, models, or apps without maintaining your own scraper.
- **Comparative analysis** — pull an entire district's worth of projects in one run to compare price/rental performance.

### How to use URA Singapore Property Data Scraper

1. Click **Try for free** or set up input in the **Input** tab.
2. Pick a lookup mode -- `projectNames`, `streetNames`, and `districts` are all searchable dropdowns pre-populated from URA's own project index, so there's no free-text typing or guessing exact names:
   - **Specific projects** — pick one or more from the `projectNames` dropdown (e.g. "THE SAIL @ MARINA BAY").
   - **Specific streets** — pick one or more from the `streetNames` dropdown.
   - **A district** — pick one or more from the `districts` dropdown to fetch every known project in those districts.
   - **Free-text search** — type into `searchQuery` to reproduce the app's own search box (case-insensitive substring match against project and street names, e.g. "sail" finds "THE SAIL @ MARINA BAY", "RIVERSAILS", "VERSAILLES"). Combine with `districts` to scope it.
   - **The whole index** — set `crawlAll` to `true` to fetch all ~3,200 projects island-wide (use `maxProjects` to cap this for a first test run).
3. Choose which data types to include: project summary, transaction history, rental history.
4. Run the Actor and download results from the **Dataset** tab, or read them via the Apify API/CLI.

### Input

| Field | Type | Description |
|---|---|---|
| `projectNames` | array of strings | Exact/near-exact project names to fetch directly |
| `streetNames` | array of strings | Street names to fetch directly (best-effort) |
| `searchQuery` | string | Free-text substring search over project/street names, same as the app's search box |
| `districts` | array of strings | URA district codes (`01`–`28`) to browse via the bundled project index |
| `crawlAll` | boolean | Fetch every project in the bundled index |
| `maxProjects` | integer | Cap on resolved projects/streets actually fetched (0 = no cap) |
| `includeProjectSummary` | boolean | Fetch project-level summary |
| `includeTransactions` | boolean | Fetch sale transaction history |
| `includeRentals` | boolean | Fetch rental history |
| `transactionMonths` / `rentalQuarters` | integer | How far back to request (URA caps actual results at the project's available history) |
| `concurrency` | integer | Parallel project fetches |
| `requestDelayMs` | integer | Pause between calls per project |

Example input:

```json
{
  "districts": ["09", "10"],
  "includeProjectSummary": true,
  "includeTransactions": true,
  "includeRentals": true,
  "maxProjects": 100
}
```

### Output

Each dataset item is one record — a project summary, a single sale transaction, or a single quarter of rental stats — tagged with `dataType` and the project/street/district it belongs to.

```json
{
  "dataType": "transaction",
  "projectName": "THE SAIL @ MARINA BAY",
  "streetName": null,
  "districtCode": "01",
  "districtName": "Raffles Place, Cecil, Marina, People's Park",
  "floorRange": "01 to 05",
  "areaSqft": 883.0,
  "areaSqm": 82.05,
  "price": 1608000.0,
  "refPeriod": "JUL 2026",
  "unitPricePsf": 1822.0,
  "unitPricePsm": 19611.87
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

#### Data fields

URA reports area and price rates in imperial units (sqft, PSF) only -- this Actor derives the metric equivalents (sqm, PSM) itself using 1 sqm = 10.7639 sqft, so every row carries both.

| Field | Applies to | Description |
|---|---|---|
| `projectName`, `streetName`, `districtCode`, `districtName` | all | Project/location context |
| `lastTransactedRefPeriod`, `lastTransactedValuePsf`, `lastTransactedValuePsm` | projectSummary | Most recent transacted price rate and period |
| `lastRentalRefPeriod`, `lastRentalValuePsf`, `lastRentalValuePsm` | projectSummary | Most recent median rental rate/month and period |
| `marketSegment`, `tenure`, `propertyType` | projectSummary | Segment (CCR/RCR/OCR), tenure, property type code |
| `floorRange`, `areaSqft`, `areaSqm`, `price`, `unitPricePsf`, `unitPricePsm`, `refPeriod` | transaction | Per-unit sale record |
| `medianPsfPerMonth`, `medianPsmPerMonth`, `p25PsfPerMonth`, `p25PsmPerMonth`, `p75PsfPerMonth`, `p75PsmPerMonth`, `refPeriod` | rental | Quarterly rental price distribution |

### How much does it cost to scrape URA property data?

This Actor makes lightweight SOAP calls, not browser rendering, so it's cheap to run on Apify's compute-unit pricing. A single project lookup (summary + full transaction + rental history) typically completes in a few seconds. Fetching a whole district (dozens to low hundreds of projects) or the full island-wide index (~3,200 projects) scales roughly linearly — use `maxProjects` and the default polite `concurrency`/`requestDelayMs` settings to keep runs predictable in both cost and load on URA's servers.

### Tips

- Start with a `maxProjects` cap when exploring `districts` or `crawlAll` mode.
- Project names must match URA's own naming closely — check `data.gov.sg`'s URA Property Transaction dataset or the PMI app if a lookup returns nothing.
- Keep `concurrency` modest (default 5) — this is a public government service, not a bulk API.

### FAQ, disclaimers, and support

This Actor calls a public, unauthenticated web service used by URA's own PMI Mobile app to serve property market data to the public. It performs read-only queries and does not require credentials. Data accuracy and availability depend entirely on URA; this Actor does not modify, cache-poison, or resell URA data beyond what the source service already returns.

The bundled project name/street/district index is a static snapshot (dated 2014) used only to resolve *which* projects exist for district/island-wide browsing — all price, rental, and transaction data returned for each project is fetched live at run time. Very recently launched projects that are not yet in this static index may not surface via `districts`/`crawlAll` mode; use `projectNames` directly for those.

Found a bug or have a feature request? Use the Issues tab on this Actor's page.

# Actor input Schema

## `projectNames` (type: `array`):

Pick specific private residential projects to fetch directly. List is sourced from URA's own project index.

## `streetNames` (type: `array`):

Pick specific streets to fetch transactions/rentals for (best-effort; URA's street search is stricter than project search and may return no rows for some streets).

## `searchQuery` (type: `string`):

Free-text search, same as the search box in the URA PMI app -- case-insensitive substring match against project names and street names in the bundled index (e.g. "sail" finds "THE SAIL @ MARINA BAY"). Combine with districts to scope the search to specific districts.

## `districts` (type: `array`):

Pick one or more URA postal districts. Every project in these districts (per the bundled project index) is resolved and fetched. Combine with maxProjects to cap run size.

## `crawlAll` (type: `boolean`):

Fetch every project in the bundled index (~3,200 projects island-wide) instead of a specific list/district. This is a long, heavy run -- use maxProjects to cap it, and prefer scoping by district when possible.

## `maxProjects` (type: `integer`):

Safety cap on the number of resolved projects/streets to actually fetch (0 = no cap). Recommended when using districts or crawlAll.

## `includeProjectSummary` (type: `boolean`):

Fetch project-level summary: last transacted price, last median rental, market segment, tenure. Only works with project name lookups (not street name).

## `includeTransactions` (type: `boolean`):

Fetch unit-level sale transaction history (floor range, area, price, PSF, period).

## `includeRentals` (type: `boolean`):

Fetch quarterly rental price statistics (median, 25th/75th percentile PSF/month).

## `transactionMonths` (type: `integer`):

How many months of sale transactions to request, counting back from the current month. URA appears to cap actual results at the project's full available history regardless of this value.

## `rentalQuarters` (type: `integer`):

How many quarters of rental statistics to request, counting back from the current quarter.

## `concurrency` (type: `integer`):

How many projects to fetch in parallel. Keep modest -- this is a public government service, not built for bulk traffic.

## `requestDelayMs` (type: `integer`):

Pause between each SOAP call within a single project's fetch, to stay polite to URA's servers.

## Actor input object example

```json
{
  "projectNames": [],
  "streetNames": [],
  "searchQuery": "",
  "districts": [],
  "crawlAll": false,
  "maxProjects": 0,
  "includeProjectSummary": true,
  "includeTransactions": true,
  "includeRentals": true,
  "transactionMonths": 240,
  "rentalQuarters": 60,
  "concurrency": 5,
  "requestDelayMs": 300
}
```

# Actor output Schema

## `results` (type: `string`):

Project summary, sale transaction, and rental history rows.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("rl1987/ura-property-data").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("rl1987/ura-property-data").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 '{}' |
apify call rl1987/ura-property-data --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rl1987/ura-property-data"
        }
    }
}

```

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/3TXQheGULgJjFNWvB/builds/nDRlPIYavVbVmqKnp/openapi.json
