RVE LogoReact Video EditorDOCS
RVE SDK/Quick Start/Setup Sounds

Setup Sounds

Integrate LotsOfSounds audio into your video editor via a server-side proxy

RVE ships with a built-in LotsOfSounds audio adaptor. It works through a proxy pattern. Your server holds the API key, the editor calls your local routes, never the LotsOfSounds API directly.

Why a proxy?

The editor runs in the browser. If you called the LotsOfSounds API directly from the client, your API key would be exposed in network requests for anyone to steal. By routing through your own server, the key stays secret and never leaves your backend.

How it works

Editor UI  →  /api/sounds/search?q=...   →  Your server  →  api.lotsofsounds.com
Editor UI  →  /api/sounds/stream/[id]    →  Your server  →  api.lotsofsounds.com

The adaptor is included in the default audio adaptors automatically. You just need to set up two server-side proxy routes.

Step 1: Get a LotsOfSounds API key

Sign up at lotsofsounds.com and get an API key. Add it to your environment:

NEXT_LOTSOFSOUNDS_API_KEY=your_api_key_here

Step 2: Create the search proxy route

Create app/api/sounds/search/route.ts:

import { NextRequest, NextResponse } from 'next/server';

const LOTSOFSOUNDS_API_URL = 'https://api.lotsofsounds.com';

export async function GET(requst) {
  const apiKey = process.env.NEXT_LOTSOFSOUNDS_API_KEY;
  if (!apiKey) {
    return NextResponse.json({ error: 'API key not configured' }, { status: 500 });
  }

  const { searchParams } = new URL(request.url);
  const params = new URLSearchParams();
  const q = searchParams.get('q');
  if (q) params.set('q', q);
  params.set('limit', searchParams.get('limit') || '20');
  params.set('page', searchParams.get('page') || '1');

  const response = await fetch(
    `${LOTSOFSOUNDS_API_URL}/api/v1/sounds?${params.toString()}`,
    { headers: { 'x-api-key': apiKey } }
  );

  if (!response.ok) {
    return NextResponse.json(
      { error: `API error: ${response.status}` },
      { status: response.status }
    );
  }

  return NextResponse.json(await response.json());
}

Step 3: Create the stream proxy route

Create app/api/sounds/stream/[id]/route.ts:

import { NextRequest, NextResponse } from 'next/server';

const LOTSOFSOUNDS_API_URL = 'https://api.lotsofsounds.com';

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  const apiKey = process.env.NEXT_LOTSOFSOUNDS_API_KEY;
  if (!apiKey) {
    return NextResponse.json({ error: 'API key not configured' }, { status: 500 });
  }

  const { id } = await params;

  // Get signed download URL
  const downloadResponse = await fetch(
    `${LOTSOFSOUNDS_API_URL}/api/v1/sounds/${encodeURIComponent(id)}/download`,
    { headers: { 'x-api-key': apiKey } }
  );

  if (!downloadResponse.ok) {
    return NextResponse.json(
      { error: `API error: ${downloadResponse.status}` },
      { status: downloadResponse.status }
    );
  }

  const data = await downloadResponse.json();
  const signedUrl = data?.data?.download_url;

  if (!signedUrl) {
    return NextResponse.json({ error: 'No download URL returned' }, { status: 502 });
  }

  // Pipe audio bytes to client
  const audioResponse = await fetch(signedUrl);
  const contentType = audioResponse.headers.get('content-type') || 'audio/mpeg';

  return new NextResponse(audioResponse.body, {
    status: 200,
    headers: {
      'Content-Type': contentType,
      'Cache-Control': 'public, max-age=3600',
    },
  });
}

Step 4: That's it

The default audio adaptors already include LotsOfSounds. When you pass no audio key in your adaptors prop, RVE uses it automatically. The sounds panel will show up in the editor sidebar with search and pagination.

If you're already passing custom adaptors, the LotsOfSounds adaptor is available as a named export:

import { lotsofsoundsAudioAdaptor } from '@reactvideoeditor/react-video-editor/adaptors/lotsofsounds-audio-adaptor';

<ReactVideoEditor
  adaptors={{
    audio: [lotsofsoundsAudioAdaptor],
    // ...other adaptors
  }}
/>