Spotify Card

A premium Spotify card that fetches metadata and features a morphing album-to-disc animation.

The Spotify Card component is a premium, interactive interface that fetches live metadata from Spotify. When clicked, the album cover smoothly morphs into a rotating vinyl disc and plays an audio preview.

Preview

Usage

Installation

$ pnpm dlx shadcn add https://klarden.vercel.app/r/spotify-card.json

API Setup

The Spotify Card requires a server-side route to fetch metadata. The registry should automatically create this at app/api/spotify/metadata/route.ts.

Note: If the registry fails to install the API route automatically, please manually create the file at app/api/spotify/metadata/route.ts and paste the code below.

import { NextRequest, NextResponse } from "next/server";
import got from "got";
import * as cheerio from "cheerio";

export async function GET(req: NextRequest) {
  const { searchParams } = new URL(req.url);
  const trackUrl = searchParams.get("url");

  if (!trackUrl) {
    return NextResponse.json({ error: "No URL provided" }, { status: 400 });
  }

  try {
    const { body: html } = await got(trackUrl, {
      headers: {
        "user-agent":
          "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
      },
    });

    const $ = cheerio.load(html);

    const title =
      $('meta[property="og:title"]').attr("content") || "Unknown Track";
    const image = $('meta[property="og:image"]').attr("content") || "";
    const previewUrl =
      $('meta[property="og:audio"]').attr("content") ||
      $('meta[name="twitter:audio:src"]').attr("content") ||
      "";

    // Spotify's og:description is often: "Artist · Album · Song · Year"
    const description =
      $('meta[property="og:description"]').attr("content") || "";
    // Usually the first part is the Artist
    const artist = description.split("·")[0]?.trim() || "Unknown Artist";

    return NextResponse.json({
      title,
      artist,
      albumArt: image,
      previewUrl,
    });
  } catch (error) {
    console.error("Spotify Metadata Fetch Error:", error);
    return NextResponse.json(
      { error: "Failed to fetch metadata" },
      { status: 500 },
    );
  }
}

Basic Example

import { SpotifyCard } from "@/components/spotify-card";

export default function App() {
  return (
    <div className="flex items-center justify-center p-8">
      <SpotifyCard trackUrl="https://open.spotify.com/track/3sK8wGT43QFpWrvNQsrQya" />
    </div>
  );
}

Properties

PropTypeDefaultDescription
trackUrlstringThe full Spotify track URL to fetch metadata from.
classNamestringAdditional CSS classes for the card container.