
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.

𝗧𝗵𝗲 𝟮 𝗵𝗼𝘂𝗿𝘀 𝟰𝟯 𝗺𝗶𝗻𝘂𝘁𝗲𝘀, 𝗺𝗶𝗻𝘂𝘁𝗲 𝗯𝘆 𝗺𝗶𝗻𝘂𝘁𝗲
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.

What JalNetra does
plaintext
RIVER FORECASTS|v1. WATCH 681 river points across India, every 3 hours|v2. PREDICT which of 291 villages the water reaches, and when| (now, +3, +6, +12, +24 hours)v3. DECIDE a person reviews the map and the advisory| and approves or rejects. Nothing is automaticv4. 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.

plaintext
EventBridge Scheduler every 3 hours|vLambda: river monitor scores 681 river points|vAmazon S3 one snapshot of today's status|vCloudFront + WAF serves the live map to everyone|vOperator 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:

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|vLambda 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 placevStep Functions announce, wait 90 s, escalate| (a call is never retried)vVillage head's phone rings

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 TRANSACTION1. lock the operator row2. check cooldown + daily caps3. write a UNIQUE ledger row|limit reached --> HTTP 429, approval untouched|vDISPATCH ONE CALL(number from Secrets Manager only)|vSTEP FUNCTIONS: announce,wait 90 s, escalate. Never retries

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.25inputs: 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
- 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.
- 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.
- Bedrock in Mumbai needed a regional inference profile. The
apac.Nova Lite profile worked where the plain model id did not.
- 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: https://d1oi8xa605dsj6.cloudfront.net
How it runs on AWS: https://d1oi8xa605dsj6.cloudfront.net/aws-flow
Code: https://github.com/Swastikkkkk/jalnetra
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article