JavaScript drop-ins for map and geocoder libraries

Front-end code is where a provider change hurts most, because the map library, the geocoder widget and the billing are tangled together. These loaders and settings let you keep the library code you have. Geocoding, autocomplete and elevation come from us. The map is drawn with free OpenStreetMap tiles loaded straight from the visitor's browser, because we do not serve map tiles. Loading a library is free, and only geocoding, autocomplete and elevation calls count toward your quota.

For the REST side, the matrix of all seventeen hosts and the migration checklist are on how the drop-ins work.

On this page

Google Maps JavaScript API

Load the maps library from gapi.mygeocode.com instead of maps.googleapis.com. The google.maps namespace is provided: the Geocoder, Places Autocomplete and the ElevationService are answered by us, and the map, markers and shapes are drawn with the open source Leaflet library on free OpenStreetMap tiles. Loading the library does not count toward your quota.

Before
<script async defer
  src="https://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_KEY&libraries=places&callback=initMap">
</script>
After
<script async defer
  src="https://gapi.mygeocode.com/maps/api/js?key=YOUR_MYGEOCODE_KEY&libraries=places&callback=initMap">
</script>
Then use it as before
// Nothing below this line changes.
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 51.5074, lng: -0.1278 },
    zoom: 12
  });

  const geocoder = new google.maps.Geocoder();
  geocoder.geocode({ address: "221B Baker Street, London" }, (results, status) => {
    if (status === "OK") {
      map.setCenter(results[0].geometry.location);
      new google.maps.Marker({ map, position: results[0].geometry.location });
    }
  });

  const input = document.getElementById("search");
  const autocomplete = new google.maps.places.Autocomplete(input, { fields: ["geometry", "formatted_address"] });
  autocomplete.addListener("place_changed", () => {
    const place = autocomplete.getPlace();
    if (place.geometry) map.panTo(place.geometry.location);
  });
}

Included

  • google.maps.Map on OpenStreetMap tiles (one road map; the satellite and terrain map types show it too)
  • Marker, InfoWindow, Polyline, Polygon, Circle, Rectangle, LatLng, LatLngBounds, event
  • Geocoder (forward and reverse)
  • places.Autocomplete widget and places.AutocompleteService
  • ElevationService
  • Zoom control, gestures and map events (click, idle, bounds_changed, zoom_changed and more)
  • google.maps.importLibrary and marker.AdvancedMarkerElement

Not included

  • Street View
  • Directions, Distance Matrix and Routes
  • Places Details, Photos and Nearby Search
  • Drawing, Visualization and Geometry libraries
  • 3D and WebGL overlay views
  • Satellite and terrain imagery, and styled map types

What counts as a request. Loading the library is free. Each Geocoder call and each Autocomplete lookup counts as one request, and each point sent to the ElevationService counts as one. The Autocomplete widget looks up after a short pause in typing, and choosing a prediction makes one Geocoder call.

Bing Maps V8 Web Control

The V8 control is retired along with the rest of Bing Maps for Enterprise. Load the control from bing.mygeocode.com and the Microsoft.Maps namespace keeps working, with our geocoding and autosuggest behind it and the map drawn on free OpenStreetMap tiles.

Before
<script async defer
  src="https://www.bing.com/api/maps/mapcontrol?key=YOUR_BING_KEY&callback=loadMap">
</script>
After
<script async defer
  src="https://bing.mygeocode.com/api/maps/mapcontrol?key=YOUR_MYGEOCODE_KEY&callback=loadMap">
</script>
Then use it as before
function loadMap() {
  const map = new Microsoft.Maps.Map("#map", { center: new Microsoft.Maps.Location(47.6396, -122.13), zoom: 12 });

  Microsoft.Maps.loadModule("Microsoft.Maps.Search", () => {
    const search = new Microsoft.Maps.Search.SearchManager(map);
    search.geocode({
      where: "1 Microsoft Way, Redmond, WA",
      callback: (result) => {
        const loc = result.results[0].location;
        map.setView({ center: loc, zoom: 15 });
        map.entities.push(new Microsoft.Maps.Pushpin(loc));
      }
    });
  });
}

Included

  • Microsoft.Maps.Map, Location, LocationRect, Pushpin, Infobox, Polyline, Polygon, Layer
  • Search module: SearchManager.geocode and reverseGeocode
  • Autosuggest module: AutosuggestManager and the input attachment
  • Road and grayscale map types on OpenStreetMap tiles (aerial shows the road map)
  • Events, navigation bar and map options

Not included

  • Directions module
  • Traffic, Spatial Data Services and Spatial Math advanced functions
  • Aerial, Bird's eye and Streetside imagery
  • Well Known Text, GeoJSON and GeoXml modules (use the GeoJSON module from Leaflet or MapLibre instead)

What counts as a request. Loading the control is free. Each geocode, reverseGeocode and autosuggest lookup counts as one request; choosing a suggestion makes one geocode call.

Mapbox GL JS and mapbox-gl-geocoder

Keep your map code. Render with MapLibre GL JS, the open source fork of Mapbox GL JS, and any free style, for example OpenFreeMap's; point mapbox-gl-geocoder at our host with its origin option, so the geocoder control needs no other change. We do not serve map styles or tiles.

Before
const map = new mapboxgl.Map({
  container: "map",
  style: "mapbox://styles/mapbox/streets-v12",
  accessToken: "YOUR_MAPBOX_TOKEN"
});
map.addControl(new MapboxGeocoder({
  accessToken: "YOUR_MAPBOX_TOKEN",
  mapboxgl: mapboxgl
}));
After
const map = new maplibregl.Map({
  container: "map",
  style: "https://tiles.openfreemap.org/styles/liberty"
});
map.addControl(new MapboxGeocoder({
  accessToken: "YOUR_MYGEOCODE_KEY",
  origin: "https://mapbox.mygeocode.com",
  mapboxgl: maplibregl
}));
Then use it as before
// Direct calls keep the same shape too
const res = await fetch(
  "https://mapbox.mygeocode.com/geocoding/v5/mapbox.places/Oxford%20Street%20London.json?access_token=YOUR_MYGEOCODE_KEY"
);
const { features } = await res.json();
map.flyTo({ center: features[0].center, zoom: 15 });

Included

  • mapbox-gl-geocoder with the origin option, including proximity, bbox and countries
  • Direct calls to the Geocoding API v5 with the same response shape

Not included

  • Mapbox GL JS v2 and later (its licence requires Mapbox tokens; use MapLibre)
  • Directions, Isochrone, Matrix and Optimization APIs
  • Map styles, vector and raster tiles and static images: use a free style such as OpenFreeMap's, or keep your current map provider for the map

What counts as a request. Each geocoder request counts as one request; the autocomplete keystrokes are debounced by the control as usual.

Leaflet geocoder plugins

Leaflet talks to geocoders through plugins, and the popular ones accept a service URL. Point Leaflet Control Geocoder or leaflet-geosearch at osm.mygeocode.com and keep your base map: OpenStreetMap's tiles, or any tile server you use.

Before
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
  attribution: "&copy; OpenStreetMap contributors"
}).addTo(map);

L.Control.geocoder({
  geocoder: L.Control.Geocoder.nominatim()
}).addTo(map);
After
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
  attribution: "&copy; OpenStreetMap contributors"
}).addTo(map);

L.Control.geocoder({
  geocoder: L.Control.Geocoder.nominatim({
    serviceUrl: "https://osm.mygeocode.com/",
    geocodingQueryParams: { key: "YOUR_MYGEOCODE_KEY" }
  })
}).addTo(map);
Then use it as before
// leaflet-geosearch works the same way
import { OpenStreetMapProvider, GeoSearchControl } from "leaflet-geosearch";

const provider = new OpenStreetMapProvider({
  searchUrl: "https://osm.mygeocode.com/search",
  reverseUrl: "https://osm.mygeocode.com/reverse",
  params: { key: "YOUR_MYGEOCODE_KEY", addressdetails: 1 }
});
map.addControl(new GeoSearchControl({ provider, style: "bar" }));

Included

  • Leaflet Control Geocoder: nominatim, google, bing, mapbox, here, opencage, latLng and mapquest geocoders, each pointed at the matching mygeocode.com host
  • leaflet-geosearch: OpenStreetMapProvider, GoogleProvider, BingProvider, HereProvider, LocationIQProvider, OpenCageProvider, GeoapifyProvider
  • Any other plugin that lets you set the Nominatim URL

Not included

  • Routing plugins (Leaflet Routing Machine and similar)
  • Map tiles: keep OpenStreetMap's or the tile server you already use

What counts as a request. Each geocode and each reverse geocode counts as one request.

HERE Maps API for JavaScript

Load the mapsjs bundles from here.mygeocode.com and create the platform as usual. H.Map, H.service.Platform and the search service keep their signatures, with geocoding from us and the map drawn on free OpenStreetMap tiles.

Before
<script src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>
After
<script src="https://here.mygeocode.com/v3/3.1/mapsjs-core.js"></script>
<script src="https://here.mygeocode.com/v3/3.1/mapsjs-service.js"></script>
<script src="https://here.mygeocode.com/v3/3.1/mapsjs-ui.js"></script>
<script src="https://here.mygeocode.com/v3/3.1/mapsjs-mapevents.js"></script>
Then use it as before
const platform = new H.service.Platform({ apikey: "YOUR_MYGEOCODE_KEY" });
const layers = platform.createDefaultLayers();
const map = new H.Map(document.getElementById("map"), layers.vector.normal.map, {
  center: { lat: 52.5304, lng: 13.3853 }, zoom: 13
});

platform.getSearchService().geocode(
  { q: "Invalidenstraße 116, Berlin" },
  (result) => {
    const { position } = result.items[0];
    map.setCenter(position);
    map.addObject(new H.map.Marker(position));
  },
  (err) => console.error(err)
);

Included

  • H.Map, H.map.Marker, H.map.Polyline, H.map.Polygon, H.map.Group
  • H.service.Platform with createDefaultLayers (every layer shows the OpenStreetMap road map)
  • SearchService: geocode, reverseGeocode, autosuggest and autocomplete
  • H.ui.UI default controls, H.ui.InfoBubble and H.mapevents.Behavior
  • H.geo.Point, H.geo.Rect and helpers

Not included

  • Routing, Isoline and Public Transit services
  • Traffic and incident layers
  • Places Discover and Browse
  • Satellite and terrain imagery, and custom map styles from HERE Style Editor

What counts as a request. Loading the library is free. Each geocode, reverseGeocode and autosuggest call counts as one request.

MapQuest.js

MapQuest.js wraps Leaflet and adds L.mapquest.geocoding(). Load the bundle from mapquest.mygeocode.com and set your key as before.

Before
<script src="https://api.mqcdn.com/sdk/mapquest-js/v1.3.2/mapquest.js"></script>
<link type="text/css" rel="stylesheet" href="https://api.mqcdn.com/sdk/mapquest-js/v1.3.2/mapquest.css"/>
After
<script src="https://mapquest.mygeocode.com/sdk/mapquest-js/v1.3.2/mapquest.js"></script>
<link type="text/css" rel="stylesheet" href="https://mapquest.mygeocode.com/sdk/mapquest-js/v1.3.2/mapquest.css"/>
Then use it as before
L.mapquest.key = "YOUR_MYGEOCODE_KEY";

const map = L.mapquest.map("map", {
  center: [41.8789, -87.6359],
  layers: L.mapquest.tileLayer("map"),
  zoom: 12
});

L.mapquest.geocoding().geocode("233 S Wacker Dr, Chicago, IL", (err, response) => {
  const loc = response.results[0].locations[0].latLng;
  map.setView(loc, 15);
  L.marker(loc, { icon: L.mapquest.icons.marker() }).addTo(map);
});

Included

  • L.mapquest.map and tileLayer on OpenStreetMap tiles: map, light and dark (hybrid and satellite show the map)
  • L.mapquest.geocoding with geocode, batch geocode and reverse, and L.mapquest.geocodingControl
  • Icons, control positions and the standard Leaflet API

Not included

  • Directions and route layers
  • Traffic layer
  • Static Map API
  • L.mapquest.searchAhead (autocomplete)
  • Satellite imagery

What counts as a request. Loading the library is free. Each geocode and reverse request counts as one request; a batch geocode counts one per location.

Maps and tiles

My Geocode does not serve map tiles. The Google, Bing, HERE and MapQuest.js drop-ins draw their maps with the open source Leaflet library, which they include, on OpenStreetMap's standard tile server, loaded straight from your visitor's browser. Those tiles are free for reasonable use under the OpenStreetMap tile usage policy: keep the attribution the libraries add, and for a busy site use a tile provider of your own.

To draw the maps with another tile server, set MYGEOCODE_TILES before the library loads:

Another tile server
<script>
  window.MYGEOCODE_TILES = {
    url: "https://tiles.example.com/{z}/{x}/{y}.png",
    attribution: "&copy; OpenStreetMap contributors",
    maxZoom: 19
  };
</script>
<script async defer
  src="https://gapi.mygeocode.com/maps/api/js?key=YOUR_MYGEOCODE_KEY&libraries=places&callback=initMap">
</script>

MapLibre and Mapbox GL take a style URL instead: OpenFreeMap's styles, such as https://tiles.openfreemap.org/styles/liberty, are free and need no key.

Keys in the browser

Use a browser key in client-side code, never a server key. A key in page source is a key anyone can read, and a server key works from only two or three IP addresses at a time, so it stops working after the second or third visitor anyway.

Create a browser key for your website in the dashboard and put it where YOUR_MYGEOCODE_KEY is above. It works only from scripts on that one website (with or without www.), has no IP limit, and can have a daily spending limit so a copied key cannot run up your credit. One website per key: create another browser key for each further website. See keys and browsers. The library loaders need no key, and the map itself comes from OpenStreetMap, so it always shows.

You can also send the geocoding, autocomplete and elevation calls through your own server. The loaders accept a proxy parameter (gapi.mygeocode.com/maps/api/js?proxy=https://yoursite.com/geo) and send those calls there, on the same path they would use on our host. Your server adds a server key and passes the request on to us. In that case, leave the YOUR_MYGEOCODE_KEY placeholders above empty.

  • Your proxy can add caching and its own limits.
  • Requests then arrive from your server's address, so one server key covers any number of visitors.