Google Maps JavaScript API Tips

On May 2, 2018 Google announced changes to the Google Maps platform. Beginning June 11, you will need a valid API key and a Google Cloud Platform billing account to access core Google Maps products.

To start using Google Maps JavaScript API please follow the instructions in the official documentation.

According to the best practices to secure an API key it is strongly recommended to enable application and API restrictions.

Google Maps API error: RefererNotAllowedMapError

Problem

I was getting the following message in the console.

Google Maps API error: RefererNotAllowedMapError https://developers.google.com/maps/documentation/javascript/error-messages#referer-not-allowed-map-error Your site URL to be authorized: http://www.website.com/page-that-has-google-map

Cause

According to the link in the error message:

The current URL loading the Maps JavaScript API has not been added to the list of allowed referrers. Please check the referrer settings of your API key on the Google Cloud Platform Console.

The most obvious cause for this message is that the page where Google Maps API is used (for example, http://www.website.com/page-that-has-google-map) is not listed in the list of allowed referrers.

Another undocumented cause of this error is that used API is not listed in the list of allowed API. In my example I needed to use Places Autocomplete widget and enabled Places API only. Thanks to this answer on StackOverflow I discovered that only Maps JavaScript API needs to be selected for Places Autocomplete widget to work.

In case with Places Autocomplete widget, what adds to the confusion is that on API Libraries page for your project, both Maps JavaScript API and Places API need to be enabled. But when restricting use of API key, only Maps JavaScript API needs to be selected.

Solution

Loading the Maps JavaScript API

Maps JavaScript API can be loaded synchronously and asynchronously with latter being preferred, see official documentation. Asynchronous loading will allow your page to load faster but you need to be able to specify callback method in URL.

Asynchronous loading


<body>
   <div id="map"></div>
   <script>
      var map;
      function initMap() {
         map = new google.maps.Map(document.getElementById('map'), {
            center: {lat: -34.397, lng: 150.644},
         zoom: 8
         });
      }
   </script>
   <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script>
</body>

Synchronous loading


<body>
   <div id="map"></div>
   <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
   <script>
      var map;
      function initMap() {
         map = new google.maps.Map(document.getElementById('map'), {
            center: {lat: -34.397, lng: 150.644},
         zoom: 8
         });
      }

      google.maps.event.addDomListener(window, 'load', initMap);
   </script>
</body>

In my project I needed to initialize Places Autocomplete widget when DOM content is loaded using jQuery ready() method. I decided to use synchronous loading method, but in this case Places Autocomplete widget was not initializing every time, only on full page reload.

Problem


<body>
   <div id="map"></div>
   <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
   <script>
      $(document).ready(function(){
         var map;
         function initMap() {
            map = new google.maps.Map(document.getElementById('map'), {
               center: {lat: -34.397, lng: 150.644},
               zoom: 8
            });
         }

         google.maps.event.addDomListener(window, 'load', initMap);
      });
   </script>
</body>

It turns out, load event on subsequent reloads when all content was cached by the browser was occurring before callback specified in jQuery ready() method.

According to the note in jQuery ready() method documentation:

Note that although the DOM always becomes ready before the page is fully loaded, it is usually not safe to attach a load event listener in code executed during a .ready() handler.

I am currently using the following workaround.

Solution


<body>
   <div id="map"></div>
   <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
   <script>
      $(document).ready(function(){
         var map;
         function initMap() {
            map = new google.maps.Map(document.getElementById('map'), {
               center: {lat: -34.397, lng: 150.644},
               zoom: 8
            });
         }

         // If document is not fully loaded
         if(document.readyState !== 'complete'){
            // Handle document load event
            window.addEventListener('load', function(){ initMap(); });

         // Otherwise, if document is fully loaded
         } else {
            initMap();
         }
      });
   </script>
</body>

You May Also Like

Leave a Reply

(optional)

This site uses Akismet to reduce spam. Learn how your comment data is processed.