Oref Alert Proxy

March 24, 2026 · View on GitHub

Local relay proxy for Israel Homefront Command (Pikud HaOref) real-time alert data.

Why This Exists

Israel's Homefront Command publishes real-time rocket, UAV, and threat alerts through an unofficial JSON endpoint. There is no official public API — the data comes from the same internal feed that powers the Oref website and the official HFC app.

If you're building anything that consumes this data — a dashboard, a Telegram bot, a home automation trigger, a desktop notification app — you need to poll the endpoint every few seconds. The problem is that if you run multiple services, each one polls independently, which means:

  • Redundant traffic to the same endpoint
  • Inconsistent state — each service may see a slightly different snapshot depending on timing
  • Harder to manage — polling logic, error handling, and BOM-stripping duplicated everywhere

This proxy solves that by polling once and serving the data locally via a simple HTTP API. All your downstream services read from the proxy instead.

┌────────────────────┐          ┌──────────────────┐
│   Oref (Pikud      │  ──3s─▶  │  This Proxy      │
│   HaOref endpoint) │          │  (port 8764)     │
│   Geo-restricted   │          │  Runs in Israel  │
└────────────────────┘          └────────┬─────────┘

                           ┌─────────────┼─────────────┐
                           ▼             ▼             ▼
                     ┌──────────┐ ┌──────────┐ ┌──────────┐
                     │Dashboard │ │Telegram  │ │Home      │
                     │          │ │Bot       │ │Automation│
                     └──────────┘ └──────────┘ └──────────┘

Design Philosophy

This is a dumb relay. It passes through whatever Oref returns, verbatim:

  • No category remapping — if Oref says category 10, you get category 10
  • No alert persistence — when alerts disappear from Oref's response, they disappear here too
  • No interpretation — shelter instructions, early warnings, and drills are passed through as-is
  • No authentication — it's a local service, bind it to localhost or your LAN

Interpretation is the consumer's job. A dashboard might want to color-code by category and track alert duration. A bot might only care about threshold crossings. The proxy doesn't make those decisions.

API Endpoints

EndpointDescription
GET /api/alertsCurrent active alerts (polled every POLL_INTERVAL)
GET /api/alerts/rawRaw Oref response text for consumers that want to parse it themselves
GET /api/historyToday's full alert history (polled every HISTORY_INTERVAL)
GET /api/healthHealth check
GET /api/statusPoller stats — poll count, error count, timing, current alert count

Response Formats

GET /api/alerts

{
  "alerts": [
    {
      "data": "תל אביב - מרכז העיר",
      "cat": 1,
      "title": "ירי רקטות וטילים",
      "desc": "",
      "alertDate": "2026-03-10 14:22:05"
    }
  ],
  "timestamp": 1710115325.4
}

When there are no active alerts, the array is empty:

{
  "alerts": [],
  "timestamp": 1710115328.1
}

GET /api/status

{
  "uptime_seconds": 3600.0,
  "alerts": {
    "poll_count": 1200,
    "error_count": 0,
    "last_poll_ago": 1.2,
    "last_nonempty_ago": null,
    "current_count": 0,
    "poll_interval": 3
  },
  "history": {
    "poll_count": 60,
    "error_count": 0,
    "last_poll_ago": 12.4,
    "current_count": 379,
    "poll_interval": 60
  }
}

Oref Alert Format Reference

The alert objects come directly from Oref. Key fields:

FieldTypeDescription
datastringArea name in Hebrew (e.g., "ירושלים - דרום")
catintAlert category number
titlestringAlert type description in Hebrew
descstringAdditional description (often empty)
alertDatestringTimestamp in YYYY-MM-DD HH:MM:SS format

Alert Categories

CategoryMeaningSeverity
1–4Rockets & MissilesActive threat
6Unauthorized AircraftActive threat
7Hostile Aircraft IntrusionActive threat
8InfiltrationActive threat
9TsunamiActive threat
10EarthquakeActive threat
11RadiologicalActive threat
12Hazardous MaterialsActive threat
13All ClearEvent ended
14Pre-WarningAlert expected shortly
15–28DrillsNot real alerts

Note: Oref sometimes sends single-object responses (instead of an array) for special messages like shelter instructions or early warnings. The proxy normalizes these into a single-element array, but does not remap the category. Consumers should handle categories 13 (all-clear) and 15–28 (drills) appropriately.

Setup

git clone https://github.com/danielrosehill/Oref-Alert-Proxy.git
cd Oref-Alert-Proxy
docker compose up -d

Direct

pip install httpx fastapi uvicorn
python server.py

Environment Variables

VariableDefaultDescription
POLL_INTERVAL3Active alert poll interval in seconds
HISTORY_INTERVAL60History poll interval in seconds
HOST0.0.0.0Bind address
PORT8764Listen port

Geo-Restriction

The Oref API is geo-restricted to Israeli IP addresses. This proxy must run from within Israel — either on a machine with an Israeli IP, or behind a VPN/proxy with an Israeli exit node. Non-Israeli IPs will get empty or error responses.

Resource Usage

Polling every 3 seconds sounds aggressive, but it's extremely lightweight:

ResourceEstimateContext
Requests/day~28,800One GET every 3s
Response size (quiet)0 bytesEmpty string when no alerts
Response size (alerts)1–50 KBSmall JSON array
Bandwidth/day (quiet)~30–100 MBMostly TLS overhead
Bandwidth/day (mass attack)Up to ~500 MBSustained large payloads
CPU/day~30 seconds cumulativeJSON parse + cache update
RAM~30–50 MBPython + FastAPI + httpx connection pool

For comparison, a single browser tab on a news website generates more daily traffic than this proxy. The official Oref website itself polls at the same 3-second interval — this is the intended consumption pattern.

Consuming the Proxy

Python

import httpx

resp = httpx.get("http://localhost:8764/api/alerts")
alerts = resp.json()["alerts"]

for alert in alerts:
    area = alert["data"]
    category = alert["cat"]
    print(f"{area}: category {category}")

JavaScript

const resp = await fetch("http://localhost:8764/api/alerts");
const { alerts } = await resp.json();

alerts.forEach(alert => {
    console.log(`${alert.data}: category ${alert.cat}`);
});

curl

# Current alerts
curl -s http://localhost:8764/api/alerts | jq .

# Poller status
curl -s http://localhost:8764/api/status | jq .

License

MIT