A Story of Spotify Embeds

generalengineeringfrontendemail editor
A Story of Spotify Embeds

Every six week cycle, the Builder Squad is constantly adding new features to our landing page editor and email editor. We want creators to have the best in class experience using these editors and to be able to have the options to select customized items for their subscribers to view. Some examples of these items are YouTube video embeds, social media icons, links and even countdown timers. Some fairly new editor features for creators to add are Twitter embeds and Spotify Embeds.

Spotify Plan

We wanted a way for creators to be able to have a Spotify song, playlist, album and/or artist embedded within a landing page or email editor which is then rendered beautifully within top ESPs (email service providers like Google, Apple Mail, etc).

We wanted to be able to have all of a creator’s subscribers, who would be reading these emails, see the same embeds from the editor rendered beautifully in their inboxes.

Some might think this is easy. You read the Spotify documentation, see that they have widgets and iframes and realize you can replace the id or type within a URL and poof, a pretty embed appears on the page.

Taylor Swift landing page

That is (kind of) correct! It is the approach that was done for landing pages since both the landing page editor and the rendering of the website of the landing page is JavaScript and React. It was easy to use Spotify’s iframe that was available in their API. It worked great. It was a quick check off the todo list.

Next, there was the challenge of adding the embed to the email editor AND have it rendered correctly in a sent email. JavaScript is limited within ESPs and plain HTML with tables can lead to a tedious nested process, but we needed to decide if it was the path forward. We needed the designs to look and behave the same way as our React editor, as it did in rendered emails.

We had already done some embed feature work in the past, so that is where I started.

Tweet embed

During a previous cycle, I helped release Twitter embeds for landing pages and for the email editor. It works by a user going to a tweet, copying the url of the tweet and then pasting that url into the email editor or landing page. It is then transpiled into a Twitter embed similar to how an individual tweet looks on Twitter. Knowing we had this feature working correctly already, I wanted to use the same approach for Spotify embeds.

A user would go to Spotify, copy the song, album, artist or playlist link, then return to our app and paste that link- resulting in a well designed Spotify embed component.

const handledTransferType = (type) => type === "text" || type === "html";

const embedTypes = [
{
name: "spotify",
regex:
/https?:\/\/.*spotify\.com\/(playlist|track|album|artist)\/.+(\?si=.+)?/,
command: (editor, href) => {
editor.insertSpotify({ href });
},
},
{
name: "tweet",
regex: /http(?:s)?:\/\/(?:www\.)?twitter\.com\/.+\/status\/\d+(?:\/)?/,
command: (editor, href) => {
editor.insertTweet({ href });
},
},
];

export default () => ({
onPaste(event, editor, next) {
const transfer = getEventTransfer(event);
let embedMatch;

if (!handledTransferType(transfer.type)) return next();
if (!isUrl(transfer.text)) return next();

const embed = embedTypes.find((embedType) => {
embedMatch = transfer.text.match(embedType.regex)?.[0];
if (embedMatch) {
return embedType;
}
});

if (!embed) return next();
if (editor.props[`${embed.name}Embed`] === false) return next();
embed.command(editor, embedMatch);
},
});

This then led to a refactor of the copy paste work that Twitter embeds were using. We found a way for our system to know when a url being posted was a Twitter or a Spotify URL. Then it would be embedded correctly depending on the embeds type. Our algorithm takes a URL, does some regex and results in the appropriate embed. This code change could lead to saved developer time when adding future embeds and make the overall developer experience centered in one place.

There were a handful of bugs that popped up. As developers we strive to have less bugs in our code and one way to avoid bugs is to learn from experience! I did not want this bug from a Twitter embed to happen for Spotify embeds. And of all the bugs I’ve dealt with, this is the funniest.

Tweet ticket issue

Let’s look at an example from a Tier 3 bug I got with a Twitter embed not working.

This issue is saying a certain tweet is not embedding at all. When the URL is pasted, it is only adding the text URL. This is what is supposed to happen if it is an incorrect Twitter URL. Let’s investigate why the embed paste url was not working correctly. https://twitter.com/DennysDiner/status/837041513649606656

Denny's tweet

After looking into the URL, we discovered that the tweet was from March 2017, making the id on the tweet 18 characters. We wrote the code to limit the id to 19 characters. Why? Who knows! We thought that was the limit on the id length. An overlooked edge case that was fixed with editing the regex for getting the tweet id. I still can’t believe that this Denny’s tweet broke the feature.

At this point, things are looking much better and I was able to avoid this bug for future Spotify embeds.

Ticket solution

We are able to tell if a URL being pasted is either a Twitter or a Spotify link AND there is not a limit on the id length within the regex so we are ready to move on to the next tasks.

Next up was getting familiar with the Spotify API/documentation and learn how to get the four different types of embed URLs that could get pasted. Artist, song, playlist and album. The Spotify documentation was a great developer experience to work with.

Spotify documentation

The Twitter API response is far different from Spotify’s response. After creating a secret key for a “token” from Spotify, I used Postman to see the shape of the data. Spotify hand feeds you the curl request that you can use to copy and paste it into Postman to see the response. There are some header requirements that are laid out in the documentation that help get everything set up properly.

Now that we have a working endpoint, let’s look at our backend code.

# Spotify token request and response
class Spotify
def self.fetch(url)
arr = url.split(":")
type = arr[1]
id = arr[0]
# playlists, artists, albums, or tracks
url = URI("https://api.spotify.com/v1/#{type}s/#{id}")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = "Bearer #{auth_token}"

response = https.request(request)

data = JSON.parse(response.body)

if response.code.to_i == 200
data["tracks"] = fetch_top_tracks(id) if type == "artist"
else
log_error(response)
end

Spotify.new(data)
end

Here is the fetch request to the Spotify API. We manipulate the URL to be able to pass the type (artist, playlist, song or album) and the unique id of that type.

  def self.auth_token
token = redis.get("spotify_token")
return token if token.present?

token = fetch_token
redis.setex("spotify_token", 1.hour - 5.minutes, token)

token
end

def initialize(data)
@data = data
end

def as_json(*)
{
id: @data["id"],
title: @data["name"],
type: @data["type"],
href: @data["href"],
tracks: @data["tracks"],
properties: @data,
error: @data["error"]
}
end

As usual, there is an auth token to get from Spotify that we have set up to be saved in redis and set on a timer to refetch before every hour, since the token expires every hour. This helps avoid any errors with expired tokens. You can also see in our as_json method, the key value pairs we will be using to render on the frontend: id, title, type, href, tracks, properties and error.

Spotify code

Now let’s look at how it is rendered on the frontend. You can see the file tree on the left photo above is the main spotify.js file and an example of the Artist component on the right.

The main component has an iframe being rendered with the conditional if the target is not email. When it says “email” here it means our email editor. Which leaves the only other option, a landing page. Therefore, if a user is pasting a Spotify link in a landing page, it will paste the iframe, otherwise, it will paste our Spotify component, which uses React and HTML tables that render the same component for the email editor and within a rendered ESP.

So voila. A project I spent weeks on is only a split second for the user to perform with a simple copy/paste!

Email embed

So far, we have not seen many issues with Spotify embeds as creators are adding them to their landing pages and emails.

Some features did not make it into the project that I would have loved to have added, like pulling the main colors from the artwork and the Spotify signature gradient.

Spotify gradient options

It would also be great to be able to add Spotify podcast embeds! However, that would mean we would need to rename a lot of the “spotify.js” files since Spotify would mean music embeds and/or podcast embeds.

Overall, Spotify embeds were a journey. It started by learning how to do Twitter embeds, to see the mistakes made with limiting the id length from the silly pancake tweet, to breaking down each type into its own component with tables, making it able to render the same component for the email editor and rendering emails in ESPs.

I am excited to see the work future developers on the team can do with pasted embeds within our landing pages and email editor and eager to see how creators from all corners of creative types use the Spotify embed feature in their landing pages and emails.