A live radio player for any website. One script tag, no dependencies, no iframe. Works with any AzuraCast station โ WVVY 96.7 is just the default.
<div id="wvvy-player" data-variant="bar"></div>
<script src="https://wvvy.org/widget/player.js" async></script>
<script> on some plans. If yours does, use the iframe fallback:
<iframe src="https://wvvy.org/widget/embed.html?variant=bar" width="100%" height="104" style="border:0" title="WVVY 96.7 live"></iframe>
npm install wvvy-player-widget
import { mountPlayerWidget } from 'wvvy-player-widget';
const widget = mountPlayerWidget(document.getElementById('player'), {
station: 'https://radio.wvvy.org',
shortcode: 'wvvy',
variant: 'card',
frequency: '96.7'
});
// widget.destroy() on teardown
Every option is a data-* attribute on the container, or a key on the config object. Only station and shortcode point the widget at a stream; everything else is presentation.
| Attribute | Default | What it does |
|---|---|---|
| data-station | https://radio.wvvy.org | Base URL of the AzuraCast install. |
| data-shortcode | wvvy | Station shortcode within that install. |
| data-variant | bar | bar (single strip) or card (full console). |
| data-theme | brutalist | brutalist or modern. |
| data-accent | theme default | Any CSS colour. Drives the play button, dot, EQ, and dial. |
| data-stream | from API | Explicit stream URL. Defaults to the station's own default mount. |
| data-name | from API | Station name in the card header and bar strip. |
| data-tagline | from API | Headline beside the card's play button. |
| data-description | from API | Small line under that headline. |
| data-location | โ | Location line under the card header. |
| data-frequency | โ | e.g. 96.7. Also places the dial needle. |
| data-link | โ | Outbound link URL. Omit to hide the button. |
| data-link-label | Full player and schedule โ | Label for that link. |
| data-show-dial | true | FM dial on the card. Needs data-frequency. |
| data-show-schedule | true | Today's schedule strip. Hides itself if the station publishes none. |
| data-schedule-url | station's AzuraCast | Fetch the schedule from here instead โ any URL returning AzuraCast's schedule JSON, with CORS headers. For a schedule kept outside AzuraCast. |
| data-show-listeners | false | Live listener count. Off by default; hides itself anyway if the station doesn't publish one. |
| data-show-volume | true | Volume slider. Always hidden on iOS. |
| data-poll-interval | 20 | Metadata poll seconds. Floor of 10. |
| data-fonts | auto | auto self-hosts the web fonts; none uses system fonts and makes zero extra requests. |
The widget renders in a shadow root, so host page CSS can't reach it and its CSS can't reach your page. Custom properties are the one channel left open on purpose โ set them on the container and they cascade in.
#wvvy-player {
--wvvy-accent: #f0a500;
--wvvy-bg: #101820;
--wvvy-panel: #18222c;
--wvvy-text: #eef2f7;
--wvvy-muted: #8fa0b3;
--wvvy-line: #2c3a4b;
--wvvy-live: #c4452f;
}