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

Spider

venturing

1

Believe

venturing

2

alucarda lives!

smiling broadly

3

fake blood recipe

smiling broadly

4

flower bed

defsharp

5

sheaskedwhatmylifeislike

ericdoa

6

Caught up (in circles)

Syzy

7

Pastel Express

Cynax

8

St. Chroma (feat. Daniel Caesar)

Tyler, The Creator, Daniel Caesar

9

let's go home

Jane Remover

10

can you tell?

Jane Remover

11

champ

Jane Remover

12

pretender

Jane Remover

13

kodak moment

Jane Remover

14

movies for guys

Jane Remover

15

misplace

Jane Remover

16

Catch me if you can

tn-shi

17

natural

zeroth

18

mint

Snail's House

19

Emerald Lakeside - Action

はがね, Kitsui Akira

20

back off!!!

Jane Remover, kmoe, juno

21

one more life

Murphmusic, park.

22

Clinozoisite

Ludicin

23

Duhhhhhhhhhhhhhhhhh

underscores

24

Rabbit In The Black Room

Rabbit House

25

String Theocracy - Key Ingredient ver.

Mili

26

My guy (Corporate shuffle)

underscores

27

wizards

xaev, mopearound

28

Everything Goes On

Porter Robinson, League of Legends

29

phobie d’impulsion

glaive

30

PUSH UR T3MPRR

femtanyl

31

Amethyst Aurora

BilliumMoto

32

the now now and never

what is your name?

33

Reverse Nightmare Tower

bye2

34

pop music

Limonène

35

EXACTLY WHY I'M STILL HERE - TURQUOISEDEATH Remix

bunnyprodge, TURQUOISEDEATH

36

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

glaive

37

Tojita Sekai

Camellia

38

commatose

glass beach

39

200

glass beach

40

until the dawn breaks

Deathbrain

41

dumb party

Internet Girl

42

skinz

8485

43

Algas Danses

seatrus

44

うみのゆき

seatrus

45

Palmy Flakes

seatrus

46

Cloud99 (As Above Mix)

Machine Girl

47

enchanted love

linear ring

48

Midnight Theater

Kano, Nagi Nemoto

49

Mola mola

Marmalade butcher

50

Another Ride

ippo.tsk, Synthesizer V ANRI

51

neon glow

glass beach

52

I Still Miss You

bo en, Tomggg

53

(We Are) Friends

bo en, Winamp Boys

54

Our Time

bo en, PAS TASTA

55

Kansoku-eisei

Nanahira, Camellia

56

GURUGURU

Snail's House

57

About 10 Hours of Doubting Myself

Yem

58

GHOST OF LORELEY

lasah

59

awesome ends with ME and ugly starts with U

c0ncernn

60

DILF repellent

c0ncernn

61

タイニーリトル・アジアンタム

ShibayanRecords

62

lastnaut

Sleeping Pola

63

NekovhParavh

Sad Keyboard Guy, Gardens

64

cool delusions about morphing into a cat

crxw

65

Blooming Afternoon

ミツキヨ

66

you're Nxt -Dreams Remix- (feat. MisoilePunch)

uma, Morimori Atsushi, MisoilePunch♪

67

Tenebre Rosso Sangue (ULTRAKILL Original Game Soundtrack)

Keygen Church

68

Altars of Apostasy

Heaven Pierce Her

69

Charisma Overload

Spacey☆Jester

70

Floccinaucinihilipilification

Marmalade butcher

71

Get Your Wish - Anamanaguchi Remix

Porter Robinson, Anamanaguchi

72

Mirror

Porter Robinson

73

Blossom

Porter Robinson

74

Look at the Sky

Porter Robinson

75

Get Your Wish

Porter Robinson

76

Something Comforting

Porter Robinson

77

Falling Behind

Laufey

78

Take Note

Portraits Of Tracy

79

Misery Song

Adust Rain

80

Voice of Chloe

Marmalade butcher

81

Mate Um Bonito Hoje Mesmo!

Marcioz

82

Raindrop

seatrus

83

Amanita

Marmalade butcher

84

though I fear, I still walk

ippo.tsk

85

oyasumination

ippo.tsk

86

oyasumination

ippo.tsk

87

oyasumination

ippo.tsk

88

ギターと孤独と蒼い惑星

kessoku band

89

Jamal Dub

Earl Grey

90

Steppa Pig

JPEGMAFIA, Danny Brown

91

Lean Beef Patty

JPEGMAFIA, Danny Brown

92

GONE, GONE / THANK YOU

Tyler, The Creator

93

IGOR'S THEME

Tyler, The Creator

94

Take Me Home

PinkPantheress

95

Alone - Soru Remix

Yutaka Yamada, Soru

96

星座になれたら

kessoku band

97

NEW MAGIC WAND

Tyler, The Creator

98

waitingforyou

linear ring

99

I DON'T LOVE YOU ANYMORE

Tyler, The Creator

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