AWS Builder Center
2 Hours 43 Minutes Too Late: Building JalNetra, an AI Flood Early-Warning System

2 Hours 43 Minutes Too Late: Building JalNetra, an AI Flood Early-Warning System

On 26 August 2026, a glacier collapse in Nepal sent a flood 226 km to the Indian border, and the first gauge alarm came 2 hours 43 minutes later. JalNetra watches 681 rivers, predicts which villages the water will reach, and lets a person approve a Hindi warning call to the village head. I built it on AWS with Lambda, Bedrock, Polly and Step Functions. IAM, regions and cost taught me the most.


"An ounce of prevention is worth a pound of cure."— Benjamin Franklin, on preventing fires in Philadelphia (Pennsylvania Gazette, 1735)
“When the well’s dry, we know the worth of water.”
On 26 August 2026 a glacier collapsed above Langtang in Nepal. Seven minutes later the flood had already travelled 20 km. It ran 226 km to the Indian border.
The water was not the only failure. The silence was. The first alarm on the gauge network came 2 hours 43 minutes after the collapse, and by then the gauges nearest the source had gone dark while still reading normal.
We built JalNetra (जल water + नेत्र eye: the eye on the water) to close that gap. It runs entirely on AWS.
JalNetra glacier story screen on Sentinel-2 satellite imagery, showing the flood path from Langtang Lirung glacier with the Rasuwagadhi, Syabrubesi and Betrawati gauges marked offline, and the stats 08:50 first gauge lost, 11:20 first alarm, 2 h 43 min after the collapse.


𝗧𝗵𝗲 𝟮 𝗵𝗼𝘂𝗿𝘀 𝟰𝟯 𝗺𝗶𝗻𝘂𝘁𝗲𝘀, 𝗺𝗶𝗻𝘂𝘁𝗲 𝗯𝘆 𝗺𝗶𝗻𝘂𝘁𝗲

TIME
What happened
08:37
Glacier collapse at Langtang Lirung
+7 min
The flood has already travelled about 20 km
Next
The gauges near the source go dark, still reading normal. No alarm is raised
11:20
First alarm on the gauge network, 2 h 43 min after the collapse
Evening
Water crosses into India at Valmikinagar
Villages downstream had hours they were never told about. The problem wasn't the size of the flood. It was the communication gap.
JalNetra glacier story screen on satellite imagery showing the river crossing from Nepal into India at Valmikinagar barrage, with low villages along the Gandak marked in orange, and the stats 226 km glacier to border, 1.04–1.42 lakh cusecs and 15 low villages shown.


What JalNetra does

plaintext
RIVER FORECASTS
|
v
1. WATCH 681 river points across India, every 3 hours
|
v
2. PREDICT which of 291 villages the water reaches, and when
| (now, +3, +6, +12, +24 hours)
v
3. DECIDE a person reviews the map and the advisory
| and approves or rejects. Nothing is automatic
v
4. WARN one Hindi voice call, a spoken advisory,
a walking route to the safe place
  • Watch. Every river is judged against its own record, not one national threshold
  • Decide. Opening an alert never calls anyone. Only Approve does

How the live map decides

Every 3 hours a small program checks 681 river points across India. A flow that is a flood on one river is a normal day on another, so each river is compared against its own record, not one national number.
Status
Rule (7-day forecast peak)
DANGER
At or above the river's maximum
WARNING
At or above the river's 90th percentile
RISING
At least 1.25 × today's flow and above the river's median
NORMAL
Everything else
If a river's flow is below a minimum, it is forced back to NORMAL, so a trickle never raises a flag.
JalNetra live map of India on satellite terrain, with the monitored river lines and points, a panel summarising the river network (7 above 2025 peak, 4 high, 0 rising fast, 670 normal), and an alerts panel listing exercise alerts that need a person's approval.

plaintext
EventBridge Scheduler every 3 hours
|
v
Lambda: river monitor scores 681 river points
|
v
Amazon S3 one snapshot of today's status
|
v
CloudFront + WAF serves the live map to everyone
|
v
Operator opens an alert Opening never calls anyone

How it runs on AWS

Every stage uses a managed service, and nothing runs on a server we have to patch. The scene below shows the whole data flow. You can open it live and click through each step:
The same architecture as a 3D scene: every service is a mailbox, and every piece of data is an envelope travelling between them.

Every service is a mailbox. Every piece of data is an envelope.
Service
Job in JalNetra
EventBridge Scheduler + Lambda
Every 3 hours the monitor reads river forecasts and writes one snapshot
S3 + CloudFront + WAF
The website, the snapshot and cached Hindi audio, behind managed rules and rate limits
API Gateway + Lambda
Throttled public API, approvals and helpers
RDS PostgreSQL + Secrets Manager
Call ledger, per-alert and daily limits, the one allowed destination number
Amazon Bedrock (Nova Lite)
Fact-bound Hindi and English advisory drafts, always reviewed by a person
Amazon Polly (Kajal)
The spoken Hindi advisory, cached in S3
Amazon Location Service
Real walking routes to the safe place
Amazon Rekognition
First-screen check of a citizen's flood photo
Step Functions + SNS + SQS
After approval: wait, check, escalate. A call is never retried
CloudWatch + CDK
Dashboard, alarms and infrastructure as code

From a river reading to a ringing phone

  • Monitor. EventBridge wakes a Lambda that scores every river point against its own record. One snapshot goes to S3 and CloudFront serves it.
  • Approve. The operator opens an alert and sees the villages, the timing and the advisory draft. Opening an alert never calls anyone. Only Approve does.
  • Voice and route. Polly speaks the Hindi advisory, Location Service finds the walking route, and the village head gets a link that opens the route in 3D, with an AR arrow on the phone.
plaintext
PERSON APPROVES AN ALERT
|
v
Lambda API ---------> Amazon Bedrock writes the Hindi + English
| warning from the flood facts
|---------> Amazon Polly turns it into spoken Hindi
| (cached in S3)
|---------> Location Service finds the walking route
| to the safe place
v
Step Functions announce, wait 90 s, escalate
| (a call is never retried)
v
Village head's phone rings
After a person approves, Bedrock drafts the warning from the flood facts, Polly speaks it in Hindi, and Location Service finds the walking route.

Service
What it does
Guardrail
Amazon Bedrock (Nova Lite)
Drafts the advisory in Hindi and English
Uses only the facts it is given, and a person reviews every draft
Amazon Polly (Kajal)
Speaks the advisory in Hindi
The same text is cached in S3, so it is only generated once
Amazon Location Service
Finds the walking route
Real routes to the safe place
Amazon Rekognition
First-screen check of a citizen's flood photo
A first check only, never a decision

Safety by design

A warning system that can phone people has to be hard to misuse. The browser can only ask. The server decides.
Rule
How it works
No call without a human
Only an explicit Approve can reserve a call. Opening an alert never does
Nobody picks the number
No request can carry a phone number. The destination is stored in Secrets Manager
One attempt per alert
A unique ledger row in RDS PostgreSQL. A call is never retried
Limits
A cooldown, 3 calls per session and a daily cap, all enforced on the server
Honest status
"Dispatched" is never shown as "answered". Failed or unknown outcomes stay locked
Exercises are labelled
Exercise data is marked EXERCISE everywhere and kept apart from real incidents
plaintext
ALERT RAISED --> OPERATOR REVIEWS --> APPROVE?
|
no ---------------+--------------- yes
| |
nothing sent ONE DATABASE TRANSACTION
1. lock the operator row
2. check cooldown + daily caps
3. write a UNIQUE ledger row
|
limit reached --> HTTP 429, approval untouched
|
v
DISPATCH ONE CALL
(number from Secrets Manager only)
|
v
STEP FUNCTIONS: announce,
wait 90 s, escalate. Never retries
A simulated flood and its evacuation route. There is no flood where we tested, so the water here is a made-up one.

The village head gets a link that opens this route in 3D, with an AR arrow on the phone.

How good is the model? Honest numbers

The village score is a small logistic model on four things: the 72-hour peak river flow, the village's height above the river, its height relative to its surroundings, and its distance from the river. A village is flagged when the probability reaches 0.25.
plaintext
flag a village when P(flooded) >= 0.25
inputs: ln(Q72max / 4000), height above river, height vs surroundings, distance
Result
Value
Flooded villages caught
56% and 66% (two radar dates)
Ranking skill (AUC)
0.72 to 0.75 (0.5 is a coin flip)
Flagged villages that were really flooded (29 Sept)
36%, with 70 false alarms
This is an early-warning screen, not a guarantee. Radar only sees open water, so flooding under trees and from local rain is missed. We would rather say that plainly than oversell it.

What surprised us

  1. The free weather API rate-limited our own site. Hundreds of points at once meant HTTP 429s. A cached proxy on Lambda plus one shared snapshot in S3 fixed it.
  1. AWS WAF cannot attach to an HTTP API. The website sits behind WAF on CloudFront. The API relies on stage throttling and server-side limits instead.
  1. Bedrock in Mumbai needed a regional inference profile. The  apac.  Nova Lite profile worked where the plain model id did not.
  1. Amazon Translate needed a subscription we did not have, so Hindi comes from Bedrock and Polly.

What I learned

I came in knowing AWS as a list of service names. I'm leaving knowing that the services are the easy part. The real engineering is in the decisions around them: what runs on a schedule, what the AI is allowed to say, and what a human must approve. A system that can phone a village at 3 a.m. should be built like it.

What's next

Subscribe village heads and district officers to alerts through SNS
  • Replace the single demo phone with a verified contact list per district
  • A second app, Oasis Builder, for prevention
Try it live: https://d1oi8xa605dsj6.cloudfront.net

Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article