Sync Spotify Playlist with Notion

This developer documentation provides a step-by-step guide to create an integration between the Notion API and the Spotify API using JavaScript. The integration fetches data from a Spotify playlist and populates a Notion database with track metadata, including musical properties.

Prerequisites

  • Node.js installed on your machine
  • A Spotify Developer account
  • A Notion account

Step 1: Get Your API Keys

Spotify API Key

  1. Log in to your Spotify Developer account.
  2. Go to theย Spotify Developer Dashboard.
  3. Click onย Create an App.
  4. Fill in the required details and clickย Create.
  5. Copy theย Client IDย andย Client Secret.

Notion API Key

  1. Log in to your Notion account.
  2. Go toย Notion Integrations.
  3. Click onย New Integration.
  4. Fill in the required details and clickย Submit.
  5. Copy the generatedย Internal Integration Token.

Step 2: Set Up Your Notion Database

  1. Create a new database in Notion with the following properties:
  • Titleย (Title)
  • Artistย (Text)
  • Albumย (Text)
  • Durationย (Number)
  • Popularityย (Number)
  • External_URLย (URL)
  • Keyย (Text)
  • Modeย (Text)
  • Tempoย (Number)
  • Danceabilityย (Number)
  1. Share the database with your integration:
  • Click on theย three dots in the top-right corner of the page.
  • Underย Connections, click on Connect to and search for your integration and connect to it.

Step 3: Project Structure

This step is not necessary but we suggest projects to be structured like so:

project-root/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ config/
โ”‚   โ”‚   โ””โ”€โ”€ spotify.js
โ”‚   โ”‚   โ””โ”€โ”€ notion.js
โ”‚   โ”œโ”€โ”€ integrations/
โ”‚   โ”‚   โ”œโ”€โ”€ spotifyIntegration.js
โ”‚   โ”‚   โ””โ”€โ”€ notionIntegration.js
โ”‚   โ”œโ”€โ”€ main.js
โ”œโ”€โ”€ .env
โ”œโ”€โ”€ package.json

Step 4: Create .env file

Create a .env file and populate with the following information:

NOTION_TOKEN='your_notion_integration_token'
SPOTIFY_CLIENT_ID='your_spotify_client_id'
SPOTIFY_CLIENT_SECRET='your_spotify_client_secret'
SPOTIFY_PLAYLIST_ID='your_playlist_id'
NOTION_DATABASE_ID='your_notion_database_id'

Step 5: Packages

Install the required Node.js packages using the following command:

npm install @notionhq/client dotenv

Create a package.json file and add the following:

{
    "name": "spotify_integration",
    "version": "1.0.0",
    "main": "src/main.js",
    "scripts": {
        "start": "node src/main.js"
    },
    "dependencies": {
        "@notionhq/client": "^1.0.4",
        "dotenv": "^8.6.0",
    }
}

Step 6: Set Up Spotify and Notion API Client

Create a spotify.js file to set up the Spotify API client.

const querystring = require('querystring');

// Function to get Spotify access token
async function getSpotifyAccessToken() {
  const fetch = (await import('node-fetch')).default;
  const postData = querystring.stringify({
    grant_type: 'client_credentials'
  });

  const response = await fetch('https://accounts.spotify.com/api/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': `Basic ${Buffer.from(`${process.env.SPOTIFY_CLIENT_ID}:${process.env.SPOTIFY_CLIENT_SECRET}`).toString('base64')}`
    },
    body: postData
  });

  const data = await response.json();
  return data.access_token;
}

module.exports = { getSpotifyAccessToken };

Create a notion.js file to set up the Notion API client.

// notion.js
const { Client } = require('@notionhq/client');
const dotenv = require('dotenv');

dotenv.config();

const notion = new Client({ auth: process.env.NOTION_TOKEN });
const databaseId = process.env.NOTION_DATABASE_ID;

module.exports = { notion, databaseId };

Step 7: Set Up Integrations

Create spotifyIntegration.js to fetch tracks from a Spotify playlist.

const { getSpotifyAccessToken } = require('../config/spotify');

// Helper function to make GET requests
async function fetchJson(url, headers) {
  const fetch = (await import('node-fetch')).default;
  const response = await fetch(url, { headers });
  return response.json();
}

// Fetch tracks from a Spotify playlist
async function getSpotifyPlaylistTracks(playlistId) {
  const accessToken = await getSpotifyAccessToken();
  const headers = {
    'Authorization': `Bearer ${accessToken}`
  };

  const playlistResponse = await fetchJson(`https://api.spotify.com/v1/playlists/${playlistId}/tracks`, headers);
  const tracks = playlistResponse.items.map(item => {
    const track = item.track;
    return {
      title: track.name,
      artist: track.artists.map(artist => artist.name).join(', '),
      album: track.album.name,
      duration: track.duration_ms,
      popularity: track.popularity,
      external_url: track.external_urls.spotify,
      id: track.id
    };
  });

  // Fetch additional audio features for each track
  const trackIds = tracks.map(track => track.id).join(',');
  const audioFeaturesResponse = await fetchJson(`https://api.spotify.com/v1/audio-features?ids=${trackIds}`, headers);
  const audioFeatures = audioFeaturesResponse.audio_features;

  return tracks.map((track, index) => ({
    ...track,
    key: audioFeatures[index].key,
    mode: audioFeatures[index].mode,
    tempo: audioFeatures[index].tempo,
    danceability: audioFeatures[index].danceability
  }));
}

module.exports = { getSpotifyPlaylistTracks };

Additionally create notionIntegration.js to populate the database with the track information.

const { Client } = require('@notionhq/client');

// Initialize the Notion client
const notion = new Client({ auth: process.env.NOTION_TOKEN });

// Add data to the Notion database
async function addToNotionDatabase(databaseId, track) {
  try {
    await notion.pages.create({
      parent: { database_id: databaseId },
      properties: {
        'Title': {
          title: [
            {
              text: {
                content: track.title
              }
            }
          ]
        },
        'Artist': {
          rich_text: [
            {
              text: {
                content: track.artist
              }
            }
          ]
        },
        'Album': {
          rich_text: [
            {
              text: {
                content: track.album
              }
            }
          ]
        },
        'Duration': {
          number: track.duration
        },
        'Popularity': {
          number: track.popularity
        },
        'External_URL': {
          url: track.external_url
        },
        'Key': {
          rich_text: [
            {
              text: {
                content: track.key.toString()
              }
            }
          ]
        },
        'Mode': {
          rich_text: [
            {
              text: {
                content: track.mode.toString()
              }
            }
          ]
        },
        'Tempo': {
          number: track.tempo
        },
        'Danceability': {
          number: track.danceability
        }
      }
    });
  } catch (error) {
    console.error('Error adding to Notion database:', error);
  }
}

module.exports = { addToNotionDatabase };

Step 8: Main Script

Create a main.js file that uses the modules created above to execute the integration logic.

require('dotenv').config();

const { getSpotifyPlaylistTracks } = require('./integrations/spotifyIntegration');
const { addToNotionDatabase } = require('./integrations/notionIntegration');

const NOTION_DATABASE_ID = process.env.NOTION_DATABASE_ID;
const SPOTIFY_PLAYLIST_ID = process.env.SPOTIFY_PLAYLIST_ID;

// Main function to fill the Notion database with Spotify playlist data
async function fillNotionDatabase() {
  const tracks = await getSpotifyPlaylistTracks(SPOTIFY_PLAYLIST_ID);
  
  for (const track of tracks) {
    await addToNotionDatabase(NOTION_DATABASE_ID, track);
    console.log(`Added to Notion: Title: ${track.title}, Artist: ${track.artist}, Album: ${track.album}`);
  }
}

fillNotionDatabase();

Step 9: Run the Integration

Execute the integration script by running the following command:

npm start

๐Ÿ”‘

Customize the code to match your Notion database structure and desired track properties. Handle pagination for large playlists.