Skip to content

Tracks

The Tracks service fetches track information, audio features, and detailed audio analysis.

Getting Tracks

Get a single track

import { Effect } from "effect";
import { Tracks, makeSpotifyLayer } from "@spotify-effect/core";
const program = Effect.gen(function* () {
const tracks = yield* Tracks;
const track = yield* tracks.getTrack("4cOdK2wGLETKBW3PvgPWqT", {
market: "US",
});
console.log(`${track.name} by ${track.artists[0]?.name}`);
console.log(`Album: ${track.album.name}`);
console.log(`Duration: ${track.duration_ms}ms`);
console.log(`Popularity: ${track.popularity}`);
});

Get multiple tracks

const program = Effect.gen(function* () {
const tracks = yield* Tracks;
const results = yield* tracks.getTracks(["4cOdK2wGLETKBW3PvgPWqT", "5as3aKm2oGOikBg4arGMLi"]);
for (const track of results) {
if (track) {
console.log(track.name);
}
}
});

Audio Features

Audio features are numerical representations of track characteristics.

Get audio features for a track

const program = Effect.gen(function* () {
const tracks = yield* Tracks;
const features = yield* tracks.getAudioFeaturesForTrack("4cOdK2wGLETKBW3PvgPWqT");
console.log(`Energy: ${features.energy}`); // 0-1
console.log(`Danceability: ${features.danceability}`); // 0-1
console.log(`Tempo: ${features.tempo} BPM`);
console.log(`Key: ${features.key}`); // 0-11 (C to B)
console.log(`Mode: ${features.mode}`); // 0 (minor) or 1 (major)
console.log(`Valence: ${features.valence}`); // 0-1 (sad to happy)
});

Feature descriptions

FeatureRangeDescription
acousticness0-1Confidence of acoustic
danceability0-1Suitable for dancing
energy0-1Intensity and activity
instrumentalness0-1No vocals
liveness0-1Audience presence
loudness-60-0 dBOverall loudness
speechiness0-1Spoken words
tempoBPMSpeed
valence0-1Musical positiveness
key0-11C, C#, D, etc.
mode0-1Minor (0) or Major (1)

Get audio features for multiple tracks

const program = Effect.gen(function* () {
const tracks = yield* Tracks;
const features = yield* tracks.getAudioFeaturesForTracks([
"4cOdK2wGLETKBW3PvgPWqT",
"5as3aKm2oGOikBg4arGMLi",
]);
for (const feature of features) {
if (feature) {
console.log(`${feature.tempo} BPM - Energy: ${feature.energy}`);
}
}
});

Audio Analysis

Audio analysis provides detailed musical breakdown.

Get full audio analysis

const program = Effect.gen(function* () {
const tracks = yield* Tracks;
const analysis = yield* tracks.getAudioAnalysisForTrack("4cOdK2wGLETKBW3PvgPWqT");
console.log(`Duration: ${analysis.track.duration}s`);
console.log(`Time signature: ${analysis.track.time_signature}/4`);
console.log(`Tempo: ${analysis.track.tempo} BPM`);
console.log("Sections:");
for (const section of analysis.sections) {
console.log(` ${section.start}s - ${section.loudness}dB`);
}
console.log("Segments:", analysis.segments.length);
});

Practical Examples

Build a mood playlist based on audio features

import { Effect } from "effect";
import { Tracks, Search, Playlists, Users } from "@spotify-effect/core";
import { paginateAll } from "@spotify-effect/core";
const buildMoodPlaylist = (userId: string, mood: "chill" | "energetic" | "happy" | "sad") => {
const featureTargets = {
chill: { target_energy: 0.3, target_valence: 0.5 },
energetic: { target_energy: 0.8, target_valence: 0.6 },
happy: { target_valence: 0.8, target_energy: 0.5 },
sad: { target_valence: 0.2, target_energy: 0.3 },
};
return Effect.gen(function* () {
const search = yield* Search;
const tracks = yield* Tracks;
const playlists = yield* Playlists;
const results = yield* search.search(mood, ["track"], { limit: 100 });
const trackIds = results.tracks?.items.map((t) => t.id) ?? [];
const features = yield* tracks.getAudioFeaturesForTracks(trackIds);
const targets = featureTargets[mood];
const filtered = features.filter((f) => {
if (!f) return false;
return (
Math.abs(f.energy - (targets.target_energy ?? 0)) < 0.3 &&
Math.abs(f.valence - (targets.target_valence ?? 0)) < 0.3
);
});
const playlist = yield* playlists.createPlaylist(userId, `${mood} vibes`, {
description: `Tracks matching ${mood} mood`,
public: false,
});
yield* playlists.addItemsToPlaylist(
playlist.id,
filtered.map((f) => `spotify:track:${f.track_id}`),
);
return playlist;
});
};

Analyze playlist energy

const analyzePlaylistEnergy = (playlistId: string) =>
Effect.gen(function* () {
const tracks = yield* Tracks;
const playlists = yield* Playlists;
const playlistItems = yield* paginateAll(
(offset, limit) => playlists.getPlaylistItems(playlistId, { offset, limit }),
100,
);
const trackIds = playlistItems.items
.map((item) => (item.track?._tag === "Track" ? item.track.id : null))
.filter((id): id is string => id !== null);
const features = yield* tracks.getAudioFeaturesForTracks(trackIds);
const validFeatures = features.filter((f): f is NonNullable<typeof f> => f !== null);
const avgEnergy = validFeatures.reduce((sum, f) => sum + f.energy, 0) / validFeatures.length;
const avgTempo = validFeatures.reduce((sum, f) => sum + f.tempo, 0) / validFeatures.length;
const avgDanceability =
validFeatures.reduce((sum, f) => sum + f.danceability, 0) / validFeatures.length;
return {
avgEnergy,
avgTempo,
avgDanceability,
trackCount: validFeatures.length,
};
});

Find similar tracks by audio features

const findSimilarTracks = (trackId: string) =>
Effect.gen(function* () {
const tracks = yield* Tracks;
const search = yield* Search;
const original = yield* tracks.getAudioFeaturesForTrack(trackId);
const results = yield* search.search(original.key.toString(), ["track"], {
limit: 50,
});
const trackIds = results.tracks?.items.map((t) => t.id) ?? [];
const candidateFeatures = yield* tracks.getAudioFeaturesForTracks(trackIds);
const similar = candidateFeatures
.filter((f) => {
if (!f || f.id === trackId) return false;
return (
Math.abs(f.energy - original.energy) < 0.15 &&
Math.abs(f.tempo - original.tempo) < 10 &&
Math.abs(f.danceability - original.danceability) < 0.2
);
})
.slice(0, 10);
return similar;
});

Next steps