Skip to content

AnowHosting/radio-browser-api-documentation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“» Radio Browser API - Complete Developer Documentation

The Ultimate Guide to Radio Browser API Integration

API Stations License Documentation


πŸ“– Table of Contents

  1. Introduction
  2. API Base URL & Servers
  3. Quick Start
  4. Station Endpoints
  5. Search & Filter
  6. Categories & Lists
  7. Statistics & Counts
  8. Logo & Favicon Handling
  9. Voting & Click Tracking
  10. Advanced Queries
  11. Pagination & Limits
  12. Code Examples
  13. Error Handling
  14. Rate Limiting
  15. Best Practices
  16. Use Cases
  17. FAQ
  18. Support & Donation

🎯 Introduction

Radio Browser is a free, open-source API providing access to 45,000+ radio stations worldwide. This documentation covers every endpoint, parameter, and technique you need to build powerful radio applications.

✨ What You Can Build

Application Description
πŸ“» Radio Directory Complete station listing website
🎡 Music Streaming App Mobile/Desktop radio player
πŸ”Œ WordPress Plugin Like AnowXRadio
πŸ“± Mobile Apps iOS/Android radio apps
πŸ–₯️ Desktop Apps Electron-based radio players
πŸ€– Smart Speaker Skills Alexa, Google Assistant integration
πŸ“‘ IoT Devices Raspberry Pi radio projects

🌐 API Base URL & Servers

Available Servers (Load Balanced)

https://de1.api.radio-browser.info/json/
https://nl1.api.radio-browser.info/json/
https://at1.api.radio-browser.info/json/

Auto Server Selection (Recommended)

// Get best server automatically
const servers = [
    'https://de1.api.radio-browser.info',
    'https://nl1.api.radio-browser.info',
    'https://at1.api.radio-browser.info'
];

async function getBestServer() {
    for (const server of servers) {
        try {
            const response = await fetch(`${server}/json/stats`, { 
                timeout: 5000 
            });
            if (response.ok) return server;
        } catch (e) {
            continue;
        }
    }
    return servers[0]; // fallback
}

Response Formats

Format Endpoint Prefix Content-Type
JSON /json/ application/json
XML /xml/ application/xml

πŸš€ Quick Start

Your First API Call

# Get 10 stations
curl "https://de1.api.radio-browser.info/json/stations?limit=10"

JavaScript Example

fetch('https://de1.api.radio-browser.info/json/stations?limit=10')
    .then(res => res.json())
    .then(stations => {
        stations.forEach(station => {
            console.log(`πŸ“» ${station.name} - ${station.country}`);
        });
    });

πŸ“» Station Endpoints

Get All Stations

GET /json/stations

Get Stations with Limit

GET /json/stations?limit=100&offset=0

Get Station by UUID

GET /json/stations/byuuid/{stationuuid}

Example:

curl "https://de1.api.radio-browser.info/json/stations/byuuid/96202f73-0601-11e8-ae97-52543be04c81"

Get Station by Name (Exact)

GET /json/stations/byname/{name}

Get Station by Name (Search)

GET /json/stations/bynameexact/{name}

Station Object Structure

{
    "changeuuid": "96202f73-0601-11e8-ae97-52543be04c81",
    "stationuuid": "96202f73-0601-11e8-ae97-52543be04c81",
    "name": "BBC Radio 1",
    "url": "http://stream.live.vc.bbcmedia.co.uk/bbc_radio_one",
    "url_resolved": "http://stream.live.vc.bbcmedia.co.uk/bbc_radio_one",
    "homepage": "https://www.bbc.co.uk/radio1",
    "favicon": "https://example.com/logo.png",
    "tags": "pop,rock,news,bbc",
    "country": "United Kingdom",
    "countrycode": "GB",
    "state": "London",
    "language": "english",
    "languagecodes": "en",
    "votes": 12500,
    "lastchangetime": "2024-01-15 10:30:00",
    "codec": "MP3",
    "bitrate": 128,
    "hls": 0,
    "lastcheckok": 1,
    "lastchecktime": "2024-01-20 08:00:00",
    "clickcount": 50000,
    "clicktrend": 150,
    "ssl_error": 0,
    "geo_lat": 51.5074,
    "geo_long": -0.1278,
    "has_extended_info": true
}

Field Descriptions

Field Type Description
stationuuid string Unique station identifier
name string Station name
url string Original stream URL
url_resolved string Final resolved URL (after redirects)
favicon string Logo/Favicon URL
country string Country name
countrycode string ISO 3166-1 alpha-2 code
language string Primary language
tags string Comma-separated genre tags
votes int Total upvotes
codec string Audio codec (MP3, AAC, OGG)
bitrate int Stream bitrate in kbps
lastcheckok int 1 = online, 0 = offline
clickcount int Total plays/clicks
clicktrend int Recent click trend

πŸ” Search & Filter

Basic Search

GET /json/stations/search

Search Parameters

Parameter Type Description Example
name string Station name (partial match) name=BBC
nameExact boolean Exact name match nameExact=true
country string Country name country=India
countrycode string ISO country code countrycode=IN
state string State/Province state=Tamil Nadu
language string Language language=tamil
tag string Genre/Tag tag=pop
tagList string Multiple tags (comma) tagList=pop,rock
codec string Audio codec codec=MP3
bitrateMin int Minimum bitrate bitrateMin=128
bitrateMax int Maximum bitrate bitrateMax=320
has_geo_info boolean Has coordinates has_geo_info=true
has_extended_info boolean Has extended info has_extended_info=true
is_https boolean HTTPS stream only is_https=true
order string Sort order order=votes
reverse boolean Reverse sort reverse=true
offset int Pagination offset offset=0
limit int Results per page limit=100
hidebroken boolean Hide offline stations hidebroken=true

Search Examples

Search by Country

curl "https://de1.api.radio-browser.info/json/stations/bycountry/India?limit=50"

Search by Language

curl "https://de1.api.radio-browser.info/json/stations/bylanguage/tamil?limit=50"

Search by Tag/Genre

curl "https://de1.api.radio-browser.info/json/stations/bytag/classical?limit=50"

Search by Country Code

curl "https://de1.api.radio-browser.info/json/stations/bycountrycodeexact/IN?limit=50"

Combined Search (Multiple Filters)

curl "https://de1.api.radio-browser.info/json/stations/search?country=India&language=tamil&tag=music&hidebroken=true&order=votes&limit=100"

High Quality Stations Only

curl "https://de1.api.radio-browser.info/json/stations/search?bitrateMin=256&codec=MP3&hidebroken=true&limit=50"

HTTPS Only Streams

curl "https://de1.api.radio-browser.info/json/stations/search?is_https=true&limit=50"

Sort Options (order parameter)

Value Description
name Alphabetical by name
url By stream URL
homepage By homepage URL
favicon By favicon URL
tags By tags
country By country name
state By state
language By language
votes By total votes ⭐
codec By audio codec
bitrate By bitrate
lastcheckok By online status
lastchecktime By last check time
clicktimestamp By last click time
clickcount By total clicks πŸ”₯
clicktrend By click trend πŸ“ˆ
changetimestamp By last change time
random Random order 🎲

πŸ“‚ Categories & Lists

Get All Countries

GET /json/countries

Response:

[
    {
        "name": "India",
        "iso_3166_1": "IN",
        "stationcount": 1250
    },
    {
        "name": "United States",
        "iso_3166_1": "US",
        "stationcount": 8500
    }
]

Get All Languages

GET /json/languages

Response:

[
    {
        "name": "tamil",
        "iso_639": "ta",
        "stationcount": 450
    },
    {
        "name": "english",
        "iso_639": "en",
        "stationcount": 15000
    }
]

Get All Tags/Genres

GET /json/tags

Response:

[
    {
        "name": "pop",
        "stationcount": 5200
    },
    {
        "name": "rock",
        "stationcount": 4800
    },
    {
        "name": "classical",
        "stationcount": 1200
    }
]

Get All Codecs

GET /json/codecs

Response:

[
    {
        "name": "MP3",
        "stationcount": 35000
    },
    {
        "name": "AAC",
        "stationcount": 8000
    },
    {
        "name": "OGG",
        "stationcount": 2000
    }
]

Get All States (by Country)

GET /json/states/{country}

Example:

curl "https://de1.api.radio-browser.info/json/states/India"

Filter Categories

GET /json/countries?order=stationcount&reverse=true&limit=20
GET /json/languages?order=stationcount&reverse=true&limit=20
GET /json/tags?order=stationcount&reverse=true&hidebroken=true

πŸ“Š Statistics & Counts

Global Stats

GET /json/stats

Response:

{
    "supported_version": 1,
    "software_version": "0.7.24",
    "status": "OK",
    "stations": 45000,
    "stations_broken": 5000,
    "tags": 12000,
    "clicks_last_hour": 25000,
    "clicks_last_day": 500000,
    "languages": 450,
    "countries": 220
}

Station Count by Country

// Get stations count per country
async function getCountryStats() {
    const response = await fetch(
        'https://de1.api.radio-browser.info/json/countries?order=stationcount&reverse=true'
    );
    const countries = await response.json();
    
    countries.forEach(country => {
        console.log(`${country.name}: ${country.stationcount} stations`);
    });
}

Station Count by Language

// Get stations count per language
async function getLanguageStats() {
    const response = await fetch(
        'https://de1.api.radio-browser.info/json/languages?order=stationcount&reverse=true'
    );
    const languages = await response.json();
    
    languages.forEach(lang => {
        console.log(`${lang.name}: ${lang.stationcount} stations`);
    });
}

Top Voted Stations

GET /json/stations/topvote?limit=100

Most Clicked Stations

GET /json/stations/topclick?limit=100

Recently Changed Stations

GET /json/stations/lastchange?limit=100

Recently Clicked Stations

GET /json/stations/lastclick?limit=100

Server Stats

GET /json/servers

πŸ–ΌοΈ Logo & Favicon Handling

Getting Station Logo

const station = {
    name: "BBC Radio 1",
    favicon: "https://example.com/logo.png"
};

// Default logo URL
const DEFAULT_LOGO = "https://anowhosting.com/plugins/anowxradio/default-radio.png";

function getStationLogo(station) {
    return station.favicon && station.favicon.trim() !== '' 
        ? station.favicon 
        : DEFAULT_LOGO;
}

Logo with Error Handling (HTML)

<img 
    src="${station.favicon}" 
    alt="${station.name}"
    onerror="this.src='https://anowhosting.com/plugins/anowxradio/default-radio.png'"
    loading="lazy"
/>

Logo Component (React)

function StationLogo({ station }) {
    const DEFAULT_LOGO = "/images/default-radio.png";
    const [imgSrc, setImgSrc] = useState(station.favicon || DEFAULT_LOGO);
    
    return (
        <img 
            src={imgSrc}
            alt={station.name}
            onError={() => setImgSrc(DEFAULT_LOGO)}
            className="station-logo"
        />
    );
}

Logo Component (Vue)

<template>
    <img 
        :src="logoUrl"
        :alt="station.name"
        @error="handleImageError"
        class="station-logo"
    />
</template>

<script>
export default {
    props: ['station'],
    data() {
        return {
            logoUrl: this.station.favicon || '/images/default-radio.png'
        }
    },
    methods: {
        handleImageError() {
            this.logoUrl = '/images/default-radio.png';
        }
    }
}
</script>

CSS for Logo Placeholder

.station-logo {
    width: 80px;
    height: 80px;
    object-fit: cover;
    border-radius: 8px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.station-logo[src=""] {
    content: url('/images/default-radio.png');
}

Logo Caching Strategy

// Cache logos in IndexedDB or LocalStorage
async function cacheStationLogo(stationId, logoUrl) {
    try {
        const response = await fetch(logoUrl);
        const blob = await response.blob();
        const base64 = await blobToBase64(blob);
        localStorage.setItem(`logo_${stationId}`, base64);
    } catch (e) {
        console.log('Logo caching failed:', e);
    }
}

⭐ Voting & Click Tracking

Register Click (Important!)

When a user plays a station, register the click:

POST /json/url/{stationuuid}

Example:

async function registerClick(stationuuid) {
    await fetch(
        `https://de1.api.radio-browser.info/json/url/${stationuuid}`,
        { method: 'POST' }
    );
}

// Usage: Call when user clicks play
playButton.onclick = () => {
    registerClick(station.stationuuid);
    audioPlayer.play();
};

Vote for Station

POST /json/vote/{stationuuid}

Example:

async function voteStation(stationuuid) {
    const response = await fetch(
        `https://de1.api.radio-browser.info/json/vote/${stationuuid}`,
        { method: 'POST' }
    );
    const result = await response.json();
    
    if (result.ok === true) {
        console.log('Vote registered successfully!');
    } else {
        console.log('Vote failed:', result.message);
    }
}

Vote Response

{
    "ok": true,
    "message": "voted for station successfully"
}

πŸ”§ Advanced Queries

Get Random Stations

GET /json/stations/search?order=random&limit=10

Get Stations with Geo Coordinates

GET /json/stations/search?has_geo_info=true&limit=50

Get Stations Near Location

async function getStationsNearby(lat, lon, radiusKm = 100) {
    const stations = await fetch(
        'https://de1.api.radio-browser.info/json/stations/search?has_geo_info=true&limit=1000'
    ).then(r => r.json());
    
    return stations.filter(station => {
        const distance = calculateDistance(lat, lon, station.geo_lat, station.geo_long);
        return distance <= radiusKm;
    });
}

function calculateDistance(lat1, lon1, lat2, lon2) {
    const R = 6371; // Earth's radius in km
    const dLat = (lat2 - lat1) * Math.PI / 180;
    const dLon = (lon2 - lon1) * Math.PI / 180;
    const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
              Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
              Math.sin(dLon/2) * Math.sin(dLon/2);
    return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
}

Get Broken/Offline Stations

GET /json/stations/broken?limit=100

Get Stations Needing Check

GET /json/stations/search?lastcheckok=0&limit=100

Multi-Tag Search

async function searchByMultipleTags(tags) {
    const tagList = tags.join(',');
    const response = await fetch(
        `https://de1.api.radio-browser.info/json/stations/search?tagList=${tagList}&limit=100`
    );
    return response.json();
}

// Usage
searchByMultipleTags(['pop', 'rock', '80s']);

Search by Multiple Countries

async function searchMultipleCountries(countries) {
    const results = [];
    
    for (const country of countries) {
        const stations = await fetch(
            `https://de1.api.radio-browser.info/json/stations/bycountry/${country}?limit=50`
        ).then(r => r.json());
        
        results.push(...stations);
    }
    
    return results;
}

// Usage
searchMultipleCountries(['India', 'Sri Lanka', 'Malaysia']);

πŸ“„ Pagination & Limits

Basic Pagination

Parameter Default Max Description
limit 100000 100000 Results per page
offset 0 - Skip N results

Pagination Example

class RadioPaginator {
    constructor(baseUrl, limit = 50) {
        this.baseUrl = baseUrl;
        this.limit = limit;
        this.offset = 0;
        this.hasMore = true;
    }
    
    async getNextPage() {
        if (!this.hasMore) return [];
        
        const url = `${this.baseUrl}?limit=${this.limit}&offset=${this.offset}`;
        const response = await fetch(url);
        const stations = await response.json();
        
        this.offset += this.limit;
        this.hasMore = stations.length === this.limit;
        
        return stations;
    }
    
    reset() {
        this.offset = 0;
        this.hasMore = true;
    }
}

// Usage
const paginator = new RadioPaginator(
    'https://de1.api.radio-browser.info/json/stations/bycountry/India',
    50
);

// Load first page
const page1 = await paginator.getNextPage();

// Load next page
const page2 = await paginator.getNextPage();

Infinite Scroll Implementation

let offset = 0;
const limit = 30;
let loading = false;

async function loadMoreStations() {
    if (loading) return;
    loading = true;
    
    const response = await fetch(
        `https://de1.api.radio-browser.info/json/stations/search?country=India&offset=${offset}&limit=${limit}`
    );
    const stations = await response.json();
    
    stations.forEach(station => {
        appendStationToGrid(station);
    });
    
    offset += limit;
    loading = false;
}

// Intersection Observer for infinite scroll
const observer = new IntersectionObserver(entries => {
    if (entries[0].isIntersecting) {
        loadMoreStations();
    }
});

observer.observe(document.querySelector('#load-trigger'));

πŸ’» Code Examples

JavaScript / Fetch

class RadioBrowserAPI {
    constructor() {
        this.baseUrl = 'https://de1.api.radio-browser.info/json';
    }
    
    async searchStations(params = {}) {
        const queryString = new URLSearchParams(params).toString();
        const response = await fetch(`${this.baseUrl}/stations/search?${queryString}`);
        return response.json();
    }
    
    async getByCountry(country, limit = 100) {
        const response = await fetch(
            `${this.baseUrl}/stations/bycountry/${encodeURIComponent(country)}?limit=${limit}`
        );
        return response.json();
    }
    
    async getByLanguage(language, limit = 100) {
        const response = await fetch(
            `${this.baseUrl}/stations/bylanguage/${encodeURIComponent(language)}?limit=${limit}`
        );
        return response.json();
    }
    
    async getTopVoted(limit = 50) {
        const response = await fetch(`${this.baseUrl}/stations/topvote?limit=${limit}`);
        return response.json();
    }
    
    async getCountries() {
        const response = await fetch(`${this.baseUrl}/countries`);
        return response.json();
    }
    
    async getLanguages() {
        const response = await fetch(`${this.baseUrl}/languages`);
        return response.json();
    }
    
    async getTags() {
        const response = await fetch(`${this.baseUrl}/tags`);
        return response.json();
    }
    
    async registerClick(stationuuid) {
        await fetch(`${this.baseUrl}/url/${stationuuid}`, { method: 'POST' });
    }
    
    async vote(stationuuid) {
        const response = await fetch(
            `${this.baseUrl}/vote/${stationuuid}`, 
            { method: 'POST' }
        );
        return response.json();
    }
}

// Usage
const api = new RadioBrowserAPI();

// Search Tamil stations
const tamilStations = await api.searchStations({
    language: 'tamil',
    hidebroken: true,
    order: 'votes',
    limit: 50
});

// Get Indian stations
const indianStations = await api.getByCountry('India');

// Get top voted
const topStations = await api.getTopVoted(100);

Python

import requests
from typing import List, Dict, Optional

class RadioBrowserAPI:
    def __init__(self):
        self.base_url = "https://de1.api.radio-browser.info/json"
        self.headers = {
            "User-Agent": "MyRadioApp/1.0"
        }
    
    def search_stations(self, **params) -> List[Dict]:
        """Search stations with filters"""
        response = requests.get(
            f"{self.base_url}/stations/search",
            params=params,
            headers=self.headers
        )
        return response.json()
    
    def get_by_country(self, country: str, limit: int = 100) -> List[Dict]:
        """Get stations by country"""
        response = requests.get(
            f"{self.base_url}/stations/bycountry/{country}",
            params={"limit": limit},
            headers=self.headers
        )
        return response.json()
    
    def get_by_language(self, language: str, limit: int = 100) -> List[Dict]:
        """Get stations by language"""
        response = requests.get(
            f"{self.base_url}/stations/bylanguage/{language}",
            params={"limit": limit},
            headers=self.headers
        )
        return response.json()
    
    def get_top_voted(self, limit: int = 50) -> List[Dict]:
        """Get top voted stations"""
        response = requests.get(
            f"{self.base_url}/stations/topvote",
            params={"limit": limit},
            headers=self.headers
        )
        return response.json()
    
    def get_countries(self) -> List[Dict]:
        """Get all countries with station count"""
        response = requests.get(
            f"{self.base_url}/countries",
            headers=self.headers
        )
        return response.json()
    
    def get_languages(self) -> List[Dict]:
        """Get all languages with station count"""
        response = requests.get(
            f"{self.base_url}/languages",
            headers=self.headers
        )
        return response.json()
    
    def get_tags(self) -> List[Dict]:
        """Get all tags/genres"""
        response = requests.get(
            f"{self.base_url}/tags",
            headers=self.headers
        )
        return response.json()
    
    def register_click(self, stationuuid: str) -> Dict:
        """Register station click/play"""
        response = requests.post(
            f"{self.base_url}/url/{stationuuid}",
            headers=self.headers
        )
        return response.json()
    
    def vote(self, stationuuid: str) -> Dict:
        """Vote for a station"""
        response = requests.post(
            f"{self.base_url}/vote/{stationuuid}",
            headers=self.headers
        )
        return response.json()


# Usage
if __name__ == "__main__":
    api = RadioBrowserAPI()
    
    # Search Tamil stations
    tamil_stations = api.search_stations(
        language="tamil",
        hidebroken=True,
        order="votes",
        limit=50
    )
    
    for station in tamil_stations:
        print(f"πŸ“» {station['name']} - {station['country']}")
    
    # Get country stats
    countries = api.get_countries()
    for country in countries[:10]:
        print(f"{country['name']}: {country['stationcount']} stations")

PHP

<?php

class RadioBrowserAPI {
    private $baseUrl = 'https://de1.api.radio-browser.info/json';
    
    private function request($endpoint, $params = [], $method = 'GET') {
        $url = $this->baseUrl . $endpoint;
        
        if ($method === 'GET' && !empty($params)) {
            $url .= '?' . http_build_query($params);
        }
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_USERAGENT, 'MyRadioApp/1.0');
        
        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
        }
        
        $response = curl_exec($ch);
        curl_close($ch);
        
        return json_decode($response, true);
    }
    
    public function searchStations($params = []) {
        return $this->request('/stations/search', $params);
    }
    
    public function getByCountry($country, $limit = 100) {
        return $this->request("/stations/bycountry/{$country}", ['limit' => $limit]);
    }
    
    public function getByLanguage($language, $limit = 100) {
        return $this->request("/stations/bylanguage/{$language}", ['limit' => $limit]);
    }
    
    public function getTopVoted($limit = 50) {
        return $this->request('/stations/topvote', ['limit' => $limit]);
    }
    
    public function getCountries() {
        return $this->request('/countries');
    }
    
    public function getLanguages() {
        return $this->request('/languages');
    }
    
    public function getTags() {
        return $this->request('/tags');
    }
    
    public function registerClick($stationuuid) {
        return $this->request("/url/{$stationuuid}", [], 'POST');
    }
    
    public function vote($stationuuid) {
        return $this->request("/vote/{$stationuuid}", [], 'POST');
    }
}

// Usage
$api = new RadioBrowserAPI();

// Get Tamil stations
$stations = $api->searchStations([
    'language' => 'tamil',
    'hidebroken' => true,
    'order' => 'votes',
    'limit' => 50
]);

foreach ($stations as $station) {
    echo "πŸ“» {$station['name']} - {$station['country']}\n";
}

Node.js

const axios = require('axios');

class RadioBrowserAPI {
    constructor() {
        this.baseUrl = 'https://de1.api.radio-browser.info/json';
        this.client = axios.create({
            baseURL: this.baseUrl,
            headers: {
                'User-Agent': 'MyRadioApp/1.0'
            }
        });
    }
    
    async searchStations(params = {}) {
        const { data } = await this.client.get('/stations/search', { params });
        return data;
    }
    
    async getByCountry(country, limit = 100) {
        const { data } = await this.client.get(
            `/stations/bycountry/${encodeURIComponent(country)}`,
            { params: { limit } }
        );
        return data;
    }
    
    async getByLanguage(language, limit = 100) {
        const { data } = await this.client.get(
            `/stations/bylanguage/${encodeURIComponent(language)}`,
            { params: { limit } }
        );
        return data;
    }
    
    async getTopVoted(limit = 50) {
        const { data } = await this.client.get('/stations/topvote', { 
            params: { limit } 
        });
        return data;
    }
    
    async getCountries() {
        const { data } = await this.client.get('/countries');
        return data;
    }
    
    async getLanguages() {
        const { data } = await this.client.get('/languages');
        return data;
    }
    
    async getTags() {
        const { data } = await this.client.get('/tags');
        return data;
    }
    
    async registerClick(stationuuid) {
        const { data } = await this.client.post(`/url/${stationuuid}`);
        return data;
    }
    
    async vote(stationuuid) {
        const { data } = await this.client.post(`/vote/${stationuuid}`);
        return data;
    }
}

// Usage
(async () => {
    const api = new RadioBrowserAPI();
    
    const stations = await api.searchStations({
        language: 'tamil',
        hidebroken: true,
        order: 'votes',
        limit: 50
    });
    
    stations.forEach(station => {
        console.log(`πŸ“» ${station.name} - ${station.country}`);
    });
})();

cURL Examples

# Get all stations (limited)
curl "https://de1.api.radio-browser.info/json/stations?limit=50"

# Search by country
curl "https://de1.api.radio-browser.info/json/stations/bycountry/India?limit=50"

# Search by language
curl "https://de1.api.radio-browser.info/json/stations/bylanguage/tamil?limit=50"

# Search by tag
curl "https://de1.api.radio-browser.info/json/stations/bytag/pop?limit=50"

# Combined search
curl "https://de1.api.radio-browser.info/json/stations/search?country=India&language=tamil&hidebroken=true&order=votes&limit=100"

# Top voted stations
curl "https://de1.api.radio-browser.info/json/stations/topvote?limit=100"

# Get all countries
curl "https://de1.api.radio-browser.info/json/countries"

# Get all languages
curl "https://de1.api.radio-browser.info/json/languages"

# Get all tags
curl "https://de1.api.radio-browser.info/json/tags"

# Register click (POST)
curl -X POST "https://de1.api.radio-browser.info/json/url/96202f73-0601-11e8-ae97-52543be04c81"

# Vote (POST)
curl -X POST "https://de1.api.radio-browser.info/json/vote/96202f73-0601-11e8-ae97-52543be04c81"

# Get API stats
curl "https://de1.api.radio-browser.info/json/stats"

⚠️ Error Handling

HTTP Status Codes

Code Description
200 Success
400 Bad Request
404 Not Found
429 Too Many Requests
500 Server Error

JavaScript Error Handling

async function safeApiCall(url) {
    try {
        const response = await fetch(url);
        
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        
        const data = await response.json();
        return { success: true, data };
        
    } catch (error) {
        console.error('API Error:', error.message);
        return { success: false, error: error.message };
    }
}

// Usage
const result = await safeApiCall(
    'https://de1.api.radio-browser.info/json/stations?limit=50'
);

if (result.success) {
    console.log('Stations:', result.data);
} else {
    console.log('Error:', result.error);
}

Retry Logic

async function fetchWithRetry(url, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            const response = await fetch(url);
            if (response.ok) return response.json();
        } catch (error) {
            if (i === maxRetries - 1) throw error;
            await new Promise(r => setTimeout(r, 1000 * (i + 1))); // Exponential backoff
        }
    }
}

Server Failover

const servers = [
    'https://de1.api.radio-browser.info',
    'https://nl1.api.radio-browser.info',
    'https://at1.api.radio-browser.info'
];

async function fetchWithFailover(endpoint) {
    for (const server of servers) {
        try {
            const response = await fetch(`${server}${endpoint}`);
            if (response.ok) return response.json();
        } catch (e) {
            continue;
        }
    }
    throw new Error('All servers failed');
}

⏱️ Rate Limiting

Guidelines

Aspect Recommendation
Requests/second Max 2-3 requests
Bulk fetching Use larger limits, fewer requests
Caching Cache results for 5-15 minutes
User-Agent Always set custom User-Agent

Implementing Rate Limiter

class RateLimiter {
    constructor(requestsPerSecond = 2) {
        this.minInterval = 1000 / requestsPerSecond;
        this.lastRequest = 0;
    }
    
    async throttle() {
        const now = Date.now();
        const elapsed = now - this.lastRequest;
        
        if (elapsed < this.minInterval) {
            await new Promise(r => setTimeout(r, this.minInterval - elapsed));
        }
        
        this.lastRequest = Date.now();
    }
}

// Usage
const limiter = new RateLimiter(2);

async function fetchStations() {
    await limiter.throttle();
    return fetch('https://de1.api.radio-browser.info/json/stations?limit=50');
}

Caching Example

class CachedRadioAPI {
    constructor(cacheDurationMs = 300000) { // 5 minutes
        this.cache = new Map();
        this.cacheDuration = cacheDurationMs;
    }
    
    async fetch(url) {
        const cached = this.cache.get(url);
        
        if (cached && Date.now() - cached.timestamp < this.cacheDuration) {
            return cached.data;
        }
        
        const response = await fetch(url);
        const data = await response.json();
        
        this.cache.set(url, {
            data,
            timestamp: Date.now()
        });
        
        return data;
    }
}

πŸ“ Best Practices

βœ… Do's

Practice Description
Cache responses Cache for 5-15 minutes
Use hidebroken=true Filter offline stations
Set User-Agent Identify your app
Use url_resolved Use resolved URL for playback
Register clicks Call /url/{uuid} on play
Handle missing favicons Provide default logo

❌ Don'ts

Practice Description
Don't fetch all 45K stations Use pagination & filters
Don't ignore errors Implement proper error handling
Don't hammer the API Respect rate limits
Don't cache forever Refresh data periodically
Don't skip vote/click tracking Helps improve rankings

Recommended Headers

const headers = {
    'User-Agent': 'YourAppName/1.0 (yourwebsite.com)',
    'Accept': 'application/json'
};

🎯 Use Cases

1. Simple Radio Player

<!DOCTYPE html>
<html>
<head>
    <title>Simple Radio Player</title>
    <style>
        .station { padding: 10px; border: 1px solid #ddd; margin: 5px; cursor: pointer; }
        .station:hover { background: #f0f0f0; }
        .station img { width: 50px; height: 50px; object-fit: cover; }
    </style>
</head>
<body>
    <h1>πŸ“» Tamil Radio Stations</h1>
    <audio id="player" controls></audio>
    <div id="stations"></div>
    
    <script>
        const API = 'https://de1.api.radio-browser.info/json';
        const DEFAULT_LOGO = 'https://via.placeholder.com/50?text=πŸ“»';
        
        async function loadStations() {
            const response = await fetch(
                `${API}/stations/search?language=tamil&hidebroken=true&order=votes&limit=20`
            );
            const stations = await response.json();
            
            const container = document.getElementById('stations');
            
            stations.forEach(station => {
                const div = document.createElement('div');
                div.className = 'station';
                div.innerHTML = `
                    <img src="${station.favicon || DEFAULT_LOGO}" 
                         onerror="this.src='${DEFAULT_LOGO}'">
                    <strong>${station.name}</strong>
                    <small>${station.country}</small>
                `;
                div.onclick = () => playStation(station);
                container.appendChild(div);
            });
        }
        
        function playStation(station) {
            document.getElementById('player').src = station.url_resolved || station.url;
            document.getElementById('player').play();
            
            // Register click
            fetch(`${API}/url/${station.stationuuid}`, { method: 'POST' });
        }
        
        loadStations();
    </script>
</body>
</html>

2. Country Dropdown Filter

async function buildCountryDropdown() {
    const response = await fetch(
        'https://de1.api.radio-browser.info/json/countries?order=stationcount&reverse=true'
    );
    const countries = await response.json();
    
    const select = document.getElementById('countrySelect');
    
    countries.forEach(country => {
        const option = document.createElement('option');
        option.value = country.name;
        option.textContent = `${country.name} (${country.stationcount})`;
        select.appendChild(option);
    });
}

async function filterByCountry(country) {
    const response = await fetch(
        `https://de1.api.radio-browser.info/json/stations/bycountry/${country}?hidebroken=true&limit=50`
    );
    const stations = await response.json();
    displayStations(stations);
}

3. WordPress Import Function

function import_radio_stations($country, $limit = 100) {
    $api_url = "https://de1.api.radio-browser.info/json/stations/bycountry/{$country}";
    $api_url .= "?hidebroken=true&order=votes&limit={$limit}";
    
    $response = wp_remote_get($api_url);
    
    if (is_wp_error($response)) {
        return false;
    }
    
    $stations = json_decode(wp_remote_retrieve_body($response), true);
    
    foreach ($stations as $station) {
        // Check if already exists
        $existing = get_posts([
            'post_type' => 'radio_station',
            'meta_key' => 'station_uuid',
            'meta_value' => $station['stationuuid']
        ]);
        
        if (empty($existing)) {
            $post_id = wp_insert_post([
                'post_title' => $station['name'],
                'post_type' => 'radio_station',
                'post_status' => 'publish'
            ]);
            
            update_post_meta($post_id, 'station_uuid', $station['stationuuid']);
            update_post_meta($post_id, 'stream_url', $station['url_resolved']);
            update_post_meta($post_id, 'favicon', $station['favicon']);
            update_post_meta($post_id, 'country', $station['country']);
            update_post_meta($post_id, 'language', $station['language']);
            update_post_meta($post_id, 'bitrate', $station['bitrate']);
        }
    }
    
    return count($stations);
}

❓ FAQ

Q: Is the API free?

A: Yes! Radio Browser API is completely free and open-source.

Q: How many requests can I make?

A: There's no strict limit, but please be respectful. 2-3 requests/second is recommended.

Q: How often is data updated?

A: Stations are checked regularly. New stations are added by community.

Q: Can I add my radio station?

A: Yes! Visit radio-browser.info to submit your station.

Q: Why are some streams not working?

A: Use hidebroken=true to filter out offline stations. Some streams may be geo-restricted.

Q: How do I get only MP3 streams?

A: Use codec=MP3 parameter.

Q: How do I get high quality streams?

A: Use bitrateMin=128 or higher.

Q: Can I use this commercially?

A: Yes! But please credit Radio Browser and consider donating.


🀝 Support & Donation

About This Documentation

This documentation is maintained by ABM Rishi for the developer community.

πŸ“§ Contact 🌐 Website πŸ“± WhatsApp
support@anowhosting.com anowhosting.com +94 779688469

Support Radio Browser Project

Radio Browser is maintained by volunteers. Please consider supporting:

Related Projects

Project Description Link
AnowXRadio WordPress Radio Plugin anowhosting.com/plugins/anowxradio

πŸ“œ License

This documentation is provided under MIT License.

Radio Browser API is free and open-source.


πŸ”„ Changelog

Version Date Changes
1.0.0 2024-01-20 Initial release
1.1.0 2024-01-25 Added advanced examples

Made with ❀️ by ABM Rishi

GitHub Website WhatsApp

About

πŸ“» Complete Radio Browser API Documentation for Developers | 45,000+ Radio Stations | JavaScript, Python, PHP, Node.js Examples | Search, Filter, Stream Integration Guide | By ABM Rishi

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors