> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Geo search

> Use Geo search in your Vue InstantSearch app.

export const Records = () => <Tooltip tip="A record is a searchable object in an Algolia index. Each record consists of named attributes." cta="Algolia records" href="/doc/guides/sending-and-managing-data/prepare-your-data#algolia-records">
    records
  </Tooltip>;

export const Index = () => <Tooltip tip="An Algolia index is a searchable dataset that consists of records and configuration settings. These settings define how the records are searched and ranked.">
    index
  </Tooltip>;

You can use Algolia's [geographical search capabilities](/doc/guides/managing-results/refine-results/geolocation#geo-search) with the [`connectGeoSearch`](/doc/api-reference/widgets/geo-search/js#customize-the-ui-with-connectgeosearch) connector.

## Working example

The complete source code of the example on this page is available on [GitHub](https://github.com/algolia/doc-code-samples/tree/master/vue-instantsearch/geo-search).

<Note>
  This code has been specifically created for Vue 2. Some [modifications](https://v3-migration.vuejs.org/) may be required for it to work correctly in Vue 3.
</Note>

The demo is built with [Google Maps](https://developers.google.com/maps/documentation/javascript/overview) but the core logic isn't tied to any map provider
You can build your own map widget with a different provider (such as [Leaflet](https://leafletjs.com)).

This guide uses the [`vue-googlemaps`](https://github.com/Akryum/vue-googlemaps) library to access Google Maps.

## Dataset

This guide use a dataset of over 3,000 <Records /> of the biggest airports in the world.

```json JSON icon=braces theme={"system"}
{
  "objectID": "3797",
  "name": "John F Kennedy Intl",
  "city": "New York",
  "country": "United States",
  "iata_code": "JFK",
  "links_count": 911,
  "_geoloc": {
    "lat": 40.639751,
    "lng": -73.778925
  }
}
```

Latitude and longitude are stored in the record to allow hits to be displayed on the map.
You should store them in the `_geoloc` attribute to enable geo-filtering and geo-sorting.

You can download the dataset on [GitHub](https://github.com/algolia/datasets/tree/master/airports).
Have a look at how to import it in [Algolia](/doc/guides/sending-and-managing-data/send-and-update-your-data/how-to/importing-from-the-dashboard).

### Configure index settings

When displaying on a map, you still want the relevance to be good.
For that, configure the <Index /> as follows:

* [Searchable attributes](/doc/guides/managing-results/must-do/searchable-attributes) should be set to enable search in the four textual attributes: `name`, `city`, `country`, and `iata_code`.
* [Custom ranking](/doc/guides/managing-results/must-do/custom-ranking): use the **number of other connected airports** `links_count` as a ranking metric. The more connections the better.

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SetSettingsAsync(
    "INDEX_NAME",
    new IndexSettings
    {
      SearchableAttributes = new List<string> { "name", "country", "city", "iata_code" },
      CustomRanking = new List<string> { "desc(links_count)" },
    }
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.setSettings(
    indexName: "INDEX_NAME",
    indexSettings: IndexSettings(
      searchableAttributes: [
        "name",
        "country",
        "city",
        "iata_code",
      ],
      customRanking: [
        "desc(links_count)",
      ],
    ),
  );
  ```

  ```go Go theme={"system"}
  response, err := client.SetSettings(client.NewApiSetSettingsRequest(
    "INDEX_NAME",
    search.NewEmptyIndexSettings().SetSearchableAttributes(
      []string{"name", "country", "city", "iata_code"}).SetCustomRanking(
      []string{"desc(links_count)"})))
  if err != nil {
    // handle the eventual error
    panic(err)
  }
  ```

  ```java Java theme={"system"}
  UpdatedAtResponse response = client.setSettings(
    "INDEX_NAME",
    new IndexSettings()
      .setSearchableAttributes(Arrays.asList("name", "country", "city", "iata_code"))
      .setCustomRanking(Arrays.asList("desc(links_count)"))
  );
  ```

  ```js JavaScript theme={"system"}
  const response = await client.setSettings({
    indexName: 'theIndexName',
    indexSettings: {
      searchableAttributes: ['name', 'country', 'city', 'iata_code'],
      customRanking: ['desc(links_count)'],
    },
  });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings =
        IndexSettings(
          searchableAttributes = listOf("name", "country", "city", "iata_code"),
          customRanking = listOf("desc(links_count)"),
        ),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->setSettings(
      'INDEX_NAME',
      ['searchableAttributes' => [
          'name',

          'country',

          'city',

          'iata_code',
      ],
          'customRanking' => [
              'desc(links_count)',
          ],
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.set_settings(
      index_name="INDEX_NAME",
      index_settings={
          "searchableAttributes": [
              "name",
              "country",
              "city",
              "iata_code",
          ],
          "customRanking": [
              "desc(links_count)",
          ],
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.set_settings(
    "INDEX_NAME",
    Algolia::Search::IndexSettings.new(
      searchable_attributes: ["name", "country", "city", "iata_code"],
      custom_ranking: ["desc(links_count)"]
    )
  )
  ```

  ```scala Scala theme={"system"}
  val response = Await.result(
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings = IndexSettings(
        searchableAttributes = Some(Seq("name", "country", "city", "iata_code")),
        customRanking = Some(Seq("desc(links_count)"))
      )
    ),
    Duration(100, "sec")
  )
  ```

  ```swift Swift theme={"system"}
  let response = try await client.setSettings(
      indexName: "INDEX_NAME",
      indexSettings: IndexSettings(
          searchableAttributes: ["name", "country", "city", "iata_code"],
          customRanking: ["desc(links_count)"]
      )
  )
  ```
</CodeGroup>

## Displaying hits

<Steps>
  <Step title="Add the Google Maps library">
    ```js JavaScript icon=code theme={"system"}
    // main.js
    import "vue-googlemaps/dist/vue-googlemaps.css";
    import VueGoogleMaps from "vue-googlemaps";

    Vue.use(VueGoogleMaps, {
      load: {
        // Your Google API key
        apiKey: "AIxxxxx",
      },
    });
    ```
  </Step>

  <Step title="Create a custom widget">
    Create a [custom widget](/doc/guides/building-search-ui/widgets/customize-an-existing-widget/vue) for Vue InstantSearch,
    using  [`connectGeoSearch`](/doc/api-reference/widgets/geo-search/js#customize-the-ui-with-connectgeosearch) :

    <CodeGroup>
      ```html Vue 3 theme={"system"}
      <script>
      import { createWidgetMixin } from 'vue-instantsearch/vue3/es';
      import { connectGeoSearch } from 'instantsearch.js/es/connectors';

      export default {
        mixins: [createWidgetMixin({ connector: connectGeoSearch })],
      };
      </script>

      ```

      ```html Vue 2 theme={"system"}
      <script>
      import { createWidgetMixin } from 'vue-instantsearch';
      import { connectGeoSearch } from 'instantsearch.js/es/connectors';

      export default {
        mixins: [createWidgetMixin({ connector: connectGeoSearch })],
      };
      </script>
      ```
    </CodeGroup>
  </Step>

  <Step title="Add map to the template">
    Now that you have access to the data from the Geo Search connector, you want
    to add a regular map in the template.

    <Info>
      To make the map actually visible, give  the map element a height with CSS.
    </Info>

    ```html Vue icon=code-xml theme={"system"}
    <template>
      <div v-if="state" class="ais-GeoSearch">
        <googlemaps-map
          :center="center"
          :zoom.sync="zoom"
          class="ais-GeoSearch-map"
        >
        </googlemaps-map>
      </div>
    </template>

    <script>
    export default {
      data() {
        return {
          center: { lat: 0, lng: 0 },
          zoom: 12,
        };
      },
    };
    </script>
    ```
  </Step>

  <Step title="Display results">
    Loop over `this.state.items` to display the search results:

    <CodeGroup>
      ```html Vue 3 theme={"system"}
      <template>
        <div v-if="state" class="ais-GeoSearch">
          <googlemaps-map
            :center="center"
            :zoom.sync="zoom"
            class="ais-GeoSearch-map"
          >
            <googlemaps-marker
              v-for="item of state.items"
              :key="item.objectID"
              :title="item.name"
              :position="item._geoloc"
            />
          </googlemaps-map>
        </div>
      </template>

      <script>
      import { createWidgetMixin } from 'vue-instantsearch/vue3/es';
      import { connectGeoSearch } from 'instantsearch.js/es/connectors';

      export default {
        mixins: [createWidgetMixin({ connector: connectGeoSearch })],
        data() {
          return {
            zoom: 12,
          };
        },
        computed: {
          center() {
            return this.state.items[0]._geoloc;
          },
        },
      };
      </script>

      ```

      ```html Vue 2 theme={"system"}
      <template>
        <div v-if="state" class="ais-GeoSearch">
          <googlemaps-map
            :center="center"
            :zoom.sync="zoom"
            class="ais-GeoSearch-map"
          >
            <googlemaps-marker
              v-for="item of state.items"
              :key="item.objectID"
              :title="item.name"
              :position="item._geoloc"
            />
          </googlemaps-map>
        </div>
      </template>

      <script>
      import { createWidgetMixin } from 'vue-instantsearch';
      import { connectGeoSearch } from 'instantsearch.js/es/connectors';

      export default {
        mixins: [createWidgetMixin({ connector: connectGeoSearch })],
        data() {
          return {
            zoom: 12,
          };
        },
        computed: {
          center() {
            return this.state.items[0]._geoloc;
          },
        },
      };
      </script>
      ```
    </CodeGroup>
  </Step>
</Steps>

## Going further

This guide only explains how to display hits on a map, but [`connectGeoSearch`](/doc/api-reference/widgets/geo-search/js#customize-the-ui-with-connectgeosearch) connector has more features, such as refining the search when the map moves and automatically centering on the correct items.
Feel free to explore the options given to `state` from the connector to make these experiences.
