# SoundCloudAudio

Audio component that plays SoundCloud tracks and sets through the SoundCloud Widget

The [SoundCloud Widget](https://developers.soundcloud.com/docs/api/html5-widget) plays public and private SoundCloud tracks and sets. This component drives the widget and reports its state like a native `<audio>` element, so a [player skin](https://videojs.org/docs/framework/react/guides/skins) can control it.

## Import

```bash
pnpm add @videojs/soundcloud-audio
```

```tsx
import { SoundCloudAudio } from '@videojs/react/media/soundcloud-audio';
```

## Load a source

`src` takes any of these SoundCloud URLs:

- A track: `soundcloud.com/<user>/<track>`
- A set: `soundcloud.com/<user>/sets/<set>`
- A private track or set, with its secret token: `soundcloud.com/<user>/<track>/s-<token>`
- An API resource: `api.soundcloud.com/tracks/<id>` or `api.soundcloud.com/playlists/<id>`, with an optional `secret_token`. The id can also be a URN such as `soundcloud:tracks:<id>`
- A widget embed URL: `w.soundcloud.com/player/?url=...`, as SoundCloud’s own embed code gives it

`m.soundcloud.com` links work too. Add `#t=` to start at a given time, in seconds (`#t=90`), clock time (`#t=1:30`), or units (`#t=1m30s`). Profiles, likes, and other pages that list sounds are not supported.

```tsx
<SoundCloudAudio src="https://soundcloud.com/forss/flickermood#t=1:30" />
```

## Controls

The widget is the only UI SoundCloud offers, so `controls` decides whether the component is visible at all. Without `controls`, the component hides itself and plays as an invisible transport: a hidden iframe still loads and plays, so a [player skin](https://videojs.org/docs/framework/react/guides/skins) drives playback while the widget takes no room on the page.

```tsx
<AudioPlayer>
  <AudioSkin>
    <SoundCloudAudio src="https://soundcloud.com/forss/flickermood" />
  </AudioSkin>
</AudioPlayer>
```

With `controls`, the component shows the widget, and the audio skin draws its controls below it, so the two do not overlap. Anything the listener does in the widget shows in the skin: play, pause, seeking on the waveform, and picking another track of a set. The widget is also the part of the page that credits the uploader and links back to the sound on SoundCloud (see [SoundCloud’s terms of use](#soundclouds-terms-of-use)).

```tsx
<SoundCloudAudio src="https://soundcloud.com/forss/flickermood" controls />
```

With `controls`, the component is 166 pixels tall by default, SoundCloud’s classic layout. Set a height to change it. From about 300 pixels, a set also shows its track list, and 450 pixels shows most of it. The large artwork layout of `visual: true` (see [widget parameters](#widget-parameters)) needs 300 pixels or more. At the default height, the artwork shows only behind the waveform.

```tsx
<SoundCloudAudio
  source={{ src: 'https://soundcloud.com/forss/flickermood', engine: { soundcloud: { visual: true } } }}
  controls
  style={{ height: 300 }}
/>
```

## Widget parameters

By default, the component hides the parts of the widget a skin has no use for: the buy, share, and download buttons, comments, reposts, the teaser, the related tracks shown after a track ends, and the large artwork layout. The uploader, the title, the artwork, and the SoundCloud logo stay whenever the widget shows.

Change any of these, or set `color`, under `source.engine.soundcloud`, spelled as SoundCloud spells them:

```tsx
<SoundCloudAudio
  source={{
    src: 'https://soundcloud.com/forss/sets/soulhack',
    engine: { soundcloud: { color: '#ff5500', start_track: 2, sharing: true } },
  }}
/>
```

Engine options win over the parameters of a widget embed URL, which win over the defaults. Set an option to `null` to drop a default.

## Behavior

- A set plays as one source. When the widget moves on to the next track, `duration` changes, `currentTime` starts again from `0`, and `durationchange` fires. `ended` fires only after the last track. `play()` after the end starts the set again from its first track.
- `loop` replays the track, or the set from its first track. If the widget does not start again, `ended` still fires.
- Volume and mute both work. The widget has no separate mute, so muting sets its volume to `0` and unmuting restores the previous level. Mute applies before autoplay starts, so a muted autoplay starts muted.
- `autoplay` starts playback once the widget is ready. Browsers can still refuse it, as they do for any embed. The widget’s own `auto_play` parameter does the same and is never written to the widget URL, so the volume always applies first.
- `buffered` is the stretch the widget reports as loaded, from where playback last started or landed.
- The widget does not support playback rate, picture-in-picture, fullscreen, or text tracks, so the component offers none of them, and a player skin hides those controls.
- `preload`, `playsinline`, and `poster` are accepted for parity with `<audio>` but have no effect.
- A track that is private without its secret token, removed, or not available in the listener’s region reports a `MEDIA_ERR_SRC_NOT_SUPPORTED` error, and so does a URL the component does not recognize. A widget that has not finished loading after 5 seconds reports a `MEDIA_ERR_NETWORK` error. An error the widget reports during playback fires a non-fatal `error` event but leaves `error` empty, because a set moves on to its next track by itself.

## SoundCloud’s terms of use

The widget is covered by the [SoundCloud Terms of Use](https://soundcloud.com/terms-of-use#use-of-soundcloud-players-and-widget), in the section about players and widgets. Without written consent from SoundCloud, you may not use the widget to:

- Aggregate SoundCloud content into a separate destination that substantially replicates what SoundCloud offers, or into a content service where SoundCloud content is a material part.
- Embed content on a site dedicated to one artist, unless the content is yours and you are that artist or represent them, or on a site dedicated to one genre.

These limits apply to commercial and non-commercial use. You also may not use the widget in a way that suggests that SoundCloud, an artist, or anyone else endorses or supports your site. SoundCloud can block your use of the widget at any time, for any reason.

The [SoundCloud API terms](https://developers.soundcloud.com/docs/api/terms-of-use), which ask you to credit the uploader and SoundCloud with links back to the sound, apply when you use the SoundCloud API, for example to play stream URLs in a player of your own. This component uses the widget, which [SoundCloud says handles that credit itself](https://developers.soundcloud.com/docs/api/buttons-logos). The widget gives that credit only while it shows, which is with `controls`. Without `controls`, we recommend that your page give the credit itself: name the uploader, name SoundCloud as the source, and link to the sound on SoundCloud. The Terms of Use also say you must not remove trademark, copyright, or other proprietary or legal notices that appear on content from SoundCloud.

## Privacy

The widget loads from SoundCloud as soon as the component renders. The [SoundCloud Privacy Policy](https://soundcloud.com/pages/privacy) says that SoundCloud may receive personal data when a visitor opens a page with an embedded widget, including which site they are on, and may recognize the visitor. The widget also stores data in the visitor’s browser. SoundCloud does not document an embed mode that avoids this, so if your site needs consent before it loads third-party content, render the component only after the visitor agrees.

## Examples

### Basic Usage

**App.tsx**

```tsx
import { SoundCloudAudio } from '@videojs/react/media/soundcloud-audio';

export default function BasicUsage() {
  return (
    <div className="soundcloud-audio">
      <SoundCloudAudio src="https://soundcloud.com/forss/flickermood" controls />
    </div>
  );
}
```

**App.css**

```css
.soundcloud-audio {
  width: 100%;
}
```

## API Reference

### Props

Accepts these Video.js-specific props:

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `autoplay` | `boolean` | `false` | Starts playback once the widget is ready, after the volume and start position apply. Browsers may refuse it. |
| `controls` | `boolean` | `false` | |
| `defaultMuted` | `boolean` | `false` | |
| `loop` | `boolean` | `false` | Replays the track, or a set from its first track, when the last one ends. |
| `muted` | `boolean` | `false` | |
| `playsInline` | `boolean` | `true` | |
| `poster` | `string` | `''` | |
| `preload` | `MediaPreloadType` | `'metadata'` | |
| `source` | `{ src?: string; engine?: SoundCloudSourceEngineConfig } \| null` | `null` | SoundCloud URL in `src`, widget parameters under `engine.soundcloud`. Replacing it re-derives `src`. |
| `src` | `string` | `''` | |

### Engine options

#### `source.engine.soundcloud`

Pass [SoundCloud Widget parameters](https://developers.soundcloud.com/docs/api/html5-widget#parameters) under `source.engine.soundcloud`, spelled exactly as SoundCloud spells them, plus anything SoundCloud adds next. [Media Sources](https://videojs.org/docs/framework/react/guides/media-sources) covers how engine options fit into a structured source.

The sound comes from `src`, so `url` has no `engine.soundcloud` spelling. `referrerPolicy` sets the `referrerpolicy` of the widget iframe rather than a widget parameter.

| Option | Type | Description |
| --- | --- | --- |
| `auto_play` | `boolean \| null \| undefined` | Start playback once the widget is ready, as `autoplay` does. Never written to the URL. |
| `buying` | `boolean \| null \| undefined` | Show the buy button. Defaults to `false`. |
| `color` | `string \| null \| undefined` | Hex color of the play button and other accents, such as `'#ff5500'`. |
| `download` | `boolean \| null \| undefined` | Show the download button. Defaults to `false`. |
| `hide_related` | `boolean \| null \| undefined` | Hide the related tracks the widget offers once a track ends. Defaults to `true`. |
| `referrerPolicy` | `ReferrerPolicy \| undefined` | `referrerpolicy` for the widget iframe. Not a widget parameter. |
| `sharing` | `boolean \| null \| undefined` | Show the share button. Defaults to `false`. |
| `show_artwork` | `boolean \| null \| undefined` | Show the artwork. |
| `show_comments` | `boolean \| null \| undefined` | Show listener comments on the waveform. Defaults to `false`. |
| `show_playcount` | `boolean \| null \| undefined` | Show the play count. |
| `show_reposts` | `boolean \| null \| undefined` | Show reposts. Defaults to `false`. |
| `show_teaser` | `boolean \| null \| undefined` | Show SoundCloud's promotional teaser. Defaults to `false`. |
| `show_user` | `boolean \| null \| undefined` | Show the uploader's name. The widget is what credits the uploader, so keep it unless the page does that elsewhere. |
| `single_active` | `boolean \| null \| undefined` | When `false`, playing this widget does not pause the other SoundCloud widgets on the page. |
| `start_track` | `number \| null \| undefined` | Index of the track in a set to start from. |
| `visual` | `boolean \| null \| undefined` | The large artwork layout. Defaults to `false`. |

### Refs

#### `ref`

Forwards to the rendered `<iframe>`, an [HTMLIFrameElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement). The `<iframe>` cannot play or seek; use [`mediaRef`](#mediaref) for playback.

```tsx
const ref = useRef<HTMLIFrameElement>(null);

<SoundCloudAudio ref={ref} />
```

#### `mediaRef`

Receives the `SoundCloudAdapter` that drives the embed, which exposes media methods and properties such as `play()` and `currentTime`. It is set once the adapter has attached to the `<iframe>`, so its `target` is already that element, and it is cleared when the element unmounts.

```tsx
import type { SoundCloudAdapter } from '@videojs/soundcloud-audio';

const mediaRef = useRef<SoundCloudAdapter>(null);

<SoundCloudAudio mediaRef={mediaRef} />

// In an event handler
mediaRef.current?.play();
```

### Events

Handle standard media events with React event props such as `onPlay` and `onTimeUpdate`. The adapter dispatches them, not the `<iframe>`. For events without a React prop, call `addEventListener` on the adapter from `mediaRef`.

---

React documentation: https://videojs.org/docs/framework/react/llms.txt
All documentation: https://videojs.org/llms.txt
