I made $9 of hardware see people through walls

The first time I saw it working, when a real person walked down the hallway behind a closed door, the whole heatmap on my laptop was moving around. I just sat there smiling.

It’s a device that knows when someone walks through the room on the opposite side of a wall. It doesn’t have a camera or a lens or anything that could ever record a face. The parts cost $9.

I built it for Protector, and it’s probably the most sci-fi thing I’ve ever made.

Backstory

Protector is a private security company. You open the app and can instantly book an armed agent, a credentialed security detail, as easily as booking a car. People ask me about this client all the time because a tweet about them went viral.

In February 2025, when Protector was launching in both Los Angeles and New York, Nikita Bier announced that it was “Uber with guns,” adding that it would debut at number three on the App Store. The post had millions of impressions. As did the TikTok that a few influencers made of them getting picked up at the airport.

The Protector team thinks about privacy all day, so they were early on a trend that most other tech companies ignored: sensors can actually pose a threat themselves.

This is a pretty hot topic right now. Flock Safety sells these license plate cameras to police departments, promising that they’ll make neighborhoods safer. When it came out that officers had used their network to track exes and that local departments had been running thousands of immigration searches for federal ICE agents, dozens of cities started canceling their contracts.1 People were literally cutting the camera poles down. The safety argument seemed to not carry weight.

Cameras are the obvious way to detect people, but they have problems. You can’t put them in bedrooms, bathrooms, hotel rooms, or anywhere somebody gets undressed, sleeps, or expects that they won’t be observed. The data they collect is only as safe as the people who have access to it. Most security products do not actually need vision. They don’t need to know what a person looks like. They just want to know if somebody is there at all. If you can figure out how to do that, you’ve basically captured most of the value of a camera without the cost.

So the task: know if a person is there, but not who they are. As a bonus, don’t be in the room with them.

That would be crazy: a presence sensor that can literally see through walls, both private and useful.

The task

The idea for the project came from a research paper called “DensePose From WiFi.”2 Basically, three researchers at Carnegie Mellon were able to reconstruct full-body human poses (arms, legs, posture, and twenty-four regions of surface geometry) only from WiFi signals. Below is a figure from the paper. At the top, you can see their input, and at the bottom, you can see what the neural network was able to reconstruct.

Figure 7 from “DensePose From WiFi”: WiFi amplitude and phase plots above a photo of two people overlaid with dense pose meshes recovered from the signalAmplitude and phase across the subcarriers of a WiFi channel. You can see the two human reconstructions on the bottom. Figure 7 of “DensePose From WiFi,” annotated ground truth via an image-based network. The only input was the WiFi amplitude and phase.

But Protector didn’t even need human poses. They just needed to know if a person was there. This is critical information for SWAT operations and other high-risk home maneuvers. After reading the paper, I thought this was very achievable.

$9 of materials

The entire bill of materials was just two ESP32 development boards. One was a transmitter, and the other was the receiver. Each was a few dollars.

A hand holding a small dark circuit board with ESP32 DEVKIT V1 TYPEC silkscreened on the back, two jumper wires plugged into the header pinsOne of the ESP32 boards.

All this for $9, while the presence detectors on the market right now cost hundreds of dollars per room. And those systems aren’t scams. The ESP32 is an extremely inexpensive WiFi chip, priced originally for rice cookers, that gives you a ton of freedom in testing and construction. Basically, any experiment I wanted to run with it was cheaper than a Blue Bottle coffee.

Here’s our whole rig:

Hardware2× ESP32 dev boards
Bill of materials~$9
Channel1, at 2.412 GHz
Transmit rate100 packets per second
Transmit power20 dBm, the legal ceiling
Serial link921,600 baud
Packet framing0xAA … payload … 0xBB
Hardware sprintMarch 18–19, 2025

How it works

Every WiFi packet that gets to the receiver is shaped by the room it travels through. It bounces off walls and furniture. It takes a bunch of different paths to get to the antenna. There, the signal is recombined. Ordinary WiFi hardware measures the distortion on each packet so it can undo it to read your data. That measurement is called channel state information (CSI). It includes an amplitude and phase value for every subcarrier in the channel.3 What usually happens is the radio computes it, then uses it, then throws it away. This happens millions of times a day in the devices you own.

So all we had to do was not get rid of that data.

Basically, human bodies are big and conductive, while drywall is almost transparent to WiFi frequencies. When you move through a room, you rearrange the paths that the radio waves take, and the CSI records that disturbance. The walls are basically irrelevant.

The whole task ends up being almost trivial. Put one ESP32 somewhere, sending out a hundred packets a second on channel 1. Put another somewhere else in promiscuous mode.4 For each packet, the ESP-IDF gives its callback the channel measurement, which the firmware sends through the USB cable, framed with single-byte markers so the serial port can distinguish them:

void wifi_csi_cb(void *ctx, wifi_csi_info_t *info) {
  memcpy(&csi_info, info, sizeof(wifi_csi_info_t));
 
  uint8_t header[5] = {0xAA, (uint8_t)csi_len, (uint8_t)csi_info.rx_ctrl.rssi,
                       (uint8_t)csi_info.rx_ctrl.rate, (uint8_t)csi_info.rx_ctrl.sig_mode};
  Serial.write(header, 5);
  Serial.write(csi_info.buf, csi_len);
  Serial.write(0xBB);
}

Then we can use Python to reassemble the stream and render it as a heatmap, with packets across the x-axis and subcarriers on the y. This is what one second of capture looks like:5

A CSI amplitude heatmap: horizontal colored stripes across 999 packets and 57 subcarriersOne second of channel state information data. The horizontal stripes are each subcarrier’s standing amplitude. Basically, it’s a fingerprint of a specific arrangement of walls, furniture, and bodies. If you rearrange anything, the stripes will move.

An empty room draws uninteresting stripes, because the paths don’t change. Basically, the stripes are the room, and the pattern of bright and dark shows the interference of that arrangement. That means you can play with it. Here’s what moving around the geometry does to that fingerprint:

the room being protectedthe hallway with the boardsdrywallTXRXdrag me
57 subcarriers ↑scatter path 10.43 m · direct 8.85 mtime →
A simulation of the real physics: channel 1 at 2.412 GHz, 57 subcarriers 312.5 kHz apart, a direct path, three fixed wall bounces, and one path that scatters off of the dot. If you stay still, the heatmap draws flat stripes, but if you move around the room, every subcarrier ripples exactly the way a real capture would. The wall is irrelevant, by the way.

Tuning the results

Getting a demo to detect a person is actually pretty easy. The hard part is making the sensor reliable. Raw CSI data is kind of a mess. The readings are very noisy, and any auxiliary radio signal, like the neighbor’s network or a microwave oven, will destroy the results.

The ESP32 actually has some of its own cleanup features to filter and merge measurements, but the rest of it is software that needs to distinguish what a human moving looks like. The classical detector is extremely simple. All it does is normalize the CSI, take the Fourier transform of each subcarrier’s history, and measure the energy in the low-frequency bins. The reason it’s so easy is because humans walk at such a slow pace relative to thermal noise, so you just need a low-pass filter.

But the hard part is that getting the device tuned changes with the environment. The toolkit source says this: “The optimal threshold setting varies with the environment.”6 If you’re going to turn this into more than a demo, that would be the place to start, because for Protector, false negatives would be disastrous.

What I loved about this project

My day job is mostly to build software that looks expensive, but this project taught me the opposite. It taught me how to build hardware that looks like nothing but is extremely powerful. We didn’t need a camera or anything. Just two cheap boards sitting in a hallway could tell us whether humans were on the other side of a wall or not.

There’s obviously a genre of product that can and probably will come out of this. The WiFi in your house is already capturing this data. Nobody’s doing anything with it. Maybe one day Protector will change that.7

Footnotes

  1. NPR on the cancellations, which have happened in at least 30 cities since the beginning of 2025, after 404 Media found that about 4,000 immigration-related searches had been run through local department cameras. TechCrunch on the vandalism. ABC on the guardrails Flock added afterwards, including case numbers on every search, automatic lockouts, and a seven-day retention default window, down from 30.

  2. Geng, Huang, and De la Torre, Carnegie Mellon, arXiv:2301.00250, December 2022. You can also see their previous paper, “Person-in-WiFi”, from 2019.

  3. WiFi doesn’t just transmit on one frequency, but instead splits its channel into dozens of parallel subcarriers. Each one has its own amplitude and phase, and a body disturbs each slightly differently. That’s how you can pick up the signal’s fingerprint.

  4. This is the technical term for a radio that listens to every packet on the air, not just its own.

  5. The CSI sanitization toolkit ships with sample data that includes 999 packets, 57 subcarriers, and 3 antennas. It’s rendered the same way that visualize_csi.py renders ESP32 captures: viridis, subcarriers against packets.

  6. naive_intrusion.m, comment on the second argument. There’s also a Bluetooth version of the experiment in the repo, ESP32_BLE_Transmitter.ino, because originally, before CSI, we tried signal strength. While RSSI can tell you that something happened, only CSI can tell you what happened and where, so for that reason WiFi won.

  7. The rest of my work for Protector was regular software. I built their app and the systems to support it, but I think that this is the coolest part of the work. Being able to see through walls without a camera is just lit.