cooler spotify embeds with 99.9061% less javascript

7/11/2024


hi this is my first blog post! i suck at writing anything down anything so hopefully talking about random things helps.

this all started when i wanted to display my favorite songs on my /about page, i already have a spotify playlist of them so i could just use the official embed. the problem is that the embed loads 1.96 mb of minified javascript.

spotify embed requests

…and also makes tons of strange requests back to spotify, is extremely loud (with no volume slider!), and preloads some songs. on my old site i just gave in and used the official embed, but after seeing that scraping spotify embeds was possible (thanks l-m!), i tried making my own.

all of that javascript is even more insane considering this was meant to be used on other sites, you’d think the multi-billion $ company would care about performance for a simple embed. but it’s no secret that a lot of the web is getting megabytes of javascript larger, from complex frameworks and overkill libraries just to render mostly static sites. tonsky already has a great article on this.

here they are!

extremely good songs

open in spotify
playlist thumbnail

My Darling, My Companion

Jamie Paige

1

NOGWAPNOLIFE

bleood

2

BIRDBRAIN

Jamie Paige, OK Glass

3

In the dark

venturing

4

Set In Stone

slayr

5

Love Blur

slayr

6

Music Baby

Jane Remover

7

media offline

ariiol

8

The End

Danny Brown, ta Ukrainka, Zheani, Cynthoni

9

Music and Me

fakemink

10

MIRINAE

TAK, Zekk

11

Rain Capsule

Namitape

12

Overfeel

Namitape

13

All At Once

Ninajirachi

14

Infohazard

Ninajirachi

15

Delete

Ninajirachi

16

weathergirl

FLAVOR FOLEY

17

Lawsyn

ayowitty

18

THUNDRRR

Quadeca

19

THAT'S WHY

Quadeca

20

WAGING WAR

Quadeca, Olēka

21

NO QUESTIONS ASKED

Quadeca

22

Always Have Always Will

Jane Remover

23

SLAM PUNK

Che

24

Akibare

Mylta

25

My life is mine alone! (feat. nenne)

Mylta, nenne

26

disarmed

kumosai, Sayako

27

spectrum

icesawder

28

NOWNEVER

Jaron

29

Pretty Peach

Lucy Bedroque

30

How to Pretend

Lucy Bedroque

31

Knot Me

Lucy Bedroque

32

Sweet Pitcher

Lucy Bedroque

33

Thousand yard stare

kmoe

34

angels in camo

Jane Remover

35

Professional Vengeance

Jane Remover

36

Dreamflasher

Jane Remover

37

Experimental Skin

Jane Remover

38

Psychoboost

Jane Remover, Danny Brown

39

Dancing with your eyes closed

Jane Remover

40

Spider

venturing

41

Believe

venturing

42

alucarda lives!

smiling broadly

43

fake blood recipe

smiling broadly

44

flower bed

defsharp

45

sheaskedwhatmylifeislike

ericdoa

46

Caught up (in circles)

Syzy

47

Pastel Express

Cynax

48

St. Chroma (feat. Daniel Caesar)

Tyler, The Creator, Daniel Caesar

49

let's go home

Jane Remover

50

can you tell?

Jane Remover

51

champ

Jane Remover

52

pretender

Jane Remover

53

kodak moment

Jane Remover

54

movies for guys

Jane Remover

55

misplace

Jane Remover

56

Catch me if you can

tn-shi

57

natural

zeroth

58

mint

Snail's House

59

Emerald Lakeside - Action

はがね, Kitsui Akira

60

back off!!!

Jane Remover, kmoe, juno

61

one more life

Murphmusic, park.

62

Clinozoisite

Ludicin

63

Duhhhhhhhhhhhhhhhhh

underscores

64

Rabbit In The Black Room

Rabbit House

65

String Theocracy - Key Ingredient ver.

Mili

66

My guy (Corporate shuffle)

underscores

67

Wizards

xaev, mopearound

68

Everything Goes On

Porter Robinson, League of Legends

69

phobie d’impulsion

glaive

70

PUSH UR T3MPRR

femtanyl

71

Amethyst Aurora

BilliumMoto

72

the now now and never

what is your name?

73

Reverse Nightmare Tower

bye2

74

pop music

Limonène

75

EXACTLY WHY I'M STILL HERE - TURQUOISEDEATH Remix

bunnyprodge, TURQUOISEDEATH

76

even when the sun is dead, will you tell them how hard i tried

glaive

77

Tojita Sekai

Camellia

78

commatose

glass beach

79

200

glass beach

80

until the dawn breaks

Deathbrain

81

dumb party

Internet Girl

82

skinz

8485

83

Algas Danses

seatrus

84

うみのゆき

seatrus

85

Palmy Flakes

seatrus

86

Cloud99 (As Above Mix)

Machine Girl

87

enchanted love

linear ring

88

Midnight Theater

Kano, Nagi Nemoto

89

Mola mola

Marmalade butcher

90

Another Ride

ippo.tsk, Synthesizer V ANRI

91

neon glow

glass beach

92

I Still Miss You

bo en, Tomggg

93

(We Are) Friends

bo en, Winamp Boys

94

Our Time

bo en, PAS TASTA

95

Kansoku-eisei

Nanahira, Camellia

96

GURUGURU

Snail's House

97

About 10 Hours of Doubting Myself

Yem

98

GHOST OF LORELEY

lasah

99

awesome ends with ME and ugly starts with U

c0ncernn

100

there's more songs on spotify :)

the now now and never

what is your name?

open in spotify
playlist thumbnail

the track embed was made with 0 JS, and the playlist embed was made with 1.84kb (minified) of JS, that’s 99.9061% smaller than the official embed, and i think it fits my site much better :)

ill get the playlist volume slider done one of these days… (9/14/2024: done!)

how

first, you can just make a fetch request to the normal embed url (either for a song or playlist) pretending to be a browser

const res = await fetch(
	`https://open.spotify.com/embed/playlist/2m2lebj9Lg6Riwfyv7G9AD`,
	{
		headers: {
			"User-Agent":
				"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:124.0) Gecko/20100101 Firefox/124.0",
			Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
			"Accept-Language": "en-US,en;q=0.5",
			"Upgrade-Insecure-Requests": "1",
			"Sec-Fetch-Dest": "iframe",
			"Sec-Fetch-Mode": "navigate",
			"Sec-Fetch-Site": "cross-site",
			Pragma: "no-cache",
			"Cache-Control": "no-cache",
		},
		method: "GET",
	},
);

const html = await res.text();

and in the html response you get back, at the end there’s a magical script tag with the id __NEXT_DATA__ that contains everything you need!

response

const json = html.substring(
	html.lastIndexOf(`type="application/json">`) +
		`type="application/json">`.length,
	html.lastIndexOf(`</script>`),
);

const data: PlaylistEmbedData = JSON.parse(json);

you can make whatever with this data now! i’d highly recommend caching it. you can cache song embed data much more aggressively than playlists cause those shouldn’t change.

it’s possible to make your embeds use 0 JS by using the native <audio /> element, which is what i do for singular song embeds. there’s a pretty big problem when using <audio /> for each song in a playlist embed though, it might take safari 8 seconds to load your site sometimes (not an exaggeration).

yes i did pinpoint the loading times to the hundred <audio /> elements, safari really doesn’t like that rendering that many…

note that you can barely style <audio /> elements and the element looks very different across each browser. because of all that i used a bit of JS with web components for my playlist embed, which gets server side rendered with astro.

source code for scraper, components, and typescript types


have a question/comment? want to say hi?

you can also just contact me on discord, @squisket