A curated, free, and open list of internet radio stations — organized by genre, country, and language. Machine-readable JSON, plus auto-generated M3U and PLS for classic media players.
Use it in your own app, on your NAS, in your car, or wherever you play audio.
| File | Purpose |
|---|---|
stations.json |
Master list — all stations with full metadata |
by-genre.json |
Stations grouped by genre (Ambient, Jazz, Classical, etc.) |
by-country.json |
Stations grouped by ISO 3166-1 country (US, HK, FR, GB, …) |
by-language.json |
Stations grouped by BCP 47 language tag (en, zh-HK, fr, …) |
stations.m3u |
Standard M3U playlist for VLC, iTunes, foobar2000, and most media players |
stations.pls |
PLS playlist for older tools that prefer it |
Auto-generated views regenerate from stations.json on every push, so all files stay in sync.
https://niftyopen.github.io/OpenStations/stations.json
https://niftyopen.github.io/OpenStations/stations.m3u
let url = URL(string: "https://niftyopen.github.io/OpenStations/stations.json")!
let (data, _) = try await URLSession.shared.data(from: url)
let catalog = try JSONDecoder().decode(RadioCatalog.self, from: data)
Each station in stations.json:
{
"id": "somafm-groove-salad",
"name": "Groove Salad",
"streamURL": "https://ice1.somafm.com/groovesalad-128-mp3",
"genre": "Ambient",
"country": "US",
"language": "en",
"bitrate": 128,
"codec": "mp3",
"homepage": "https://somafm.com/groovesalad/"
}
id — stable identifier, kebab-casecountry — ISO 3166-1 alpha-2 codelanguage — BCP 47 tagcodec — mp3, aac, hls, ogg, or flacbitrate — kbps (optional; omit or set null for HLS adaptive
streams and hosts that don’t publish a fixed bitrate)homepage — station’s official pageartworkURL — optional direct link (https) to a square PNG or JPEG logo,
at least 100 px (300+ preferred), no SVG. Apps use it instead of guessing
a logo from the homepage. Omit when unknown, never null.Optional availability flags. A station without them is usable. Apps should hide any station that carries either flag. The entries stay in the catalog so they can be restored later.
restricted (true) + restrictedReason — set by hand when a station
shouldn’t be played by third-party apps, for example because of rights or
legal concerns.offline (true) + offlineSince (YYYY-MM-DD) — set automatically when
the stream fails the maintainers’ health check (10 seconds of real audio).
The flag is removed once it plays again.stations.m3u and stations.pls leave flagged stations out, because plain
players can’t filter them. The by-*.json views include them with their
flags.
This project is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0).
You are free to use, adapt, and share this list — including commercially. In exchange, please credit OpenStations and link back to this repository.
Suggested attribution:
Radio station list from OpenStations, licensed under CC BY 4.0.
Suggestions welcome. See CONTRIBUTING.md for how to submit a station or report a broken stream.
Using OpenStations in your project? Open a PR to add yourself here.
If OpenStations saves you time or helps your project, consider tipping via GitHub Sponsors or Ko-fi (links coming soon).