# Singapore Open Data Studio — Gov Data Joins (`subimpact/sg-open-data-studio`) Actor

Value layer on Singapore's official open data API (data.gov.sg): 6 cross-dataset join presets (Housing & HDB, Demography, Labour, Vehicles & COE, Education, Health) + custom joins, CSV/JSON/XLSX delivery, webhooks, AI-ready output with Singapore Open Data Licence attribution.

- **URL**: https://apify.com/subimpact/sg-open-data-studio.md
- **Developed by:** [subimpact](https://apify.com/subimpact) (community)
- **Categories:** AI, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 joined pulls

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

## Singapore Open Data Studio — Gov Data Joins

Join Singapore's official open data into clean CSV/JSON/XLSX with AI-ready output and attribution.

Sister actor to [my-open-data-studio](https://apify.com/subimpact/my-open-data-studio) — same value-layer engine, Singapore data source (data.gov.sg).

### What it does

Every preset pulls multiple official data.gov.sg datasets, aligns them on a common key (year), and delivers one flat joined file. Raw APIs can't do this — that's the value layer.

### Presets

- **S1 — Housing & HDB by Year**: HDB dwelling units under management × completed units, by financial year.
- **S2 — Demography by Year**: Total deaths × live births, by year.
- **S3 — Labour Market by Year**: Female LFPR × female employment rate × resident long-term unemployment, by year.
- **S4 — Vehicles & COE by Year**: COE quota (all categories) × cars by engine capacity, by year.
- **S5 — Education by Year**: Primary enrolment × secondary enrolment × secondary teachers (both sexes), by year.
- **S6 — Health by Year**: Public hospital admissions × doctors per 10k × male life expectancy, by year.

### Custom joins

Choose `preset=custom` and supply your own data.gov.sg dataset ids (`d_...`), key columns, optional filters, and aggregation. The engine probes each dataset and guesses numeric fields if you don't specify them.

### Inputs

| Input | Default | Description |
| --- | --- | --- |
| preset | S1 | S1-S6 or custom |
| customDatasets | \[] | Dataset ids for custom joins |
| customKey | \["year"] | Key columns for custom joins |
| customJoinType | inner | inner or left |
| customParams | {} | JSON filters applied to every dataset |
| customAgg | none | none, sum, or mean |
| format | json | json, csv, or xlsx |
| webhookUrl | (empty) | POST result file after run |
| aiReady | true | Emit JSON Schema + data dictionary |
| includeAttribution | true | Attach source/licence sidecar |

### Output

Key-value store records: `<preset>_join.<ext>`, `<preset>_ai_ready.json`, `<preset>_attribution.json`, `<preset>_verification.json`. Dataset records (JSON) are always emitted alongside the file.

### Pricing

Pay per joined pull (single event). Usage (compute) is billed to the user's Apify account; the event price is the creator's revenue.

### Data & licence

Source: [data.gov.sg](https://data.gov.sg) — Singapore's official open data portal (Singapore Department of Statistics, HDB, MOH, MOE, MOM, LTA, ICA, NEA, and more). Licensed under the Singapore Open Data Licence (CC BY 4.0-based). Attribution is attached to every output.

### Rate limits

data.gov.sg's public API is keyless but rate-limited (datastore: 4 calls/10s without a key). The actor paces its fetches within the limit; large datasets take longer but never fail on rate limits.

# Actor input Schema

## `mode` (type: `string`):

studio = value layer (presets, joins, AI-ready package). extract = raw data pull of 1-5 datasets by ID (cheaper per-pull event).

## `datasetIds` (type: `array`):

For mode=extract: list of data.gov.sg dataset ids (d\_...) to pull raw (1-5). Leave empty to use studio mode.

## `preset` (type: `string`):

Join bundle. S1 = Housing & HDB by Year. S2 = Demography by Year. S3 = Labour Market by Year. S4 = Vehicles & COE by Year. S5 = Education by Year. S6 = Health by Year. custom = bring your own dataset ids.

## `customDatasets` (type: `array`):

For preset=custom: list of data.gov.sg dataset ids (d\_...) to join (2-6). Leave empty to use a preset.

## `customKey` (type: `array`):

For preset=custom: key parts to join on. Use 'year' (auto-extracted from year/financial\_year/month fields) or raw field names. All datasets must share these keys.

## `customJoinType` (type: `string`):

inner keeps only keys present in every dataset; left keeps all keys from the first dataset.

## `customParams` (type: `string`):

For preset=custom: JSON object of extra API params applied to every dataset, e.g. {"filters": {"sex": "female"}}.

## `customAgg` (type: `string`):

none = keep raw rows (last value per key). sum = aggregate numeric values per key. mean = average numeric values per key.

## `format` (type: `string`):

File format delivered to the key-value store (dataset records are always JSON).

## `webhookUrl` (type: `string`):

POST the result file to this URL after the run (3 retries with backoff). Leave empty to skip.

## `aiReady` (type: `boolean`):

Also emit JSON Schema + data dictionary + sample rows for LLM/RAG ingestion.

## `includeAttribution` (type: `boolean`):

Attach source/licence metadata sidecar to every output (Singapore Open Data Licence).

## Actor input object example

```json
{
  "mode": "studio",
  "preset": "S1",
  "customKey": [
    "year"
  ],
  "customJoinType": "inner",
  "customAgg": "none",
  "format": "json",
  "aiReady": true,
  "includeAttribution": true
}
```

# Actor output Schema

## `runSummary` (type: `string`):

One summary record per run: mode, preset, row count, format, files, year range.

## `joinedData` (type: `string`):

The joined dataset file (CSV/JSON/XLSX) in the default key-value store.

## `extractedData` (type: `string`):

Raw dataset file(s) (CSV/JSON/XLSX) in the default key-value store.

## `aiReadyPackage` (type: `string`):

JSON Schema + data dictionary + sample rows for LLM/RAG ingestion.

## `attribution` (type: `string`):

Source and licence metadata (Singapore Open Data Licence, CC BY 4.0-based).

# 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("subimpact/sg-open-data-studio").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("subimpact/sg-open-data-studio").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 subimpact/sg-open-data-studio --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,subimpact/sg-open-data-studio"
        }
    }
}

```

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/C1PrUAcPgh1WymAat/builds/SD9RmWr5JtmUj8YyH/openapi.json
