Skip to main content
Back to all posts
Oct. 20268 min read

My condo flooded twice in seven months. In my test, Ring's camera saw the water and recorded nothing, so I built the app that makes it record.

With a real Ring flood sensor in a bowl in front of a real Ring Indoor Cam, the Ring app's own history shows 0 recordings in the 3 minutes after the sensor found water. Watermark opens a live session the moment the sensor fires, so the camera records, and builds an evidence pack for the insurer. First Ring frame: 6.85 s after the sensor, median of 10 runs through the real Ring API.

Amazon Developer HackathonRing Partner APIAWSAmazon RekognitionAWS IoT CoreOpen sourceSmart homeHackathon
I wrote this post for Build, Ship, Shape: Amazon Developer Hackathon (October 2026, Ring track, with the AWS Builder and Open Source mini-challenges), and built Watermark for the same submission. Source at github.com/JonathanSolvesProblems/watermark, and the Ring client it is built on at github.com/JonathanSolvesProblems/ringwire (also on PyPI). A read-only replay of the recorded runs is at watermark.jonathansolvesproblems.com while judging runs.
The claim in one sentence: graded by Ring's own timestamps, the first Ring frame arrived 6.85 s after the sensor event (median of 10 runs through the real Ring API, range 6.6 to 11.2 s), and graded by the Ring app's own event history, Ring alone recorded 0 motion events in the 3 minutes my real camera watched water rise in front of it. Not claimed: a real flood. The sensor event in the 10 runs is simulated, because Ring's Developer Playground has no sensors, and Watermark never names a cause.
The Watermark home page: the headline "The camera goes to the water when the sensor finds it" beside a phone photo of my basement on 20 June 2026, with water across a newly laid wood floor under a window.
My basement, 20 June 2026, on a floor laid the week before. A phone photo, because nothing was recording.

Two floods, and two phone videos

My condo flooded on December 5, 2025, from a badly sloped drain pipe and a toilet leak. I rebuilt. On June 20, 2026, one week after the repairs finished, the city sewer backed up into more than 60 units, and in mine water also came in through the foundation, gaps beside the electrical panel and a basement window. The mitigation company's report said heavy rain, and floated my backyard shed as the cause. The only reason that didn't stick was two phone videos I took while it was happening, because I happened to be home. Whether that water was sewer backup or clean rainwater decided which coverage limit applied. Next time I won't be home.

Two photos side by side: an opened ceiling exposing black drain pipes, dated December 5, 2025, and a water-streaked basement wall beside a closet door, dated June 20, 2026.
Two floods in my condo, the second one week after the repairs from the first finished.

Ring already knows. It just doesn't record.

A Ring Flood & Freeze sensor tells your phone there is water. What it does not do is make a camera record it. I tested that with my real devices: my sensor in a bowl, my Indoor Cam pointed at it, water poured in slowly. The Ring app alerted at 8:35 PM. Its own event history shows nothing after 8:27, and still nothing at 8:38. Slowly rising water does not trip motion detection, so the one camera that saw it kept nothing. That is the gap Watermark fills: when the sensor fires, it opens a live session on the camera that already sees the room, which forces it to record, and keeps pulling frames with Ring's own time until the sensor reads dry.

A large 8:38 PM beside a screenshot of the Ring app's Event History for Flood Cam: the latest entry is a motion event at 8:27 PM showing a white bowl, with nothing recorded after it.
With Watermark off: Ring alerted my phone at 8:35 PM, and the camera's own history shows nothing after 8:27 while water sat in view.

Ring's frames, with Ring's time

Every frame in a pack comes from a Ring Partner API live session, downloaded with Ring's own X-Media-Timestamp burned in, and any frame further than Ring's documented 10 s tolerance from the request is flagged. Measured on Ring's Developer Playground through the real API, the first frame arrived 6.85 s after the sensor event, median of 10 runs, range 6.6 to 11.2 s. The camera in those runs is the Playground's doorbell, which is why the demo frames show a bird feeder in the snow rather than a basement. Webhooks are written to disk before anything else, because Ring keeps no history for sensor events, and a reconcile loop polls status so a missed webhook can neither start nor end a capture silently.

The Watermark incident page for the Ring Playground camera: a frame of bird feeders in the snow stamped 7:57:22 PM, a timeline from 0 s to 1:17 with frame notches, and the summary that the first frame arrived 6.9 s after the sensor went wet, 39 frames, 2 of 7 claim questions answered and no gaps.
One incident: Ring's own frames and timestamps, the first 6.9 s after the sensor, and how long the water stood.
A grid of Ring frames of bird feeders, each stamped with Ring's time from 7:57:14 to 7:57:22 PM; two carry Amazon Rekognition labels such as Bird Feeder 94% and the note labels only, wetness not judged.
Every frame keeps Ring's own time. Amazon Rekognition labels what is in view, and is never allowed to say a floor is dry.

Amazon Rekognition labels what is in each captioned frame, and the flooring question in the pack cites the floor material it names. I tested it on my own June flood footage first: it labels a film of water on hardwood exactly as it labels the dry floor. So in Watermark it can add "water visible" but never "no water", and the sensor stays the record of wetness. I designed prose captions for Amazon Bedrock and the code is still in place, but Bedrock is blocked on my account in every region I tried.

The pack, against my adjuster's questions

What comes out is one evidence pack a homeowner can print or send: the timeline, the frames, device health, and an integrity section that lists every gap it could not verify. Then it maps itself against the 7 questions my adjuster actually asked on my June claim. On one of the 10 runs (first frame in 6.9 s), it answers 2: when the water started and how long it stood, and where it was, which is the footage that would have settled sewer backup against rainwater. It partly answers 2 more, flooring and contents, where the frames show what was there but the homeowner adds the rest. The other 3 are about the house and the policy, and are mine to answer.

The first page of a Watermark evidence pack for the Ring Playground camera: water from 19:56:36 to 19:57:53 on 2026-10-09, the line Simulated sensor, Ring Playground camera, Evidence complete, and a timeline of the 39 frames.
The evidence pack. Its first page says the sensor was simulated before it says anything else.
The claim map: When did the water start and how long did it stand, answered; Was it sewer backup or clean rainwater, answered with 39 timed frames for the adjuster to judge; What flooring was there, partly answered; What contents were damaged, partly answered.
Against the 7 questions my adjuster actually asked: 2 answered, 2 partly answered, and the rest are the homeowner's.

It refuses to name a cause

Cause is what the mitigation report got wrong, so Watermark never states one. The pack's "What this record cannot vouch for" section comes before the claim map: frame labels describe what is visible and are not measurements, the sensor event in these runs is simulated, events learned by polling rather than by webhook are marked, and camera offline windows are reported as gaps. A script, check_claims.py, fails the build if a number in the docs disagrees with the committed runs.

The What this record cannot vouch for section: frame captions were written by rekognition:DetectLabels, describe what is visible and never state a cause; the sensor event is simulated because Ring's Developer Playground has no sensors.
It never names a cause, and it lists everything the record cannot vouch for before anything else.

ringwire, and a pull request to Amazon's sample

For the Open Source challenge I split the Ring client out of Watermark and published it as ringwire, a typed Python client for the Ring Partner API built around the Early Access sensor scope: sensor status with flood, freeze, contact and tamper state, the sensor webhooks with HMAC verification, chime playback, WHEP live sessions, the two-step media downloads and the account-linking nonce. It encodes three traps in Ring's sensor docs so callers cannot fall into them: the never-reported 1970 epoch becomes None, tamper reads "detected" rather than "faulted", and the reporting state is never treated as liveness. I also opened a pull request to Amazon's ring-api-helloworld adding sensor_status.py, the sample's first script that reads a sensor. Every one of the 10 measured runs went through ringwire.

What is not claimed

The timing is graded by Ring's own timestamps and the ablation by the Ring app's own history, not by my code, but the scope is narrow. The 10 measured runs used a simulated sensor event and the Playground's doorbell, not a flooded basement; the bowl test used my real sensor and camera, but it was a controlled test, labelled as one, with water poured in slowly. The claim map is scored against one claim's questions, mine. The printed rover that would carry the camera to a room no fixed camera covers has its code and its AWS IoT Core dispatch in the repo (a flood event reached it through IoT Core and it reported on station 7.7 s after the sensor, with the drive simulated), but it has not driven on a real floor, so it is not in the demo. Chime playback works through the API but the Playground has no chime, so the demo does not show it. And Watermark never says what caused the water; that stays with the adjuster.

Related project

Watermark: when a Ring flood sensor fires, a Ring camera records the water and the homeowner gets an evidence pack their insurer can use

View the project