Dynamic Google Maps Integration in Umbraco — Code-First Guide

This guide shows how to integrate a dynamic Google Map on your Umbraco page using the Our.Umbraco.GMaps package, with markers pulled straight from your content pages.

Feature

  • Fetches coordinates from ProjectDetailPage/Page content nodes and Shows custom info windows with image, title, and full address (and much more) for each marker dynamically

Benefits of This Implementation

  • Improved UX: Visitors can visually locate project offices or branches directly on the map.

  • Performance Optimized: Markers are rendered once per location and bounds automatically adjusted

  • Fully dynamic 😉

Setup Instructions

Install package: https://marketplace.umbraco.com/package/our.umbraco.gmaps
and configure API key.

GMaps Configuration Screenshot

1. Content Structure in Umbraco

Make sure your ProjectDetailPage nodes have the following:

  • A location picker: Our.Umbraco.GMaps property editor with a selected location.

If a marker doesn't appear or update, check the browser console for any issues.

Example error: Console error when marker doesn't update

✅ Make sure the following APIs are enabled in your Google Cloud Console:

  • Maps JavaScript API
  • Geocoding API

Enable them here: Google Cloud API Library

3. Get Projects with Coordinates

Query and filter visible ProjectDetailPage content:

var allProjects = Umbraco.ContentAtRoot()
    .DescendantsOrSelf<ProjectDetailPage>
    ()
    .Where(x => x.IsVisible())
    .ToList();

4. HTML and Google Map Integration

Include a section for the map:

<div class="google-map-section">
    <div id="googleMap" style="width: 100%; height: 400px;"></div>
</div>

5. JavaScript and GMaps API Integration

Render project data dynamically in a <script> block:

  window.initMap = function () {
      const map = new google.maps.Map(document.getElementById("googleMap"), {
  zoom: 7,
  });

  const bounds = new google.maps.LatLngBounds();

  const buildingIcon = {
  url: "/favicon.ico",
  scaledSize: new google.maps.Size(40, 40)
  };

  const locations = [
  @{
      var culture = System.Globalization.CultureInfo.InvariantCulture;
      foreach (var project in allProjects)
      {
          var coords = project.Location?.Address?.Coordinates;
          var fullAddress = project.Location?.Address?.FullAddress;
          if (coords?.Latitude != null && coords?.Longitude != null)
          {
              var lat = coords.Latitude.ToString(culture);
              var lng = coords.Longitude.ToString(culture);
              var title = project.Title ?? project.Name;

              var address = fullAddress;
              var imageUrl = project.Image?.Url();

              <text>    {
                                      lat: @lat,
                                      lng: @lng,
                                      title: "@title",
                                      content: `<div class="info-window">
                      @if (!string.IsNullOrEmpty(imageUrl))
                      {
                          <text><img src="@imageUrl" alt="@title" style="width: 100px; height: auto;" /></text>
                      }
                                                  <h3>@title</h3>
                                                              <p>@address</p>
                    
                                                </div>`
                                  },</text>
          }
      }
  }
      ];

      if (locations.length > 0) {
          locations.forEach(function (location) {
              const position = { lat: location.lat, lng: location.lng };
              const marker = new google.maps.Marker({
                  position,
                  map,
                  title: location.title,
                  icon: buildingIcon
              });

              bounds.extend(position);

              const infoWindow = new google.maps.InfoWindow({
                  content: location.content
              });

              marker.addListener('click', function () {
                  infoWindow.open(map, marker);
              });
          });

          map.fitBounds(bounds);
          google.maps.event.addListenerOnce(map, 'bounds_changed', function () {
              if (map.getZoom() > 10) map.setZoom(10);
          });
      } else {
          new google.maps.Marker({
              position: mapCenter,
              map: map,
              title: "Fallback Location"
          });
      }
  };

6. Include Google Maps API

Add this script tag to load the API (replace the API key with your own):

<script async defer
        src="https://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_MAPS_API_KEY&callback=initMap">
</script>

Live Preview — It Just Works 👇