Getting Started

Accessing AccuTerra Maps

Welcome to AccuTerra Maps. Adding AccuTerra Maps to your mobile or web applications is a great way to empower your users with access to the most complete outdoor recreation maps avaliable.

AccuTerra provides multiple map styles for you to choose from, see the Map Styles section below for more information on each style. Each map style supports both raster and vector tiles.

Each map service requires a API key to work. You can manage your API keys within the API Keys section of your Account page.

Get started developing with AccuTerra today, create your free account.

Map Styles

AccuTerra Outdoors

AccuTerra Outdoors showcases the unique map content AccuTerra has to offer. Our public lands data, combined with . We show in bright and bold color America’s many public land types so you always know who manages the land you’re on. When combined with our extensive road and trail network and overlaid on our highly detailed terrain data, AccuTerra Outdoors is the perfect companion for your next outdoor adventure. This map is available in both metric and imperial elevation units.

AccuTerra Topo

AccuTerra Topo is another take on our unique mapping content. With a different styling for roads, trails, and terrain AccuTerra Topo gives you another option for presenting AccuTerra to your users. Topo is well suited for use outside of the United States. This map is available in both metric and imperial elevation units.

AccuTerra Terrain

AccuTerra Terrain is a clean light basemap depicting AccuTerra’s terrain layer . This map is available in both metric and imperial elevation units.

Code Samples

Web

<html>
<head>
    <title>MapBox GL</title>
    <script type="text/javascript" src="https://api.mapbox.com/mapbox-gl-js/v1.10.1/mapbox-gl.js"></script>
<link rel="stylesheet" type="text/css" href="https://api.mapbox.com/mapbox-gl-js/v1.10.1/mapbox-gl.css">
    <style type="text/css">
        body {
            margin: 0;
            padding: 0;
        }
        #my-map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }
    </style>
</head>
<body>
    <div id="my-map"></div>
    <script type="text/javascript">
        var myKey = "eXePb4yLgQNHuICMzEylJWfs1A74RiKqGKytyMi7W9IFin0dlc";
        var map = new mapboxgl.Map({
            container: 'my-map',
            style: `https://maps.accuterra.com/v1/styles/accuterra-outdoors/style.json?key=${myKey}`,
            center: [-105.00,39.65],
            zoom: 10,
            attributionControl: false
        }).addControl(new mapboxgl.AttributionControl({
            compact: false,
            customAttribution: '&copy; AccuTerra Maps'
        }));
        map.addControl(new mapboxgl.NavigationControl());
    </script>
</body>
</html>
<!DOCTYPE HTML>
<html lang="en">

<head>
  <title>Leaflet</title>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
    integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
    crossorigin="" />
  <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
    integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
    crossorigin=""></script>
  <style>
    html,
    body {
      height: 100%;
      padding: 0;
      margin: 0;
    }

    #map {
      /* configure the size of the map */
      width: 100%;
      height: 100%;
    }
  </style>
</head>

<body>
  <div id="map"></div>
  <script>
    // initialize Leaflet
    var map = L.map('map').setView({
      lon: -105.00,
      lat: 39.65
    }, 10);

    var myKey = "eXePb4yLgQNHuICMzEylJWfs1A74RiKqGKytyMi7W9IFin0dlc";
    L.tileLayer(
      `https://{s}.accuterra.com/v1/raster/accuterra-outdoors/{z}/{x}/{y}.png?key=${myKey}`, {
        maxZoom: 16,
        attribution: '&copy; AccuTerra Maps',
        subdomains: [
          "maps-d1",
          "maps-d2",
          "maps-d3",
          "maps-d4",
        ]
      }).addTo(map);
  </script>
</body>

</html>
<html>
<head>
 <title>OpenLayers</title>
 <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css">
 <style type="text/css">
    html, body, #my-map {
        width: 100%;
        height: 100%;
        margin: 0;
    }

 </style>
 <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script>
 <script type="text/javascript" src="https://unpkg.com/ol-mapbox-style@6.1.4/dist/olms.js"></script> 
</head>
<body>
 <div id="my-map"></div>
 <script type="text/javascript">
     var myKey = "eXePb4yLgQNHuICMzEylJWfs1A74RiKqGKytyMi7W9IFin0dlc";

     olms('my-map', `https://maps.accuterra.com/v1/styles/accuterra-outdoors/style.json?key=${myKey}`).then((map) => {
        let view = map.getView();
        view.setCenter(ol.proj.fromLonLat([-105.0053989, 39.6500327]));
        view.setZoom(10);
        map.setView(view);
     });
 </script>
</body>
</html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
    <link rel="stylesheet" href="https://js.arcgis.com/4.17/esri/themes/light/main.css">
    <script src="https://js.arcgis.com/4.17/"></script>
    <title>ArcGIS JavaScript</title>
    <style>
      html, body, #viewDiv {
        padding: 0;
        margin: 0;
        height: 300px;
        width: 100%;
      }
    </style>
    <script>
  require([
      "esri/Map",
      "esri/views/MapView",
      "esri/Basemap",
      "esri/layers/VectorTileLayer",
      "esri/layers/WebTileLayer",
    ], function(Map, MapView, Basemap, VectorTileLayer, WebTileLayer) {

    const myAPIKey = 'eXePb4yLgQNHuICMzEylJWfs1A74RiKqGKytyMi7W9IFin0dlc';

    //override all XHRs (used in 3.x) to append api key
    (function() {
      var proxyOpen = window.XMLHttpRequest.prototype.open;
      window.XMLHttpRequest.prototype.open = function() {
        var args = Array.prototype.slice.call(arguments);
        if (args[1].indexOf("accuterra.com")>0){
          args[1] += (args[1].indexOf("?") == -1 ? "?" : "&") + `key=${myAPIKey}`;
        }
        return proxyOpen.apply(this, [].slice.call(args));
      };})();

    //override all fetch() calls (used in 4.x) to append api key
    (function () {
      var originalFetch = fetch;
      fetch = function() {
        var args = Array.prototype.slice.call(arguments);
        if (args[0].indexOf("accuterra.com")>0){
          args[0] += (args[0].indexOf("?") == -1 ? "?" : "&") + `key=${myAPIKey}`;
        }
        return originalFetch.apply(this, args).then(function(data) {
          // someFunctionToDoSomething();
          return data;
        });
      };
    })();

    // base vector layer
    var basemap = new Basemap({
        baseLayers: [
          new VectorTileLayer({
            style: "esri-accuterra.json"
          })
        ]
      });
      
    var map = new Map({
      basemap: basemap
    });
    
    // contours vector layer
    var contourLayer = new VectorTileLayer({
            style: "esri-accuterra-contours.json"
    });    
    map.add(contourLayer);
    
    // hill shade raster layer
    var hillShadeLayer = new WebTileLayer({
      urlTemplate: `https://maps.accuterra.com/v1/data/hillshade/{level}/{col}/{row}.jpg?key=${myAPIKey}`,
          opacity: 0.2
    });
    map.add(hillShadeLayer);
    
    var view = new MapView({
      container: "viewDiv",
      map: map,
      center: [-105.0053989, 39.6500327], // longitude, latitude
      zoom: 10
    });
  });
  </script>
  </head>
  <body>
    <div id="viewDiv"></div>
  </body>
</html>    
    
<html>
  <head>
    <title>Google Maps API with AccuTerra raster as base layer</title>
    <style>
      html, body, #map {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false&key=AIzaSyBy9114j99nP1KuB4P_bAIrLhNR2JFiS8Y"></script>
    <script type="text/javascript">

        var myAPIKey = 'eXePb4yLgQNHuICMzEylJWfs1A74RiKqGKytyMi7W9IFin0dlc';

        var element = document.getElementById("map");
        /*
        Build list of map types.
        You can also use var mapTypeIds = ["roadmap", "satellite", "hybrid", "terrain", "AccuTerra"]
        but static list is dangerous because Google might update the default list of map types.
        */
        var mapTypeIds = [];
        for(var type in google.maps.MapTypeId) {
            mapTypeIds.push(google.maps.MapTypeId[type]);
        }
        mapTypeIds.push("AccuTerra");

        var map = new google.maps.Map(element, {
            center: {lat: 39.6500327, lng: -105.0053989},
            zoom: 10,
            mapTypeId: "AccuTerra",
            mapTypeControlOptions: {
                mapTypeIds: mapTypeIds
            }
        });

        map.mapTypes.set("AccuTerra", new google.maps.ImageMapType({
            getTileUrl: function(coord, zoom) {
              return `https://maps.accuterra.com/v1/raster/accuterra-outdoors/${zoom}/${coord.x}/${coord.y}.png?key=${myAPIKey}`;
            },
            tileSize: new google.maps.Size(256, 256),
            name: "AccuTerra",
            maxZoom: 18
        }));

    </script>
  </body>
</html>

Mobile

package com.accuterra.mapbox_accuterra_maps_demo

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.mapboxsdk.Mapbox
import com.mapbox.mapboxsdk.camera.CameraPosition
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.maps.MapboxMapOptions

class MainActivity : AppCompatActivity() {
    private var mapView: MapView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        Mapbox.getInstance(this, getString(R.string.mapbox_access_token))

        val options = MapboxMapOptions.createFromAttributes(this, null)
            .camera(
                CameraPosition.Builder()
                    .target(LatLng(39.375239, -104.861077))
                    .zoom(14.0)
                    .build()
            )

        mapView = MapView(this, options)
        mapView?.onCreate(savedInstanceState)

        // Visit https://accuterra.com and create your free account to get a map API key.
        val accuterraMapsKey = "YOUR-MAP-API-KEY-HERE"

        mapView?.getMapAsync { mapboxMap ->
            mapboxMap.setStyle("https://maps.accuterra.com/v1/styles/accuterra-outdoors/style.json?key=$accuterraMapsKey") {
                // Map is set up and the style has loaded. Now you can add data or make other map adjustments.
            }
        }

        setContentView(mapView)
    }

    override fun onStart() {
        super.onStart()
        mapView?.onStart()
    }

    override fun onResume() {
        super.onResume()
        mapView?.onResume()
    }

    override fun onPause() {
        super.onPause()
        mapView?.onPause()
    }

    override fun onStop() {
        super.onStop()
        mapView?.onStop()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        mapView?.onSaveInstanceState(outState)
    }

    override fun onLowMemory() {
        super.onLowMemory()
        mapView?.onLowMemory()
    }

    override fun onDestroy() {
        super.onDestroy()
        mapView?.onDestroy()
    }
}
import UIKit
import Mapbox

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Visit https://accuterra.com and create your free account to get a map API key.
        let accuterraMapsKey = "YOUR-MAP-API-KEY-HERE"
                
        let url = URL(string: "https://maps.accuterra.com/v1/styles/accuterra-outdoors/style.json?key=\(accuterraMapsKey)")
        let mapView = MGLMapView(frame: view.bounds, styleURL: url)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        mapView.setCenter(CLLocationCoordinate2D(latitude: 39.375239, longitude: -104.861077), zoomLevel: 14, animated: false)
        view.addSubview(mapView)
    }

}
package com.accuterra.google_maps_accuterra_maps_demo

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.*
import java.net.MalformedURLException
import java.net.URL

class MapsActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var mMap: GoogleMap

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_maps)
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

    /**
     * Manipulates the map once available.
     * This callback is triggered when the map is ready to be used.
     * This is where we can add markers or lines, add listeners or move the camera. In this case,
     * we just add a marker near Sydney, Australia.
     * If Google Play services is not installed on the device, the user will be prompted to install
     * it inside the SupportMapFragment. This method will only be triggered once the user has
     * installed Google Play services and returned to the app.
     */
    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap

        // Visit https://accuterra.com and create your free account to get a map API key.
        val accuterraMapsKey = "YOUR-MAP-API-KEY-HERE"

        mMap.mapType = GoogleMap.MAP_TYPE_NONE

        val tileProvider: TileProvider = object : UrlTileProvider(256, 256) {
            override fun getTileUrl(x: Int, y: Int, zoom: Int): URL? {

                /* Define the URL pattern for the tile images */
                val url = "https://maps.accuterra.com/v1/raster/accuterra-outdoors/$zoom/$x/$y.png?key=$accuterraMapsKey"
                return if (!checkTileExists(x, y, zoom)) {
                    null
                } else try {
                    URL(url)
                } catch (e: MalformedURLException) {
                    throw AssertionError(e)
                }
            }

            /*
             * Check that the tile server supports the requested x, y and zoom.
             * Complete this stub according to the tile range you support.
             * If you support a limited range of tiles at different zoom levels, then you
             * need to define the supported x, y range at each zoom level.
             */
            private fun checkTileExists(x: Int, y: Int, zoom: Int): Boolean {
                val minZoom = 8
                val maxZoom = 18
                return zoom in minZoom..maxZoom
            }
        }

        mMap.addTileOverlay(TileOverlayOptions().tileProvider(tileProvider))

        val centerPoint = LatLng(39.375239, -104.861077)
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(centerPoint, 14f))
    }
}
import UIKit
import GoogleMaps

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Visit https://accuterra.com and create your free account to get a map API key.
        let accuterraMapsKey = "YOUR-MAP-API-KEY-HERE"

        let camera = GMSCameraPosition.camera(withLatitude: 39.375239, longitude: -104.861077, zoom: 14.0)
        let mapView = GMSMapView.map(withFrame: view.frame, camera: camera)
        
        let urls: GMSTileURLConstructor = { (x, y, zoom) in
          let url = "https://maps.accuterra.com/v1/raster/accuterra-outdoors/\(zoom)/\(x)/\(y).png?key=\(accuterraMapsKey)"
          return URL(string: url)
        }

        let layer = GMSURLTileLayer(urlConstructor: urls)
        layer.zIndex = 100
        layer.map = mapView
        
        view.addSubview(mapView)
    }

}
package com.accuterra.arcgis_accuterra_maps_demo

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.esri.arcgisruntime.geometry.Point
import com.esri.arcgisruntime.geometry.SpatialReferences
import com.esri.arcgisruntime.layers.WebTiledLayer
import com.esri.arcgisruntime.mapping.ArcGISMap
import com.esri.arcgisruntime.mapping.Basemap
import com.esri.arcgisruntime.mapping.view.MapView

class MainActivity : AppCompatActivity() {
    lateinit var mapView: MapView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Get reference to map view
        mapView = findViewById(R.id.mapView)

        // Visit https://accuterra.com and create your free account to get a map API key.
        val accuterraMapsKey = "YOUR-MAP-API-KEY-HERE"
        
        val url = "https://maps.accuterra.com/v1/raster/accuterra-outdoors/{level}/{col}/{row}.png?key=$accuterraMapsKey"
        val webTiledLayer = WebTiledLayer(url)

        // Use web tiled layer as Basemap
        val map = ArcGISMap(Basemap(webTiledLayer))
        mapView.map = map

        // Custom attributes
        webTiledLayer.attribution = "Map tiles by AccuTerra Maps"

        // Set custom view point
        val point = Point(-104.861077, 39.375239, SpatialReferences.getWgs84())
        mapView.setViewpointCenterAsync(point, 5000.0)
    }

    override fun onPause() {
        super.onPause()
        mapView.pause()
    }
    override fun onResume() {
        super.onResume()
        mapView.resume()
    }
    override fun onDestroy() {
        super.onDestroy()
        mapView.dispose()
    }
}
import UIKit
import ArcGIS

class ViewController: UIViewController {
    
    @IBOutlet weak var mapView: AGSMapView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        title = "ArcGIS SDK with AccuTerra Maps"
        
        // Visit https://accuterra.com and create your free account to get a map API key.
        let accuterraMapsKey = "YOUR-MAP-API-KEY-HERE"
        
        let url = "https://maps.accuterra.com/v1/raster/accuterra-outdoors/{level}/{col}/{row}.png?key=\(accuterraMapsKey)"        
        let webTiledLayer = AGSWebTiledLayer(urlTemplate: url)
        webTiledLayer.attribution = "Map tiles by AccuTerra Maps"
        
        let basemap = AGSBasemap(baseLayer: webTiledLayer)        
        mapView.map = AGSMap(basemap: basemap)
        
        let viewpoint = AGSViewpoint(latitude: 39.375239, longitude: -104.861077, scale: 6000)
        mapView.setViewpoint(viewpoint)
    }
    
}