# How to Add Noise Level Detection to Your App (Copy-Paste Prompts Included)

- Tool: App Features
- Last updated: July 2026

## TL;DR

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.

## 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** (ui): Calls 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.
- **dB computation engine** (backend): An 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.
- **Real-time meter UI** (ui): A 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.
- **Threshold alert system** (backend): Compares 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.
- **Session log storage** (data): Supabase 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.
- **Noise history chart** (ui): A 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.

## 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.

```sql
create table public.noise_sessions (
  id uuid primary key default gen_random_uuid(),
  user_id uuid references auth.users(id) on delete cascade not null,
  label text,
  started_at timestamptz not null default now(),
  ended_at timestamptz,
  peak_db numeric(6,2),
  avg_db numeric(6,2)
);

alter table public.noise_sessions enable row level security;

create policy "Users can manage own sessions"
  on public.noise_sessions for all
  using (auth.uid() = user_id)
  with check (auth.uid() = user_id);

create table public.noise_readings (
  id uuid primary key default gen_random_uuid(),
  session_id uuid references public.noise_sessions(id) on delete cascade not null,
  db_value numeric(6,2) not null,
  recorded_at timestamptz not null default now()
);

alter table public.noise_readings enable row level security;

create policy "Users can manage own readings"
  on public.noise_readings for all
  using (
    session_id in (
      select id from public.noise_sessions where user_id = auth.uid()
    )
  )
  with check (
    session_id in (
      select id from public.noise_sessions where user_id = auth.uid()
    )
  );

create index noise_readings_session_time_idx
  on public.noise_readings (session_id, recorded_at desc);
```

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 paths

### Lovable — fit 3/10, 4–8 hours

Lovable can scaffold the Web Audio API component and Supabase session logging — use Plan Mode first to architect the AudioContext loop before generating code, or the AI will place it in the wrong lifecycle.

1. Start with Plan Mode in Lovable to describe the AudioContext lifecycle: create on button click, connect AnalyserNode, run requestAnimationFrame loop, cleanup on stop — confirm the plan before generating code
2. Switch to Agent Mode and paste the prompt below; Lovable will generate the meter component, Supabase tables, and the batched insert logic
3. Publish the project and open the HTTPS URL on a real device — microphone access will not work in the Lovable preview iframe
4. Grant microphone permission when prompted and tap Start Session; verify the meter responds to ambient sound and that readings appear in the noise_readings table via the Supabase dashboard

Starter prompt:

```
Build a noise level detection feature using the Web Audio API. Architecture: a NoiseMeter React component with a Start Session button and a Stop Session button. When Start is clicked (inside the onClick handler): create a new AudioContext, call getUserMedia({audio: true}), connect a MediaStreamSourceNode to an AnalyserNode (fftSize: 2048, smoothingTimeConstant: 0.8), and start a requestAnimationFrame loop that reads getByteTimeDomainData, computes RMS amplitude, converts to dBFS (20 * Math.log10(rms)), clamps to -100..0, and updates component state at 10fps (throttle inner loop with a lastUpdate timestamp). Display a Framer Motion animated vertical bar with three colour zones: green below -40dBFS, amber -40 to -20dBFS, red above -20dBFS. Show a numeric readout of the current dBFS value rounded to one decimal place. Show a peak indicator that holds the highest value for 3 seconds before resetting. Include a configurable threshold input (default -25dBFS) — when the current reading exceeds it, show an in-app toast (debounced, min 5s between toasts). On session start, insert a row into Supabase noise_sessions (user_id, label, started_at). Batch readings in a local array every 5 seconds and batch-insert into noise_readings (session_id, db_value, recorded_at). On session stop, update noise_sessions with ended_at, peak_db, and avg_db. Below the meter, show a Recharts LineChart of the current session's readings (last 60 seconds on x-axis). Handle microphone permission denied with a friendly error state explaining how to grant access. Handle AudioContext suspended state with a resume() call on user interaction. Add a typeof window guard on all Web Audio API code. Show the last 5 sessions in a history list below with label, date, and peak_db.
```

Limitations:

- Microphone access is blocked in the Lovable preview iframe — test only on the published HTTPS URL
- Audio processing combined with Recharts re-renders can cause Lovable to burn credits iterating on animation performance — use Plan Mode to set the architecture before generating
- No native mobile microphone output — the feature is web-only in a Lovable project

### V0 — fit 3/10, 4–7 hours

V0 generates a clean Next.js noise meter with Web Audio API and a Recharts history chart — best when noise detection is one feature in a larger Next.js dashboard.

1. Prompt V0 with the spec below; it will generate a NoiseMeter client component and a SessionHistory server component
2. Add Supabase environment variables in the Vars panel: NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY
3. Run the SQL schema from this page in the Supabase SQL editor to create noise_sessions and noise_readings tables
4. Deploy to Vercel via the Git panel — microphone access requires the deployed HTTPS URL, not the v0 sandbox
5. Test by opening the deployed URL on a real device, granting microphone permission, and starting a session

Starter prompt:

```
Create a Next.js noise level detection feature. Component: NoiseMeter — 'use client', no SSR (wrap all Web Audio API calls in typeof window !== 'undefined' guards and use dynamic import with ssr: false if needed). On Start button click inside the onClick handler: create AudioContext, call getUserMedia({audio: true}), wire MediaStreamSourceNode → AnalyserNode (fftSize 2048, smoothingTimeConstant 0.8), start a requestAnimationFrame loop computing RMS → dBFS (20 * Math.log10(rms)), clamped -100..0, state updated at 10fps. Render an animated SVG vertical meter bar with green/amber/red zones (-40dBFS and -20dBFS thresholds), a numeric readout, and a peak hold indicator (3s hold). Include a threshold number input — show an in-app toast when current dBFS exceeds threshold (5s debounce). On session start, create a Supabase noise_sessions row via Server Action. Batch readings locally every 5 seconds and call a Server Action to batch-insert noise_readings rows. On stop, update the session with ended_at, peak_db, avg_db. Show a Recharts LineChart of last 60 seconds of current session data updating live. Separate server component SessionHistory lists the last 5 sessions from Supabase with date, label, and peak_db. Handle NotAllowedError (microphone denied) with an error state and instructions to grant access in browser settings.
```

Limitations:

- Microphone access is blocked in the v0 sandbox preview — deploy to Vercel to test
- AudioContext instantiated at module scope instead of inside a click handler causes an 'AudioContext was not allowed to start' error — the prompt guards against this but check the generated code
- No native mobile output from V0

### Flutterflow — fit 4/10, 3–5 hours

FlutterFlow can use the noise_meter Flutter package via a Custom Action to read decibels from the microphone and drive a gauge widget — works on iOS and Android but requires writing Dart code for the custom action.

1. Add the noise_meter package (pub.dev) in FlutterFlow Settings → Pubspec Dependencies
2. Create a Custom Action StartNoiseMeter that instantiates NoiseMeter, subscribes to the noise stream, and updates an App State variable (type: double) with the latest dBFS value
3. Create a Custom Action StopNoiseMeter that cancels the subscription and disposes the NoiseMeter instance
4. Bind the App State dBFS variable to a Container widget whose height or colour property changes reactively — use a conditional colour expression for green/amber/red zones
5. Enable microphone permissions in Settings → Permissions → iOS Permissions: add NSMicrophoneUsageDescription; Android RECORD_AUDIO is added automatically by the noise_meter package

Limitations:

- noise_meter is not a built-in FlutterFlow action — requires Custom Action Dart code; not suitable for builders who want a fully visual experience
- Chart display for session history needs a custom widget with fl_chart integration — another Dart code requirement
- Background monitoring when the app is minimised is not possible without a native foreground service, which FlutterFlow cannot configure visually

### Custom — fit 5/10, 4–7 days

Custom development is required for calibrated SPL readings, background monitoring, raw audio export, or high-frequency time-series storage at scale.

1. Web: use Web Audio API with AudioWorklet for zero-latency processing in a separate thread; the main thread stays responsive during heavy measurement loops
2. Mobile: flutter_sound or react-native-audio-toolkit for on-device processing; platform channel for native foreground services enabling background monitoring
3. High-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
4. Device-specific calibration: apply correction curves per device model using device_info_plus to convert dBFS to calibrated dB SPL values
5. Export pipeline: write raw PCM audio alongside dB readings if compliance-grade evidence is required

Limitations:

- 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

## Gotchas

- **AudioContext blocked by browser autoplay policy** — 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** — 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** — 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** — 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** — 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

## 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.

---

Source: https://www.rapidevelopers.com/app-features/noise-level-detection
© RapidDev — https://www.rapidevelopers.com/app-features/noise-level-detection
