<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gaël</title>
    <description>The latest articles on DEV Community by Gaël (@gaelsimon).</description>
    <link>https://dev.to/gaelsimon</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F325622%2F6bdecf53-b142-4089-bdff-0a11baeb6b0b.jpeg</url>
      <title>DEV Community: Gaël</title>
      <link>https://dev.to/gaelsimon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gaelsimon"/>
    <language>en</language>
    <item>
      <title>Implement and Optimize Autocomplete with Google Places API</title>
      <dc:creator>Gaël</dc:creator>
      <pubDate>Fri, 27 Nov 2020 11:35:26 +0000</pubDate>
      <link>https://dev.to/gaelsimon/implement-and-optimize-autocomplete-with-google-places-api-461h</link>
      <guid>https://dev.to/gaelsimon/implement-and-optimize-autocomplete-with-google-places-api-461h</guid>
      <description>&lt;p&gt;The Google Places API is a service that returns places predictions using HTTP requests. &lt;br&gt;
The service can be used to provide an autocomplete functionality for text-based geographic searches by returning places such as businesses, addresses and points of interest as a user types.&lt;br&gt;
Google provides a Places library through the Maps Javascript API. This blog post focus on the usage of this library.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Implementing Google Places Autocomplete
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Enable the Places API
&lt;/h3&gt;

&lt;p&gt;Before using the Places library in the Maps JavaScript API, you must enable the Places API in the Google Cloud Platform Console.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;a href="https://console.developers.google.com/"&gt;Google Cloud Platform Console&lt;/a&gt; .&lt;/li&gt;
&lt;li&gt;Either create a new or select an existing project.&lt;/li&gt;
&lt;li&gt;At the top of the page, click on the button &lt;strong&gt;ENABLE APIS AND SERVICES&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;Places API&lt;/strong&gt;, then select it from the results list.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;ENABLE&lt;/strong&gt;. When the process finishes, Places API appears in the list of APIs on the Dashboard.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't forget to apply Application restrictions (to limit usage for the dedicated APIs - at least Places API) and API restrictions (to enable the use of this API through specific domain). (&lt;a href="https://blog.woosmap.com/registering-and-restricting-google-maps-and-woosmap-platform-api-keys#how-do-i-restrict-my-google-api-key-to-a-specific-domain"&gt;how to do it&lt;/a&gt;) &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Loading the library
&lt;/h3&gt;

&lt;p&gt;In order to use autocomplete, you must first load the Google Places library using the &lt;code&gt;libraries&lt;/code&gt; parameter in the bootstrap URL for the Google Maps JavaScript API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&amp;amp;libraries=places"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Autocompletion using the Widgets
&lt;/h3&gt;

&lt;p&gt;The Places API offers two types of autocomplete widgets, which you can add via the &lt;code&gt;Autocomplete&lt;/code&gt; and &lt;code&gt;SearchBox&lt;/code&gt; classes respectively. &lt;/p&gt;

&lt;h4&gt;
  
  
  The &lt;code&gt;Autocomplete&lt;/code&gt; Widget
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;autocomplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;places&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Autocomplete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Autocomplete&lt;/code&gt; adds a text input field on your web page. As the user enters text, autocomplete returns place predictions in the form of a dropdown pick list. When the user selects a place from the list, place details is returned in response to a &lt;code&gt;getPlace()&lt;/code&gt; request. Each entry in the pick list corresponds to a single place (as defined by the Places API).&lt;br&gt;
You can restrict the search to a particular country and particular place types, as well as setting the bounds.&lt;/p&gt;

&lt;p&gt;In the below sample, search for &lt;em&gt;"Old Coff"&lt;/em&gt; and select the first item in the pick list (&lt;em&gt;Old Coffee House&lt;/em&gt;).&lt;br&gt;
Results are biased towards with the current map bounds using &lt;code&gt;autocomplete.bindTo('bounds', map)&lt;/code&gt; but to instruct the Place Autocomplete service to return &lt;em&gt;only&lt;/em&gt; results within that region, you should set the &lt;code&gt;strictbounds: true&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://jsfiddle.net/woosmap/zsh0d8vx/embedded/result,js//dark" width="100%" height="600"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  The &lt;code&gt;SearchBox&lt;/code&gt; Widget
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;searchBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;places&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SearchBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;SearchBox&lt;/code&gt; adds a text input field to your web page, in much the same way as &lt;code&gt;Autocomplete&lt;/code&gt;. The main difference lies in the results that appear in the pick list. SearchBox supplies an extended list of predictions, which can include places (as defined by the Places API) plus suggested search terms.&lt;br&gt;
&lt;code&gt;SearchBox&lt;/code&gt; offers fewer options than Autocomplete for restricting the search. You can only bias the search towards a given &lt;code&gt;LatLngBounds&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the below sample, search for &lt;em&gt;"Coffee near Lond"&lt;/em&gt; and select the first suggested search term in the pick list.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://jsfiddle.net/woosmap/qcLkw8j3/embedded/result,js//dark" width="100%" height="600"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Autocompletion using the &lt;code&gt;AutocompleteService&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;places&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AutocompleteService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getQueryPredictions&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hotels near Lond&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;){});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can create an &lt;code&gt;AutocompleteService&lt;/code&gt; object to retrieve predictions programmatically. Call &lt;code&gt;getPlacePredictions()&lt;/code&gt; to retrieve matching places, or call &lt;code&gt;getQueryPredictions()&lt;/code&gt; to retrieve matching places plus suggested search terms. &lt;br&gt;
&lt;code&gt;AutocompleteService&lt;/code&gt; does not add any UI controls. Instead, the above methods return an array of prediction objects. Each prediction object contains the text of the prediction, as well as reference information and details of how the result matches the user input.&lt;br&gt;
This is useful if you want more control over the user interface than is offered by the Autocomplete and SearchBox described above.&lt;/p&gt;

&lt;p&gt;To get the location and more information about any of the places which are returned (when a user select the place in the pick list for example), you need to send a Place Details request with &lt;code&gt;getDatails(request, callback)&lt;/code&gt; specifying the &lt;code&gt;place_id&lt;/code&gt; and wanted &lt;code&gt;fields&lt;/code&gt; to be returned. &lt;/p&gt;

&lt;p&gt;In the below sample, search for &lt;em&gt;"Old Coff"&lt;/em&gt; and select the first item in the pick list (&lt;em&gt;Old Coffee House&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://jsfiddle.net/woosmap/xs8a06nh/embedded/result,js//dark" width="100%" height="600"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimization
&lt;/h2&gt;

&lt;p&gt;Here are different solutions to help you reduce the cost of your Places license.&lt;/p&gt;

&lt;h3&gt;
  
  
  Return data for specific fields in Place Details requests
&lt;/h3&gt;

&lt;p&gt;When the Places Autocomplete service returns results from a search, it places them within a predictions array.&lt;br&gt;
Each prediction result contains the following fields (check &lt;a href="https://developers.google.com/places/web-service/autocomplete#place_autocomplete_results"&gt;here&lt;/a&gt; for more details):&lt;br&gt;
&lt;code&gt;description&lt;/code&gt;, &lt;code&gt;place_id&lt;/code&gt;, &lt;code&gt;terms&lt;/code&gt;, &lt;code&gt;types&lt;/code&gt;, &lt;code&gt;matched_substrings&lt;/code&gt;, &lt;code&gt;structured_formatting&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;By default, when a user selects a place from the pick list, autocomplete returns all of the available data fields for the selected place, and you will be &lt;a href="https://developers.google.com/maps/billing/gmp-billing#places-details"&gt;billed accordingly&lt;/a&gt;. &lt;br&gt;
You can customize Place Detail requests to return data for specific fields used in your application and so decrease the cost of your Places API License. These fields are divided into categories: Basic, Contact, and Atmosphere. &lt;/p&gt;
&lt;h4&gt;
  
  
  Basic
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;Basic&lt;/strong&gt; category includes fields to locate the place such as the address components and geometry location. &lt;a href="https://developers.google.com/maps/documentation/places/web-service/place-data-fields#basic"&gt;see &lt;code&gt;basic&lt;/code&gt; fields&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Contact
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;Contact&lt;/strong&gt; category includes the opening hours and fields to contact the business such as the phone number and website. &lt;a href="https://developers.google.com/maps/documentation/places/web-service/place-data-fields#contact"&gt;see &lt;code&gt;contact&lt;/code&gt; fields&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Atmosphere
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;Atmosphere&lt;/strong&gt; category includes more specific fields (&lt;code&gt;price_level&lt;/code&gt;, &lt;code&gt;rating&lt;/code&gt;, &lt;code&gt;review&lt;/code&gt;,...). &lt;a href="https://developers.google.com/maps/documentation/places/web-service/place-data-fields#atmosphere"&gt;see &lt;code&gt;atmosphere&lt;/code&gt; fields&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  How to specify desired data?
&lt;/h4&gt;

&lt;p&gt;For example, to retrieve only &lt;code&gt;geometry&lt;/code&gt; field in the details response (when user select an item in the pick list), define as below: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Places &lt;strong&gt;Autocomplete widget&lt;/strong&gt;: use &lt;code&gt;autocomplete.setFields(['geometry'])&lt;/code&gt;. check the jsFiddle above to see how.&lt;/li&gt;
&lt;li&gt;Places &lt;strong&gt;SearchBox widget&lt;/strong&gt;: there is no way to constrain SearchBox requests to only return specific fields.&lt;/li&gt;
&lt;li&gt;Places &lt;strong&gt;AutocompleteService&lt;/strong&gt;: you have to use the &lt;code&gt;PlacesService&lt;/code&gt; to call the &lt;code&gt;getDetails(resuest, callback)&lt;/code&gt; and specify the fields in your &lt;code&gt;request&lt;/code&gt; parameter.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;placeId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;place_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;geometry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Per request vs Session Token
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;If your using the Autocomplete Widget you don't need to implement sessions, as the widget handles sessions automatically in the background.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;strong&gt;Per Request&lt;/strong&gt; is the default billing option when you use &lt;code&gt;AutocompleteService&lt;/code&gt;. Charges are applied per keystroke, that could lead to higher billings.&lt;/p&gt;

&lt;p&gt;You should use &lt;strong&gt;Session Tokens&lt;/strong&gt; when implementing &lt;code&gt;AutocompleteService.getPlacePredictions()&lt;/code&gt; to group together autocomplete requests for billing purposes. Session tokens group the query and selection phases of a user autocomplete search into a discrete session for billing purposes. The session begins when the user starts typing a query, and concludes when they select a place. Each session can have multiple queries, followed by one place selection.&lt;/p&gt;

&lt;p&gt;The following example shows a request using the sessiontoken parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create a new session token.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sessionToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;places&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AutocompleteSessionToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Pass the token to the autocomplete service.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;autocompleteService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;places&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AutocompleteService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;autocompleteService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getPlacePredictions&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Coffee near Lond&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sessionToken&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;displaySuggestions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use the Geocoding API
&lt;/h3&gt;

&lt;p&gt;If your application handles user-typed addresses, the addresses are sometimes ambiguous (incomplete, misspelled, or poorly formatted). You can disambiguate addresses using Autocomplete. Then, use the place IDs to get the place locations.&lt;br&gt;
If you have an exact address (or close to it), however, you can reduce costs by using Geocoding instead of Autocomplete. &lt;br&gt;
You could for example use the AutocompleteService to get the exact address name and then execute a geocoding request to get the geometry and others desired fields (instead of &lt;code&gt;AutocompleteService.getDetails()&lt;/code&gt;).&lt;br&gt;
See &lt;a href="https://developers.google.com/maps/documentation/geocoding/best-practices"&gt;Geocoding API best practices&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use debounce and minChar with AutocompleteService
&lt;/h3&gt;

&lt;p&gt;The debounce function limits the rate at which a function can fire.&lt;br&gt;
It takes at least 2 arguments, the input function to call and a time to wait before call it.&lt;br&gt;
As long as this method continues to be invoked, the function passed as parameter will not be triggered. It will be called only after the debounce function stops being called for an elapsed time (in milliseconds).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;immediate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;later&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;immediate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;callNow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;immediate&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;later&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callNow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll pass the debounce function the function to execute and the fire rate limit in milliseconds.&lt;br&gt;
The following example call the &lt;code&gt;AutocompleteService.getPlacePredictions()&lt;/code&gt; on &lt;code&gt;input&lt;/code&gt; event of the dedicated input text only when two key strokes are separated by at least 150ms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;autocomplete_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;autocompleteService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getPlacePredictions&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;displaySuggestions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Autocomplete and SearchBox widgets do not implement a debounce method. Thus each keystroke calls AutocompleteService. &lt;/p&gt;

&lt;p&gt;In addition to this mechanism, you could combine your call with a &lt;code&gt;minChar&lt;/code&gt; parameter to only trigger the Autocomplete when the text input reaches at least X characters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;autocomplete_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;//call here autocompleteService.getPlacePredictions() &lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Autocomplete on Stores
&lt;/h3&gt;

&lt;p&gt;If your main goal to implement Google Places Autocomplete is to help your users find the right store for them, why not combine an autocompletion on your stores information (name and city for example) before possibly falling back to the Google Places Autocomplete.&lt;br&gt;
If you're a Woosmap customer and already have your stores hosted on our own, you could use the &lt;a href="https://developers.woosmap.com/products/search-api/get-started/"&gt;Woosmap Search API&lt;/a&gt; to achieve this.&lt;/p&gt;

&lt;p&gt;To easily implement such a solution, have a look at &lt;a href="https://developers.woosmap.com/products/multisearch-lib/get-started/"&gt;Woosmap MultiSearch&lt;/a&gt;. This small JavaScript library is designed to return location suggestions through calling several autocomplete services. It enables you to combine stores search (through Woosmap Search API) and Google Places APIs (Places Autocomplete and Places Details). Moreover, the library implements natively debounce and minchars mechanisms. &lt;/p&gt;

&lt;p&gt;If your users are more likely to search for postal codes or localities, the MultiSearch can also retrieve suggestions from &lt;a href="https://developers.woosmap.com/products/localities/get-started/"&gt;Woosmap Localities&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  How MultiSearch combines autocomplete services?
&lt;/h4&gt;

&lt;p&gt;Autocomplete services are requested in your desired ordered. &lt;br&gt;
By comparing the user input to the returned results and computing a &lt;strong&gt;string matching score&lt;/strong&gt; between these two values, the library can automatically switch to the next autocomplete service and thereby provide suggestions that better suits the needs. &lt;/p&gt;

&lt;p&gt;For more details, check &lt;a href="https://developers.woosmap.com/products/multisearch-lib/fallback-concept/"&gt;fallback concept doc&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Fallback Example with MultiSearch
&lt;/h4&gt;

&lt;p&gt;The following sample autocomplete for Starbucks coffee shops. If no results are available (insufficient matching score between the field &lt;code&gt;name&lt;/code&gt; of Starbucks coffee shops and the user input), a Google places Autocomplete is performed.&lt;/p&gt;

&lt;p&gt;In the below sample, search for &lt;em&gt;"London"&lt;/em&gt; and select one of the coffee shops suggestion in the pick list. &lt;br&gt;
If you search for &lt;em&gt;"Coleman Coffee"&lt;/em&gt;, the autocomplete fall back on Google Places (there is no Starbucks coffee with this name).&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/multisearch-stores-google-places-jrfg5?view=preview"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To optimize Google Places Autocomplete, we recommend the following guidelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prefer using the &lt;code&gt;AutocompleteService&lt;/code&gt; instead of the Widgets to gain fine-grained control over the available optimizations.&lt;/li&gt;
&lt;li&gt;Use the Per Session billing option.&lt;/li&gt;
&lt;li&gt;Gather only required fields when getting details of a place.&lt;/li&gt;
&lt;li&gt;Implement Debounce and minChars mechanisms.&lt;/li&gt;
&lt;li&gt;Use the Geocoding API to retrieve address information instead of &lt;code&gt;getDetails()&lt;/code&gt; from Autocomplete.&lt;/li&gt;
&lt;li&gt;Alternatively, offer to autocomplete on your stores information if the first use case is to help users find them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://codesandbox.io/embed/multisearch-stores-google-places-jrfg5"&gt;last example&lt;/a&gt; implements &lt;a href="https://developers.woosmap.com/products/multisearch-lib/get-started/"&gt;Woosmap MultiSearch&lt;/a&gt; with Google &lt;code&gt;AutocompleteService&lt;/code&gt;, per Session billing, Debounce, and autocomplete on Stores before fall back to Google. It could be a good entry-point for dealing with Google Places Autocomplete.&lt;/p&gt;

</description>
      <category>googlemaps</category>
      <category>autocomplete</category>
      <category>address</category>
      <category>googleplaces</category>
    </item>
    <item>
      <title>Bulk Geocode addresses using Google Maps and GeoPy</title>
      <dc:creator>Gaël</dc:creator>
      <pubDate>Wed, 29 Jan 2020 16:23:49 +0000</pubDate>
      <link>https://dev.to/gaelsimon/bulk-geocode-addresses-using-google-maps-and-geopy-5bmg</link>
      <guid>https://dev.to/gaelsimon/bulk-geocode-addresses-using-google-maps-and-geopy-5bmg</guid>
      <description>&lt;p&gt;Geocoding is the process of converting addresses (like a street address) into geographic coordinates (like latitude and longitude).&lt;br&gt;
With &lt;a href="https://developers.woosmap.com/"&gt;Woosmap&lt;/a&gt; you can request nearby location or display on a map a lot of geographic elements like stores or any other point of interest. To take advantages of these features, you first have to push geocoded locations to our system.&lt;br&gt;
Most of the time, your dataset has addresses but no location information.&lt;/p&gt;

&lt;p&gt;The following script, hosted on our &lt;a href="https://github.com/woosmap/geopy-googlemaps-batchgeocoder"&gt;Woosmap Github Organization&lt;/a&gt;, is a basic utility for geocoding CSV files that have address data included.&lt;br&gt;
It will parse the file and add coordinate information as well as some metadata on geocoded results like the location type, as discussed below.&lt;br&gt;
It calls &lt;a href="https://developers.google.com/maps/documentation/geocoding/"&gt;Google Maps Geocoding API&lt;/a&gt; through the &lt;a href="https://github.com/geopy/geopy"&gt;GeoPy&lt;/a&gt; python client.&lt;/p&gt;

&lt;p&gt;The source code is open to view and change, and contributions are welcomed.&lt;/p&gt;
&lt;h2&gt;
  
  
  GeoPy
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/geopy/geopy"&gt;GeoPy&lt;/a&gt; is a Python client for several popular geocoding web services. &lt;br&gt;
It makes it easy for Python developers to locate the coordinates of addresses, cities, countries, and landmarks across the globe using third-party geocoders and other data sources.&lt;br&gt;
It includes geocoder classes for the &lt;a href="https://wiki.openstreetmap.org/wiki/Nominatim"&gt;OpenStreetMap Nominatim&lt;/a&gt;, &lt;a href="http://resources.arcgis.com/en/help/arcgis-rest-api/"&gt;ESRI ArcGIS&lt;/a&gt;, &lt;a href="https://developers.google.com/maps/documentation/geocoding/"&gt;Google Geocoding API&lt;/a&gt;, &lt;a href="http://developer.baidu.com/map/webservice-geocoding.htm"&gt;Baidu Maps&lt;/a&gt;, &lt;a href="https://docs.microsoft.com/en-us/bingmaps/rest-services/locations/"&gt;Bing Maps&lt;/a&gt;, &lt;a href="http://api.yandex.com/maps/doc/intro/concepts/intro.xml"&gt;Yandex&lt;/a&gt;, &lt;a href="http://www.geonames.org/"&gt;GeoNames&lt;/a&gt;, &lt;a href="http://developer.mapquest.com/web/products/open/geocoding-service"&gt;OpenMapQuest&lt;/a&gt; and many other geocoding services. The full list is available on &lt;a href="https://geopy.readthedocs.io/en/latest/#geocoders"&gt;the geopy documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Google Maps Geocoding API
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/maps/documentation/geocoding/"&gt;Google Maps Geocoding API&lt;/a&gt; is a service that provides geocoding and reverse geocoding of addresses. &lt;br&gt;
In this python script we used the GeoPy wrapper of this API but a nice alternative could be to implement the &lt;a href="https://github.com/googlemaps/google-maps-services-python"&gt;Python Client for Google Maps Services&lt;/a&gt; available on Google GitHub organization. Adapting the source code of the script to this python client would be easy as the Geocoding method accepts identical parameters and returns almost the same object.&lt;/p&gt;
&lt;h3&gt;
  
  
  Registering a Google Maps API key
&lt;/h3&gt;

&lt;p&gt;Each Google Maps Web Service request requires an API key that is available with a Google Account at &lt;a href="https://developers.google.com/console"&gt;Google Developers Console&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Steps To get an API key:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Visit the &lt;a href="https://cloud.google.com/maps-platform/"&gt;Google Maps Platform&lt;/a&gt; page and click Get started.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;strong&gt;Maps&lt;/strong&gt; product to get the APIs that are needed to work with Geopy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Continue&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;Select a project&lt;/strong&gt; step asks you to associate a name with your use of Google's APIs. Either create a new name or select an existing project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After agreeing to the terms of service, click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a billing account with the Google Maps Platform. A billing account is a requirement in the new Google Maps Platform. For more information, see the Google Maps Platform &lt;a href="https://cloud.google.com/maps-platform/user-guide/pricing-changes/"&gt;pricing and billing documentation&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This Key is a long string of generated characters and looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AIzaSyAQanhCC6g4sR3tgj9tmFlByqhGFVKBFZ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; This key should be kept secret on your server (but you can revoke a key and generate a new one if needed)&lt;/p&gt;

&lt;h3&gt;
  
  
  Restrict your API Key
&lt;/h3&gt;

&lt;p&gt;Google Maps API key restrictions are settings you apply to an API key that limit which applications, APIs, and SDKs can be used with that key. &lt;br&gt;
For example, you can specify that an API key can only be used to the Geocoding API from a server with an IP address that matches the server your backend service is running on.&lt;/p&gt;

&lt;p&gt;Restricting an API key is fast and easy. You can do it at any time from the credentials page of the Google Cloud console.&lt;/p&gt;

&lt;p&gt;Steps: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to the &lt;a href="https://console.cloud.google.com/apis/credentials"&gt;Google API credentials&lt;/a&gt; page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select your project from the menu.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the API key that you want to set a restriction on. The API key property page appears.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under Application restrictions, click &lt;strong&gt;IP Address&lt;/strong&gt; (web servers, cron jobs, ...) and enter the public IP where you're executing the script.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click Save.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Script Usage
&lt;/h2&gt;

&lt;p&gt;The script takes an &lt;strong&gt;input csv file&lt;/strong&gt; with addresses you need to geocode and produce an &lt;strong&gt;output csv file&lt;/strong&gt; that contains all values from origin csv with appended following fields :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Latitude&lt;/li&gt;
&lt;li&gt;Longitude&lt;/li&gt;
&lt;li&gt;Location_Type (see below)&lt;/li&gt;
&lt;li&gt;Formatted_Address &lt;/li&gt;
&lt;li&gt;Error (if needded, for failed geocoded addresses)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Download the script to your local machine. Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python google_batch_geocoder.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make it compatible with your own CSV file and Google keys, you have to set the following parameters on top of the script.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mandatory Parameters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ADDRESS_COLUMNS_NAME&lt;/code&gt; - &lt;em&gt;List&lt;/em&gt; - used to set a google geocoding query by merging these values into one string comma separated. it depends on your CSV input file &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NEW_COLUMNS_NAME&lt;/code&gt; - &lt;em&gt;List&lt;/em&gt; - appended columns name to processed data csv (no need to change this but you can add new columns depending on [Geocoding Google Results][geocoding_results])&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELIMITER&lt;/code&gt; - &lt;em&gt;String&lt;/em&gt; - delimiter for your input csv file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;INPUT_CSV_FILE&lt;/code&gt; - &lt;em&gt;String&lt;/em&gt; - path and name for input csv file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OUTPUT_CSV_FILE&lt;/code&gt; - &lt;em&gt;String&lt;/em&gt; - path and name for output csv file&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optional Parameters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;COMPONENTS_RESTRICTIONS_COLUMNS_NAME&lt;/code&gt; - &lt;em&gt;Dict&lt;/em&gt; - used to define component restrictions for google geocoding. See [Google componentRestrictions doc][component_restrictions] for details. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GOOGLE_API_KEY&lt;/code&gt; - &lt;em&gt;String&lt;/em&gt; - Google API Key set above.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Input Data
&lt;/h2&gt;

&lt;p&gt;The sample data (&lt;code&gt;hairdresser_sample_addresses.csv&lt;/code&gt;) supported by default is a CSV file representing various hairdressers around the world. You can see below a subset of what the file looks like:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;addressline1&lt;/th&gt;
&lt;th&gt;town&lt;/th&gt;
&lt;th&gt;postalcode&lt;/th&gt;
&lt;th&gt;isocode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hairhouse Warehouse&lt;/td&gt;
&lt;td&gt;Riverlink Shopping centre&lt;/td&gt;
&lt;td&gt;Ipswich&lt;/td&gt;
&lt;td&gt;4305&lt;/td&gt;
&lt;td&gt;AU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Room For Hair&lt;/td&gt;
&lt;td&gt;20 Jull Street&lt;/td&gt;
&lt;td&gt;ARMADALE&lt;/td&gt;
&lt;td&gt;6112&lt;/td&gt;
&lt;td&gt;AU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D'luxe Hair &amp;amp; Beauty&lt;/td&gt;
&lt;td&gt;Burra Place Shellharbour City Plaza&lt;/td&gt;
&lt;td&gt;Shellharbour&lt;/td&gt;
&lt;td&gt;2529&lt;/td&gt;
&lt;td&gt;AU&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Script Explanation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prepare the Destination File
&lt;/h3&gt;

&lt;p&gt;As described above, the destination file contains all the origins fields plus geocoded data (&lt;strong&gt;latitude&lt;/strong&gt;, &lt;strong&gt;longitude&lt;/strong&gt; and &lt;strong&gt;error&lt;/strong&gt; when occur) and some metadata (&lt;strong&gt;formatted_address&lt;/strong&gt; and &lt;strong&gt;location_type&lt;/strong&gt;). In the case of our sample file, the Header of destination CSV file looks like :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;name&lt;span class="p"&gt;;&lt;/span&gt;addressline1&lt;span class="p"&gt;;&lt;/span&gt;town&lt;span class="p"&gt;;&lt;/span&gt;IsoCode&lt;span class="p"&gt;;&lt;/span&gt;Lat&lt;span class="p"&gt;;&lt;/span&gt;Long&lt;span class="p"&gt;;&lt;/span&gt;Error&lt;span class="p"&gt;;&lt;/span&gt;formatted_address&lt;span class="p"&gt;;&lt;/span&gt;location_type
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To build it, open the input and output csv files and create a new header to append to destination file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;INPUT_CSV_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;csvinput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OUTPUT_CSV_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;csvoutput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# new csv based on same dialect as input csv
&lt;/span&gt;        &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csvoutput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dialect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ga"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# create a proper header with stripped fieldnames for new CSV
&lt;/span&gt;        &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;csvinput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DELIMITER&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

        &lt;span class="c1"&gt;# read Input CSV as Dict of Dict
&lt;/span&gt;        &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DictReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csvinput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dialect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ga"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fieldnames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 2-dimensional data variable used to write the new CSV
&lt;/span&gt;        &lt;span class="n"&gt;processed_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="c1"&gt;# append new columns, to receive geocoded information 
&lt;/span&gt;        &lt;span class="c1"&gt;# to the header of the new CSV
&lt;/span&gt;        &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fieldnames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column_name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;NEW_COLUMNS_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;column_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;processed_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build an address line
&lt;/h3&gt;

&lt;p&gt;The principle is to build for each row a line address by merging multiple values in one string, based on the list &lt;code&gt;ADDRESS_COLUMNS_NAME&lt;/code&gt;, to pass it to Google Geocoder. For instance, the first line of our csv will become the line address &lt;code&gt;"Hairhouse Warehouse, Riverlink Shopping centre, Ipswich"&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# iterate through each row of input CSV
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# build a line address 
&lt;/span&gt;    &lt;span class="c1"&gt;# based on the merge of multiple field values to pass to Google Geocoder`
&lt;/span&gt;    &lt;span class="n"&gt;line_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;','&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;column_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column_name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ADDRESS_COLUMNS_NAME&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Apply the Component Restrictions
&lt;/h3&gt;

&lt;p&gt;Google Maps Geocoding API is able to return limited address results in a specific area. This restriction is specified in the script using the filters dict &lt;code&gt;COMPONENTS_RESTRICTIONS_COLUMNS_NAME&lt;/code&gt;. &lt;br&gt;
A filter consists in a list of pairs &lt;code&gt;component:value&lt;/code&gt;. You can leave it empty &lt;code&gt;{}&lt;/code&gt; if you don't want to apply restricted area.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# if you want to use componentRestrictions feature,
# build a matching dict {'googleComponentRestrictionField' : 'yourCSVFieldValue'}
# to pass to Google Geocoder
&lt;/span&gt;&lt;span class="n"&gt;component_restrictions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;COMPONENT_RESTRICTIONS_COLUMNS_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;COMPONENT_RESTRICTIONS_COLUMNS_NAME&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;component_restrictions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Geocode the address
&lt;/h3&gt;

&lt;p&gt;Before call the geocoding method of GeoPy, instantiate a new GoogleV3 Geocoder with your Google credentials, at least the &lt;strong&gt;Server API Key&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;geo_locator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GoogleV3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GOOGLE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;secret_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GOOGLE_SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then call the geocoding method passing the geocoder instance, built line address and optional component restrictions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# geocode the built line_address and passing optional componentRestrictions
&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;geocode_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geo_locator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;component_restrictions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;geocode_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geo_locator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;component_restrictions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retry_counter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# the geopy GoogleV3 geocoding call
&lt;/span&gt;    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;geo_locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;geocode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;component_restrictions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# build a dict to append to output CSV
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;location_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Lat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Long"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="s"&gt;"formatted_address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'formatted_address'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                           &lt;span class="s"&gt;"location_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'geometry'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;'location_type'&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;location_result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Retry on Failure
&lt;/h3&gt;

&lt;p&gt;The script retries to geocode the given line address when intermittent failures occur.&lt;br&gt;
That is, when the GeoPy library raised a &lt;code&gt;GeocodeError&lt;/code&gt; exception that means that any of the retriable 5xx errors are returned from the API.&lt;br&gt;
By default the retry counter (&lt;code&gt;RETRY_COUNTER_CONST&lt;/code&gt;) is set to &lt;code&gt;5&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# To retry because intermittent failures sometimes occurs
&lt;/span&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GeocoderQueryError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;retry_counter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;RETRY_COUNTER_CONST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;geocode_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geo_locator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;component_restrictions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retry_counter&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;location_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Lat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Long"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"formatted_address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="s"&gt;"location_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handle Generic and Geocoding Exceptions
&lt;/h3&gt;

&lt;p&gt;Other exceptions can occur, like when you exceed your daily quota limit or request by seconds.&lt;br&gt;
To support them import the GeoPy exceptions and handle each errors after geocode call.&lt;br&gt;
The script also raises an error when no geocoded address is found.&lt;br&gt;
The error message is appended to &lt;code&gt;Error&lt;/code&gt; CSV field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# import Exceptions from GeoPy
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;geopy.exc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;GeocoderQueryError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;GeocoderQuotaExceeded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ConfigurationError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;GeocoderParseError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# after geocode call, if no result found, raise a ValueError
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"None location found, please verify your address line"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# To catch generic and geocoder errors.
&lt;/span&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GeocoderQuotaExceeded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConfigurationError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GeocoderParseError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;location_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Lat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Long"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"formatted_address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"location_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Query-per-Second
&lt;/h3&gt;

&lt;p&gt;You can exceed the Google Maps Platform web services usage limits by sending too many requests per second. In that case, you will raise an &lt;strong&gt;OVER_QUERY_LIMIT&lt;/strong&gt; error. You will have to wait between two API Call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# for too many requests per second, we have to sleep 500 ms between each request.
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;GOOGLE_SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;Apart from the &lt;code&gt;Latitude&lt;/code&gt; and &lt;code&gt;Longitude&lt;/code&gt; fields, here are the 3 main results appended to destination CSV file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Formatted Address
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;formatted_address&lt;/strong&gt; matches a readable address of the place (and original line address). This address is most of the time equivalent to the "postal address".&lt;/p&gt;

&lt;h3&gt;
  
  
  Geocoding Accuracy Labels
&lt;/h3&gt;

&lt;p&gt;For each succeeded geocoded address, a geocoding accuracy results is returned in &lt;code&gt;location_type&lt;/code&gt; field. It comes from the Google Maps API Geocoding service (see &lt;a href="https://developers.google.com/maps/documentation/geocoding/intro#Results"&gt;Google geocoding Results doc&lt;/a&gt; for more information). The following values are currently supported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"ROOFTOP"&lt;/strong&gt; indicates that the returned result is a precise geocode for which we have location information accuracy down to street address precision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"RANGE_INTERPOLATED"&lt;/strong&gt; indicates that the returned result reflects an approximation (usually on a road) interpolated between two precise points (such as intersections). Interpolated results are generally returned when rooftop geocodes are unavailable for a street address.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"GEOMETRIC_CENTER"&lt;/strong&gt; indicates that the returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"APPROXIMATE"&lt;/strong&gt; indicates that the returned result is approximate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Error
&lt;/h3&gt;

&lt;p&gt;Whenever the call to Google Maps API failed, the script will return an error message &lt;em&gt;"None location found, please verify your address line"&lt;/em&gt;.&lt;br&gt;
For all other errors, the message raised by GeoPy will be appended to the field value. See &lt;a href="https://geopy.readthedocs.io/en/1.10.0/#exceptions"&gt;GeoPy Exceptions&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h2&gt;
  
  
  Display your POI on a Map
&lt;/h2&gt;

&lt;p&gt;You could use Woosmap to display the geocoded addresses on a Map. If so, follow this help article to &lt;a href="https://developers.woosmap.com/support/manage-assets/upload-csv-file/"&gt;upload your CSV file to Woosmap&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is a sample of what it looks like on the Woosmap Store Locator widget.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://jsfiddle.net/woosmap/2r3wba1o/embedded/result,html//dark" width="100%" height="600"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This python script on the &lt;a href="https://github.com/woosmap/geopy-googlemaps-batchgeocoder"&gt;Woosmap Github Organization&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/geopy/geopy"&gt;GeoPy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Alternative to GeoPy : &lt;a href="https://github.com/googlemaps/google-maps-services-python"&gt;Python Client for Google Maps Services&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/maps/documentation/geocoding/geocoding-strategies#quota-limits"&gt;Google Geocoding Strategies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/maps/documentation/geocoding/intro#Results"&gt;Google geocoding Results doc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;More info on &lt;a href="https://www.woosmap.com/"&gt;Woosmap&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>geopy</category>
      <category>googlemaps</category>
      <category>woosmap</category>
      <category>geocoding</category>
    </item>
  </channel>
</rss>
