# Only Hits Radio Public API > Free internet radio streams for apps: five Only Hits stations (Top 40, 70s/80s Gold, J-Pop, K-Pop, Top Hits) with stable MP3 stream URLs, logos and plain-text now-playing. No API key, no signup, CORS open. Works in CarPlay (AVPlayer), Android Auto (Media3/ExoPlayer), web players, smart speakers and DIY radios. HLS is not offered on the public CDN. Free to use in apps, car dashboards, smart speakers and web players. No API key or signup. CORS is open. Use onlyhit.us/artwork for logos and now-playing cards, and cdn.onlyhitsradio.net for stream mounts (not the upstream origins they point to). Credit "Only Hits". - Machine-readable station list: https://api.onlyhit.us/stations.json - Now playing for all stations (JSON, with album artwork URLs): https://onlyhit.us/artwork/nowplaying/all.json - Logo kit index (every size and format, JSON): https://onlyhit.us/artwork/logo/index.json - RadioDNS SPI service information (ETSI TS 102 818, XML): https://onlyhit.us/radiodns/spi/3.1/SI.xml - Human docs: https://api.onlyhit.us/ - Website: https://onlyhit.us Use the MP3 URL on iOS/CarPlay, Android/Android Auto, web players, Icecast-style clients, ESP32/Raspberry Pi radios and smart speakers. HLS is not offered on the public CDN. Each MP3 URL redirects (HTTP 302) to the current origin. Always keep the cdn.onlyhitsradio.net stream URL in your code. For logos and now-playing cards, use the onlyhit.us/artwork URLs below (CDN logo paths remain available for legacy). Album art inside the now-playing JSON is not hosted on /artwork/: it is the same website proxy the player uses, https://onlyhit.us/cdn/{source image}?width=60 (footer), 160 (network tile) and 480 (station hero). When there is no song, that proxy wraps the station logo. ## Stations ### Only Hits Your go-to station for hit music: a nonstop stream of today's biggest chart-toppers and timeless classics from various genres. - Genres: top 40, pop, hits, chart - MP3: https://cdn.onlyhitsradio.net/onlyhits - Logo: https://onlyhit.us/artwork/logo/onlyhits.png (also .webp) - Now playing (text/plain, "Artist - Title"): https://cdn.onlyhitsradio.net/currentsong/onlyhits - Now playing (JSON: artist, title, start time; album art at onlyhit.us/cdn/{image}?width=60|160|480, station logo through the same proxy when there is no song): https://onlyhit.us/artwork/nowplaying/onlyhits.json - Now playing image card (320x240 DAB slideshow size / 1280x720): https://onlyhit.us/artwork/nowplaying/onlyhits/card-320x240.jpg / https://onlyhit.us/artwork/nowplaying/onlyhits/card-1280x720.jpg - Logo kit (square icons up to 2048-3000 px, 4:1 banner, 16:9, Open Graph card, transparent marks, RadioDNS SPI sizes; PNG/WebP/AVIF), listed with sizes in: https://onlyhit.us/artwork/logo/onlyhits/index.json - Website: https://onlyhit.us/radio/onlyhit/ ### Only Hits Gold The ultimate collection of 70s, 80s and Pop Rock hits: classic rock, disco and pop that defined a generation. - Genres: 70s, 80s, classic hits, oldies, pop rock - MP3: https://cdn.onlyhitsradio.net/gold - Logo: https://onlyhit.us/artwork/logo/gold.png (also .webp) - Now playing (text/plain, "Artist - Title"): https://cdn.onlyhitsradio.net/currentsong/gold - Now playing (JSON: artist, title, start time; album art at onlyhit.us/cdn/{image}?width=60|160|480, station logo through the same proxy when there is no song): https://onlyhit.us/artwork/nowplaying/gold.json - Now playing image card (320x240 DAB slideshow size / 1280x720): https://onlyhit.us/artwork/nowplaying/gold/card-320x240.jpg / https://onlyhit.us/artwork/nowplaying/gold/card-1280x720.jpg - Logo kit (square icons up to 2048-3000 px, 4:1 banner, 16:9, Open Graph card, transparent marks, RadioDNS SPI sizes; PNG/WebP/AVIF), listed with sizes in: https://onlyhit.us/artwork/logo/gold/index.json - Website: https://onlyhit.us/radio/gold/ ### Only Hits Japan The latest hits, classic tracks and popular songs from Japan's top artists: J-Pop, J-Rock and more. - Genres: j-pop, japanese, anime, j-rock, world - MP3: https://cdn.onlyhitsradio.net/japan - Logo: https://onlyhit.us/artwork/logo/japan.png (also .webp) - Now playing (text/plain, "Artist - Title"): https://cdn.onlyhitsradio.net/currentsong/japan - Now playing (JSON: artist, title, start time; album art at onlyhit.us/cdn/{image}?width=60|160|480, station logo through the same proxy when there is no song): https://onlyhit.us/artwork/nowplaying/japan.json - Now playing image card (320x240 DAB slideshow size / 1280x720): https://onlyhit.us/artwork/nowplaying/japan/card-320x240.jpg / https://onlyhit.us/artwork/nowplaying/japan/card-1280x720.jpg - Logo kit (square icons up to 2048-3000 px, 4:1 banner, 16:9, Open Graph card, transparent marks, RadioDNS SPI sizes; PNG/WebP/AVIF), listed with sizes in: https://onlyhit.us/artwork/logo/japan/index.json - Website: https://onlyhit.us/radio/japan/ ### Only Hits K-Pop The best K-Pop hits: the latest chart-toppers, fan favorites and timeless tracks from your favorite K-Pop artists. - Genres: k-pop, korean, world - MP3: https://cdn.onlyhitsradio.net/kpop - Logo: https://onlyhit.us/artwork/logo/kpop.png (also .webp) - Now playing (text/plain, "Artist - Title"): https://cdn.onlyhitsradio.net/currentsong/kpop - Now playing (JSON: artist, title, start time; album art at onlyhit.us/cdn/{image}?width=60|160|480, station logo through the same proxy when there is no song): https://onlyhit.us/artwork/nowplaying/kpop.json - Now playing image card (320x240 DAB slideshow size / 1280x720): https://onlyhit.us/artwork/nowplaying/kpop/card-320x240.jpg / https://onlyhit.us/artwork/nowplaying/kpop/card-1280x720.jpg - Logo kit (square icons up to 2048-3000 px, 4:1 banner, 16:9, Open Graph card, transparent marks, RadioDNS SPI sizes; PNG/WebP/AVIF), listed with sizes in: https://onlyhit.us/artwork/logo/kpop/index.json - Website: https://onlyhit.us/radio/kpop/ ### Top Hits The latest and greatest in hit music. Top Hits, the sound of now. - Genres: top 40, pop, hits, chart - MP3: https://cdn.onlyhitsradio.net/tophits - Logo: https://onlyhit.us/artwork/logo/tophits.png (also .webp) - Now playing (text/plain, "Artist - Title"): https://cdn.onlyhitsradio.net/currentsong/tophits - Now playing (JSON: artist, title, start time; album art at onlyhit.us/cdn/{image}?width=60|160|480, station logo through the same proxy when there is no song): https://onlyhit.us/artwork/nowplaying/tophits.json - Now playing image card (320x240 DAB slideshow size / 1280x720): https://onlyhit.us/artwork/nowplaying/tophits/card-320x240.jpg / https://onlyhit.us/artwork/nowplaying/tophits/card-1280x720.jpg - Logo kit (square icons up to 2048-3000 px, 4:1 banner, 16:9, Open Graph card, transparent marks, RadioDNS SPI sizes; PNG/WebP/AVIF), listed with sizes in: https://onlyhit.us/artwork/logo/tophits/index.json - Website: https://onlyhit.us/radio/tophits/ ## Full example projects (MIT) Hub (start here): https://github.com/OnlyHitsRadio/onlyhits-integrations Org: https://github.com/OnlyHitsRadio - CarPlay, Swift: https://github.com/OnlyHitsRadio/onlyhits-carplay-example - Android Auto, Kotlin + Media3: https://github.com/OnlyHitsRadio/onlyhits-android-auto-example - Web player (JS): https://github.com/OnlyHitsRadio/onlyhits-web-player (demo: https://onlyhitsradio.github.io/onlyhits-web-player/) - Desktop examples (Electron / Tauri / Wails): https://github.com/OnlyHitsRadio/onlyhits-desktop-examples - Stream widgets (OBS overlays): https://github.com/OnlyHitsRadio/onlyhits-stream-widgets (demo: https://onlyhitsradio.github.io/onlyhits-stream-widgets/) - Flutter: https://github.com/OnlyHitsRadio/onlyhits-flutter-example - React Native: https://github.com/OnlyHitsRadio/onlyhits-react-native-example - ESP32 radio (in progress): https://github.com/OnlyHitsRadio/onlyhits-esp32-radio - Raspberry Pi (in progress): https://github.com/OnlyHitsRadio/onlyhits-raspberry-pi - Home Assistant (in progress): https://github.com/OnlyHitsRadio/onlyhits-home-assistant - Desktop app (in progress): https://github.com/OnlyHitsRadio/onlyhits-desktop ## Example: CarPlay (Swift) ```swift // CarPlay audio app (iOS 15+). Needs the com.apple.developer.carplay-audio // entitlement and a CPTemplateApplicationSceneDelegate entry in Info.plist. import CarPlay import AVFoundation struct Catalog: Decodable { struct Station: Decodable { struct Streams: Decodable { let mp3: URL } let id: String let name: String let tagline: String let streams: Streams } let stations: [Station] } final class CarPlaySceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate { private let player = AVPlayer() private var interfaceController: CPInterfaceController? func templateApplicationScene(_ scene: CPTemplateApplicationScene, didConnect interfaceController: CPInterfaceController) { self.interfaceController = interfaceController try? AVAudioSession.sharedInstance().setCategory(.playback) Task { @MainActor in let url = URL(string: "https://api.onlyhit.us/stations.json")! let (data, _) = try await URLSession.shared.data(from: url) let stations = try JSONDecoder().decode(Catalog.self, from: data).stations let items = stations.map { station -> CPListItem in let item = CPListItem(text: station.name, detailText: station.tagline) item.handler = { [weak self] _, completion in self?.play(station.streams.mp3) completion() } return item } let list = CPListTemplate(title: "Only Hits", sections: [CPListSection(items: items)]) _ = try await interfaceController.setRootTemplate(list, animated: true) } } private func play(_ url: URL) { try? AVAudioSession.sharedInstance().setActive(true) player.replaceCurrentItem(with: AVPlayerItem(url: url)) player.play() interfaceController?.pushTemplate(CPNowPlayingTemplate.shared, animated: true, completion: nil) } } ``` ## Example: Android Auto (Kotlin, Media3) ```kotlin // Android Auto with Media3 (androidx.media3: media3-session, media3-exoplayer). // Declare the service in AndroidManifest.xml with the // androidx.media3.session.MediaLibraryService and android.media.browse.MediaBrowserService // intent filters, plus com.google.android.gms.car.application meta-data. import android.net.Uri import androidx.media3.common.MediaItem import androidx.media3.common.MediaMetadata import androidx.media3.common.MimeTypes import androidx.media3.exoplayer.ExoPlayer import androidx.media3.session.LibraryResult import androidx.media3.session.MediaLibraryService import androidx.media3.session.MediaLibraryService.LibraryParams import androidx.media3.session.MediaLibraryService.MediaLibrarySession import androidx.media3.session.MediaSession import com.google.common.collect.ImmutableList import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture class OnlyHitsService : MediaLibraryService() { private lateinit var session: MediaLibrarySession private val stations = listOf( station("onlyhits", "Only Hits"), station("gold", "Only Hits Gold"), station("japan", "Only Hits Japan"), station("kpop", "Only Hits K-Pop"), station("tophits", "Top Hits"), ) private val root = MediaItem.Builder() .setMediaId("root") .setMediaMetadata( MediaMetadata.Builder() .setTitle("Only Hits") .setIsBrowsable(true) .setIsPlayable(false) .setMediaType(MediaMetadata.MEDIA_TYPE_FOLDER_RADIO_STATIONS) .build() ) .build() private fun station(id: String, name: String): MediaItem = MediaItem.Builder() .setMediaId(id) .setUri("https://cdn.onlyhitsradio.net/$id") .setMimeType(MimeTypes.AUDIO_MPEG) .setMediaMetadata( MediaMetadata.Builder() .setTitle(name) .setArtworkUri(Uri.parse("https://onlyhit.us/artwork/logo/$id.png")) .setIsBrowsable(false) .setIsPlayable(true) .setMediaType(MediaMetadata.MEDIA_TYPE_RADIO_STATION) .build() ) .build() override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() session = MediaLibrarySession.Builder(this, player, object : MediaLibrarySession.Callback { override fun onGetLibraryRoot( session: MediaLibrarySession, browser: MediaSession.ControllerInfo, params: LibraryParams?, ): ListenableFuture> = Futures.immediateFuture(LibraryResult.ofItem(root, params)) override fun onGetChildren( session: MediaLibrarySession, browser: MediaSession.ControllerInfo, parentId: String, page: Int, pageSize: Int, params: LibraryParams?, ): ListenableFuture>> = Futures.immediateFuture(LibraryResult.ofItemList(stations, params)) override fun onAddMediaItems( mediaSession: MediaSession, controller: MediaSession.ControllerInfo, mediaItems: MutableList, ): ListenableFuture> = Futures.immediateFuture( mediaItems.mapNotNull { req -> stations.find { it.mediaId == req.mediaId } }.toMutableList() ) }).build() } override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession = session override fun onDestroy() { session.player.release() session.release() super.onDestroy() } } ``` ## Example: Web (JavaScript) ```js // Any browser. The public stream is the MP3 mount (HTTP 302 to the current origin). const res = await fetch("https://api.onlyhit.us/stations.json"); const { stations } = await res.json(); const audio = new Audio(); const station = stations.find(s => s.id === "onlyhits"); audio.src = station.streams.mp3; audio.play(); // Now playing, plain text "Artist - Title" const nowPlaying = await (await fetch(station.now_playing.url)).text(); ``` ## Contact api@onlyhit.us