リードの緯度経度取得と地図表示を切り分けて実装する
住所から緯度経度を取るだけなら、Salesforce標準のデータインテグレーションルールで足ります。カスタム画面に地図を出す場合に必要なGoogle側の実装と、キーを漏らさない設定を説明します。
標準のジオコード機能で足りないか確認する
住所から緯度・経度を取りたいだけなら、Google APIキーを用意しなくても済む場合があります。Salesforceには、住所を自動でジオコードするデータインテグレーションルールが標準で用意されています。Lead・Account・Contactの住所項目を対象に、Salesforce自身のジオコーディングサービスがLatitude・Longitude・Geocode Accuracyの各項目を更新します。呼び出し元の組織がGoogleのAPIキーを持っている必要はありません。
データインテグレーションルールを開く
設定のクイック検索で「データインテグレーションルール」を開きます。
対象のルールを選ぶ
リードの住所なら「Geocodes for Lead Address」を選びます。取引先の請求先・納入先住所、取引先責任者の住所にも、それぞれ専用のルールがあります。
ルールを有効化する
「有効化」ボタンを押します。値は上書きモードで更新され、以降は住所の変更を拾って自動でジオコードします。
⚠️ 更新は非同期です。有効化した直後や、住所を入力した直後には、まだLatitude・Longitudeが空のことがあります。少し時間を置いてから確認します。この機能はProfessional・Enterprise・Performance・Unlimited・Developerの各エディションで使えます。緯度・経度の値がレコードに入っていればよいだけなら、ここまでで足ります。
この記事で扱うのは地図に描画する話
標準の機能が用意するのは、レコードのLatitude・Longitude項目です。画面に地図を出し、そこにピンを立てて表示するところまでは標準機能の範囲外です。Visualforceやカスタムのページで、取得済みの緯度・経度をGoogleマップ上のマーカーとして描画したい場合は、ここから先の実装が要ります。
地図表示用のAPIキーを取得する
地図の描画にはMaps JavaScript APIを使います。取得先は、Google Cloud Consoleです。
プロジェクトを作る
Google Cloud Consoleでプロジェクトを新規作成します。
Maps JavaScript APIを有効化する
APIとサービスのライブラリから「Maps JavaScript API」を有効化します。
APIキーを作成する
認証情報の作成からAPIキーを発行します。例:
AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
利用にはGoogle Cloudの請求先アカウントの登録が要ります。Maps JavaScript APIは従量課金で、SKUごとの月間の無料枠を超えた分に料金がかかります。想定より使う可能性があるなら、Cloud Console側で現在の料金と上限をご自身で確認してください。
APIキーには制限をかける
⛔ キーを制限なしで使わないでください。このキーはVisualforceページの <script> タグに埋め込まれるため、ページを開いた人には見えます。隠すのではなく、使える範囲を絞ります。
- アプリケーションの制限:ウェブサイトのリファラー制限を使い、実際にページを配信するSalesforceのドメインだけを許可します
- APIの制限:このキーで呼べるAPIを、Maps JavaScript APIだけに絞ります
制限のないキーが第三者に使われた場合、その分の課金はキーの持ち主の責任になります。
標準機能でカバーできない住所をApexからジオコードする
カスタムオブジェクトの住所など、標準のデータインテグレーションルールが対象にしていない住所を、その場でジオコードしたい場合は、ApexからGoogleのGeocoding APIをHTTP callout で直接呼びます。
Geocoding APIのキーは、クエリ文字列の key パラメータで渡す仕様です。指定ログイン情報のマージフィールドはHTTPヘッダーとリクエスト本文でしか使えず、URLのクエリ文字列には使えません。そのため、キーをApexのコードに直書きせずに扱うには、次のようにします。
指定ログイン情報を作る
URLに
https://maps.googleapis.com/maps/api/geocode/を指定します。Googleのキーはヘッダーで渡す仕組みではないため、認証プロトコルは「認証なし」にします。キーの値をカスタムメタデータ型に持たせる
キーの値そのものはApexのソースに書かず、カスタムメタデータ型のレコードとして保存します。デプロイに含めず、管理者が本番で直接値を入れられます。
Apexでクエリ文字列に付与する
実行時にカスタムメタデータ型からキーを読み、コールアウトのURLへその場で付け足します。
public class AddressGeocoder { public static void geocode(String recordId, String address) { String key = Google_Api_Setting__mdt.getInstance('Default').Geocoding_Api_Key__c; String endpoint = 'callout:GoogleGeocoding/json' + '?address=' + EncodingUtil.urlEncode(address, 'UTF-8') + '&key=' + key; HttpRequest req = new HttpRequest(); req.setEndpoint(endpoint); req.setMethod('GET'); Http http = new Http(); HttpResponse res = http.send(req); System.debug(res.getBody()); } }
カスタムメタデータ型からキーを読み、住所をジオコードします。
Google Drive等のOAuthを使うGoogleサービスでは、Salesforceの外部ログイン情報に「Google認証プロバイダ」を設定する方法が使えます。ただしGeocoding APIはOAuthではなく、いまもこのAPIキー方式です。この記事の範囲では、外部ログイン情報のGoogle認証プロバイダは使いません。
⚠️ Apexのコールアウトには、1トランザクションあたり最大100回、コールアウト全体の累積タイムアウトは120秒という上限があります。レコードを1件ずつトリガーでジオコードする実装は、件数が増えた日に上限へ当たります。まとめてジオコードするなら、キューアブルやバッチApexに分けて呼び出します。
このサーバー側のキーにも、Geocoding APIだけを呼べるAPI制限をかけます。IPアドレス制限も使えますが、Salesforceの送信元IPは組織ごとに変わるため、記事に固定の数字は書きません。設定するなら、そのときのご自身の組織の値を確認してから使ってください。
Visualforceページとコントローラ
public with sharing class LeadMapController { private Map<Id, Lead> idLeadMap; public Id clickedLeadId { get; set; } public Lead clickedLead { get; set; } public LeadMapController() { this.idLeadMap = new Map<Id, Lead>( [SELECT Id, LastName, Latitude, Longitude FROM Lead WHERE Country = 'JP' AND Latitude != null] ); } public String getJsonLeadList() { return JSON.serialize(this.idLeadMap.values()); } public String getMapsApiKey() { return Google_Api_Setting__mdt.getInstance('Default').Maps_Js_Api_Key__c; } public void selectLead() { if (this.idLeadMap.containsKey(this.clickedLeadId)) { this.clickedLead = this.idLeadMap.get(this.clickedLeadId); } } }
カスタムメタデータ型から地図表示用のキーを取得し、リードの一覧を返すコントローラです。
WHERE Country = 'JP' AND Latitude != null として、まだジオコードされていないリードを対象から外しています。キーはコントローラのゲッター経由で取得し、Visualforceのソースには書きません。
<apex:page controller="LeadMapController"> <script src="https://maps.googleapis.com/maps/api/js?key={!mapsApiKey}&callback=initMap" async defer> </script> <script> var currentInfoWindow = null; function initMap() { var map = new google.maps.Map(document.getElementById('leadMap'), { zoom: 5, mapTypeId: google.maps.MapTypeId.ROADMAP }); var leadList = JSON.parse('{!JSENCODE(jsonLeadList)}'); leadList.forEach(function (lead) { addMarker(map, lead); }); } function addMarker(map, lead) { var position = new google.maps.LatLng(lead.Latitude, lead.Longitude); var marker = new google.maps.Marker({ position: position, map: map, title: lead.LastName }); var infoWindow = new google.maps.InfoWindow({ content: lead.LastName }); marker.addListener('click', function () { if (currentInfoWindow) { currentInfoWindow.close(); } infoWindow.open(map, marker); currentInfoWindow = infoWindow; }); } </script> <div id="leadMap" style="height:300px;"></div> </apex:page>
GoogleマップにLeadをピンで表示するVisualforceページです。
動作確認
テスト用のリードを作る
日本国内の住所を入れたリードを2件作成します。
ジオコードされるのを待つ
データインテグレーションルールの更新は非同期です。少し時間を置いてから、Latitude・Longitudeが入っていることをレポートかAPIで確認します。
ページを開く
作成したVisualforceページを開き、2件のピンが地図上に表示されることを確認します。
ピンをクリックする
ピンをクリックし、リード名の入った吹き出しが出ることを確認します。
ここで間違えやすい
| 間違い | 何が起きるか |
|---|---|
| データインテグレーションルールを有効化し忘れる | Latitude・Longitudeが空のままで、ピンが出ません |
| 地図表示用のキーにリファラー制限をかけない | 第三者にキーを使われ、想定外の課金につながります |
| キーをMaps JavaScript APIだけに制限しない | 他のGoogle APIにも同じキーが使われてしまいます |
| サーバー側のGeocoding APIキーをApexのソースに直書きする | リポジトリに残り、漏れても気づけません |
| 大量のレコードをトリガーで1件ずつジオコードする | 1トランザクション100回のコールアウト上限に当たります |
確認した環境
- 2026年9月/Salesforce Summer '26(APIバージョン67.0)時点の公式ヘルプと、Google Maps Platformの公式ドキュメントで、データインテグレーションルール・Apexのコールアウト上限・Geocoding APIの課金とキー制限を確認しています
- コードはAPIバージョン67.0で書いています
まとめ
- 住所から緯度・経度を取るだけなら、標準のデータインテグレーションルールで足ります。Google APIキーは要りません
- 地図にピンを表示するには、Maps JavaScript APIと専用のキーが別途必要です
- 表示用のキーはリファラー制限とAPI制限の両方をかけます。制限のないキーの課金は自己責任です
- 標準機能の対象外の住所をApexからジオコードするなら、キーはカスタムメタデータ型に持たせ、ソースには書きません
- Apexのコールアウトは1トランザクション100回・累積120秒が上限です。大量件数はキューアブルやバッチApexに分けます
参考:当時の画面
記事を最初に書いた当時の画面です。いまの手順と違うところは、各画像の説明に書いています。
Salesforceの導入・運用についてご相談ください
導入前の検討から、お使いの環境の改修・運用、AIとの連携まで承ります。状況を伺ったうえで、進め方をご提案します。