naif/soundcloud
A Laravel package for integrating the SoundCloud API into your application, providing a simple wrapper to authenticate and interact with SoundCloud services such as tracks, users, and playlists from your PHP code.
naif/soundcloud is a single-purpose Laravel Nova field that renders a SoundCloud embed player for a value stored on a model (usually a track URL). It is a display field, not an input widget — you still capture the URL with a normal Text/Url field and use Soundcloud to play it back.
Install
composer require naif/soundcloud
Because the package predates Nova's asset auto-discovery conventions, you will almost certainly need to publish its compiled JS/CSS into public/vendor/:
php artisan vendor:publish --tag=nova-soundcloud-assets
# or, if no tag is registered:
php artisan vendor:publish --provider="Naif\Soundcloud\FieldServiceProvider"
If the provider isn't auto-discovered (older Laravel), add it to config/app.php under providers.
Use it
use Naif\Soundcloud\Soundcloud;
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Title'),
Text::make('Soundcloud URL', 'audio_url')
->rules('nullable', 'url'),
Soundcloud::make('Preview', 'audio_url')
->onlyOnDetail(),
];
}
Where to look first
vendor/naif/soundcloud/src/ — the field class and its FieldServiceProvider (confirms the registered asset path and component name).vendor/naif/soundcloud/resources/js/ — the Vue component; this tells you exactly what value shape it expects (full URL vs. track ID) and whether it uses the SoundCloud widget API or a plain <iframe>.public/vendor/naif/soundcloud/ after publishing — if this directory is empty or 404s in the network tab, the field will render as an empty cell.First use case: add a read-only "listen" player to a detail page so editors can preview an uploaded episode/track without leaving Nova.
Split capture from playback. Keep a real form field for editing and a Soundcloud field for rendering. This keeps validation, nullable handling, and sorting on a normal column:
Text::make('Audio URL', 'audio_url')
->rules('nullable', 'url')
->hideFromIndex(),
Soundcloud::make('Preview', 'audio_url')
->onlyOnDetail()
->help('Public SoundCloud track URL'),
Restrict to detail views. Embeds inside index tables are slow and break row heights. Default to ->onlyOnDetail(), and only opt into ->showOnIndex() if you genuinely need inline playback in a table.
Normalise the stored value. Share links carry tracking query strings (?in=user/sets/...&si=abc123) and mobile links (on.soundcloud.com). Clean them on save with a mutator so the embed never receives a URL the player can't parse:
public function setAudioUrlAttribute(?string $value): void
{
$this->attributes['audio_url'] = $value
? strtok($value, '?')
: null;
}
Resolve computed values. If the URL lives in a relation or is assembled from parts, use resolveUsing so the field receives a plain string:
Soundcloud::make('Preview')
->resolveUsing(fn ($value, $resource) => $resource->track?->permalink_url)
->onlyOnDetail(),
Panel it with metadata. Group the player with duration/artist fields in a Panel so the detail page reads as a media card rather than a stack of unrelated inputs.
Custom sizing via meta. Most Nova field components pass field.* meta straight into the template. If the component reads a width/height prop, drive it from PHP:
Soundcloud::make('Preview', 'audio_url')
->withMeta(['height' => 166])
->onlyOnDetail();
Inspect resources/js/components/Field.vue first — if the props aren't there, this is the natural extension point (see Gotchas).
Replace rather than fork for one-offs. If you only need a player on one resource, a Text field with ->displayUsing(fn ($v) => ...) plus a small Blade partial inside a \Laravel\Nova\Fields\Heading or a custom detail component is usually less risk than adopting an unmaintained package.
Cannot read properties of undefined). Verify against your Nova major before wiring it into a resource; if you're on Nova 4/5, budget for rewriting the Vue component.php artisan nova:publish, then hard-refresh; check the browser network tab for 404 on vendor/naif/soundcloud/js/field.js.nova:publish after every composer update. Nova's publisher copies package assets into public/vendor; a reinstall can leave an old copy behind.secret_token in the URL. If your workflow uses secret links, store the full URL including the token and strip query params only when the token is absent.frame-src. The player is an iframe pointing at https://w.soundcloud.com. Sites with a Content-Security-Policy need frame-src https://w.soundcloud.com (and https://*.soundcloud.com for the widget API) or the frame is blocked with no visible error inside the field.http:// on an HTTPS Nova app is blocked silently. Always store https:// URLs.->hideWhenCreating()/->hideWhenUpdating() and, if needed, ->displayUsing(fn ($v) => $v ?: '—') on a companion text field so rows aren't blank.withMeta.resources/js/components/ into your own field (php artisan nova:field acme/audio) and register it yourself — you get a maintained component and full control over sizing, CSP attributes, and Vue 3 compatibility.dump() in resolveUsing; (2) are assets published and loading (network tab); (3) is the component registered (Vue devtools / console); (4) is the iframe blocked (Console CSP errors, frame-src).->component('your-component-name') lets you swap in your own Vue component while keeping the field's PHP-side API — the cheapest escape hatch if only the rendering needs to change.How can I help you explore Laravel packages today?