Tanta Innovative LogoTanta Innovative Logo
  1. Home
  2. How To Guides And Tutorials
  3. Integrating Spotify In Android Apps A Developers Guide To The Spotify Web Api And Sdk
tanta innovative logo

Lekki Peninsular, 104106 Lagos, Nigeria

+234 201-453-6000

hello@tantainnovatives.com
Become our AgentPrivacy PolicyTerms of Service
DMCA.com Protection Status

© 2025 Tanta Innovative. All Rights Reserved.

ISO Certification
  1. Home
  2. How To Guides And Tutorials
  3. Integrating Spotify In Android Apps A Developers Guide To The Spotify Web Api And Sdk

Integrating Spotify in Android Apps: Web API + SDK Tutorial 2025

Olisemeka Nwaeme

Olisemeka Nwaeme

July 5, 2025 · 9 min read min read

0

0

Integrating Spotify in Android Apps: Web API + SDK Tutorial 2025

TypeScript
1<!-- Example: If your app is called "MusicPlayer" -->
2musicplayer://callback
3

TypeScript
1<activity
2    android:name=".MainActivity"
3    android:exported="true"
4    android:launchMode="singleTop">
5    
6    <!-- Your existing intent filters -->
7    <intent-filter>
8        <action android:name="android.intent.action.MAIN" />
9        <category android:name="android.intent.category.LAUNCHER" />
10    </intent-filter>
11    
12    <!-- Spotify authentication callback -->
13    <intent-filter>
14        <action android:name="android.intent.action.VIEW" />
15        <category android:name="android.intent.category.DEFAULT" />
16        <category android:name="android.intent.category.BROWSABLE" />
17        <data
18            android:host="callback"
19            android:scheme="musicplayer" />
20    </intent-filter>
21</activity>
22

TypeScript
1object SpotifyConstants {
2    const val CLIENT_ID = "your_spotify_client_id_here"
3    const val REDIRECT_URI = "musicplayer://callback"
4    const val REQUEST_CODE = 1337
5    
6    // Spotify scopes - adjust based on your needs
7    val SCOPES = arrayOf(
8        "user-read-private",
9        "user-read-email", 
10        "user-read-playback-state",
11        "user-modify-playback-state",
12        "user-read-currently-playing",
13        "playlist-read-private",
14        "playlist-read-collaborative",
15        "playlist-modify-public",
16        "playlist-modify-private"
17    )
18}
19

TypeScript
1dependencies {
2    implementation 'com.spotify.android:auth:2.1.0'
3    implementation files('libs/spotify-app-remote-release-0.8.0.aar')
4    
5    // Additional dependencies for networking
6    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
7    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
8    implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
9}
10

TypeScript
1class SpotifyAuthManager(private val activity: Activity) {
2    
3    fun authenticate() {
4        val builder = AuthorizationRequest.Builder(
5            SpotifyConstants.CLIENT_ID,
6            AuthorizationResponse.Type.TOKEN,
7            SpotifyConstants.REDIRECT_URI
8        )
9        
10        builder.setScopes(SpotifyConstants.SCOPES)
11        builder.setShowDialog(false)
12        
13        val request = builder.build()
14        AuthorizationClient.openLoginActivity(
15            activity, 
16            SpotifyConstants.REQUEST_CODE, 
17            request
18        )
19    }
20}
21

TypeScript
1class MainActivity : AppCompatActivity() {
2    private lateinit var spotifyAuthManager: SpotifyAuthManager
3    private var accessToken: String? = null
4    
5    override fun onCreate(savedInstanceState: Bundle?) {
6        super.onCreate(savedInstanceState)
7        setContentView(R.layout.activity_main)
8        
9        spotifyAuthManager = SpotifyAuthManager(this)
10        
11        // Start authentication
12        spotifyAuthManager.authenticate()
13    }
14    
15    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
16        super.onActivityResult(requestCode, resultCode, data)
17        
18        if (requestCode == SpotifyConstants.REQUEST_CODE) {
19            val response = AuthorizationClient.getResponse(resultCode, data)
20            
21            when (response.type) {
22                AuthorizationResponse.Type.TOKEN -> {
23                    accessToken = response.accessToken
24                    onAuthenticationComplete(response.accessToken)
25                }
26                
27                AuthorizationResponse.Type.ERROR -> {
28                    Log.e("SpotifyAuth", "Auth error: ${response.error}")
29                    showError("Authentication failed: ${response.error}")
30                }
31                
32                else -> {
33                    Log.d("SpotifyAuth", "Auth cancelled")
34                }
35            }
36        }
37    }
38    
39    private fun onAuthenticationComplete(token: String) {
40        // Token received successfully
41        Toast.makeText(this, "Authentication successful!", Toast.LENGTH_SHORT).show()
42        
43        // Now you can use the Web API
44        setupSpotifyWebAPI(token)
45        
46        // And connect to the App Remote
47        connectToSpotifyAppRemote()
48    }
49    
50    private fun showError(message: String) {
51        Toast.makeText(this, message, Toast.LENGTH_LONG).show()
52    }
53}
54
54 lines

TypeScript
1interface SpotifyWebAPI {
2    @GET("me")
3    suspend fun getCurrentUser(
4        @Header("Authorization") authorization: String
5    ): Response<User>
6    
7    @GET("me/playlists")
8    suspend fun getUserPlaylists(
9        @Header("Authorization") authorization: String,
10        @Query("limit") limit: Int = 20
11    ): Response<PlaylistResponse>
12    
13    @GET("me/player/currently-playing")
14    suspend fun getCurrentlyPlaying(
15        @Header("Authorization") authorization: String
16    ): Response<CurrentlyPlaying>
17    
18    @GET("search")
19    suspend fun searchTracks(
20        @Header("Authorization") authorization: String,
21        @Query("q") query: String,
22        @Query("type") type: String = "track",
23        @Query("limit") limit: Int = 20
24    ): Response<SearchResponse>
25}
26

TypeScript
1data class User(
2    val id: String,
3    val display_name: String?,
4    val email: String?,
5    val images: List<Image>?
6)
7
8data class PlaylistResponse(
9    val items: List<Playlist>,
10    val total: Int
11)
12
13data class Playlist(
14    val id: String,
15    val name: String,
16    val description: String?,
17    val uri: String,
18    val images: List<Image>?
19)
20
21data class Image(
22    val url: String,
23    val height: Int?,
24    val width: Int?
25)
26

TypeScript
1class SpotifyApiClient {
2    companion object {
3        private const val BASE_URL = "https://api.spotify.com/v1/"
4        
5        fun create(): SpotifyWebAPI {
6            val logging = HttpLoggingInterceptor().apply {
7                level = HttpLoggingInterceptor.Level.BODY
8            }
9            
10            val client = OkHttpClient.Builder()
11                .addInterceptor(logging)
12                .build()
13            
14            return Retrofit.Builder()
15                .baseUrl(BASE_URL)
16                .client(client)
17                .addConverterFactory(GsonConverterFactory.create())
18                .build()
19                .create(SpotifyWebAPI::class.java)
20        }
21    }
22}
23

TypeScript
1private fun setupSpotifyWebAPI(accessToken: String) {
2    val api = SpotifyApiClient.create()
3    
4    lifecycleScope.launch {
5        try {
6            val authHeader = "Bearer $accessToken"
7            
8            // Get current user
9            val userResponse = api.getCurrentUser(authHeader)
10            if (userResponse.isSuccessful) {
11                val user = userResponse.body()
12                Log.d("SpotifyAPI", "Welcome ${user?.display_name}")
13            }
14            
15            // Get user's playlists
16            val playlistsResponse = api.getUserPlaylists(authHeader)
17            if (playlistsResponse.isSuccessful) {
18                val playlists = playlistsResponse.body()?.items
19                Log.d("SpotifyAPI", "Found ${playlists?.size} playlists")
20            }
21            
22        } catch (e: Exception) {
23            Log.e("SpotifyAPI", "API Error: ${e.message}")
24        }
25    }
26}
27

TypeScript
1class SpotifyPlaybackManager(private val context: Context) {
2    private var spotifyAppRemote: SpotifyAppRemote? = null
3    private val connectionParams = ConnectionParams.Builder(SpotifyConstants.CLIENT_ID)
4        .setRedirectUri(SpotifyConstants.REDIRECT_URI)
5        .showAuthView(true)
6        .build()
7    
8    fun connect(callback: (Boolean) -> Unit) {
9        SpotifyAppRemote.connect(
10            context,
11            connectionParams,
12            object : Connector.ConnectionListener {
13                override fun onConnected(appRemote: SpotifyAppRemote) {
14                    spotifyAppRemote = appRemote
15                    Log.d("SpotifyRemote", "Connected successfully")
16                    callback(true)
17                }
18                
19                override fun onFailure(throwable: Throwable) {
20                    Log.e("SpotifyRemote", "Connection failed", throwable)
21                    callback(false)
22                }
23            }
24        )
25    }
26    
27    fun disconnect() {
28        spotifyAppRemote?.let {
29            SpotifyAppRemote.disconnect(it)
30        }
31    }
32    
33    fun play(uri: String) {
34        spotifyAppRemote?.playerApi?.play(uri)
35    }
36    
37    fun pause() {
38        spotifyAppRemote?.playerApi?.pause()
39    }
40    
41    fun resume() {
42        spotifyAppRemote?.playerApi?.resume()
43    }
44    
45    fun skipToNext() {
46        spotifyAppRemote?.playerApi?.skipNext()
47    }
48    
49    fun skipToPrevious() {
50        spotifyAppRemote?.playerApi?.skipPrevious()
51    }
52    
53    fun getCurrentPlayerState(callback: (PlayerState?) -> Unit) {
54        spotifyAppRemote?.playerApi?.playerState?.setResultCallback { playerState ->
55            callback(playerState)
56        }
57    }
58}
59
59 lines

TypeScript
1private fun connectToSpotifyAppRemote() {
2    val playbackManager = SpotifyPlaybackManager(this)
3    
4    playbackManager.connect { success ->
5        if (success) {
6            // Connection successful - you can now control playback
7            setupPlaybackControls(playbackManager)
8        } else {
9            showError("Failed to connect to Spotify app. Please ensure Spotify is installed.")
10        }
11    }
12}
13
14private fun setupPlaybackControls(playbackManager: SpotifyPlaybackManager) {
15    findViewById<Button>(R.id.btn_play).setOnClickListener {
16        // Play a specific track or playlist
17        playbackManager.play("spotify:track:4iV5W9uYEdYUVa79Axb7Rh")
18    }
19    
20    findViewById<Button>(R.id.btn_pause).setOnClickListener {
21        playbackManager.pause()
22    }
23    
24    findViewById<Button>(R.id.btn_next).setOnClickListener {
25        playbackManager.skipToNext()
26    }
27    
28    // Get current player state
29    playbackManager.getCurrentPlayerState { playerState ->
30        playerState?.let { state ->
31            val isPlaying = !state.isPaused
32            val currentTrack = state.track
33            Log.d("PlayerState", "Playing: $isPlaying, Track: ${currentTrack.name}")
34        }
35    }
36}
37

TypeScript
1// Example retry implementation
2private suspend fun <T> apiCallWithRetry(
3    maxRetries: Int = 3,
4    apiCall: suspend () -> Response<T>
5): Response<T> {
6    repeat(maxRetries) { attempt ->
7        try {
8            val response = apiCall()
9            if (response.code() != 429) return response
10            
11            // Wait before retry (exponential backoff)
12            delay(1000L * (attempt + 1))
13        } catch (e: Exception) {
14            if (attempt == maxRetries - 1) throw e
15        }
16    }
17    throw Exception("Max retries exceeded")
18}
19

TypeScript
1// Example project structure
2app/
3├── data/
4│   ├── api/
5│   │   ├── SpotifyWebAPI.kt
6│   │   ├── SpotifyApiClient.kt
7│   │   └── models/
8│   └── repository/
9│       └── SpotifyRepository.kt
10├── domain/
11│   ├── models/
12│   └── usecases/
13├── presentation/
14│   ├── viewmodels/
15│   ├── activities/
16│   └── fragments/
17└── utils/
18    ├── SpotifyConstants.kt
19    └── Extensions.kt
20

TypeScript
1fun subscribeToPlayerState(callback: (PlayerState) -> Unit) {
2    spotifyAppRemote?.playerApi?.subscribeToPlayerState()?.setEventCallback { playerState ->
3        callback(playerState)
4    }
5}
6

TypeScript
1suspend fun createPlaylist(
2    accessToken: String, 
3    userId: String, 
4    name: String, 
5    description: String
6): Response<Playlist> {
7    val body = mapOf(
8        "name" to name,
9        "description" to description,
10        "public" to false
11    )
12    
13    return api.createPlaylist("Bearer $accessToken", userId, body)
14}
15

TypeScript
1suspend fun searchWithFilters(
2    accessToken: String,
3    query: String,
4    type: String = "track,album,artist",
5    market: String = "US",
6    limit: Int = 20
7): Response<SearchResponse> {
8    return api.search(
9        authorization = "Bearer $accessToken",
10        q = query,
11        type = type,
12        market = market,
13        limit = limit
14    )
15}
16

KotlinSpotifyAndroid Development
Loading comments...
Olisemeka Nwaeme

Olisemeka Nwaeme

0 Articles

Olise is a product-oriented Software Engineer specializing in Android development. As the Android Development Lead at Tanta Innovative, he’s dedicated to creating impactful mobile solutions that elevate client success and drive business efficiency. Beyond coding, Olise is a passionate Arsenal FC fan and anime lover. He values community and enjoys connecting with fellow developers at meetups.

Related Articles

Discover more insights and stories from our collection of articles

Getting started with the LLAMA 3.2-11B with groq
How To Guides And Tutorials3 min read min read

Getting started with the LLAMA 3.2-11B with groq

The LLAMA 3.2-11B model is a very powerful model that can perform both text and vision tasks.

Omolayo Timothy Ipinsanmi
Omolayo Timothy Ipinsanmi
Streamline Your Backend Workflow with Reusable Components
How To Guides And Tutorials6 min read min read

Streamline Your Backend Workflow with Reusable Components

Learn how backend developers can save time by creating reusable components for common tasks, streamlining project setups, improving consistency, and boosting productivity.

Meshach Philips
Meshach Philips
Getting Started with Google Maps in Flutter
How To Guides And Tutorials3 min read min read

Getting Started with Google Maps in Flutter

Learn how to integrate Google Maps into your Flutter app with this step-by-step guide. From API key setup to your first interactive map, get your mapping features running in minutes!

Omokehinde Igbekoyi
Omokehinde Igbekoyi
View More Articles
Complete Guide to Spotify Android Integration: Web API + SDK Tutorial 2025
Introduction
Prerequisites
Development Environment
Accounts & Access
Technical Knowledge
Setting Up Spotify Developer Account
Step 1: Create Your Spotify App
Step 2: Configure Redirect URI
Step 3: Save Important Credentials
Configuring Android Project
Step 1: Update AndroidManifest.xml
Step 2: Create Constants File
Step 3: Get SHA1 Fingerprint
Adding Spotify SDK
Method 1: Using Gradle (Recommended)
Method 2: Manual AAR Integration
User Authentication & Authorization
Step 1: Create Authentication Manager
Step 2: Handle Authentication Response
Accessing Spotify Web API
Step 1: Create API Interface
Step 2: Create Data Models
Step 3: Setup Retrofit Client
Step 4: Use the API
Implementing Music Playback
Step 1: Connect to Spotify App Remote
Step 2: Implement Playback Controls
Common Issues & Troubleshooting
Authentication Issues
Playback Issues
API Rate Limiting
Best Practices
Security
Performance
User Experience
Code Organization
Advanced Features
Real-time Player State Updates
Custom Playlist Creation
Search with Filters
Next Steps
Resources
Transform your Android app into a music-powered experience by integrating 
Spotify's Web API
 and 
Android SDK
. This comprehensive guide walks you through creating seamless music integration that allows users to discover, control, and interact with Spotify's vast music library directly from your application.
What you'll learn:
Perfect for:
Before starting your Spotify integration journey, ensure you have:
The redirect URI is crucial for OAuth authentication. Choose a unique scheme:
After creating your app, save these values securely:
Add the intent filter to handle Spotify authentication callbacks:
Create a 
SpotifyConstants.kt
 file to store your configuration:
Run this command in Android Studio terminal:
./gradlew signingReport
Copy the SHA1 fingerprint and add it to your Spotify app settings along with your package name.
Add to your app-level 
build.gradle
 file:
In your Activity:
Problem
: "AUTHENTICATION_SERVICE_UNAVAILABLE" error
Solution
:
Problem
: Redirect URI mismatch
Solution
:
Problem
: "Player command failed: Restriction violated"
Solution
:
Problem
: SpotifyAppRemote connection fails
Solution
:
Problem
: HTTP 429 Too Many Requests
Solution
:
You've now mastered the complete integration of Spotify's powerful APIs into your Android application! This implementation provides:
✅ 
Secure user authentication
 with OAuth 2.0
✅ 
Complete playback control
 through Spotify's remote API
✅ 
Access to rich music data
 via the Web API
✅ 
Production-ready error handling
 and best practices
✅ 
Scalable architecture
 for future enhancements
Happy coding, and may your app bring the joy of music to users worldwide!
Last updated: July 2025 | Compatible with Spotify Android SDK v0.8.0





  • Complete Spotify developer setup process
  • Authentication and authorization implementation
  • Real-time music playback control
  • Accessing user data and playlists
  • Best practices for production apps
  • Android developers building music apps
  • Developers creating social or entertainment platforms
  • Portfolio projects requiring advanced API integration
  • Apps needing music discovery features
  • Android Studio (latest stable version recommended)
  • Android API Level 21+ (Android 5.0 Lollipop)
  • Kotlin or Java knowledge
  • Git for version control
  • Spotify Premium account (required for playback features)
  • Spotify Developer account (free registration)
  • Android device or emulator with Spotify app installed
  • Basic Android development experience
  • Understanding of REST APIs
  • Familiarity with OAuth 2.0 authentication
  • Navigate to the 
  • Click "Create App"
  • Fill out the application form:
    • App Name: Choose a descriptive name
    • App Description: Brief description of your app's functionality
    • Website: Your app's website or GitHub repository
    • Redirect URI: your-app-scheme://callback (we'll configure this next)
  • Client ID: Used for authentication requests
  • Client Secret: Keep this private and secure
  • Download the 
  • Create a libs folder in your app directory
  • Place the .aar file in the libs folder
  • Add the dependency as shown above
  • Ensure Spotify app is installed and updated
  • Verify SHA1 fingerprint is correctly added to Spotify dashboard
  • Check that package name matches exactly
  • Verify the redirect URI in your code matches the one in Spotify dashboard
  • Ensure the scheme is unique and properly formatted
  • User needs Spotify Premium for playback control
  • Some tracks may have regional restrictions
  • Check if Spotify app is installed: SpotifyApi.isSpotifyInstalled(context)
  • Ensure your app's package name and SHA1 are correctly configured
  • Implement proper retry logic with exponential backoff
  • Cache API responses when possible
  • Be mindful of rate limits (varies by endpoint)
  • Never expose your Client Secret in client-side code
  • Store access tokens securely using Android Keystore
  • Implement token refresh logic for long-running apps
  • Use HTTPS for all API communications
  • Cache API responses to reduce network calls
  • Implement pagination for large datasets
  • Use coroutines for non-blocking API calls
  • Optimize image loading with libraries like Glide or Coil
  • Handle offline scenarios gracefully
  • Provide loading states during API calls
  • Implement proper error messages for users
  • Respect user's playback state - don't interrupt their music unexpectedly
  • Enhance the UI with album artwork and track visualizations
  • Implement offline caching for better performance
  • Add social features like playlist sharing
  • Explore advanced analytics with Spotify's additional APIs
  • Consider implementing your own music recommendation engine
  • Spotify Developer Dashboard
    Spotify Android SDK
    Spotify Web API Documentation
    Android SDK GitHub Repository
    Spotify Developer Community
    OAuth 2.0 Best Practices