TREM real-time station data
trem.rts.v1 is the real-time snapshot of ExpTech TREM-net (the TREM seismic network). One message every 0.5 seconds (2 Hz) lists every station that sent data in the last 5 seconds, with its continuous seismic intensity, peak ground acceleration (PGA), and whether it is part of an earthquake, plus earthquake sources from the last 240 seconds. Use it to draw a live intensity map and to show which stations are shaking.
How to connect, decode, and reconnect is in SSE connection.
TREM data notice
TREM data are automated, real-time observations from ExpTech's own station network (TREM-net). They are not official earthquake information. In Taiwan, the authority on earthquake information is the Central Weather Administration (CWA) of the Ministry of Transportation and Communications, and information published by the CWA always prevails. In this notice, TREM data means TREM-net observations and detections. TREM EEW is provided only to specific users who have ExpTech's individual approval or a contract, and its use is governed by Article 4-1 of the Terms of Service.
When you use TREM data, you must:
- Defer to the CWA.Earthquake reports, earthquake early warnings, seismic intensity and tsunami information published by the CWA prevail. Where TREM data differ from official information, follow the official information.
- Label it as unofficial.Wherever you present TREM data, show the data source together with the statement "Unofficial information; the Central Weather Administration's releases prevail."
- Comply with the Meteorological Act.Under Article 17(1) of Taiwan's Meteorological Act, forecasts and warnings of earthquakes are issued exclusively by the central meteorological authority, and Article 18 does not allow other agencies, schools, organizations or individuals to issue earthquake forecasts or any warnings to the general public; providing them to specific users is not restricted. Violations are subject to a fine of NT$200,000 to NT$1,000,000 under Article 24(2), which may be imposed for each violation.
- Never use it unlawfully.Do not use TREM data to predict earthquakes or to issue earthquake or tsunami warnings, and do not spread unverified earthquake information. Spreading rumours or false information about disasters that harms the public or others is punishable under Article 53(3) of the Disaster Prevention and Protection Act by up to three years of imprisonment, detention, or a fine of up to NT$1,000,000. Spreading rumours that may disturb public peace is punishable under Article 63(1)(5) of the Social Order Maintenance Act by detention of up to three days or a fine of up to NT$30,000.
- Know its limits.TREM observations are automated and not reviewed by staff. Noise, device faults or network delays can cause false detections, missed events or delays. Never use them as the sole basis for evacuation, closures or any other safety decision.
Data license
Section titled “Data license”AttributionData: ExpTech Studio TREM (exptech.dev) · Non-commercial use · Unofficial information; the Central Weather Administration's releases prevail
Where to show it, examples and commercial-use requests: Data licensing and attribution.
Authentication
Section titled “Authentication”No token is required (public topic). If you send a valid token, usage is recorded under the permission trem.rts, and going over the quota does not disconnect the stream. See SSE connection: Authentication.
Subscribe
Section titled “Subscribe”- Multiplexed entry:
/api/v1/trem/sse?topics=trem.rts.v1, event nametrem.rts.v1. - Single-topic path:
modesleep: send a snapshot only when at least one station has alert. live: send every snapshot, every 0.5 seconds.
tokenAPI Token (optional). Prefer the Authorization: Bearer header.
curl -N --compressed "https://api.lb.exptech.dev/api/v1/trem/sse/rts"curl -N --compressed "https://api.lb-tpe1.exptech.dev/api/v1/trem/sse/rts"curl -N --compressed "https://api.lb-khh1.exptech.dev/api/v1/trem/sse/rts"const res = await fetch("https://api.lb.exptech.dev/api/v1/trem/sse/rts");if (!res.ok) throw new Error(`HTTP ${res.status}`);
// text/event-stream:逐段讀取const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();for (;;) { const { value, done } = await reader.read(); if (done) break; console.log(value);}const res = await fetch("https://api.lb-tpe1.exptech.dev/api/v1/trem/sse/rts");if (!res.ok) throw new Error(`HTTP ${res.status}`);
// text/event-stream:逐段讀取const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();for (;;) { const { value, done } = await reader.read(); if (done) break; console.log(value);}const res = await fetch("https://api.lb-khh1.exptech.dev/api/v1/trem/sse/rts");if (!res.ok) throw new Error(`HTTP ${res.status}`);
// text/event-stream:逐段讀取const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();for (;;) { const { value, done } = await reader.read(); if (done) break; console.log(value);}import requests
with requests.get( "https://api.lb.exptech.dev/api/v1/trem/sse/rts", stream=True, timeout=30,) as res: res.raise_for_status() for line in res.iter_lines(decode_unicode=True): if line: print(line)import requests
with requests.get( "https://api.lb-tpe1.exptech.dev/api/v1/trem/sse/rts", stream=True, timeout=30,) as res: res.raise_for_status() for line in res.iter_lines(decode_unicode=True): if line: print(line)import requests
with requests.get( "https://api.lb-khh1.exptech.dev/api/v1/trem/sse/rts", stream=True, timeout=30,) as res: res.raise_for_status() for line in res.iter_lines(decode_unicode=True): if line: print(line)text/event-stream; data is base64(gzip(JSON))
retry: 3000
event: infodata: {"location":"lb-tpe1"}
data: H4sIAAAAAAAC/02OywrDIBRE...The token is invalid, expired, or revoked
invalid tokenMessage format
Section titled “Message format”Each decoded data is one JSON object:
{ "source": "core-tnn1", "ts": 1790619680000, "stations": { "117825C": { "i": 0.0, "pga": 0.61 }, "11DFDBC": { "i": 0.4, "pga": 0.87, "alert": 1 }, "1A50B18": { "i": 3.3, "pga": 4.05, "alert": 1 }, "1C086D8": { "i": -3.0 } }, "eq": [[23.94, 121.52, 32, 1790619645]]}| Field | Type | Description |
|---|---|---|
source | string | Name of the node that published this snapshot, for example core-tnn1. It changes when the node switches. |
ts | int | Snapshot time, Unix milliseconds (server time, corrected with NTP). |
stations | object | Station snapshots. The key is the station device ID (for example 11DFDBC). Only stations that sent data in the last 5 seconds are included. |
<裝置 ID>.i | number | Instrumental seismic intensity, 1 decimal place. It can be negative. When there is no signal it is fixed at -3.0. See the table below for the intensity level. |
<裝置 ID>.pga | number | Peak acceleration in this 0.5 seconds, in gal (cm/s²), the three-axis vector sum, 2 decimal places. The field is omitted until a value has been measured. |
<裝置 ID>.alert | int | Always 1, meaning this station is part of an earthquake in progress. When it is not, the field is omitted (it is never 0). |
eq | array | Earthquake sources from the last 240 seconds. Each item is [latitude, longitude, depth (kilometers), origin time (Unix seconds)]. The field is always present. It is [] when there is no earthquake. |
Intensity conversion
Section titled “Intensity conversion”Bounds for turning i into an intensity level:
i |
< 0.5 | 0.5–1.5 | 1.5–2.5 | 2.5–3.5 | 3.5–4.5 | 4.5–5.0 | 5.0–5.5 | 5.5–6.0 | 6.0–6.5 | ≥ 6.5 |
|---|---|---|---|---|---|---|---|---|---|---|
| Intensity | 0 | 1 | 2 | 3 | 4 | 5 lower | 5 upper | 6 lower | 6 upper | 7 |
Each range includes the lower bound and excludes the upper bound. Do not convert pga through an intensity formula. Read intensity from i.
Station coordinates
Section titled “Station coordinates”The keys of stations are station device IDs. For the latitude, longitude, and township code of a device ID, use ExpTech’s public station list station.csv (id is the device ID, lat and lon are the coordinates, and code is the township code).
Advanced example
Section titled “Advanced example”A browser receives live-mode snapshots on the single-topic path. Data events have no name, so use onmessage, decode, and turn i into an intensity level.
async function decodeData(b64) { const bytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)); const stream = new Blob([bytes]).stream().pipeThrough(new DecompressionStream("gzip")); return await new Response(stream).text();}
function toLevel(i) { const labels = ["0", "1", "2", "3", "4", "5弱", "5強", "6弱", "6強", "7"]; if (i < 4.5) return labels[Math.max(0, Math.round(i))]; return labels[Math.min(9, 5 + Math.floor((i - 4.5) / 0.5))];}
const es = new EventSource("https://api.lb.exptech.dev/api/v1/trem/sse/rts?mode=live");es.onmessage = async (e) => { const rts = JSON.parse(await decodeData(e.data)); for (const [id, s] of Object.entries(rts.stations)) { if ("alert" in s) console.log(id, `intensity ${toLevel(s.i)}`, s.pga !== undefined ? `${s.pga} gal` : ""); }};- Use field presence for
alertandpga. A station that is not part of an earthquake has noalertfield. A station that has not measured a peak acceleration yet has nopgafield. The value is never0. alertstays on for a while. It disappears only after every earthquake that station joined has ended, andihas stayed below 0.5 for 15 seconds in a row.ican be negative. When a station is very quiet (effective acceleration below about 0.34 gal),iis negative. Treat-0.0as 0.-3.0is the fixed value for “no signal”. It is not a measurement.- Stations appear and disappear. A station with no data in the last 5 seconds is not in
stations. It comes back once it sends data again. Missing from the list means “nothing received for these few seconds”. It does not mean intensity 0. - Every message is a full snapshot. Replace the previous one with the new one. Snapshots have no sequence number. If you miss one, use the next.
- Nothing is replayed. After a disconnect and reconnect, you start from the latest snapshot.
- Time units differ.
tsis Unix milliseconds. The origin time insideeqis Unix seconds. - Traffic. Live mode is 2 messages per second, and each one includes every station (several KB per message after decompression). Use the default sleep mode when you only need data during an earthquake.
