Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate SoundCloud API with V0

Integrate the SoundCloud API with your V0-generated Next.js app by creating a server-side API route that fetches track and playlist data using your SoundCloud client credentials. Embed audio players using SoundCloud's oEmbed endpoint or Widget API, and store your client ID in Vercel environment variables. This lets you build custom music player interfaces displaying independent artist tracks without exposing credentials to the browser.

What you'll learn

  • How to fetch SoundCloud track and playlist data via a Next.js API route
  • How to embed SoundCloud audio players using the oEmbed endpoint
  • How to control the SoundCloud Widget API from React for custom player UI
  • How to store your SoundCloud client_id securely in Vercel environment variables
  • How to build a custom music player interface with track listings and waveform display
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate12 min read35 minutesSocialApril 2026RapidDev Engineering Team
TL;DR

Integrate the SoundCloud API with your V0-generated Next.js app by creating a server-side API route that fetches track and playlist data using your SoundCloud client credentials. Embed audio players using SoundCloud's oEmbed endpoint or Widget API, and store your client ID in Vercel environment variables. This lets you build custom music player interfaces displaying independent artist tracks without exposing credentials to the browser.

Building a Custom SoundCloud Music Player with V0

SoundCloud hosts over 300 million tracks from independent artists, podcasters, and creators. If you are building a music discovery app, artist portfolio, or creator platform, the SoundCloud API lets you display track listings, artist profiles, and embed playable audio directly in your V0-generated Next.js app. Unlike Spotify which restricts playback to its own apps, SoundCloud's public tracks can be played via the Widget API in any web page.

The SoundCloud integration has two layers: the oEmbed API for generating embeddable player code for specific tracks (no API key needed — just pass a track URL), and the REST API for programmatically fetching track metadata, searching for tracks, getting user playlists, and more. The REST API requires a client_id that you get by registering an application at SoundCloud's developer portal. For most music player use cases, you will use both: oEmbed for the audio player UI and the REST API for search, track listings, and metadata.

V0 handles the UI generation: waveform-style visualization placeholders, track cards with artwork, play/pause controls, volume sliders, and playlist views. The Next.js API routes handle the SoundCloud data fetching. The SoundCloud Widget JavaScript library manages actual audio playback and emits events (play, pause, finish) that your React components can respond to for custom playback UI.

Integration method

Next.js API Route

SoundCloud API integration uses two complementary approaches: the oEmbed endpoint for embeddable players (no authentication required) and the SoundCloud REST API for fetching track metadata, user profiles, and playlists (requires a client_id). Your Next.js API route proxies calls to the SoundCloud API using a client_id stored in Vercel environment variables, while the SoundCloud Widget API handles audio playback directly in the browser.

Prerequisites

  • A V0 account at v0.dev with a Next.js project created
  • A SoundCloud account — sign up at soundcloud.com
  • A SoundCloud API app registration at soundcloud.com/you/apps to get a client_id
  • A Vercel account connected to your V0 project for deployment
  • The SoundCloud tracks or profiles you want to display (public tracks only for basic API access)

Step-by-step guide

1

Generate the Music Player UI with V0

Start in V0 and describe the music player interface you want to build. A good starting point is a track listing component that shows artwork, title, and play controls, plus an embed area for the SoundCloud player. V0 will generate React components using Tailwind CSS with proper media player semantics and accessible controls. Ask for specific UI elements relevant to your use case: a sticky player bar that persists as users browse, a waveform placeholder (SoundCloud provides the actual waveform via the Widget API), track cards in a grid or list layout, and a search input. Specify the color scheme you want — many music apps use dark themes with accent colors. Make sure V0 generates loading skeleton states for the track list since API calls have latency. Ask V0 to create TypeScript interfaces for the SoundCloud track data shape so the components are fully typed from the start. Once V0 generates the components, review them in the preview to confirm the player controls look and feel right, then proceed to wire up the actual SoundCloud data.

V0 Prompt

Build a music player page with a dark theme. At the top, a currently playing bar with track artwork (50x50), artist name, track title, and playback controls (previous, play/pause, next, volume). Below, a track listing with thumbnail, title, artist, duration, and play count. Include a search bar. Use the SoundCloud orange (#FF3300) as the accent color. Show skeleton cards while loading. Fetch data from /api/soundcloud/tracks.

Paste this in V0 chat

Pro tip: SoundCloud's brand color is #FF3300 (orange). Using it as an accent in your V0 player makes the integration feel native and recognizable to users who are familiar with SoundCloud.

Expected result: A styled dark-theme music player UI renders in the V0 preview with track cards, skeleton loading states, and playback control buttons.

2

Create the SoundCloud Tracks API Route

Create a Next.js App Router route handler at app/api/soundcloud/tracks/route.ts. The SoundCloud API v2 uses your client_id as a query parameter for authentication — there is no Bearer token needed for public track fetching. The base URL is https://api.soundcloud.com. To fetch tracks from a specific user, call the /users/{user_id}/tracks endpoint. To search for tracks globally, use the /tracks endpoint with a q query parameter. The API returns an array of track objects with properties like artwork_url, title, permalink_url, duration, playback_count, and waveform_url. Your route handler should accept query parameters for userId (to fetch a specific user's tracks), query (for search), and limit for pagination. Parse the SoundCloud response and return a cleaned payload with just the fields your frontend needs — this reduces payload size and keeps your API contract clean. Add error handling for 401 (invalid client_id), 404 (user not found), and rate limit errors. SoundCloud's public API allows around 15,000 requests per day for registered apps.

app/api/soundcloud/tracks/route.ts
1// app/api/soundcloud/tracks/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4const SC_BASE = 'https://api.soundcloud.com';
5
6export async function GET(request: NextRequest) {
7 const { searchParams } = new URL(request.url);
8 const userId = searchParams.get('userId');
9 const query = searchParams.get('query');
10 const limit = searchParams.get('limit') || '20';
11
12 try {
13 let endpoint: string;
14
15 if (userId) {
16 endpoint = `${SC_BASE}/users/${userId}/tracks`;
17 } else if (query) {
18 endpoint = `${SC_BASE}/tracks`;
19 } else {
20 return NextResponse.json(
21 { error: 'Provide either userId or query parameter' },
22 { status: 400 }
23 );
24 }
25
26 const url = new URL(endpoint);
27 url.searchParams.set('client_id', process.env.SOUNDCLOUD_CLIENT_ID!);
28 url.searchParams.set('limit', limit);
29 if (query) url.searchParams.set('q', query);
30
31 const response = await fetch(url.toString(), {
32 next: { revalidate: 60 }, // Cache for 60 seconds
33 });
34
35 if (!response.ok) {
36 return NextResponse.json(
37 { error: `SoundCloud API error: ${response.status}` },
38 { status: response.status }
39 );
40 }
41
42 const data = await response.json();
43 const tracks = (Array.isArray(data) ? data : data.collection || []).map(
44 (track: Record<string, unknown>) => ({
45 id: track.id,
46 title: track.title,
47 artworkUrl: track.artwork_url,
48 permalinkUrl: track.permalink_url,
49 duration: track.duration,
50 playbackCount: track.playback_count,
51 waveformUrl: track.waveform_url,
52 user: {
53 username: (track.user as Record<string, unknown>)?.username,
54 avatarUrl: (track.user as Record<string, unknown>)?.avatar_url,
55 },
56 })
57 );
58
59 return NextResponse.json({ tracks });
60 } catch (error) {
61 console.error('SoundCloud tracks error:', error);
62 return NextResponse.json({ error: 'Failed to fetch tracks' }, { status: 500 });
63 }
64}

Pro tip: SoundCloud artwork URLs use //i1.sndcdn.com format — prefix with https: if you need absolute URLs for the Next.js Image component.

Expected result: Calling /api/soundcloud/tracks?userId=123 returns a JSON array of track objects with titles, artwork URLs, and durations.

3

Embed SoundCloud Players Using oEmbed

For actually playing audio, use SoundCloud's oEmbed endpoint rather than the REST API. The oEmbed endpoint at https://soundcloud.com/oembed accepts a track permalink URL and returns an HTML iframe embed code. This is the simplest way to get a playable SoundCloud player into your Next.js page without any API key — it is completely public. Create a route handler at app/api/soundcloud/embed/route.ts that accepts a track URL, calls the oEmbed endpoint, and returns the iframe HTML. Your React component can then set the iframe HTML using dangerouslySetInnerHTML or parse the src URL from the HTML string and render it as a proper React iframe element. The oEmbed endpoint supports parameters like color (hex color without #), auto_play (true/false), hide_related (true/false), show_comments (true/false), and visual (true/false — shows the waveform). Using color matching your app's theme makes the embedded player feel native. The iframe approach means SoundCloud handles all playback, DRM, and licensing — you do not need to handle audio files directly.

V0 Prompt

Create an EmbedPlayer component that accepts a trackUrl prop and renders an embedded SoundCloud player. Fetch the embed code from /api/soundcloud/embed?url={trackUrl} and render it as a responsive iframe. Show a loading skeleton while fetching. The player should be 100% wide and about 166px tall for the compact player style.

Paste this in V0 chat

app/api/soundcloud/embed/route.ts
1// app/api/soundcloud/embed/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4export async function GET(request: NextRequest) {
5 const trackUrl = request.nextUrl.searchParams.get('url');
6
7 if (!trackUrl) {
8 return NextResponse.json({ error: 'url parameter is required' }, { status: 400 });
9 }
10
11 try {
12 const oEmbedUrl = new URL('https://soundcloud.com/oembed');
13 oEmbedUrl.searchParams.set('url', trackUrl);
14 oEmbedUrl.searchParams.set('format', 'json');
15 oEmbedUrl.searchParams.set('color', 'ff3300'); // SoundCloud orange
16 oEmbedUrl.searchParams.set('auto_play', 'false');
17 oEmbedUrl.searchParams.set('hide_related', 'true');
18 oEmbedUrl.searchParams.set('show_comments', 'false');
19 oEmbedUrl.searchParams.set('visual', 'true');
20
21 const response = await fetch(oEmbedUrl.toString(), {
22 next: { revalidate: 3600 }, // Cache embed for 1 hour
23 });
24
25 if (!response.ok) {
26 return NextResponse.json(
27 { error: 'Failed to fetch SoundCloud embed' },
28 { status: response.status }
29 );
30 }
31
32 const data = await response.json();
33
34 return NextResponse.json({
35 html: data.html,
36 title: data.title,
37 author: data.author_name,
38 thumbnailUrl: data.thumbnail_url,
39 });
40 } catch (error) {
41 console.error('SoundCloud embed error:', error);
42 return NextResponse.json({ error: 'Embed fetch failed' }, { status: 500 });
43 }
44}

Pro tip: The oEmbed endpoint requires no API key and works for any public SoundCloud track. Use it as the primary playback mechanism to keep your integration simple.

Expected result: Calling /api/soundcloud/embed?url=https://soundcloud.com/artist/trackname returns embed HTML that renders a playable SoundCloud player.

4

Add the SOUNDCLOUD_CLIENT_ID Environment Variable

To use the SoundCloud REST API for track search and metadata fetching, you need a client_id. Register your app at https://soundcloud.com/you/apps by logging into SoundCloud and clicking 'Register a new application'. Fill in your app name, description, and the Vercel deployment URL as your homepage. Once registered, you receive a client_id. In the Vercel Dashboard, navigate to your project, then click Settings → Environment Variables. Add SOUNDCLOUD_CLIENT_ID with your client_id value. Do not add the NEXT_PUBLIC_ prefix — this keeps it server-side only. Set it for Production, Preview, and Development scopes. For the oEmbed-only use case (no track search, just embedding by URL), you do not need a client_id at all — the oEmbed endpoint is completely public. The client_id is only required for the /tracks REST API endpoint used for search and user track listings. After adding the environment variable, redeploy your project from the Vercel Dashboard to ensure the new value is available to your serverless functions.

Pro tip: SoundCloud's API registration at soundcloud.com/you/apps can sometimes have approval delays. For development, oEmbed players work without any credentials — start with those while waiting for API access.

Expected result: The SOUNDCLOUD_CLIENT_ID variable appears in Vercel environment settings and the /api/soundcloud/tracks route returns real track data.

Common use cases

Artist Portfolio with Embedded Tracks

A music producer uses V0 to build their portfolio site with a track listing that embeds their SoundCloud uploads. Each track card shows artwork, title, play count, and an embedded SoundCloud player.

V0 Prompt

Create an artist portfolio music player with a grid of track cards. Each card shows album artwork (square), track title, genre tag, play count, and a play button. Clicking play expands the card to show an embedded audio player with a waveform. Include a header with artist name, avatar, follower count, and track count. Fetch tracks from /api/soundcloud/tracks.

Copy this prompt to try it in V0

Music Discovery Feed

A music blog uses V0 to build a curated track discovery feed showing the latest tracks from specific SoundCloud genres. Users can play tracks inline without leaving the page.

V0 Prompt

Build a music discovery feed with a search bar at the top to find SoundCloud tracks by artist or genre. Show results as a vertical list with artwork thumbnail, track title, artist name, track duration, and waveform visualization placeholder. Include an audio player bar at the bottom of the page that persists while browsing, showing current track info and playback controls.

Copy this prompt to try it in V0

Podcast Player Interface

A podcast network publishes episodes on SoundCloud and uses V0 to build a custom podcast player site that fetches episode data from their SoundCloud profile and renders a branded listening experience.

V0 Prompt

Create a podcast episode listing page with a sidebar showing podcast artwork and description, and a main feed of episode cards with title, publish date, duration, and description excerpt. Clicking an episode opens a full-width audio player at the top with playback controls. Fetch episodes from /api/soundcloud/playlist.

Copy this prompt to try it in V0

Troubleshooting

SoundCloud API returns 401 with 'Invalid client_id'

Cause: The SOUNDCLOUD_CLIENT_ID environment variable is missing, incorrect, or the Vercel deployment has not been updated since adding the variable.

Solution: Verify the client_id in Vercel Dashboard under Settings → Environment Variables. Make sure it matches exactly what is shown in your SoundCloud app registration at soundcloud.com/you/apps. Redeploy the project after making any changes.

SoundCloud oEmbed returns 404 or empty response

Cause: The track URL passed to the oEmbed endpoint is invalid, private, or the track has been deleted by the creator.

Solution: Make sure the track URL is a valid, publicly accessible SoundCloud permalink like https://soundcloud.com/artist-name/track-name. Private tracks cannot be embedded via oEmbed. Validate URLs before passing them to the embed endpoint.

Track artwork images are blocked or show broken image icons

Cause: SoundCloud artwork URLs use protocol-relative format (//i1.sndcdn.com/...) which does not work with the Next.js Image component or in mixed-content contexts.

Solution: Prefix protocol-relative URLs with https: before using them in Image components or fetch calls.

typescript
1const artworkUrl = track.artwork_url?.startsWith('//')
2 ? `https:${track.artwork_url}`
3 : track.artwork_url;

SoundCloud API returns 403 Forbidden on some track endpoints

Cause: Your SoundCloud app has not been approved for extended API access, or you are trying to access private tracks or endpoints that require OAuth user authentication.

Solution: The public SoundCloud API (with just a client_id) only allows access to public content. For accessing a user's own private tracks or performing actions on behalf of a user, OAuth 2.0 user authentication is required. For most public player use cases, this is not needed.

Best practices

  • Store SOUNDCLOUD_CLIENT_ID in Vercel environment variables without the NEXT_PUBLIC_ prefix
  • Use the oEmbed endpoint for audio playback — it requires no API key and handles all licensing and DRM
  • Cache SoundCloud API responses with next: { revalidate: 60 } to reduce API calls and improve page load speed
  • Prefix protocol-relative artwork URLs (//i1.sndcdn.com) with https: before using them in Next.js Image components
  • Handle the case where tracks have no artwork by providing a fallback placeholder image
  • Use track permalink_url (not track ID) as the stable identifier when saving favorites or history
  • Display track duration formatted as mm:ss rather than raw milliseconds for user-friendly playback display

Alternatives

Frequently asked questions

Do I need a SoundCloud API key to embed tracks?

No. The SoundCloud oEmbed endpoint is completely public and requires no API key. You can embed any public SoundCloud track by passing its URL to https://soundcloud.com/oembed and rendering the returned iframe HTML. A client_id (API key) is only needed if you want to search tracks or fetch user profiles programmatically via the SoundCloud REST API.

Can I use the SoundCloud API to play full tracks on my website?

Yes, but only for tracks that the creator has set to allow embedding and only through the SoundCloud Widget (the iframe player). You cannot access raw audio file URLs for direct playback outside of the SoundCloud player — this is a licensing restriction. The Widget API gives you full playback control (play, pause, seek, volume) while keeping SoundCloud in control of the audio stream.

How do I find a SoundCloud user ID for the tracks API?

A SoundCloud user's numeric ID is not immediately visible from the profile URL. The easiest way to find it is to call the SoundCloud API resolve endpoint: https://api.soundcloud.com/resolve?url=https://soundcloud.com/username&client_id=YOUR_ID. This returns the full user object including the numeric id field.

Is SoundCloud's API free to use?

SoundCloud offers a free tier for registered API apps with a daily request limit of approximately 15,000 calls. For production apps with higher traffic, you need to contact SoundCloud about a commercial API agreement. The oEmbed endpoint has no documented rate limits and is generally more permissive.

Can V0 generate a waveform visualization for SoundCloud tracks?

V0 can generate a visual waveform placeholder using CSS bars or an SVG visualization. For real waveform data, SoundCloud provides a waveform_url in the track object that returns a JSON array of amplitude values. You can fetch this URL from your API route and pass the data to a V0-generated waveform component for authentic visualizations.

Does the SoundCloud Widget API work in Next.js?

Yes, but the Widget JavaScript library must be loaded client-side only. Use next/script with strategy='lazyOnload' to load the SoundCloud Widget API script, and initialize the widget inside a useEffect hook to ensure it only runs in the browser. The widget attaches to an existing iframe element and gives you programmatic control over playback.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.