Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decipher the X-Apple-Store-Front header for requests to iTunes API endpoints #1

Open
baltpeter opened this issue Jan 10, 2023 · 8 comments
Labels

Comments

@baltpeter
Copy link
Member

Many endpoints on itunes.apple.com (and subdomains) accept/expect an X-Apple-Store-Front header. Its value consists of between one and three numbers and has the following format: <country>-<language>,<platform> (only <country> is required, the others can be left off).

Setting <country> to 143443 means Germany for example; a list of possible countries used to be available in the iTunes affiliate partner documentation and can still be accessed through the Internet Archive.

Among the available values for <language> are 1 (US English), 2 (British English), 3 (French), and 4 (German). It is not possible to combine country and language arbitrarily, for example setting US English as the language but Germany as the country does not work, whereas British English does work for Germany.

Finally, the <platform> value determines the Apple application the request is (supposedly) coming from, with 28 meaning iTunes 12 for example. The endpoint's response format changes depending on the platform set. When setting a graphical client like iTunes, an HTML site will be returned that contains a script element which assigns the actual API return value to its.serverData. Some endpoints instead return data in a PLIST or JSON format (like 26 or 29).

We should try to get full lists of the possible values for each of these parameters.

@baltpeter
Copy link
Member Author

For the country parameter, getting a full list is straightforward thanks to the list Apple used to publish. Conveniently, that list was published as an HTML table that can be converted to machine-readable data with little effort.

To generate a JSON object mapping from country code to storefront country ID, go to to https://web.archive.org/web/20191206001952/https://affiliate.itunes.apple.com/resources/documentation/linking-to-the-itunes-music-store/#appendix, open the browser dev tools, select the <table> element in the appendix, and in the console, run:

[...$0.querySelectorAll('tr')].reduce(
    (acc, cur) => ({
        ...acc,
        [cur.querySelector('td:nth-child(2)')?.innerText]: +cur.querySelector('td:nth-child(3)')?.innerText,
    }),
    {}
);
Output
{
    "DZ": 143563,
    "AO": 143564,
    "AI": 143538,
    "AG": 143540,
    "AR": 143505,
    "AM": 143524,
    "AU": 143460,
    "AT": 143445,
    "AZ": 143568,
    "BH": 143559,
    "BD": 143490,
    "BB": 143541,
    "BY": 143565,
    "BE": 143446,
    "BZ": 143555,
    "BM": 143542,
    "BO": 143556,
    "BW": 143525,
    "BR": 143503,
    "VG": 143543,
    "BN": 143560,
    "BG": 143526,
    "CA": 143455,
    "KY": 143544,
    "CL": 143483,
    "CN": 143465,
    "CO": 143501,
    "CR": 143495,
    "CI": 143527,
    "HR": 143494,
    "CY": 143557,
    "CZ": 143489,
    "DK": 143458,
    "DM": 143545,
    "DO": 143508,
    "EC": 143509,
    "EG": 143516,
    "SV": 143506,
    "EE": 143518,
    "FI": 143447,
    "FR": 143442,
    "DE": 143443,
    "GH": 143573,
    "GR": 143448,
    "GD": 143546,
    "GT": 143504,
    "GY": 143553,
    "HN": 143510,
    "HK": 143463,
    "HU": 143482,
    "IS": 143558,
    "IN": 143467,
    "ID": 143476,
    "IE": 143449,
    "IL": 143491,
    "IT": 143450,
    "JM": 143511,
    "JP": 143462,
    "JO": 143528,
    "KZ": 143517,
    "KE": 143529,
    "KR": 143466,
    "KW": 143493,
    "LV": 143519,
    "LB": 143497,
    "LI": 143522,
    "LT": 143520,
    "LU": 143451,
    "MO": 143515,
    "MK": 143530,
    "MG": 143531,
    "MY": 143473,
    "MV": 143488,
    "ML": 143532,
    "MT": 143521,
    "MU": 143533,
    "MX": 143468,
    "MD": 143523,
    "MS": 143547,
    "NP": 143484,
    "NL": 143452,
    "NZ": 143461,
    "NI": 143512,
    "NE": 143534,
    "NG": 143561,
    "NO": 143457,
    "OM": 143562,
    "PK": 143477,
    "PA": 143485,
    "PY": 143513,
    "PE": 143507,
    "PH": 143474,
    "PL": 143478,
    "PT": 143453,
    "QA": 143498,
    "RO": 143487,
    "RU": 143469,
    "SA": 143479,
    "SN": 143535,
    "RS": 143500,
    "SG": 143464,
    "SK": 143496,
    "SI": 143499,
    "ZA": 143472,
    "ES": 143454,
    "LK": 143486,
    "KN": 143548,
    "LC": 143549,
    "VC": 143550,
    "SR": 143554,
    "SE": 143456,
    "CH": 143459,
    "TW": 143470,
    "TZ": 143572,
    "TH": 143475,
    "BS": 143539,
    "TT": 143551,
    "TN": 143536,
    "TR": 143480,
    "TC": 143552,
    "UG": 143537,
    "GB": 143444,
    "UA": 143492,
    "AE": 143481,
    "UY": 143514,
    "US": 143441,
    "UZ": 143566,
    "VE": 143502,
    "VN": 143471,
    "YE": 143571
}

@baltpeter
Copy link
Member Author

baltpeter commented Jan 16, 2023

The languages are less straightforward. I haven't found a way to get a full list of those (which is why we'll leave this issue open as a TODO).

For now, I'm using the list from https://stackoverflow.com/a/58776183/3211062.

Also note: Not all combinations between country and language are possible. A list of possible combinations can be obtained from this Apple Music endpoint: https://api.music.apple.com/v1/storefronts (which unfortunately doesn't use the numerical IDs).

If no language is included in the X-Apple-Store-Front header, a sensible default is used (also listed in the API response).

@baltpeter
Copy link
Member Author

It's similar for the platforms: I haven't found a way to get a full list. This is also still a TODO.

For now, I'm using the list from https://gist.github.com/sgmurphy/1878352?permalink_comment_id=2977743#gistcomment-2977743.

According to that comment, it was possible to learn the platform name for a given numerical value through the response to an app details endpoint. I was unfortunately not able to reproduce that anymore.

Also somewhat crucially, many of the platform names aren't clear at all. While ones like iTunes10 are pretty obvious, this isn't the case for all of them, especially the "interesting" ones (i.e. the ones returning JSON). What do K7, P7, P84, K84 etc. mean?

@baltpeter
Copy link
Member Author

For fun, here's what ChatGPT thinks:

The platform codes you listed are internal codes used by Apple to identify the platform that a request is coming from. Some of them are obvious such as Mac, K8 and P8, but others are less so.

P6 is likely a code for a previous version of the iOS operating system (version 6) running on an iPhone or iPad. Similarly, K6 and P71 are likely codes for previous versions of the iOS operating system running on an iPod touch or iPad respectively. "K" usually means iPod and "P" usually means iPhone, and the number following it is the version of iOS.

Configurator is likely a code for requests coming from Apple Configurator, a tool used by businesses and schools to configure and deploy iOS devices.

MacAMPLibrary1, MacMusic1, MacPodcasts1 and MacTV1 are likely codes for requests coming from different sections of the iTunes application for Mac, respectively the Library, Music, Podcasts and TV sections.

iTunes122, iTunes12, iTunes11 and iTunes10 are likely codes for requests coming from different versions of the iTunes application for Mac and Windows.

Mac1, EnterpriseStore, VolumeStore and iTunes122 are likely codes for requests coming from different sections or versions of the iTunes application for Mac and Windows.

It's worth noting that these codes are subject to change and might not be up to date.

Could you give me more details about the K… and P… codes?

Sure. The K... and P... codes in the X-Apple-Store-Front header are likely codes used to identify the specific iOS device and version that a request is coming from.

The K... codes are likely used to identify requests coming from an iPod touch. The number following the "K" is likely the version of the iOS operating system running on the device. For example, "K8" would indicate that the request is coming from an iPod touch running iOS 8.

The P... codes are likely used to identify requests coming from an iPhone. The number following the "P" is likely the version of the iOS operating system running on the device. For example, "P8" would indicate that the request is coming from an iPhone running iOS 8.

It's worth noting that these codes might change over time and these assumptions might not be accurate.

Sounds genuinely plausible but it's of course just a guess. I can maybe do some more verification when I have an iPhone to test. Unfortunately, I don't have an iPod lying around.

@baltpeter
Copy link
Member Author

Actually, considering #2 (comment), K might also stand for iPad?

@baltpeter
Copy link
Member Author

One more data point: I found an old traffic dump from an iPhone running iOS 14.5.1. It used:

User-Agent: AppStore/3.0 iOS/14.5.1 model/iPhone10,4 hwp/t8015 build/18E212 (6; dt:160) AMS/1
X-Apple-Store-Front: 143443-2,29

This lines up with P meaning iPhone (29 is P84). But the version is obviously not 8.4. Maybe they stopped incrementing the platform because the API didn't change anymore? The list from the Gist only has a handful of (potential) version numbers anyway.

@baltpeter
Copy link
Member Author

Another iPhone with iOS 14.8 used the same store front:

x-apple-store-front: 143443-2,29
user-agent: AppStore/3.0 iOS/14.8 model/iPhone9,3 hwp/t8010 build/18H17 (6; dt:139) AMS/1

@baltpeter
Copy link
Member Author

baltpeter commented Jan 17, 2023

Seems like they did indeed stick with using 29/P84 as the platform, even in the newer versions of the App Store. This is from an iPhone 6s running iOS 15.7.2:

x-apple-store-front: 143443-2,29 t:apps3
user-agent: AppStore/3.0 iOS/15.7.2 model/iPhone8,1 hwp/s8003 build/19H218 (6; dt:141) AMS/1

With that, I'm quite confident that we can use 29 as well without problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant