I've been stuck on this for some time now and no matter how hard I search I can't find an answer. I'm trying to add a custom playlist cover to a Spotify playlist but I keep getting a response of 401. I've checked many times that I'm passing the correct access token and playlist ID. I added all the required scope as pointed out on Spotify's API too. I've even tested different images with different KB sizes. Below is my code
const url = `https://api.spotify.com/v1/playlists/${playlist.id}/images`;
let imgFile = process.env.COVER_PHOTO;
axios.put(url, imgFile, {
headers: {
'Authorization': "Bearer " + token,
'Content-Type': 'image/jpeg'
}
})
Error 401 means Unauthorized your token. Not collect assign scopes
OR Not get token by Authorization Code Flow
Image Update API
URL
PUT /playlists/{playlist_id}/images
Scopes
ugc-image-upload
playlist-modify-public
playlist-modify-private
In here
demo.js
const fs = require('fs'); - Adds the ability to read and write files in the program.
const imageData = fs.readFileSync('car.jpg', { encoding: 'base64' }); - Reads the 'car.jpg' file and converts it to a Base64 string.
const accessToken = await getToken(code); - Retrieves an access token using a provided code.
const updateStatus = await updatePlaylistCoverImage(accessToken, imageData); - Sends the encoded image to Spotify to update the playlist cover.
response.send(Image Update Status: ${updateStatus}); - Responds with the status of the image upload process.
const express = require("express");
const axios = require('axios');
const cors = require("cors");
const fs = require('fs'); // Required to read files
const app = express();
app.use(cors());
const CLIENT_ID = "{your client ID}";
const CLIENT_SECRET = "{your client secret}";
const PORT = 3000; // {your redirect URI port number}
const REDIRECT_URI = `http://localhost:${PORT}/callback`;
const SCOPE = 'ugc-image-upload playlist-modify-public playlist-modify-private';
const PLAYLIST_ID = '{Your playlist ID}'; // Your playlist ID
const getToken = async (code) => {
try {
const resp = await axios.post(
'https://accounts.spotify.com/api/token',
new URLSearchParams({
'grant_type': 'authorization_code',
'redirect_uri': REDIRECT_URI,
'code': code
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
auth: {
username: CLIENT_ID,
password: CLIENT_SECRET
}
})
return Promise.resolve(resp.data.access_token);
} catch (err) {
console.error(err)
return Promise.reject(err)
}
}
const updatePlaylistCoverImage = async (accessToken, imageData) => {
try {
const response = await axios.put(
`https://api.spotify.com/v1/playlists/${PLAYLIST_ID}/images`,
imageData,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'image/jpeg'
}
}
);
return response.status;
} catch (error) {
console.error(error);
return error.response.status;
}
}
app.get("/login", (request, response) => {
const redirect_url = `https://accounts.spotify.com/authorize?response_type=code&client_id=${CLIENT_ID}&scope=${encodeURIComponent(SCOPE)}&state=123456&redirect_uri=${REDIRECT_URI}&prompt=consent`
response.redirect(redirect_url);
});
app.get("/callback", async (request, response) => {
const code = request.query["code"];
try {
const accessToken = await getToken(code);
const imageData = fs.readFileSync('car.jpg', { encoding: 'base64' });
const updateStatus = await updatePlaylistCoverImage(accessToken, imageData);
response.send(`Image Update Status: ${updateStatus}`);
} catch (error) {
response.status(500).send(`Error: ${error.message}`);
}
});
app.listen(PORT, () => {
console.log(`Listening on :${PORT}`);
});
custom image
car.jpg
Base64 encoded JPEG image data, maximum payload size is 256 KB.
Access
http://localhost:{your port}/login