Feature spec
IntermediateCategory
scanning-devices
Build with AI
4–8 hours with Lovable
Custom build
4–7 days custom dev
Running cost
$0/mo (client-side only) · $0–25/mo with Supabase session logging
Works on
Everything it takes to ship Noise Level Detection — parts, prompts, and real costs.
Noise level detection uses the browser's Web Audio API (or the noise_meter Flutter package on mobile) to read microphone amplitude, convert it to dBFS, and display a live meter. The whole client-side stack is free — Web Audio API is built into every modern browser, no library purchase required. Costs appear only if you log session data to Supabase (free tier handles most volumes) or need background monitoring on native mobile (requires custom dev).
What Noise Level Detection Actually Is
Noise level detection reads the microphone input, measures amplitude in real time, and converts it to a decibel value the app can display, log, or act on. Typical use cases include restaurant noise monitors, classroom focus tools, baby monitors, sound-triggered recording apps, and occupational health trackers. The browser's Web Audio API provides everything needed on web — no external SDK, no API key, no per-measurement fee. The engineering challenge is making the measurement loop fast enough to feel live (10+ fps), preventing the audio context from being blocked by browser autoplay policies, and deciding how much data to write to the database without overwhelming it.
What users consider table stakes in 2026
- Decibel readout updates at least 10 times per second — anything slower feels laggy for a live meter
- Visual gauge or waveform bar reacts immediately to changes in ambient sound, with distinct colour zones (green, amber, red)
- Configurable alert threshold with a non-annoying notification when the level is exceeded (debounced to one alert per 5 seconds minimum)
- Session start/stop controls so users can bracket a measurement period and review it later
- Peak dB indicator that holds its maximum reading for 3 seconds before resetting
- Microphone permission prompt with a clear fallback message explaining how to grant access if denied
Anatomy of the Feature
Six components. The dB computation engine and the high-frequency write strategy are where AI-built versions most commonly fail in production.
Microphone access layer
UICalls getUserMedia({audio: true}) to request microphone access and connects the resulting MediaStream to a Web Audio API AudioContext. On mobile, the same Web Audio API works on iOS Safari 14.5+ and Chrome Android. The AudioContext must be created or resumed inside a user gesture handler — component-mount creation causes a browser autoplay policy block.
Note: Requires HTTPS and a user gesture (button click) before the AudioContext is allowed to start. AI tools frequently create the AudioContext at module mount, causing a silent 'was not allowed to start' error.
dB computation engine
BackendAn AnalyserNode connected to the AudioContext reads time-domain data via getByteTimeDomainData() into a Uint8Array. A JavaScript loop computes RMS (root mean square) amplitude from the array and converts it to dBFS using 20 * Math.log10(rms). Output is clamped to the range -100 to 0 dBFS. The loop runs inside requestAnimationFrame at approximately 60fps, but meter updates are throttled to 10fps to reduce React re-renders.
Note: On iOS Safari 16, the AudioContext sometimes reports incorrect RMS at startup. Discard the first 30 frames (about 500ms) before showing values to the user.
Real-time meter UI
UIA React component renders an SVG arc gauge or animated vertical bar using Framer Motion transitions or CSS custom properties driven by the current dBFS value. Three colour zones: green for levels below -40dBFS (quiet), amber for -40 to -20dBFS (moderate), red above -20dBFS (loud). A separate peak indicator element holds its position for 3 seconds then drops.
Note: Use CSS transitions for the bar fill rather than Framer Motion on every animation frame — animating at 60fps with Framer can cause jank on lower-end devices.
Threshold alert system
BackendCompares the current dBFS reading to a user-configured threshold stored in component state. When the threshold is exceeded, triggers a browser Notification API alert or an in-app toast. A debounce guard (minimum 5 seconds between alerts) prevents repeated notifications during a sustained loud period.
Note: Browser Notifications require a separate permission request. In-app toasts require no extra permission and are the safer default for most use cases.
Session log storage
DataSupabase tables noise_sessions and noise_readings persist measurement history. The client batches readings in memory and inserts an array every 5 seconds rather than on every animation frame — this keeps Supabase write volume manageable at scale. Session metadata (label, peak_db, avg_db) is written on session end.
Note: If you insert every reading at 60fps, a single user generates 3,600 rows per minute. Batch inserts every 5 seconds reduce that to 12 rows per minute per user.
Noise history chart
UIA Recharts LineChart (web) or fl_chart (Flutter) renders db_value over recorded_at timestamps for the current session, showing the last 60 seconds of data on the visible x-axis. Supports zoom and pan for longer sessions. Colour fills match the three dBFS zones.
Note: Load chart data from Supabase only on session open — do not subscribe to real-time inserts for the chart, or you'll trigger a full re-render on every batch insert.
The data model
Two tables: sessions for metadata and batched readings for the time-series data. Run this in the Supabase SQL editor — it creates both tables with RLS and the composite index needed for fast chart queries.
1create table public.noise_sessions (2 id uuid primary key default gen_random_uuid(),3 user_id uuid references auth.users(id) on delete cascade not null,4 label text,5 started_at timestamptz not null default now(),6 ended_at timestamptz,7 peak_db numeric(6,2),8 avg_db numeric(6,2)9);1011alter table public.noise_sessions enable row level security;1213create policy "Users can manage own sessions"14 on public.noise_sessions for all15 using (auth.uid() = user_id)16 with check (auth.uid() = user_id);1718create table public.noise_readings (19 id uuid primary key default gen_random_uuid(),20 session_id uuid references public.noise_sessions(id) on delete cascade not null,21 db_value numeric(6,2) not null,22 recorded_at timestamptz not null default now()23);2425alter table public.noise_readings enable row level security;2627create policy "Users can manage own readings"28 on public.noise_readings for all29 using (30 session_id in (31 select id from public.noise_sessions where user_id = auth.uid()32 )33 )34 with check (35 session_id in (36 select id from public.noise_sessions where user_id = auth.uid()37 )38 );3940create index noise_readings_session_time_idx41 on public.noise_readings (session_id, recorded_at desc);Heads up: The RLS policy on noise_readings checks ownership via the parent session — this is cleaner than duplicating user_id on every reading row. The index keeps chart queries fast even when a session accumulates thousands of rows.
Build it — pick your path
Each tool fits this feature differently. Switch tabs to compare fit, time, the exact steps, and a copy-paste prompt.
Custom development is required for calibrated SPL readings, background monitoring, raw audio export, or high-frequency time-series storage at scale.
Step by step
- 1Web: use Web Audio API with AudioWorklet for zero-latency processing in a separate thread; the main thread stays responsive during heavy measurement loops
- 2Mobile: flutter_sound or react-native-audio-toolkit for on-device processing; platform channel for native foreground services enabling background monitoring
- 3High-frequency write path: batch readings to a local buffer, write to TimescaleDB or InfluxDB for time-series queries optimised for sensor data at millions of rows
- 4Device-specific calibration: apply correction curves per device model using device_info_plus to convert dBFS to calibrated dB SPL values
- 5Export pipeline: write raw PCM audio alongside dB readings if compliance-grade evidence is required
Where this path bites
- Most expensive path — only justified for compliance monitoring, IoT integration, or building-management system connectivity
- AudioWorklet requires a separate worklet JavaScript file served from the same origin; incompatible with some CDN setups
Third-party services you'll need
The entire client-side processing stack is free. Costs appear only for data persistence:
| Service | What it does | Free tier | Paid from |
|---|---|---|---|
| Web Audio API | Browser-native microphone access, AnalyserNode for amplitude measurement — no library needed | Built into all modern browsers, free | Free |
| noise_meter (Flutter pub.dev) | Dart package providing a noise stream from the device microphone for Flutter apps | Open source, free | Free |
| Supabase | noise_sessions and noise_readings tables, RLS, and optional Realtime subscription for live session sharing | Free tier: 2 projects, 500MB DB, 500K Edge Function invocations/mo | Pro $25/mo (8GB DB) |
| Recharts | React charting library for noise history LineChart — open source, no API key | Open source, free | Free |
Swipe the table sideways to see pricing.
What it costs to run
Drag through the tiers to see how your monthly bill scales with users — no surprises later.
Estimated monthly running cost
Entirely client-side processing — no server costs for the meter itself. Supabase free tier handles session logs for 100 users with batched inserts comfortably.
Estimates use verified 2026 pricing and assume typical usage per user. Your real bill depends on activity, storage, and third-party plans.
What breaks when AI tools build this
The failures people actually hit on their first build — the symptom, why it happens, and the exact fix.
AudioContext blocked by browser autoplay policy
Symptom: Browsers throw 'AudioContext was not allowed to start' when AudioContext is created or .resume() is called before a user gesture. AI tools frequently create the AudioContext on component mount (inside useEffect) rather than inside a click handler, causing the noise meter to silently show zero dBFS at all times.
Fix: Create the AudioContext exclusively inside the Start button's onClick handler. If you need to store the context reference across renders, create it lazily — check if it exists before constructing. Alternatively, create it on mount in suspended state and call audioCtx.resume() inside the click handler.
Microphone access blocked in preview iframes
Symptom: getUserMedia({audio: true}) requires a secure context (HTTPS) and is rejected in the sandboxed iframes used by Lovable and v0 previews. The component renders, the Start button appears, but clicking it either shows nothing or throws a NotAllowedError that goes unhandled.
Fix: Test only on the published HTTPS URL. Add explicit error handling in the catch block of getUserMedia to render a permission-denied state with instructions — do not let the error silently disappear.
SSR crash with AudioContext in Next.js
Symptom: V0-generated Next.js code sometimes references AudioContext or navigator at module scope, causing 'window is not defined' or 'navigator is not defined' during server-side rendering. The build passes locally but crashes on Vercel at deployment.
Fix: Wrap every Web Audio API reference in typeof window !== 'undefined' guards. For the NoiseMeter component, add 'use client' at the top and import it with next/dynamic and ssr: false from a page that needs SSR.
High-frequency database writes overload Supabase free tier
Symptom: If the requestAnimationFrame loop triggers a Supabase insert on every frame (60 writes per second per user), the free tier rate limit is hit almost instantly, causing 429 errors and lost data. AI tools often wire the DB insert directly inside the animation loop.
Fix: Batch readings in a local JavaScript array. Set a setInterval at 5 seconds to flush the array as a single batch INSERT. Use a JSONB column or an array of row objects in a single Supabase call. This reduces DB writes from 3,600/min to 12/min per active user.
iOS Safari AudioContext sample rate reports incorrect RMS at startup
Symptom: On some iOS Safari 16 versions, the AudioContext initialises with a sample rate mismatch that causes the first 200–500ms of AnalyserNode readings to return near-zero values. This makes the meter look broken on first launch even though the microphone is working.
Fix: Add a 500ms warm-up delay before displaying meter values. Discard the first 30 frames from the requestAnimationFrame loop — set a frameCount counter and skip state updates until it reaches 30.
Best practices
Always create AudioContext inside a user gesture handler (button click), never on component mount — browser autoplay policy blocks silent creation
Batch Supabase inserts every 5 seconds instead of on every animation frame — one user's 30-minute session should produce 360 rows, not 108,000
Cap the meter update rate at 10fps for React state updates even though the AnalyserNode reads at 60fps — excessive re-renders cause jank without improving perceived responsiveness
Show a peak dB indicator that holds the maximum reading for 3 seconds — users often miss the peak reading on a live meter
Debounce threshold alerts to a minimum of 5 seconds between notifications — a sustained loud environment triggers alerts every frame without debouncing, which is unusable
Stop the microphone stream and close the AudioContext when the component unmounts — an active microphone indicator in the browser tab header causes user alarm
Provide a calibration note in the UI: dBFS is relative to the device's microphone sensitivity, not absolute dB SPL — set correct expectations so users do not report 'wrong' readings
When You Need Custom Development
Lovable and V0 handle noise monitoring for most consumer use cases. These requirements consistently exceed what AI-tool builds can deliver reliably:
- Continuous background monitoring when the app is minimised — this requires a native foreground service on Android and a background audio session on iOS, both beyond FlutterFlow's visual tools
- Calibrated SPL (dB SPL) readings with device-specific correction curves — dBFS values vary by device microphone sensitivity and require hardware calibration data
- Exporting raw WAV audio alongside dB readings for compliance evidence in occupational health or noise enforcement contexts
- Integration with building management systems, IoT sensors, or industrial noise monitoring hardware via MQTT or proprietary protocols
RapidDev builds these features for production
Real auth, database, and payments — fixed price, delivered in weeks. You own 100% of the code.
Frequently asked questions
How do I access the microphone in a web app without writing native code?
Call navigator.mediaDevices.getUserMedia({audio: true}) inside a button click handler — this is the browser's standard Web Audio API, available in all modern browsers with no library or API key required. Connect the resulting MediaStream to an AudioContext and AnalyserNode to start reading amplitude values.
What is the difference between dBFS and dB SPL in a noise detection app?
dBFS (decibels relative to full scale) measures the digital amplitude of the audio signal, where 0dBFS is the maximum the microphone can record and -100dBFS is near silence. dB SPL (sound pressure level) measures physical air pressure and requires a calibrated microphone with a known sensitivity curve. Browser-based apps produce dBFS values. For consumer noise awareness features dBFS is sufficient; for compliance-grade occupational health monitoring you need calibrated dB SPL hardware.
Why does the noise meter not work in the Lovable or V0 preview?
Both preview environments use sandboxed iframes that block microphone access via getUserMedia(). This is a browser security restriction applied to the iframe, not a bug in your code. Publish the app and test the HTTPS URL on a real device to verify the meter works.
How do I prevent AudioContext from being blocked by the browser?
Create the AudioContext inside the Start button's onClick handler rather than on component mount. If the context already exists (user clicked start before), call audioCtx.resume() instead of creating a new one. Never create AudioContext in useEffect with an empty dependency array — that runs before any user interaction and triggers the autoplay block.
How many database writes does a noise monitoring session generate?
With naive implementation (one insert per animation frame at 60fps), a single 30-minute session generates 108,000 rows — enough to hit Supabase free tier limits within minutes across a handful of users. The correct approach is to batch readings in memory and insert an array every 5 seconds, which produces 360 rows for the same 30-minute session.
Can I build a noise level detector in FlutterFlow without writing any code?
Not fully. FlutterFlow does not have a built-in noise meter action. You need to add the noise_meter pub.dev package and write a Custom Action in Dart to subscribe to the noise stream and update an App State variable. The rest — gauge widget, colour zones, session controls — can be built visually once the Custom Action exists.
How do I add a threshold alert that notifies the user when it gets too loud?
In your requestAnimationFrame loop, compare the current dBFS reading to the user's threshold value. If exceeded, trigger a browser Notification (requires a separate permission) or an in-app toast. Store the time of the last alert in a ref and skip new alerts if less than 5 seconds have elapsed — without this debounce, a sustained loud environment fires hundreds of alerts per minute.
Can noise monitoring run in the background on mobile?
Not with a web app or a standard FlutterFlow build. Background audio processing on iOS requires a background audio session entitlement, and on Android it requires a foreground service with a persistent notification. Both are native capabilities that require custom Flutter or React Native code outside of visual AI builders.
Need this feature production-ready?
RapidDev builds noise level detection into real apps — auth, database, payments — at $13K–$25K.
Book a free consultation30-min call. No commitment.