Tutorial5 min read

How to extract Apple Maps POI icons symbols

Viktor Shchelochkov
Viktor ShchelochkovFullstack developer
A lot of Apple Maps POI icons extracted as PNGs

Today I was working on a virtual map of my Minecraft server, Demovio and wanted to added icons of every building we've made with my friends so far. Apple is always best with design stuff so I wanted to grab icons from there.

It turned it to be much harder than I thought. Obviously these icons are not present in SF Symbols, they were created especially for maps. Also you can't just pull these from .app's resources.

And they're not in Assets.car...

Decompiled using https://github.com/bartoszj/acextract
Decompiled using https://github.com/bartoszj/acextract

So I quickly hooked up mitmproxy and started wandering around maps hoping they'd be downloaded from Apple's servers...

After some digging, still nothing. The app actually does download some icons packed into .icondatapack format. I even found them on my computer, cached in ~/Library/Caches/GeoServices/RegionalResources:

And I even found a way of decompiling them. There is exactly one app in the internet that is capable of doing so, and it's not even the main feature of the app. It's paid and it's fairly easy to find it so I won't link it here, but even after decompressing these Apple Maps icondatapacks I found some brand logos and local city icons, not POI icons.

Corporate_Icons-43.icondatapack opened
Corporate_Icons-43.icondatapack opened

I didn't give up. Obviously there was just one place left where I haven't looked yet, and that's for a reason. Who wants to decompile native Swift apps? Well, Apple didn't give me a choice.

I tried malimite with Ghidra IDE but it looks like it only works for IPA files. So I downloaded Hopper Disassembler paid closed-source software and loaded Apple Maps macOS app there.

It does let you search through app strings, labels and swift processes, but Apple obviously obfuscates everything. I tried different combinations of search such as "Icon", "Glyph", tried some icons names such as "Pizza" but no luck. I guess they're using UIBezierPath because I found one match for it, but I have no idea where paths are stored in all this mess. I spent a few hours but gave up since no one paid me to spend so much time digging some icons lol.

I had one last trick up my sleeve though. I saved it for last resort but there was no choice — we're digging to web version of Apple Maps. The downside is that these icons have no gradient, but you can fix it yourself easily. The most important thing is that the icons themselves are same and colors seems to match too.

https://duckduckgo.com/?q=new+york
https://duckduckgo.com/?q=new+york

Web Apple Maps suck — they're slow, unoptimized and sometimes just reload the page randomly (Apple should definetely hire me — cv.hloth.dev), but somewhere on their CDN they store these icons and it's infinitely times easier to get those through DevTools than through swift decompilation tools.

So after some reverse engineering and experimenting with mapkit APIs, the workflow for scaping is actually very simple:

  1. Make GET request to https://duckduckgo.com/local.js?get_mk_token=1 (or obtain mapkit token somehow else)
  2. Make GET request to https://cdn.apple-mapkit.com/ma/bootstrap?apiVersion=2&mkjsVersion=5.78.158&poi=1 with Authorization header having token from previous step. This should give you JSON response with "accessKey" in it, which is the key we're hunting for. This will give us access to Apple MapKit CDN
  3. Finally you can make GET requests to https://cdn.apple-mapkit.com with this accessKey in query

Access key looks like this: 1743879209_3285637747132202088_/_gViGKMuzZNzmDskrn2ovwl0pl9XMsGcon7VsPG9kfmg= and works for 30 minutes.

All query parameters for cdn.apple-mapkit.com are very well documented, so you won't have any troubles making those.

I'm just kidding lol. Obviously it's obfuscated too and I have no clue what they mean, but I managed to find one of parameters that gives you different icons and using that I enumerated about 490 different icons.

Basically the URL is:

1https://cdn.apple-mapkit.com/md/v1/icon?scale=2&subtype=poi&tint=dark&emphasis=standard&style=1&zoom=13&attributes=4:226,5:3,6:115,10:14,16:1,47:50,82:5,85:11,89:6,164:1,193:1&accessKey=1743875780_4578807989659320900_%2F_sfsG0vv9WUfbnNCBtCA210EMB0WHnPggaB1dEJOS1XM%3D

You should use these parameters:

  • scale — set to 3
  • subtype — set to poi
  • tint — set to dark
  • emphasis — set to standard
  • style — set to 1
  • zoom — set to something very big, like 128
  • attributes — that's the most tricky part, see below
  • accessKey — url encode your access key and put it here

I used 4:226,5:3,6:SOMERANDOMNUMBER,10:0,82:3,85:13,89:1,164:1,193:1 string for attributes and I couldn't find what each of these parameters mean. I only found that they're called "style attributes" in MapKit JavaScript library and these are key-value pairs of something. Replace SOMERANDOMNUMBER with number from 0 to 500 and you should get 52x52 png image.

Here is a JS program I wrote to automate it:

1import fs from "fs/promises"
2
3const accessKey = '' // <-- paste your access key here
4
5const max = 500
6for (let i = 0; i < max; i++) {
7 const scale = 3
8 const id = i
9 const imgReq = await fetch('https://cdn.apple-mapkit.com/md/v1/icon?scale=' + scale + '&subtype=poi&tint=dark&emphasis=standard&style=1&zoom=128&attributes=4:226,5:3,6:' + id + ',10:0,82:3,85:13,89:1,164:1,193:1&accessKey=' + encodeURIComponent(accessKey));
10 if(imgReq.status !== 200) {
11 console.log(await imgReq.text());
12 console.log(`Error: ${imgReq.status}`);
13 console.log(i)
14 break
15 }
16 const content = Buffer.from(await imgReq.arrayBuffer())
17 const hash = Bun.hash(content)
18 const emptyIconHash = '14793898150699695213'
19 if (hash.toString() !== emptyIconHash) {
20 await fs.writeFile(`./icons/52x52/${id}.png`, content);
21 }
22 console.log(id, Math.round(i / max * 100) + '%')
23}
24
25// Run `mkdir ./icons && mkdir ./icons/52x52`
26// Run with `bun apple-maps-poi-icons-extract.ts`
27
28// This will skip empty icons

The result

If you just want to grab the icons, go ahead and download the zip file I ended up with after downloading all icons I could get from the CDN.

(you just need to click the "donate" button to reveal content)

Attached files & links
Please consider donating to support the blogClicking the button below will open donation page in a new tab and reveal files and links. Donations are not mandatory, but highly appreciated.Donate
  1. Download apple_maps_icons.zipeCeSapVEDEIvEtkFNqePuiFbMNuZItfadNPzKvAxSaBmxjpoyPhFlckqqsdhhSYmvsVodOxmuiToUFqTBJDvqevHNlWeURWMPkQDeixGxmybkmCijJJSoKPcdLnCqLfOzBRtl
Published at: April 5