NewWe just added 1,500 new sounds to the library
Adding Sound Effects to a React App with Lotsofsounds
|4 min read|lotsofsounds team

Adding Sound Effects to a React App with Lotsofsounds

Sound effects make apps feel more responsive and polished. A subtle click on a button press, a chime on a notification, an error buzz on validation failure — these small details add up.

Here's how to add sound effects to a React app using the Lotsofsounds API.

Architecture

Fetch sounds during your build and bundle them as static assets. Simpler and avoids runtime API calls.

Fetch signed URLs from your backend and play them on demand. Better when sounds change without redeploying.

Build-time approach

Fetch sounds in a build script

scripts/fetch-sounds.js
const fs = require("fs");
const path = require("path");

const API_KEY = process.env.LOS_API_KEY;
const BASE = "https://api.lotsofsounds.com/api/v1";
const OUT_DIR = path.join(__dirname, "../public/sounds");

const SOUNDS = {
  click: "ui click soft",
  success: "success chime short",
  error: "error buzz notification",
  notification: "gentle notification bell",
};

async function main() {
  fs.mkdirSync(OUT_DIR, { recursive: true });

  for (const [name, query] of Object.entries(SOUNDS)) {
    const searchRes = await fetch(
      `${BASE}/sounds?q=${encodeURIComponent(query)}&limit=1&sort=avg_rating`,
      { headers: { "x-api-key": API_KEY } }
    );
    const { data } = await searchRes.json();
    if (!data.length) continue;

    const dlRes = await fetch(`${BASE}/sounds/${data[0].id}/download`, {
      headers: { "x-api-key": API_KEY },
    });
    const { data: dl } = await dlRes.json();

    const audio = await fetch(dl.download_url);
    const buffer = Buffer.from(await audio.arrayBuffer());
    fs.writeFileSync(path.join(OUT_DIR, `${name}.mp3`), buffer);
    console.log(`Downloaded: ${name}.mp3`);
  }
}

main();

Create a React hook

hooks/useSound.ts
import { useCallback, useRef } from "react";

export function useSound(src: string) {
  const audioRef = useRef<HTMLAudioElement | null>(null);

  const play = useCallback(() => {
    if (!audioRef.current) {
      audioRef.current = new Audio(src);
    }
    audioRef.current.currentTime = 0;
    audioRef.current.play().catch(() => {});
  }, [src]);

  return { play };
}

Use it in a component

SubmitButton.tsx
import { useSound } from "@/hooks/useSound";

function SubmitButton() {
  const { play: playClick } = useSound("/sounds/click.mp3");
  const { play: playSuccess } = useSound("/sounds/success.mp3");

  async function handleSubmit() {
    playClick();
    const result = await submitForm();
    if (result.ok) playSuccess();
  }

  return <button onClick={handleSubmit}>Submit</button>;
}

Runtime approach

If you need sounds to change without redeploying, proxy the API through your backend:

app/api/sounds/play/route.ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const query = searchParams.get("q");

  const searchRes = await fetch(
    `https://api.lotsofsounds.com/api/v1/sounds?q=${query}&limit=1`,
    { headers: { "x-api-key": process.env.LOS_API_KEY! } }
  );
  const { data } = await searchRes.json();
  if (!data.length)
    return Response.json({ error: "Not found" }, { status: 404 });

  const dlRes = await fetch(
    `https://api.lotsofsounds.com/api/v1/sounds/${data[0].id}/download`,
    { headers: { "x-api-key": process.env.LOS_API_KEY! } }
  );
  return Response.json(await dlRes.json());
}
routes/sounds.js
app.get("/api/sounds/play", async (req, res) => {
  const { q } = req.query;

  const searchRes = await fetch(
    `https://api.lotsofsounds.com/api/v1/sounds?q=${q}&limit=1`,
    { headers: { "x-api-key": process.env.LOS_API_KEY } }
  );
  const { data } = await searchRes.json();
  if (!data.length) return res.status(404).json({ error: "Not found" });

  const dlRes = await fetch(
    `https://api.lotsofsounds.com/api/v1/sounds/${data[0].id}/download`,
    { headers: { "x-api-key": process.env.LOS_API_KEY } }
  );
  res.json(await dlRes.json());
});

Tips

Best practices

  • Preload sounds on page load for instant playback — don't fetch on click
  • Respect user preferences: Check prefers-reduced-motion and provide a mute toggle
  • Keep sounds short: UI sounds should be under 1 second. Use max_duration=1 in your search
  • Cache aggressively: Downloaded sounds don't change, so cache at the CDN and browser level

Get started

Sign up and get a Pro plan

Generate an API key

Browse sounds in the dashboard to find what you need

Use the build script above or the API docs to integrate