PLAYER
WIDGET

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.

TRY IT

INSTALL

Any HTML page

<div id="wvvy-player" data-variant="bar"></div>
<script src="https://wvvy.org/widget/player.js" async></script>
Squarespace, Wix, and Google Sites strip <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>
It loads the same bundle. The one thing you give up is lock-screen and CarPlay controls, which browsers only bind to the top-level page.

npm

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

OPTIONS

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-stationhttps://radio.wvvy.orgBase URL of the AzuraCast install.
data-shortcodewvvyStation shortcode within that install.
data-variantbarbar (single strip) or card (full console).
data-themebrutalistbrutalist or modern.
data-accenttheme defaultAny CSS colour. Drives the play button, dot, EQ, and dial.
data-streamfrom APIExplicit stream URL. Defaults to the station's own default mount.
data-namefrom APIStation name in the card header and bar strip.
data-taglinefrom APIHeadline beside the card's play button.
data-descriptionfrom APISmall 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-labelFull player and schedule โ†’Label for that link.
data-show-dialtrueFM dial on the card. Needs data-frequency.
data-show-scheduletrueToday's schedule strip. Hides itself if the station publishes none.
data-schedule-urlstation's AzuraCastFetch the schedule from here instead โ€” any URL returning AzuraCast's schedule JSON, with CORS headers. For a schedule kept outside AzuraCast.
data-show-listenersfalseLive listener count. Off by default; hides itself anyway if the station doesn't publish one.
data-show-volumetrueVolume slider. Always hidden on iOS.
data-poll-interval20Metadata poll seconds. Floor of 10.
data-fontsautoauto self-hosts the web fonts; none uses system fonts and makes zero extra requests.

THEMING

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;
}

NOTES