MapKit JS lets you embed interactive maps directly into your websites across platforms and operating systems, including iOS and Android. Like MapKit for apps, you can also add annotations and overlays to the map to call out points of interest or user destinations.
GeoJSON Import
View description and code
State:
Population:
Region and Zoom Limits
View description and code
San Francisco
Toronto
Embed
View description and code
Add Annotations
View description and code
Custom Callout
View description and code
Draggable Annotations
View description and code
Long press the annotation, then drag it to anywhere on the map.
MapKit JS Dashboard
Track your website’s use of Apple Maps services with the MapKit JS Dashboard. Monitor map initializations and service requests in real time, or view up to a year of activity by day, week, month, or year.
MapKit JS provides a free daily limit of 250,000 map views and 25,000 service calls per Apple Developer Program membership. For additional capacity needs, contact us.
Snapshots are static map images retrieved from a URL that you can customize to display a region of the world, mark specific points with different styles of annotations and overlays, show the Dark Mode map, and more. Use Snapshots whenever you don't need an interactive map or where you'd use a typical image URL — for example, in websites and in places where JavaScript isn’t available, such as email clients.
Snapshots offer a free daily limit of 25,000 unique requests per day per Apple Developer Program membership. For additional capacity needs, contact us.
Create a map with two annotations. Shift-clicking on the map adds a new annotation where the shift-click is detected and removes the annotation on the map that was previously added with shift-click, if one exists.
<!DOCTYPE html><html><head><metacharset="utf-8"><scriptsrc="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js"></script><style>#map{height:600px;}</style></head><body><divid="map"></div><script>varMarkerAnnotation=mapkit.MarkerAnnotation,clickAnnotation;varsfo=newmapkit.Coordinate(37.616934,-122.383790),work=newmapkit.Coordinate(37.3349,-122.0090201);mapkit.init({authorizationCallback:function(done){varxhr=newXMLHttpRequest();xhr.open("GET","/services/jwt");xhr.addEventListener("load",function(){done(this.responseText);});xhr.send();}});varmap=newmapkit.Map("map");// Setting properties on creation:varsfoAnnotation=newMarkerAnnotation(sfo,{color:"#f4a56d",title:"SFO",glyphText:"✈️"});// Setting properties after creation:varworkAnnotation=newMarkerAnnotation(work);workAnnotation.color="#969696";workAnnotation.title="Work";workAnnotation.subtitle="Apple Park";workAnnotation.selected="true";workAnnotation.glyphText="";// Add and show both annotations on the mapmap.showItems([sfoAnnotation,workAnnotation]);// Drop an annotation where a Shift-click is detected:map.element.addEventListener("click",function(event){if(!event.shiftKey){return;}if(clickAnnotation){map.removeAnnotation(clickAnnotation);}varcoordinate=map.convertPointOnPageToCoordinate(newDOMPoint(event.pageX,event.pageY));clickAnnotation=newMarkerAnnotation(coordinate,{title:"Click!",color:"#c969e0"});map.addAnnotation(clickAnnotation);});</script></body></html>
Custom Callout
Create annotations with custom callouts for the landmarks of San Francisco.
A “loupe” is used to demonstrate draggable annotations. This example shows how to make a pin draggable, style a map with CSS, observe map events, and update the region of a second map in response to map events.
<!DOCTYPE html><html><head><metacharset="utf-8"><scriptsrc="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js"></script><styletype="text/css">html,body,#container{height:100%;overflow:hidden;}body{margin:0;padding:0;}#loupe{width:200px;width:20vw;height:200px;height:20vw;position:absolute;top:11px;left:11px;overflow:hidden;border:8pxsolid#FFF;-webkit-box-shadow:005px4pxrgba(0,0,0,0.2);-moz-box-shadow:005px4pxrgba(0,0,0,0.2);box-shadow:005px4pxrgba(0,0,0,0.2);}</style></head><body><divid="container"></div><divid="loupe"></div><scripttype="text/javascript">varMAGNIFICATION_FACTOR=8,LOUPE_DIAMETER=180;varcenter=newmapkit.Coordinate(37.7952,-122.4028);// Transamerica Pyramid, SFmapkit.init({authorizationCallback:function(done){varxhr=newXMLHttpRequest();xhr.open("GET","/services/jwt");xhr.addEventListener("load",function(){done(this.responseText);});xhr.send();}});// Call when the zoom level has changed.// Update the loupe to region centered on the marker that is 8x the map.functioncalculateMagnifiedRegion(map,marker){varratio=Math.min(window.innerWidth,window.innerHeight)/LOUPE_DIAMETER,delta=map.region.span.latitudeDelta/(MAGNIFICATION_FACTOR*ratio),newSpan=newmapkit.CoordinateSpan(delta,delta);returnnewmapkit.CoordinateRegion(marker.coordinate,newSpan);}varmap=newmapkit.Map("container",{center:center});map.addEventListener("zoom-end",function(){// Update the loupe's magnification after a zoom changezoomedMap.setRegionAnimated(calculateMagnifiedRegion(map,marker));});varmarker=newmapkit.MarkerAnnotation(map.center,{draggable:true,selected:true,title:"Drag me"});marker.addEventListener("drag-start",function(event){// No need to show "Drag me" message once user has draggedevent.target.title="";});marker.addEventListener("drag-end",function(){// Center the loupe on the marker's new locationzoomedMap.setCenterAnimated(marker.coordinate);});map.addAnnotation(marker);// Initialize the loupe based on the marker's location on the mapvarzoomedMap=newmapkit.Map("loupe",{isScrollEnabled:false,isZoomEnabled:false,showsCompass:mapkit.FeatureVisibility.Hidden,showsZoomControl:false,showsMapTypeControl:false});zoomedMap.setRegionAnimated(calculateMagnifiedRegion(map,marker));</script></body></html>
GeoJSON Import
Create a map with an overlay for each state in the U.S. The color of each overlay represents the population in that
state.
This sample uses GeoJSON data derived from cartographic boundary files and 2018 population estimates provided by the United States Census Bureau. The code shows how to use a delegate when importing GeoJSON
data to add style and data to the imported items; the color of each overlay gives an indication of its population,
and selecting an overlay displays the the information associated with that state.
<!DOCTYPE html><html><head><title>GeoJSON Import</title><metacharset="utf-8"><scriptsrc="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js"></script><style>html,body{height:100%;overflow:hidden;}body{margin:0;padding:0;font-family:"-apple-system-font","HelveticaNeue-Medium","Helvetica","Arial","sans-serif";}.container{position:relative;}#map{width:100%;max-width:600px;height:600px;}#infoPopup{display:none;top:7px;left:67px;background:#FFFFFF;padding:5px15px;position:absolute;z-index:1000;min-width:180px;font:13px/16px"-apple-system-font","HelveticaNeue-Medium","Helvetica","Arial","sans-serif";color:#212121;border:1pxsolidrgba(0,0,0,0.2);border-radius:3px;}.container.map-legend{position:absolute;z-index:1000;top:7px;left:7px;}.map-legenddiv{margin-bottom:5px;width:40px;font-size:12px;color:#fff;padding:4px7px;}#infoPopup.info{padding:10px0;box-sizing:border-box;}#infoPopup.info:first-child{border-bottom:1pxsolidrgba(0,0,0,0.2);}#infoPopup.info-country,#infoPopup.info-population{margin-left:5px;color:#464545;font-style:italic;}</style></head><body><divclass="container"><divid="map"></div><divid="infoPopup"><divclass="info"><span>State:</span><spanclass="info-country"></span></div><divclass="info"><span>Population:</span><spanclass="info-population"></span></div></div><divclass="map-legend"></div></div><script>varLINE_WIDTH_DEFAULT=0.5;varLINE_WIDTH_SELECTED=3;varMAP_COLORS=[{color:"#fcc5c0",range:"< 1M",num:1000000},{color:"#fa9fb5",range:"1M +",num:5000000},{color:"#f768a1",range:"5M +",num:10000000},{color:"#dd3497",range:"10M +",num:20000000},{color:"#ae017e",range:"20M +",num:30000000},{color:"#7a0177",range:"> 30M",num:Infinity}];// Initialize mapkit and create a new map.mapkit.init({authorizationCallback:function(done){varxhr=newXMLHttpRequest();xhr.open("GET","/services/jwt");xhr.addEventListener("load",function(){done(this.responseText);});xhr.send();}});varmap=newmapkit.Map("map",{isRotationEnabled:false,isZoomEnabled:false,showsZoomControl:false});// Setup the UI to show a popup when a state is selected.varinfoPopup=document.getElementById("infoPopup");varinfoCountry=infoPopup.querySelector(".info-country");varinfoPopulation=infoPopup.querySelector(".info-population");varmapLegend=document.querySelector(".map-legend");functionshowInfo(data){infoCountry.innerText=data.name;infoPopulation.innerText=data.population.toLocaleString();infoPopup.style.display="block";}functioncloseInfo(){infoPopup.style.display="none";}functionaddLegend(){varel,textNode;MAP_COLORS.forEach(function(mColor){el=document.createElement("div");textNode=document.createTextNode(mColor.range);el.appendChild(textNode);el.style.background=mColor.color;mapLegend.appendChild(el);});}addLegend();// Import GeoJSON data with the shape of the states and their population.mapkit.importGeoJSON("states.json",{// Some states are represented as MultiPolygons; we transform them into// a single PolygonOverlay by concatenating the lists of lists of points.itemForMultiPolygon:function(collection,geoJSON){varoverlays=collection.getFlattenedItemList();varpoints=overlays.reduce(function(points,overlay){returnpoints.concat(overlay.points);},[]);returnnewmapkit.PolygonOverlay(points);},// After an overlay has been created for a feature (either directly or through// itemForMultiPolygon above), the properties of the feature are used to add data// and set the style (especially the fill color) based on population count.itemForFeature:function(overlay,geoJSON){varpopulation=geoJSON.properties.population;// Add data to the overlay to be shown when it is selected.overlay.data={name:geoJSON.properties.name,population:geoJSON.properties.population};// Find the right color for the population and the set the style.for(vari=0;i<MAP_COLORS.length;++i){if(population<MAP_COLORS[i].num){overlay.style=newmapkit.Style({fillOpacity:0.7,lineWidth:LINE_WIDTH_DEFAULT,fillColor:MAP_COLORS[i].color});break;}}returnoverlay;},// When all the data has been imported, we can show the results.geoJSONDidComplete:function(overlays){map.addItems(overlays);map.showItems(overlays.getFlattenedItemList().filter(function(overlay){// Focus the map on the continental states at first.varname=overlay.data.name;returnname!=="Alaska"&&name!=="Hawaii";}),{// Leave some padding for the color key.padding:newmapkit.Padding(0,0,0,67)});}});// Show info about the selected state.map.addEventListener("select",function(event){if(event.overlay&&event.overlay.data){event.overlay.style.lineWidth=LINE_WIDTH_SELECTED;showInfo(event.overlay.data);}});// Hide info when a state is deselected.map.addEventListener("deselect",function(event){if(event.overlay){event.overlay.style.lineWidth=LINE_WIDTH_DEFAULT;closeInfo();}});</script></body></html>
Region and Zoom Limits
Create a map restricted by camera boundaries and zoom range to two cities (San Francisco and Toronto). Click on the
desired city to change the region and zoom limits.
<!DOCTYPE html><html><head><title>Region and Zoom Limits</title><metacharset="utf-8"><scriptsrc="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js"></script><style>html,body{height:100%;overflow:hidden;}body{margin:0;padding:0;}#city-regions{width:100%;height:40px;cursor:default;font-family:"-apple-system-font",Futura,"Helvetica Neue","Helvetica","Arial","sans-serif";}#city-regionsdiv{float:left;width:50%;height:100%;text-align:center;background-color:white;}#city-regionsp{margin-top:9px;margin-bottom:10px;}#city-regionsdiv.selected-city{background-color:#08f;color:#f8f9f0;}#map{width:100%;height:560px;}</style></head><body><divid="city-regions"><divid="sanfrancisco"><p>San Francisco</p></div><divid="toronto"><p>Toronto</p></div></div><divid="map"></div><script>varSELECTED_CITY_CLASS="selected-city";// Define camera boundaries and zoom ranges for San Francisco and Toronto.varCITIES={sanfrancisco:{region:newmapkit.CoordinateRegion(newmapkit.Coordinate(37.7812,-122.44755),newmapkit.CoordinateSpan(0.10,0.11)),zoomRange:newmapkit.CameraZoomRange(250,15000)},toronto:{region:newmapkit.CoordinateRegion(newmapkit.Coordinate(43.6451,-79.37505),newmapkit.CoordinateSpan(0.05,0.11)),zoomRange:newmapkit.CameraZoomRange(250,20000)}}// Initialize mapkit.mapkit.init({authorizationCallback:function(done){varxhr=newXMLHttpRequest();xhr.open("GET","/services/jwt");xhr.addEventListener("load",function(){done(this.responseText);});xhr.send();}});// Create the map and set the current city to San Francisco when ready.varmap=newmapkit.Map("map");mapkit.addEventListener("configuration-change",functionconfigurationChanged(){mapkit.removeEventListener("configuration-change",configurationChanged);setCity("sanfrancisco");});// Show the selected city on the map and highlight its name.functionsetCity(name){// Highlight the current city.vardiv=document.getElementsByClassName(SELECTED_CITY_CLASS)[0];if(div){div.classList.remove(SELECTED_CITY_CLASS);}document.getElementById(name).classList.add(SELECTED_CITY_CLASS);// Show it on the map, with camera boundaries and zoom range for this city.varcity=CITIES[name];map.cameraZoomRange=city.zoomRange;map.cameraBoundary=city.region;map.region=city.region;}// Listen to click events to change the city.varcityRegionsElement=document.getElementById("city-regions");cityRegionsElement.addEventListener("click",function(event){setCity(event.target.id||event.target.parentNode.id);});</script></body></html>