Build a collaborative playlist over WhatsApp with Rails, Twilio, and Spotify
Time to read: 7 minutes
Sharing music over playlists is a great way to discover new and old music. Spotify has collaborative playlists, but I don't like how they let your friends re-order and delete songs from the list. We can fix this by building our own collaborative playlist that only allows additions using the Spotify Web API. With the Twilio API for WhatsApp we can let our friends send in a song whenever they are struck by inspiration.
In this post we are going to build a WhatsApp bot that can do all of the above using Ruby on Rails.
Getting started
To build this application we will need a few things:
- Ruby version 2.5.1 installed
- Rails and bundler, which can be installed with
gem install rails bundler
- A Twilio account (sign up for a free Twilio account here)
- The WhatsApp sandbox set up in our Twilio account
- A Spotify developer account
- ngrok, so we can tunnel through to our locally developed application to use webhooks
Spotify API Credentials
To work with the Spotify API we will need to generate some API credentials. From the Spotify developer dashboard create a new application and follow the 3 step process.
- First, fill in some details about the app. Name it, I called mine WhatsPlaying, provide a short description and check what app type it is, I chose "website"
- Next we are asked if this is a commercial integration; choose "no"
- Finally, check the agreements
Once these steps are complete we will see the application dashboard. We will need the Client ID and Client Secret from this page.
There's one more thing we need to do here. Click on "edit settings", enter the redirect URL http://localhost:3000/auth/spotify/callback
and click "add".
Now that credentials are sorted, we can start to build our app.
Preparing the project
I've started the project off, so clone or download the repo from GitHub and checkout the getting-started
branch.
Change into the directory and install the project's dependencies.
Copy the config/env.yml.example
file to config/env.yml
(we're using envyable to manage environment variables for the application). Open config/env.yml
and fill in the Spotify Client ID and Client Secret we just generated. We'll fill in the rest soon.
We're now going to generate a Spotify access token for your account on Spotify as well as a new playlist, called "WhatsPlaying", that we are going to use as our collaborative playlist. Run the Rails app with:
Open the app at http://localhost:3000. There will be a link to "Sign in with Spotify". Click the link and follow the OAuth process. All of this is handled by the RSpotify gem and omniauth, you can check out the config required to make this work in config/initializers/rspotify.rb
.
Once you have been directed back to the application you will see your Spotify user ID, access token, refresh token, and playlist ID on the page in front of you. Copy these into config/env.yml
, restart the application, and open http://localhost:3000 again. You will find the playlist that the script just created empty and embedded in the page. Now it's time to build the integration between WhatsApp, Twilio, and Spotify.
Getting to grip with webhooks
When you send a message to a WhatsApp number that you control with Twilio, Twilio will send an HTTP request, or webhook, to an application URL we provide. We will use this to respond to incoming messages and add songs to our playlist. Let's set up our webhook endpoint first.
To do so we will install the twilio-ruby gem. This will make writing TwiML, the XML that Twilio understands and takes direction from, easier. Open up the Gemfile
and under the line that includes RSpotify, add twilio-ruby:
Install the gem by running bundle install
in the project directory again.
We now need a new controller to handle the incoming webhooks. Use the Rails generator to create a new one:
Open up the newly generated app/controllers/twilio/messages_controller.rb
and start by removing the default Rails CSRF protection. Webhooks are, by definition, a cross site request and we should secure them by validating that the request came from Twilio. We can do so later using the Twilio request validation Rack middleware provided by the twilio-ruby gem.
Next we need an action to handle the incoming webhook requests. In the context of Rails, I consider webhooks to be create
actions, so make a new create
method.
To make sure we're on track, let's make this respond with a simple message first. We'll use the TwiML generation capability of the twilio-ruby gem to respond to any incoming message with the customary "Hello World!".
This action needs a route too. Open config/routes.rb
and add the following:
This is all we need to get a response, so let's hook up the Twilio WhatsApp sandbox to this application.
Start your app:
Start up an ngrok tunnel so that the Twilio webhook can reach your app with a public URL. In a new terminal window on the command line run:
Take the URL ngrok generates, add the /twilio/messages
path and enter it as the URL when "A MESSAGE COMES IN" for the WhatsApp channel.
Send a message to the WhatsApp sandbox number and you will get a response back saying "Hello World!". Now it's time to hook up the Spotify API.
Connecting with the Spotify API
We're going to build a conversational interface to interact with the Spotify API. We'll assume that when a user sends their first message it is a song title they want to add to the playlist. We'll use the Spotify API to search for that song and send the user back the first result to see if that's what they wanted. If they confirm with a positive response then we'll add the track to the playlist. If they say no we'll ask them to search again. If they send anything else back we can assume that is a new search.
We're using the excellent RSpotify library for this application, but let's create a class that is more suited to our use. Create a new directory in the app
directory called services
and a file in there called spotify.rb
. Open spotify.rb
and create a new class:
In the initializer we will use the credentials we created earlier to create an authenticated user.
Searching for a track is performed by passing a query to the RSpotify::Track.search
method and we only want to return the first result.
We can add tracks to a playlist by getting the track ID from the result of track_search
, searching for the playlist by ID, and then adding the track to the playlist.
Let's use this class in our controller now, open app/controllers/twilio/messages_controller.rb
again. At the start of the create
method, get the body of the message, which we'll use as the search term and instantiate a new Spotify object using the credentials in the environment.
Searching for songs
We'll start by testing the search functionality and returning the name and artist of the first track we find. Spotify returns the artists as a list as there could be more than one responsible for a track. We can turn that into a sentence with a bit of ActiveSupport trickery. WhatsApp also supports some basic message formatting; if we surround our track and artist names with underscores, they will appear in italics.
Restart the application and send a message, searching for a track you want to hear. You should get a message back listing the track you wanted. If you get a different song, try adding the artist or album to narrow down the search.
We do need to to handle the case if we don't find any songs though.
Adding to the playlist
We can handle search requests. Now we need to be able to add the track if the user responds with a positive answer.
Like SMS conversations on Twilio, we can use the session to retain data between messages. For this application we can store the track URI, which identifies it to Spotify, in the session. Then, if we have a track in the session we can look for a "yes" in the response. If we get "yes", we add the track to the playlist and clear the session.
I added some other options for saying "yes" including the emoji thumbs up 👍. Who doesn't love emoji?
You can test this path through the application by sending a song to the WhatsApp number and following up with "yes". Then check that the song appears in the playlist.
Other responses
To complete our Spotify WhatsApp bot we need to handle the other potential responses. If the user sends back a negative response, then we want to ask what track they want to add instead. Any other response and we'll assume it's a new search.
Restart the app one more time and start searching and confirming or denying tracks. You can see the songs you add appear on your playlist and in the embedded playlist on the homepage of your app too.
A bot and a brand new playlist
With the Spotify API and the Twilio API for WhatsApp we've just built a collaborative playlist. The interaction is quite simple right now, but you could build on this to include voting on songs to move them up in the playlist or ways to better share the playlist with more friends.
If you want to see all the code for this application, check out the repo on GitHub.
I thought it would be fun to see what you would add to the playlist, so I've deployed my version of this app. You can add songs to it by connecting to my WhatsApp sandbox by messaging "join beaver-wrasse" to this Twilio WhatsApp number: +14155238886. Then start sending me all your favourite songs! Check out the playlist online here!
Got any ideas for collaborative applications you can build with WhatsApp and Twilio? Let me know in the comments, on Twitter or by email at philnash@twilio.com.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.