diff --git a/lib/geocoder/lookups/esri.rb b/lib/geocoder/lookups/esri.rb
index c634f1a955fe7e41e2e5d8062f6f638b0e3764d6..16bf95e0ff673316dad28d6a2ae6f04643c8b17d 100644
--- a/lib/geocoder/lookups/esri.rb
+++ b/lib/geocoder/lookups/esri.rb
@@ -10,14 +10,16 @@ module Geocoder::Lookup
     end
 
     def query_url(query)
-      search_keyword = query.reverse_geocode? ? "reverseGeocode" : "find"
-
-      "#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{search_keyword}?" +
-        url_query_string(query)
+      base_query_url(query) + url_query_string(query)
     end
 
     private # ---------------------------------------------------------------
 
+    def base_query_url(query)
+      action = query.reverse_geocode? ? "reverseGeocode" : "find"
+      "#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{action}?"
+    end
+
     def results(query)
       return [] unless doc = fetch_data(query)
 
@@ -32,6 +34,17 @@ module Geocoder::Lookup
       end
     end
 
+    def cache_key(query)
+      base_query_url(query) + hash_to_query(cache_key_params(query))
+    end
+
+    def cache_key_params(query)
+      # omit api_key and token because they may vary among requests
+      query_url_params(query).reject do |key,value|
+        [:api_key, :token].include?(key)
+      end
+    end
+
     def query_url_params(query)
       params = {
         :f => "pjson",
diff --git a/test/unit/lookups/esri_test.rb b/test/unit/lookups/esri_test.rb
index a14ac8a59ea66246ebafbe70135e0f0269c9745c..a2d2e624915e9977134a0d7fc4065cb48f3be39e 100644
--- a/test/unit/lookups/esri_test.rb
+++ b/test/unit/lookups/esri_test.rb
@@ -110,6 +110,17 @@ class EsriTest < GeocoderTestCase
       result.viewport
   end
 
+  def test_cache_key_doesnt_include_api_key_or_token
+    token = Geocoder::EsriToken.new('xxxxx', Time.now + 60)
+    Geocoder.configure(esri: {token: token, api_key: "xxxxx", for_storage: true})
+    query = Geocoder::Query.new("Bluffton, SC")
+    lookup = Geocoder::Lookup.get(:esri)
+    key = lookup.send(:cache_key, query)
+    assert_match /forStorage/, key
+    assert_no_match /token/, key
+    assert_no_match /api_key/, key
+  end
+
   def teardown
     Geocoder.configure(esri: {token: nil, for_storage: nil})
   end