I Built a Teeth Grinding Detector in One Night (Here's Why)
March 24, 2026 · 6 min read · Jacobo
A few months ago, my dentist looked at my molars and said: “You're grinding. A lot.”
I had no idea. I sleep alone, I don't wake up mid-grind, and I thought the occasional sore jaw was just... stress. Turns out I was destroying my teeth every night while blissfully unconscious.
She told me to get a custom nightguard — $400 — but also said: “If you want to track whether it's getting better or worse, you'd need to come back every few months for an exam.” That's not a feedback loop. That's a billing loop.
So I built one.
The Problem With Existing Tools
There's an app called AutoSnore that did $60K tracking snoring — same concept, different sound. But bruxism is different. The grinding sound is higher frequency, shorter in duration, and much harder to isolate from ambient noise (AC, traffic, a partner's breathing). Most “sleep sound” apps just record everything and leave you to scrub through 7 hours of audio. That's not useful.
The insight: you don't need to record everything. You need to detect the specific acoustic signature of teeth grinding — that dry, grating, slightly horrifying sound — and clip it, timestamp it, and score it.
How It Works
The app uses the Web Audio API to record from your microphone overnight. Instead of storing raw audio (too much data, too much privacy risk), it runs a real-time frequency analysis in the browser. Bruxism events have a characteristic spectral footprint in the 2–8 kHz range with a sharp onset and short decay.
// Simplified detection logic
const analyser = audioCtx.createAnalyser();
analyser.fftSize = 2048;
const dataArray = new Float32Array(analyser.frequencyBinCount);
function detectBruxism() {
analyser.getFloatFrequencyData(dataArray);
const bruxRange = dataArray.slice(40, 180); // ~2-8kHz bins
const energy = bruxRange.reduce(
(sum, v) => sum + Math.pow(10, v / 10), 0
);
const avgEnergy = energy / bruxRange.length;
if (avgEnergy > BRUXISM_THRESHOLD) logEvent();
}Every detected event gets logged with a timestamp and intensity. At the end of the night, the app calculates a 0–100 bruxism score based on event count, intensity, and clustering pattern (back-to-back events in the same hour are worse than isolated ones).
The Score
The scoring algorithm took the most thought. A single loud grind event at 2AM isn't the same as 20 mild events clustered between 3–4AM. I ended up with a weighted formula:
- Event count: baseline (0–40 points)
- Peak intensity: how hard (0–30 points)
- Clustering: events in bursts = worse (0–20 points)
- Recency: late-night events are harder on your jaw (0–10 points)
A score above 70 means “talk to your dentist.” Below 30 means “you're probably fine.” The scale is deliberately clinical, not wellness-washed.
What Surprised Me
Building this, I realized how good browsers have gotten at audio processing. The Web Audio API handles everything — recording, real-time FFT analysis, noise gating — without a single server call. Your audio never leaves your device. That felt important for something this intimate.
The other surprise: the empty state design mattered waymore than I expected. The first version showed a blank dashboard with a “Record Tonight” button. It felt cold. I redesigned it so the empty state shows what the populated dashboard will look like — blurred placeholder stats, greyed-out chart axes, a soft pulsing mic icon. Users told me the new version made them actually want to set it up.
What I'd Do Next
- Baseline calibration — record one ambient night first to tune the threshold to your specific room noise
- Mobile app — a phone on the nightstand beats a laptop
- Correlation features — did you drink alcohol? Eat late? Tags that make trend data 10x more useful
- SOAP note export — a real format dentists can actually use in chart notes
Try it yourself
Free, runs entirely in the browser, no account required. Your audio never leaves your device.
Built in one night. Shipped 5 AM. Jaw still hurts.