Skip to content

Instantly share code, notes, and snippets.

@karlding
Created March 3, 2016 05:17
Show Gist options
  • Save karlding/954388cb6cd2665d4f3a to your computer and use it in GitHub Desktop.
Save karlding/954388cb6cd2665d4f3a to your computer and use it in GitHub Desktop.
Grab iTunes image artwork from the DOM using the Open Graph meta tags

iTunes Artist Photos

The iTunes API doesn't provide a way to grab artist images, but the iTunes website uses Open Graph meta tags, which embeds a meta tag with a property attribute value set to og:image. As it turns out, this seems to be the same image used in the iTunes artwork.

The URL structure is similar to the artworkUrl values returned by the API, but what concerns us here is the part I've indicated at the end of the URL.

http://is3.mzstatic.com/image/thumb/Music7/v4/68/68/41/68684190-833b-bfb4-5018-e5a2e6f69eb0/source/1200x630bf.jpg
                                                                                                   └─ widthxheight

The maximum image dimensions seems to be 10,000px by 10,000px. We can simply replace 1200x630bf.jpg with the dimensions we want.

var x = document.querySelector('meta[property="og:image"]').getAttribute("content");
var image = x.substring(0, x.lastIndexOf("/") + 1) + "10000x10000-999.jpg";
window.location = image;

Note the -999 at the end, which denotes that we want the highest quality image.

For example, consider Taylor Swift

Running the above gives the following page:

http://is3.mzstatic.com/image/thumb/Music7/v4/68/68/41/68684190-833b-bfb4-5018-e5a2e6f69eb0/source/10000x10000-999.jpg

tayisbae

What's nice about this is that this method can be used to grab any images (including album art, TV show pictures, movie pictures, iBook covers, etc), since they all use the og:image Open Graph meta value. I don't use iTunes as my daily media player, but this should be the same as the iTunes artwork for all the media types.

You can even cobble together a bash script to download the image files you need (it might be easier to run a headless browser, like a CapserJS module, or at least something that can parse DOM).

url=https://itunes.apple.com/ca/artist/taylor-swift/id159260351
img=$(curl $url | grep -Eo "<meta content=\"[a-zA-Z0-9 :\/\.\-]+.jpg\" property=\"og:image\" \/>" | grep -Eo "http(s)?://[a-zA-Z0-9:\/\.\-]+.jpg")
wget $img

You can combine this with the API and search for an artist, grab their artistId, navigate to their artist page (which is just your country's base iTunes url with /artist/id and then the artistId). From here, you can then grab their artist and album art photos.

For most operations (other than getting the Artist Photo), you can just use Ben Dodson's iTunes Artwork Finder, which works by leveraging the iTunes Search API.

@thefinnomenon
Copy link

Just wanted to leave a note for anyone else who ends up here. This solution is great but the format of the meta tag changed a bit since this was written up. The fork of this gist has the updated code but here is what I ended up using on my Node server,

// Input: artistUrl = "https://music.apple.com/us/artist/jon-bellion/659289673"
// Output: "https://is2-ssl.mzstatic.com/image/thumb/Features128/v4/16/77/49/16774954-6eec-d5d4-99e4-c412fe8d6e0f/mzl.rdvmhiih.jpg/{w}x{h}cw.png"
axios
  .get(artistUrl)
  .then(response => {
    const html = response.data;
    const ogImage = html.match(/<meta property=\"og:image\" content=\"(.*png)\"/)[1];
    return ogImage.replace(/[\d]+x[\d]+/, '{w}x{h}');
  })
  .catch(error => {
    console.log(error);
  });

@concatime
Copy link

Is it possible to get the original picture? Take this: https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/bd/ed/cf/bdedcfcf-3b3d-35ae-f752-175e2d8034dc/194152826486.png/1200x630wp-60.jpg. We can deduce that the original picture is a png, but the link https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/bd/ed/cf/bdedcfcf-3b3d-35ae-f752-175e2d8034dc/194152826486.png does not work.

@thefinnomenon
Copy link

Not that I know of.

@MenschLennart
Copy link

MenschLennart commented Nov 6, 2021

I created a version for Flutter in dart which works perfect for me.

import 'package:http/http.dart' as http;

static int width = 300;
static int height = 300;

Future<String> getArtistArtworkUrl(String artistId) async {
    final response = await http
        .get(Uri.parse('https://music.apple.com/de/artist/$artistId'));
    final document = response.body;

    RegExp regEx = RegExp("<meta property=\"og:image\" content=\"(.*png)\"");
    RegExpMatch? match = regEx.firstMatch(document);

    if (match != null) {
      String rawImageUrl = match.group(1) ?? '';
      String imageUrl = rawImageUrl.replaceAll(
          RegExp(r'[\d]+x[\d]+(cw)+'), '${width}x${height}cc');
      return imageUrl;
    }

    throw Exception();
  }

Simply use it within an async function to get the artwork url.

@itsnikolayy
Copy link

Is it possible to get the original picture? Take this: https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/bd/ed/cf/bdedcfcf-3b3d-35ae-f752-175e2d8034dc/194152826486.png/1200x630wp-60.jpg. We can deduce that the original picture is a png, but the link https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/bd/ed/cf/bdedcfcf-3b3d-35ae-f752-175e2d8034dc/194152826486.png does not work.

Artwork can only be a max of 4000x4000 so if you go to https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/bd/ed/cf/bdedcfcf-3b3d-35ae-f752-175e2d8034dc/194152826486.png/4000x4000.png you see that the size apple returns us is 3000x3000 which indicates that https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/bd/ed/cf/bdedcfcf-3b3d-35ae-f752-175e2d8034dc/194152826486.png/3000x3000.png is the original file.

@Alhadis
Copy link

Alhadis commented Jul 3, 2025

which indicates that https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/bd/ed/cf/bdedcfcf-3b3d-35ae-f752-175e2d8034dc/194152826486.png/3000x3000.png is the original file.

@itsnikolayy You can retrieve the image in its ostensibly native dimensions using 1x1ss.jpg (the width and height here are arbitrary; the important part is that ss be used). For example:

  1. Taylor Swift (2400×2400)
  2. AmaLee - The Remixes (3000×3000)
  3. Lorde - Pure Heroine (1500×1500)
  4. Lorde - Virgin (3000×3000)

I'm not sure why this works, or what the ss component stands for; I discovered it by accident when experimenting with crop/resize parameter names.

UPDATE: According to @bendodson's itunes-artwork-finder, the original artwork URLs use a different syntax than thumbnails do:

Thumbnail: https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/*/{w}x{h}{c}.{f}
Original:  https://a5.mzstatic.com/us/r1000/0/Music126/v4/*

This does indeed appear to be the artwork file as uploaded by the artist, judging by the inclusion of Photoshop-specific metadata in Pure Heroine's artwork (other images feature different EXIF metadata, suggesting a verbatim copy of whatever file had on-hand).

sed(1) script to convert between thumbnail and source URLs
#!/usr/bin/env sed -E
s/^https?://i
s'^//''
s'^([^./]+\.)*mzstatic\.com/'mzstatic.com/'i

# Thumbnail to source
/^mzstatic\.com\/image\/thumb\// {
	s'^mzstatic\.com/image/thumb/'a5.mzstatic.com/us/r1000/0/'i
	/\/Music[0-9]+\/v[0-9]+(\/[^\/]+){6}$/ {
		s'(/[^/]+)\.([^./]+)/[^/]+$'\1.\2'
	}
}

# Source to thumbnail
/^mzstatic\.com\/[^\/]+\/r1000\/0\// {
	s'^mzstatic\.com/[a-zA-Z]+/r1000/0/'is1-ssl.mzstatic.com/image/thumb/'i
	/\/Music[0-9]+\/v[0-9]+(\/[^\/]+){5}$/ {
		s'(/[^/]+)\.([[:alnum:]]+)$'\1.\2/1000x1000bb.\2'
	}
}

s'^'https://'

@Alhadis
Copy link

Alhadis commented Jul 3, 2025

Note the -999 at the end, which denotes that we want the highest quality image.

This appears to be a compression quality parameter, relevant to JPEG and WebP images only. Values appear to be percentile in nature; -999 and -100 yield identical files, but -99 produces an image with a slightly smaller filesize:

$ img=https://is3-ssl.mzstatic.com/image/thumb/Music7/v4/68/68/41/68684190-833b-bfb4-5018-e5a2e6f69eb0/source/1x1ss
$ for quality in 99 100 999; do wget "$img-$quality.jpg"; done
$ exiftool -All= -overwrite_original 1x1ss-*.jpg
$ sha256sum 1x1ss-{??,???}.jpg
e9203292661bec0c99faacb36a3e6f155d5e8fbf23e777a2f6cc09d1fe4ce663  1x1ss-99.jpg
a3e4d22182fc3dd8b8caa0718aabc3f759cc59e36809196a88661233053e4474  1x1ss-100.jpg
a3e4d22182fc3dd8b8caa0718aabc3f759cc59e36809196a88661233053e4474  1x1ss-999.jpg
$ ls -lhrS 1x1ss-{??,???}.jpg
-rw-r--r--  1 Alhadis  wheel   2.2M  4 Jul 07:14 1x1ss-99.jpg
-rw-r--r--  1 Alhadis  wheel   6.5M  4 Jul 07:14 1x1ss-999.jpg
-rw-r--r--  1 Alhadis  wheel   6.5M  4 Jul 07:14 1x1ss-100.jpg

The default quality setting is 60 for WebP images and 80 for JPEG:

$ wget https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/bd/ed/cf/bdedcfcf-3b3d-35ae-f752-175e2d8034dc/194152826486.png/3000x3000{,-60}.webp
$ exiftool -All= -overwrite_original 3000x3000*.png
$ sha256sum 3000x3000{,-60}.webp
a40aa0100fa6d74b9bdc3c42b13498293a0d8ed075c62119057bdd5cdb659c34  3000x3000.webp
a40aa0100fa6d74b9bdc3c42b13498293a0d8ed075c62119057bdd5cdb659c34  3000x3000-60.webp

Note: exiftool is used here to strip embedded metadata so that SHA-256 checksums can be calculated reliably. The downloaded images differ only in their UserComment field, which contains a request-specific string (the X-Apple-Jingle-Correlation-Key header sent from the server, to be precise).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment