MolinoPro

maps-geocoding-appscript-reference

Master Codebase Guidebook
Markdown + HTML Dev-Docs Renderer - Frontend Client Module

Default Index
Open README.md
Root: README.mdintegrations
Milestones
H1Maps Geocoding AppScript Reference

Status: reference manual for future post-launch Next.js re-versioning.

This preserves the current Google Apps Script pattern for address geocoding and reverse geocoding. It is not wired into the Next.js app yet. Use it later as source material when adding a guarded in-app Maps/geocoding layer for trip planning, provider cleanup, market research, map rendering, or operational address normalization.

H2Why Keep This
  • It already demonstrates address -> latitude/longitude using Maps.newGeocoder().
  • It already demonstrates latitude/longitude -> formatted address.
  • It supports country/region bias through GEOCODING_REGION document properties.
  • It is sheet-friendly for manual operational cleanup.
  • It can be remodelled later as a small, user-triggered Next.js endpoint.
H2Future In-App Remodel Target

Potential files:

lib/maps/geocoding-client.ts
app/api/maps/geocode/route.ts
app/api/maps/reverse-geocode/route.ts

Potential behavior:

  • One address per explicit user action by default.
  • Small batch mode only with confirmation.
  • Cache by normalized address + region.
  • Store results in existing data Json? first, or add a dedicated cache table later.
  • Surface quota/cost warnings before broad operations.
  • Keep region bias available for Spain, Morocco, Portugal, and future featured cities.
H2Reference AppScript
// Geocode Addresses
// Copyright (c) 2016 - 2017 Max Vilimpoc
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Bias the geocoding results in favor of these geographic regions.
// The regions are specified as ccTLD codes.
// The original source included a commented REGIONS map for country -> ccTLD.

function getGeocodingRegion() {
  return PropertiesService.getDocumentProperties().getProperty('GEOCODING_REGION') || 'us';
}

/*
function setGeocodingRegion(region) {
  PropertiesService.getDocumentProperties().setProperty('GEOCODING_REGION', region);
  updateMenu();
}

function promptForGeocodingRegion() {
  var ui = SpreadsheetApp.getUi();
  var result = ui.prompt(
    'Set the Geocoding Country Code (currently: ' + getGeocodingRegion() + ')',
    'Enter the 2-letter country code (ccTLD) that you would like ' +
    'the Google geocoder to search first for results. ' +
    'For example: Use \'uk\' for the United Kingdom, \'us\' for the United States, etc. ' +
    'For more country codes, see: https://en.wikipedia.org/wiki/Country_code_top-level_domain',
    ui.ButtonSet.OK_CANCEL
  );

  if (result.getSelectedButton() == ui.Button.OK) {
    setGeocodingRegion(result.getResponseText());
  }
}
*/

// Forward Geocoding -- convert address to GPS position.
function addressToPosition() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var cells = sheet.getActiveRange();
  var popup = SpreadsheetApp.getUi();

  var columnCount = cells.getNumColumns();
  var rowCount = cells.getNumRows();

  if (columnCount < 3) {
    popup.alert("Select at least 3 columns: Address in the leftmost column(s); the geocoded Latitude, Longitude will go into the last 2 columns.");
    return;
  }

  var latColumn = columnCount - 1;
  var lngColumn = columnCount;
  var geocoder = Maps.newGeocoder().setRegion(getGeocodingRegion());
  var addresses = sheet.getRange(cells.getRow(), cells.getColumn(), rowCount, columnCount - 2).getValues();

  for (var addressRow = 1; addressRow <= rowCount; ++addressRow) {
    var address = addresses[addressRow - 1].join(' ');
    address = address.replace(/'/g, "%27");

    Logger.log(address);

    var location = geocoder.geocode(address);

    if (location.status == 'OK') {
      var lat = location["results"][0]["geometry"]["location"]["lat"];
      var lng = location["results"][0]["geometry"]["location"]["lng"];

      cells.getCell(addressRow, latColumn).setValue(lat);
      cells.getCell(addressRow, lngColumn).setValue(lng);
    } else {
      Logger.log(location.status);
    }
  }
}

// Reverse Geocode -- GPS position to nearest address.
function positionToAddress() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var cells = sheet.getActiveRange();
  var popup = SpreadsheetApp.getUi();

  var columnCount = cells.getNumColumns();

  if (columnCount < 3) {
    popup.alert("Select at least 3 columns: Latitude, Longitude in the first 2 columns; the reverse-geocoded Address will go into the last column.");
    return;
  }

  var latColumn = 1;
  var lngColumn = 2;
  var addressColumn = columnCount;
  var geocoder = Maps.newGeocoder().setRegion(getGeocodingRegion());

  for (var addressRow = 1; addressRow <= cells.getNumRows(); ++addressRow) {
    var lat = cells.getCell(addressRow, latColumn).getValue();
    var lng = cells.getCell(addressRow, lngColumn).getValue();
    var location = geocoder.reverseGeocode(lat, lng);

    Logger.log(location.status);

    if (location.status == 'OK') {
      var address = location["results"][0]["formatted_address"];
      cells.getCell(addressRow, addressColumn).setValue(address);
    }
  }
}
H2Next.js Guardrails
  • Do not add broad auto-geocoding without a user action.
  • Do not geocode entire provider lists by default.
  • Normalize and cache address + region before making any external call.
  • Prefer small operations attached to a city, provider, hotel, experience, or trip block.
  • Keep the AppScript route available as an external runtime option if direct Maps API integration is not yet active.