Small Group Tutorials

Here to help students catch up, keep up, and move ahead. Book a consultation here.

Punggol Haze API Tutorial | Python, data.gov.sg PM2.5, PSI, JSON and Real Data

Watertown, nearby HDB flats and road construction at sunset in Punggol

How do you get real Singapore haze readings in Python? Use NEA’s free official data.gov.sg v2 real-time /pm25 endpoint, inspect data.items and readings.pm25_one_hourly, and print the regional values with their units and timestamps. The separate /psi endpoint provides current PSI, not a substitute for the official next-day PSI forecast. Data cover Singapore’s five reporting regions—not a sensor at every Punggol flat.

This tutorial provides usable Python requests code, response fields verified against the live v2 API, date filters, pagination, error handling, graphing principles and source attribution. The examples are for education and data literacy, not a new government-authorised haze-warning service.

Watertown and Punggol HDB flats in a sunset street scene
Owned Punggol neighbourhood photo. Its sky colour is not an API reading, calibrated measurement or forecast.

Navigate the tutorial: What is the live Singapore haze API? · Why Python examples need error handling · How to request readings for a particular date · A real worked calculation with fictional teaching data · What about an AI haze predictor? · A seven-step educational project plan

What is the live Singapore haze API?

Two official NEA datasets are available without scraping a website

To retrieve Singapore’s measured one-hour PM2.5 programmatically, send an HTTP GET request to api-open.data.gov.sg/v2/real-time/api/pm25. To retrieve current PSI information, use the /psi endpoint. The datasets are published by the National Environment Agency through data.gov.sg, with readings grouped across five regions. The website indicates that the data are updated at approximately 15-minute intervals. This is not the same as having a sensor mounted at every Punggol block.

Why this is worth learning

A student can use the data to practise API requests, structured JSON parsing, units, time stamps, missing values and honest graphing with real public information. A parent may appreciate knowing why one app displays an east-region number while another displays a different city or index. A developer can make a small educational dashboard that links back to NEA without pretending to create an official forecast. The code should be treated as a learning example, not an emergency alert service that overrides NEA or MOH.

Read measured data before attempting predictions

An API reading is an observation

The /pm25 endpoint returns the latest available observed PM2.5 values unless a date parameter requests other records. The one-hour PM2.5 data describe ambient fine-particle mass concentration in micrograms per cubic metre. A data record includes a timestamp, update time, region metadata and readings by region. Each field matters: a ‘North’ concentration does not mean every rooftop, bus stop and living room in the north has that exact concentration.

Tomorrow’s forecast is a separate product

The /psi endpoint returns current PSI-related readings and sub-index information rather than simply issuing the government’s forecast for tomorrow. A common coding error is to call /psi, take its current 24-hour value and label it ‘forecast tomorrow’. That is incorrect. For next-day outdoor planning, use NEA’s official forecast page and the corresponding advisory; for actual immediate conditions, use the current one-hour PM2.5 record. Measured and predicted data are different products even when both come from the same environmental authority.

How the live PM2.5 response is organised

Look inside data.items

The 2026 data.gov.sg v2 response contains a top-level code, a data object and optional error information. Within data, the regionMetadata array describes region labels and coordinate information, while items contains one or more time-stamped observations. Each item has a readings object and a pm25_one_hourly map with keys including north, south, east, west and central. The currently returned success code is 0; a robust program should also check the HTTP status and whether items exist.

Do not hardcode the present air value into a guide

A number such as 45 µg/m³ is meaningful only with its reporting region and observation timestamp. The current feed will change as NEA updates it. A WordPress article with ‘Punggol is currently at 45’ would become stale or inaccurate, and the North region is not a measurement at the exact residential location of the reader. Instead, include the API endpoint and show how to inspect the newest value responsibly. Never compare it against an old screenshot without identifying the dates.

First working Python example

Install the small dependency

You can run this example on Python 3.9 or later with the requests library installed. In a personal terminal, the ordinary command is python -m pip install requests. For a school environment with managed computers, follow the institution’s policies rather than installing packages without permission. The example requests the public feed with a sensible timeout; it does not require a secret key for an ordinary basic request at the public rate limit.

Read, validate and print the official fields

The code checks for HTTP errors, verifies that data.items exists, then prints the timestamp and the regional PM2.5 estimates. It intentionally does not label the north reading as a private Punggol monitor. If the endpoint structure changes, consult the dataset’s current API specification instead of guessing a new property name. If the request fails, report that data could not be retrieved rather than showing a made-up value or claiming the air is normal.

Runnable example 1: latest regional one-hour PM2.5

# Python 3.9+ — install with: python -m pip install requests
import requests
from datetime import datetime
from zoneinfo import ZoneInfo

URL = "https://api-open.data.gov.sg/v2/real-time/api/pm25"
response = requests.get(URL, timeout=15)
response.raise_for_status()

payload = response.json()
if payload.get("code") != 0:
    raise RuntimeError("API returned an error: " + str(payload.get("errorMsg")))

items = payload.get("data", {}).get("items", [])
if not items:
    raise RuntimeError("No PM2.5 observations returned")

item = items[-1]
when = datetime.fromisoformat(item["timestamp"].replace("Z", "+00:00"))
sg_time = when.astimezone(ZoneInfo("Asia/Singapore"))
print("Observation time (SGT):", sg_time.isoformat())

values = item["readings"]["pm25_one_hourly"]
for region, ug_m3 in sorted(values.items()):
    print(region, ug_m3, "µg/m³")

This example prints the actual API observation timestamp converted to Singapore time and the five region values. It does not hardcode today’s haze condition. Keep the source attribution when republishing results.

Why Python examples need error handling

APIs are not always reachable

A live API can experience network interruptions, rate limiting or temporary unavailable data. data.gov.sg documents HTTP 400 for invalid requests, 404 for missing data in a particular query, and 429 for exceeding allowed request rates, in addition to successful 200 responses. A Python program using raise_for_status() and a bounded timeout can stop with a meaningful error. A trustworthy dashboard should show ‘latest data unavailable’ rather than silently reusing a stale value without its time.

Do not retry endlessly

Repeatedly querying every second can consume rate limits without adding scientific value. The public data are not a sensor stream updating continuously every millisecond. A family decision interface should refresh at a sensible interval and display the last actual observation time. If a request encounters 429, stop or follow documented retry guidance rather than launching many simultaneous requests. Developers who need higher quotas can use the site’s optional API key according to its rules.

Understanding time and time zones

ISO strings should not lose their offset

The live API returns timestamps in an ISO 8601-compatible format, commonly including a Singapore time offset such as +08:00. In some published documentation examples, a trailing Z indicates UTC. These are different representations of a moment in time, not necessarily different measurements. A coding worksheet should parse the offset and convert to Asia/Singapore before displaying the time to local readers. Copying only ’20:00′ without date or zone can be misleading when historical data are involved.

Difference between timestamp and updatedTimestamp

The timestamp field identifies the observation time, while updatedTimestamp indicates when the record was updated or published. A sensor observation can be posted after the actual observation time, so they need not match exactly. A student should label them separately rather than claim the monitor read at the update time. This becomes important when correlating PM2.5 with a photograph taken at a specified hour or when writing a responsible news caption.

Why there are five regions, not every estate

How to interpret regionMetadata

The dataset provides region labels and coordinates for North, South, East, West and Central. Those geographic points are metadata for reporting regions; they do not necessarily identify the precise laboratory location of each instrument or represent individual street readings. Punggol lies in north-east Singapore, but a script fetching the ‘north’ dictionary key is retrieving a North-region public reading, not a measurement from a particular Punggol block.

Avoid invented coordinates or local detail

A Punggol parent may ask whether the value applies exactly to a Waterway Park entrance, SIT Punggol, or a bedroom near Northshore. The API cannot provide that exact claim. Use official NEA regional information for a general public reference and explain that local conditions and indoor air may differ. Do not create a marker labelled ‘live Punggol sensor at Waterway Point’ using regionMetadata’s label position. A map pin is not proof of a sampling device at that landmark.

PSI is a different dataset and unit

The current 24-hour PSI field

The separate /psi endpoint returns readings including psi_twenty_four_hourly by region, plus other pollutant sub-indexes and rolling pollutant data. A PSI number is an index, not a concentration in micrograms per cubic metre. The PM2.5 endpoint provides one-hour concentration readings. A programmer must use the correct label and should not subtract the PM2.5 concentration from the PSI and call the difference ‘pollution improvement’.

Why a current PSI is not the forecast

Even when an API has a psi_twenty_four_hourly field, it is a reported current 24-hour index, not the government’s next-day 24-hour forecast. The official public health system makes this distinction because the two have different uses: immediate activity adjustments versus advance scheduling. A website or app that calls one field ‘tomorrow’s PSI’ without a forecast source is misleading. The Punggol haze measurement guide covers the distinction for non-programmers, while this article shows it in data field names.

How to request readings for a particular date

An ordinary query parameter is enough

The PM2.5 API documentation accepts a date parameter such as 2026-10-17 for readings from that day. A date-time form can request the most recent record at a specified moment. This makes it useful for classroom studies comparing a fixed period rather than relying on today’s moving live values. The resulting dataset may contain many items and may need pagination to retrieve the full date; consult the current API specification.

Past data are not a forecast

A historic reading from 17 October should be labelled ‘observed on 17 October’, not presented as today’s value or proof of what will happen tomorrow. When building a chart, convert timestamps consistently and handle missing hours honestly. If no data are returned, that is not evidence that the pollution was zero. A student should write ‘data unavailable for requested period’ until the issue is understood.

Runnable example 2: one-hour PM2.5 versus current PSI

# Compare two different datasets; do not mix their units.
import requests

BASE = "https://api-open.data.gov.sg/v2/real-time/api/"
def get_latest(name):
    r = requests.get(BASE + name, timeout=15)
    r.raise_for_status()
    data = r.json()
    if data.get("code") != 0 or not data.get("data", {}).get("items"):
        raise RuntimeError("No usable data for " + name)
    return data["data"]["items"][-1]

pm = get_latest("pm25")
psi = get_latest("psi")

# "north" is a REGION example, NOT a sensor at a Punggol address.
print("North region one-hour PM2.5 (µg/m³):",
      pm["readings"]["pm25_one_hourly"]["north"])
print("North region current 24-hour PSI (index):",
      psi["readings"]["psi_twenty_four_hourly"]["north"])

# Do not label the /psi response as tomorrow's forecast.

The code deliberately labels the North-region example, avoiding a false assertion that the dataset has a unique sensor at a Punggol MRT entrance. It also avoids mislabelling current PSI as tomorrow’s forecast.

Pagination for longer historical requests

What paginationToken means

Some date-filtered API requests return a paginationToken when additional pages of observations are available. To retrieve a complete series, a program must make subsequent requests with that token as documented until there is no next page. Counting only the first page as an entire day could omit observations and produce misleading statistics. The program should also keep sensible request limits and stop if the API reports an error.

Careful statistics need a complete time series

A missing afternoon could seriously distort a daily maximum, mean or chart of changing smoke. Check sample count, time coverage and whether repeated records have identical timestamps before calculating statistics. An observed mean based on 12 of 24 intended hours should not be described as an official daily mean. When data are incomplete, report the limitation plainly. A small honest dataset is more educational than a grand-looking chart with hidden missing values.

Optional API keys and security

Public requests may work without a key

data.gov.sg documents an optional x-api-key request header for higher rate limits and support. Basic public calls can work without it. A student should never paste a private API key into a WordPress article, public GitHub repository or classroom screenshot. If a key is required for a larger integration, use appropriate server-side environment configuration and restrict sharing in accordance with the provider’s requirements.

Why refresh frequency matters

A clever-looking widget that polls every second can waste resources and trigger 429 rate limits even though NEA’s public regional readings update at a slower cadence. For a public website, cache sensibly, display the source and observation time, and ensure failure handling does not silently preserve an outdated green reading. The goal is to inform people, not create misleading ‘live’ animation. A properly designed educational widget is as clear when data are unavailable as when all fields return successfully.

Runnable example 3: date filtering and pagination

# A date-filtered request: observations for one calendar day.
import requests

endpoint = "https://api-open.data.gov.sg/v2/real-time/api/pm25"
params = {"date": "2026-10-17"}
all_items = []

while True:
    response = requests.get(endpoint, params=params, timeout=15)
    response.raise_for_status()
    obj = response.json()
    if obj.get("code") != 0:
        raise RuntimeError(str(obj.get("errorMsg")))
    page = obj.get("data", {})
    all_items.extend(page.get("items", []))
    token = page.get("paginationToken")
    if not token:
        break
    params["paginationToken"] = token

print("Records returned:", len(all_items))
# Check time coverage and duplicates before computing an average.

This shows the documented paginationToken pattern for a date query. Real applications should implement polite rate limiting and preserve time coverage and error information.

How to graph a PM2.5 series without lying

Labels need units and time

If a student plots the North-region hourly PM2.5 readings, the horizontal axis should show observation times in Singapore time and the vertical axis should show µg/m³. Each point must come from an actual observation, with missing data represented appropriately. Avoid drawing a continuous line across a long outage without indicating the gap. A smoothing algorithm may make a chart easier to see but should not conceal rapid changes that matter for immediate activity advice.

Do not overlay PSI raw numbers as though they shared units

If also graphing 24-hour PSI, use a separate panel or clearly labelled axis and explain that it is an index with a different averaging period. A student who adds a 24-hour rolling index to a one-hour particle concentration is not producing a valid combined risk score. It is reasonable to compare whether the trends rose or fell over a period, with careful timing, but never turn a visual similarity into proof they measure the same thing.

A real worked calculation with fictional teaching data

Three hourly concentration estimates

Suppose three successive hourly North-region PM2.5 values in a fictional worksheet are 20, 32 and 44 µg/m³. Their simple arithmetic mean is (20 + 32 + 44)/3 = 32 µg/m³. The maximum of the three values is 44, and the increase from the first to third is 24 µg/m³. These are valid calculations on the three numbers. They are not an official PSI, not a full-day average, and not a forecast of the next hour.

What the learner should write

A correct conclusion might say: ‘The fictional one-hour PM2.5 measurements rose across three recorded hours. The three-point mean is 32 µg/m³. Because only three hours are included, it does not describe the whole day’s conditions.’ This is a stronger answer than declaring the family can cycle tomorrow because the mean is lower than an index threshold. The example teaches mathematical transparency, source labels and the limits of averages.

How to turn raw data into a Primary or SEC learning task

Primary students can learn careful graph reading

A Primary 5 or Primary 6 pupil can practise ordering values, interpreting a column chart or finding an arithmetic difference using clearly labelled hypothetical data. The assignment should first distinguish the source, date and unit, then ask a simple question. It is inappropriate to assign the child a personal medical decision or a scientifically precise health-risk calculation based on one observation. The data are a teaching context for numeracy and critical thinking.

Secondary students can ask more demanding questions

Under Singapore’s evolving Secondary Education Certificate context, older students may work with statistics, scatter plots, ratios, temporal patterns and uncertainty. A useful comparison might ask whether higher public PM2.5 values coincide with a weather event on the same date, while recognising that correlation does not prove causation. The Punggol Geography source-based haze guide and G3 Mathematics modelling article contain further original study approaches that complement, rather than duplicate, a coding tutorial.

Build a data dictionary before writing a dashboard

Five fields every chart needs

At minimum record the dataset name, publisher, exact endpoint, pollutant or index field, unit, and observation timestamp or time zone. For regional records, keep the official region key and whether the value is measured, calculated or forecast. A UI label like ‘Punggol PSI NOW’ hides too much because it may actually display the North region’s 24-hour PSI or a PM2.5 value from another time. A more accurate label reads ‘NEA North-region one-hour PM2.5, µg/m³, observed at …’.

Regional data are a public service, not a personal sensor

Do not combine data.gov.sg coordinates with a Google map and falsely place a pollution instrument at someone’s HDB block. Metadata helps depict reporting regions but is not proof of the exact station position. If a school project wants a Punggol map, it can show Punggol as a learning location and separately show which official reporting-region value it used. This is good scientific source attribution and avoids the illusion of hyperlocal precision.

Open data licensing and attribution

Reuse is allowed, but follow the conditions

Singapore’s Open Data Licence version 1.0 allows broad personal and commercial reuse of eligible data, including derived analyses, subject to its terms. It requires conspicuous acknowledgement of the dataset’s source and a link to the licence. It also prohibits implying government endorsement of your product. A family website or school dashboard should not use the NEA logo or the title ‘Official Punggol Haze Warning App’ in a way that makes an independent experiment look like an authorised government service.

A concrete attribution for a project

A good notice could say: ‘Contains information from National Environment Agency PM2.5 data accessed on [date] via data.gov.sg, under the Singapore Open Data Licence version 1.0’, with links to the dataset and licence. Update the date when actual new data are used. A blog article linking to an API as a source is different from redistributing data through a public live dashboard, which calls for carefully implementing the full licence conditions. Read the original terms; never invent a blanket exemption for student projects.

What about an AI haze predictor?

Train and test with appropriate time periods

A student may feed historic public data into a simple model to predict future pollution categories. That project can be educational, but it must separate past training periods from future test periods to prevent data leakage. A model that ‘predicts’ a value after reading that same timestamp in its input has demonstrated memorisation rather than forecasting skill. Models should report accuracy during difficult high-pollution days, not just clean days when predicting Normal is easy.

Do not misrepresent the result

A personal model built from public PM2.5 data is not the government’s official next-day PSI forecast or a licensed medical device. If the model says ‘90% sure tomorrow is clear’, the family should still use official NEA guidance and current observations. A model may miss new fires, wind shifts and rainfall. The Punggol AI haze forecasting article explains transport models and uncertainty separately; this API guide supplies the practical underlying data literacy.

Understand privacy and location carefully

These datasets do not require household tracking

NEA’s five region metadata entries describe public ambient measurements. An app does not need a student’s precise home address, child identity or continuous GPS tracking simply to display those values. Avoid collecting private user coordinates unless a legitimate use and appropriate consent justify it. A school project can operate with the public regional labels and timestamps alone.

Keep demo code free of secrets

Never store API keys, account credentials, private student records or school messaging tokens inside published code blocks. The examples here intentionally use publicly documented endpoints with no credentials. If a developer wants to integrate with classroom systems, the school should approve data handling separately. Environmental education should not become a reason to create an unnecessary database of children’s locations or personal health.

Troubleshooting real API errors

HTTP 429 is not a pollution reading

If the server returns 429 Too Many Requests, slow down and follow the documented rate limits; do not interpret 429 as a PM2.5 concentration. A 400 request error may mean the date format or other parameter is invalid. A 404 may mean the requested data are unavailable. JSON may also return an empty items array or a documented error field even when the connection succeeded. Check the structure before indexing into it.

Never replace missing data with zero

A student who fills missing readings with zero without explanation may bias a graph downward and make the air appear cleaner than was observed. Show ‘missing’ and explain the cause when known. For dates and time zones, keep the original timestamps and standardise carefully before drawing comparisons. If a public safety decision is involved, do not rely on a broken educational script: direct readers to the actual NEA official public page.

Three practical Punggol questions for a coding lesson

Question one: what does the endpoint return?

Ask the learner to fetch the latest PM2.5 item and list its keys, timestamp, updatedTimestamp and each reporting region. They should be able to explain why the record is not a street-level sensor at Punggol Waterway Point. For a worked example they can choose the ‘north’ dictionary entry but must label it North region, not exact Punggol concentration. A source-aware table is more useful than a decorative map with fabricated pin precision.

Questions two and three: what is missing and what is not predictable?

Ask whether the /psi response includes a current reported 24-hour PSI sub-index and whether that is tomorrow’s official forecast. The correct answer is that the API provides current PSI readings; the next-day forecast must be obtained separately from the authoritative forecast source. Then ask what should appear on a dashboard if no latest reading is available. The correct answer is a conspicuous unavailable-data state, not a green Normal badge or a randomly guessed replacement. These habits teach reliability beyond Python.

A seven-step educational project plan

Build small and label everything

Step one: document the NEA dataset and v2 endpoint. Step two: make one request with a timeout. Step three: inspect the JSON data.items and timestamps. Step four: select and label the actual reporting region. Step five: graph a small historical series when complete. Step six: annotate missing observations and the difference from forecast. Step seven: publish a student explanation with the required government data attribution and a link to official NEA advice.

Finish with a quality checklist

Confirm that no live numeric value is hardcoded; that units match the pollutant; that dates use Singapore time; that no consumer app AQI is passed off as NEA PSI; that requested pages are retrieved fully where needed; and that errors never become zero. Check that the page says clearly it is an educational dashboard, not official emergency information. A small accurate chart gives readers more value than a complicated AI warning system built on misunderstood fields.

What to label in a haze data dashboard

FieldMeaningCorrect display label
pm25_one_hourlyOne-hour PM2.5 concentrationRegion, µg/m³, observation time
psi_twenty_four_hourlyCurrent 24-hour PSI indexRegion, PSI, observation time
regionMetadataReporting region labels and map metadataRegion reference, not a doorstep monitor
timestampObservation timeFormatted in Singapore time
updatedTimestampData publication/update timeLast update, different from observation
paginationTokenAdditional data pages availableImplementation detail, not a pollutant

Frequently asked questions about Singapore’s haze APIs

What is the official Singapore PM2.5 API URL?

The NEA dataset’s public v2 real-time endpoint is https://api-open.data.gov.sg/v2/real-time/api/pm25. A normal GET without a date requests the latest reading. The dataset documentation explains the response structure, region metadata, optional date filter and rate limits.

Does the PM2.5 API give exact Punggol measurements?

No. It provides readings for five large Singapore reporting regions. A reading for ‘north’ is not a certified concentration inside a home at Punggol Waterway Point or a particular bus stop. Use official regional labels without inventing hyperlocal sensor locations.

Is data.gov.sg PSI the same as the forecast for tomorrow?

No. The /psi endpoint contains current PSI and sub-index readings including psi_twenty_four_hourly. The government next-day 24-hour PSI forecast is a separate public planning product available through NEA’s official haze information. Don’t label current API data as a forecast.

Can I fetch a fixed date?

Yes. The PM2.5 documentation accepts a YYYY-MM-DD date parameter or a datetime in the documented format for historical queries. Handle pagination where a date returns more records than a single response, and identify missing observations rather than filling them with zero.

Do I need an API key?

Basic public calls can work without one, while an optional x-api-key header is documented for higher rate limits and support. Do not paste secret keys in a WordPress article or public code. If rate limited, slow down and check the current developer documentation.

What does HTTP 429 mean?

It means too many requests under the current rate limit, not that pollution is 429. HTTP errors, empty data and stale timestamps require separate handling. Display an unavailable-data message rather than an invented safe air-quality number.

What unit is pm25_one_hourly?

The data.gov.sg PM2.5 dataset specifies micrograms per cubic metre (µg/m³). Those values are concentrations, not Singapore’s PSI index. Always label the reporting region and observation time as well as the unit.

Can I create a Punggol map of the regional data?

You can create an educational map using source-attributed public regional metadata, but avoid labelling a metadata point as the exact location of a Punggol sampling instrument or implying a street-level reading. A proper caption says which NEA reporting region is shown and explains coverage limitations.

Can my school project publish the data?

The Singapore Open Data Licence allows broad reuse subject to its terms, including source acknowledgement and a link to the licence, and prohibits implying official endorsement. Check the actual licence and classroom data policies before redistribution.

Can I use this API to tell parents when to send kids outdoors?

An educational script can display official public readings, but decisions require MOH’s actual health advice, individual medical needs, planned exertion and any school instructions. Don’t claim that your program overrides NEA’s dashboard or authorises a school closure. Link readers directly to official current information.

Official API documentation and open data reuse rules

Fact-checked 18 October 2026 against the published v2 API specification and response structure. The scripts are educational examples; API schemas, rates and current measurements can change. The official NEA dashboard remains the authoritative public information source. The example code does not retrieve a Punggol-specific station, claim to forecast future PSI or provide individual health clearance. Include data.gov.sg attribution and licence terms for any reused live data.

Continue from here: Start Here · Tuition · Education · Pathways · Parenting 101 · All Site Routes

eduKate Punggol

Contact

83 Punggol Central, Singapore 828761

edu|Kate Bukit Timah

8 Fourth Avenue, Singapore 268674

By Appointment +65 8823 1234
admin@edukatesg.com

Email Us

When a child finally understands, school becomes less frightening and the future opens wider. Email us for the latest schedules and fees.

← 返回

感谢您的回复。 ✨

了解 eduKate Punggol 的更多信息

立即订阅以继续阅读并访问完整档案。

继续阅读