Have you ever faced this error when trying to play audio using useEffect
in React?
NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
This happens because modern browsers block autoplay audio until the user interacts with the page.
1. Create a useStableAudio hook
To handle this, use a custom hook that preloads and safely plays audio:
ts
function useStableAudio(url: string) { const contextRef = useRef<AudioContext>(); const bufferRef = useRef<AudioBuffer | null>(null); const [ready, setReady] = useState(false); useEffect(() => { contextRef.current = new (window.AudioContext || (window as any).webkitAudioContext)(); fetch(url) .then((res) => res.arrayBuffer()) .then((buffer) => contextRef.current?.decodeAudioData(buffer, (decoded) => { bufferRef.current = decoded; setReady(true); }) ); }, [url]); const play = useCallback(() => { if (!contextRef.current || !bufferRef.current) return; const source = contextRef.current.createBufferSource(); source.buffer = bufferRef.current; source.connect(contextRef.current.destination); if (contextRef.current.state === "suspended") { contextRef.current.resume().then(() => source.start(0)); } else { source.start(0); } }, []); return { play, ready }; }
2. Example Usage
tsx
function NotifySound() { const { play, ready } = useStableAudio("/sounds/notify.mp3"); useEffect(() => { if (ready) play(); }, [ready, play]); return null; }
⚠️ Note: Browsers like Chrome and Safari block autoplay. Make sure the audio is triggered after a user interaction (e.g., a button click or page focus).