

# How to use Amazon Location Service
<a name="using-amazon-location"></a>

**Note**  
We released a new version of the Places, Maps, and Routes APIs, see the updated [Developer Guide](https://docs.aws.amazon.com//location/latest/developerguide/what-is.html) for revised information and new topics, such as [Geofences](https://docs.aws.amazon.com//location/latest/developerguide/geofences.html) and [Trackers](https://docs.aws.amazon.com//location/latest/developerguide/trackers.html).

You can use Amazon Location Service capabilities to complete geographic and location-related tasks. You can then combine these tasks to address more complex uses cases such as geomarketing, delivery, and asset tracking. 

When you're ready to build location features into your application, use the following methods to use the Amazon Location Service functionality, depending on your goals and inclinations: 
+ **Exploration tools** – If you want to experiment with Amazon Location resources, the following tools are the fastest way to access and try out the APIs: 
  + The [Amazon Location console](https://console.aws.amazon.com/location/home) provides a variety of quick-access tools. You can create and manage your resources and try the APIs using [the Explore page](https://console.aws.amazon.com/location/explore/home). The console is also useful for creating resources (typically a one-time task) in preparation for using any of the other methods described later.
  + The [AWS Command Line Interface](https://aws.amazon.com/cli/) (CLI) lets you create resources and access the Amazon Location APIs using a terminal. The AWS CLI handles authentication when you configure it with your credentials.
  + You can see [code examples and tutorials](samples.md) that show how to perform tasks using the Amazon Location Service APIs. This includes [an example](example-explore.md) that mimics much of the functionality of the Explore page in the console.
+ **Platform SDKs** – If you aren't visualizing data on a map, you can use any of the [AWS standard tools](https://aws.amazon.com/tools/) to build on AWS. 
  + The following SDKs are available: C\$1\$1, Go, Java, JavaScript, .NET, Node.js, PHP, Python, and Ruby.
+ **Frontend SDKs and libraries** – If you want to use Amazon Location to build an application on a mobile platform or visualize data on a map on any platform, you have the following options:
  + The AWS Amplify libraries integrate Amazon Location within [ iOS](https://docs.amplify.aws/guides/location-service/setting-up-your-app/q/platform/ios), [ Android](https://docs.amplify.aws/guides/location-service/setting-up-your-app/q/platform/android), and [ JavaScript](https://docs.amplify.aws/guides/location-service/setting-up-your-app/q/platform/js) web applications.
  + The MapLibre libraries let you render client-side maps into [iOS](https://docs.aws.amazon.com/location/previous/developerguide/tutorial-maplibre-ios.html), [Android](https://docs.aws.amazon.com/location/previous/developerguide/tutorial-maplibre-android.html), and [JavaScript](https://docs.aws.amazon.com/location/previous/developerguide/tutorial-maplibre-gl-js.html) web applications using Amazon Location.
  + Tangram ES libraries enable you to render 2D and 3D maps from vector data using OpenGL ES within [iOS](https://docs.aws.amazon.com/location/previous/developerguide/tutorial-tangram-es-ios.html) and [Android](https://docs.aws.amazon.com/location/previous/developerguide/tutorial-tangram-es-android.html) web applications. There is also Tangram for[ JavaScript](https://docs.aws.amazon.com/location/previous/developerguide/tutorial-tangram-js.html) web applications.
+ **Sending direct HTTPS requests** – If you are working with a programming language for which there is no SDK available, or if you want more control over how you send a request to AWS, you can access Amazon Location by sending direct HTTPS requests authenticated by the Signature Version 4 signing process. For more information on the[ Signature Version 4 signing process](https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html), see the* AWS General Reference*.

This chapter describes many of the tasks that are common to applications using location data. The [common use cases](https://docs.aws.amazon.com/location/previous/developerguide/common-usecases.html) section describes how to combine these with other AWS services to achieve more complex use cases. 

**Topics**
+ [Prerequisites for using Amazon Location Service](gs-prereqs.md)
+ [Using Amazon Location Maps in your application](using-maps.md)
+ [Searching place and geolocation data using Amazon Location](searching-for-places.md)
+ [Calculating routes using Amazon Location Service](calculating-routes.md)
+ [Geofencing an area of interest using Amazon Location](geofence-an-area.md)
+ [Tag your Amazon Location Service resources](tagging.md)
+ [Grant access to Amazon Location Service](how-to-access.md)
+ [Monitor Amazon Location Service](monitoring.md)
+ [Create Amazon Location Service resources with AWS CloudFormation](creating-resources-with-cloudformation.md)

# Prerequisites for using Amazon Location Service
<a name="gs-prereqs"></a>

This section describes what you need to do to use Amazon Location Service. You must have an AWS account and have set up access to Amazon Location for users that want to use it.

## Sign up for an AWS account
<a name="sign-up-for-aws"></a>

If you do not have an AWS account, complete the following steps to create one.

**To sign up for an AWS account**

1. Open [https://portal.aws.amazon.com/billing/signup](https://portal.aws.amazon.com/billing/signup).

1. Follow the online instructions.

   Part of the sign-up procedure involves receiving a phone call or text message and entering a verification code on the phone keypad.

   When you sign up for an AWS account, an *AWS account root user* is created. The root user has access to all AWS services and resources in the account. As a security best practice, assign administrative access to a user, and use only the root user to perform [tasks that require root user access](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#root-user-tasks).

AWS sends you a confirmation email after the sign-up process is complete. At any time, you can view your current account activity and manage your account by going to [https://aws.amazon.com/](https://aws.amazon.com/) and choosing **My Account**.

## Create a user with administrative access
<a name="create-an-admin"></a>

After you sign up for an AWS account, secure your AWS account root user, enable AWS IAM Identity Center, and create an administrative user so that you don't use the root user for everyday tasks.

**Secure your AWS account root user**

1.  Sign in to the [AWS Management Console](https://console.aws.amazon.com/) as the account owner by choosing **Root user** and entering your AWS account email address. On the next page, enter your password.

   For help signing in by using root user, see [Signing in as the root user](https://docs.aws.amazon.com/signin/latest/userguide/console-sign-in-tutorials.html#introduction-to-root-user-sign-in-tutorial) in the *AWS Sign-In User Guide*.

1. Turn on multi-factor authentication (MFA) for your root user.

   For instructions, see [Enable a virtual MFA device for your AWS account root user (console)](https://docs.aws.amazon.com/IAM/latest/UserGuide/enable-virt-mfa-for-root.html) in the *IAM User Guide*.

**Create a user with administrative access**

1. Enable IAM Identity Center.

   For instructions, see [Enabling AWS IAM Identity Center](https://docs.aws.amazon.com//singlesignon/latest/userguide/get-set-up-for-idc.html) in the *AWS IAM Identity Center User Guide*.

1. In IAM Identity Center, grant administrative access to a user.

   For a tutorial about using the IAM Identity Center directory as your identity source, see [ Configure user access with the default IAM Identity Center directory](https://docs.aws.amazon.com//singlesignon/latest/userguide/quick-start-default-idc.html) in the *AWS IAM Identity Center User Guide*.

**Sign in as the user with administrative access**
+ To sign in with your IAM Identity Center user, use the sign-in URL that was sent to your email address when you created the IAM Identity Center user.

  For help signing in using an IAM Identity Center user, see [Signing in to the AWS access portal](https://docs.aws.amazon.com/signin/latest/userguide/iam-id-center-sign-in-tutorial.html) in the *AWS Sign-In User Guide*.

**Assign access to additional users**

1. In IAM Identity Center, create a permission set that follows the best practice of applying least-privilege permissions.

   For instructions, see [ Create a permission set](https://docs.aws.amazon.com//singlesignon/latest/userguide/get-started-create-a-permission-set.html) in the *AWS IAM Identity Center User Guide*.

1. Assign users to a group, and then assign single sign-on access to the group.

   For instructions, see [ Add groups](https://docs.aws.amazon.com//singlesignon/latest/userguide/addgroups.html) in the *AWS IAM Identity Center User Guide*.

## Grant access to Amazon Location Service
<a name="gs-grant-access"></a>

Your non-admin users have no permissions by default. Before they can access Amazon Location, you must grant permission by attaching an IAM policy with specific permissions. Make sure to follow the principle of least privilege when granting access to resources. 

**Note**  
For information about giving unauthenticated users access to Amazon Location Service functionality (for example, in a web-based application), see [Grant access to Amazon Location Service](how-to-access.md).

The following example policy gives a user permission to access all Amazon Location operations. For more examples, see [Identity-based policy examples for Amazon Location Service](security_iam_id-based-policy-examples.md).

```
{
  "Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Action": [
        "geo:*"
      ],
      "Resource": "*",
      "Effect": "Allow"
    }
  ]
}
```

To provide access, add permissions to your users, groups, or roles:
+ Users and groups in AWS IAM Identity Center:

  Create a permission set. Follow the instructions in [Create a permission set](https://docs.aws.amazon.com//singlesignon/latest/userguide/howtocreatepermissionset.html) in the *AWS IAM Identity Center User Guide*.
+ Users managed in IAM through an identity provider:

  Create a role for identity federation. Follow the instructions in [Create a role for a third-party identity provider (federation)](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_roles_create_for-idp.html) in the *IAM User Guide*.
+ IAM users:
  + Create a role that your user can assume. Follow the instructions in [Create a role for an IAM user](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_roles_create_for-user.html) in the *IAM User Guide*.
  + (Not recommended) Attach a policy directly to a user or add a user to a user group. Follow the instructions in [Adding permissions to a user (console)](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_users_change-permissions.html#users_change_permissions-add-console) in the *IAM User Guide*.

When creating applications that use Amazon Location Service, you may need some users to have unauthenticated access. For these use cases, see [Enabling unauthenticated access using Amazon Cognito](authenticating-using-cognito.md).

# Using Amazon Location Maps in your application
<a name="using-maps"></a>

**Note**  
We released a new version of the Maps API, see the updated [Maps Developer Guide](https://docs.aws.amazon.com//location/latest/developerguide/maps.html) or [Maps API](https://docs.aws.amazon.com//location/latest/APIReference/API_Operations_Amazon_Location_Service_Maps_V2.html) for revised information.

Amazon Location maps are cost-effective and interactive. You can replace an existing map in your application to save money, or add a new one to display location-based data visually, such as your store location.

![\[\]](http://docs.aws.amazon.com/location/previous/developerguide/images/maps_park_example.png)


Amazon Location Service lets you choose a data provider for map operations by creating and configuring a map resource. The map resource configures the data provider and the style that is used to render the map.

After you create your resource, you can send requests by using the AWS SDK directly, or by using a library made specifically for rendering maps in your environment. 

**Note**  
For an overview of map concepts, see [Learn about Maps resources in Amazon Location Service](map-concepts.md).

**Topics**
+ [Prerequisites for using Amazon Location maps](map-prerequisites.md)
+ [Display a map in your application with Amazon Location](display-map.md)
+ [Drawing data features on a map](drawing-on-a-map.md)
+ [Setting extents for a map using MapLibre](setting-map-extents.md)
+ [Managing your map resources with Amazon Location](managing-maps.md)

# Prerequisites for using Amazon Location maps
<a name="map-prerequisites"></a>

Before you start utilizing the mapping capabilities of Amazon Location Service, there are a few prerequisites that need to be fulfilled. This page outlines the necessary steps and requirements to ensure a smooth integration of interactive maps into your applications. 

## Create a map resource
<a name="create-map-resource"></a>

To use a map in your application you must have a map resource, which specifies the map style and data provider to use in your maps.

**Note**  
If your application is tracking or routing assets you use in your business, such as delivery vehicles or employees, you must not use Esri as your geolocation provider. See section 82 of the [AWS service terms](https://aws.amazon.com/service-terms) for more details.

You can create a map resource using the Amazon Location Service console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To create a map resource using the Amazon Location Service console**

1. In the Amazon Location console, on the [https://console.aws.amazon.com/location/maps/home](https://console.aws.amazon.com/location/maps/home) page, choose **Create map** to preview map styles.

1. Add a name and description for the new map resource.

1. Choose a map style.
**Note**  
If your application is tracking or routing assets you use in your business, such as delivery vehicles or employees, you must not use Esri as your geolocation provider. See section 82 of the [AWS service terms](https://aws.amazon.com/service-terms) for more details.

1. Choose from the [Political views](map-concepts.md#political-views) to use.

1. Agree to the **Amazon Location Terms and Conditions**, then choose **Create map**. You can interact with the map that you've chosen: zoom in, zoom out, or pan in any direction.

1. To allow your users to switch styles (for example, to allow them to switch between satellite imagery and vector style), you must create a map resource for each style.

   You can delete resources with map styles that you don’t want to use on the [Maps home page](https://console.aws.amazon.com/location/maps/home) in the console. 

------
#### [ API ]

**To create a map resource using the Amazon Location APIs**

Use the `[CreateMap](https://docs.aws.amazon.com/location/previous/APIReference/API_CreateMap.html)` operation from the Amazon Location APIs.

The following example is an API request to create a map resource called *ExampleMap* using the *VectorEsriStreets* map style. 

```
POST /maps/v0/maps HTTP/1.1
Content-type: application/json

{
   "Configuration": { 
      "Style": "VectorEsriStreets"
   },
   "MapName": "ExampleMap"
   }
}
```

**Note**  
If your application is tracking or routing assets you use in your business, such as delivery vehicles or employees, you must not use Esri as your geolocation provider. See section 82 of the [AWS service terms](https://aws.amazon.com/service-terms) for more details.

------
#### [ AWS CLI ]

**To create a map resource using AWS CLI commands**

Use the `[create-map](https://docs.aws.amazon.com/cli/latest/reference/location/create-map.html)` command.

The following example creates a map resource called *ExampleMap* using *VectorEsriStreets* as the map style. 

```
aws location \
  create-map \
  --configuration Style="VectorEsriStreets" \
  --map-name "ExampleMap"
```

**Note**  
If your application is tracking or routing assets you use in your business, such as delivery vehicles or employees, you must not use Esri as your geolocation provider. See section 82 of the [AWS service terms](https://aws.amazon.com/service-terms) for more details.

------

## Authenticating your requests
<a name="using-maps-set-up-authentication"></a>

Once you create a map resource and you're ready to begin building location features into your application, you need to choose how you would authenticate your requests.

**Note**  
Most maps front end applications require unauthenticated access to the maps or other features of Amazon Location Service. Depending on your application, you might want to use AWS Signature v4 to authenticate requests, or you can use Amazon Cognito or Amazon Location API keys for unauthenticated use. To learn more about all of these options, see [Grant access to Amazon Location Service](how-to-access.md).

# Display a map in your application with Amazon Location
<a name="display-map"></a>

This section provides tutorials on how to use map rendering tools to display a map in your mobile or web application when using Amazon Location APIs. As mentioned in the [How to use Amazon Location Service](using-amazon-location.md) topic, you have a choice of libraries to use when rendering maps with Amazon Location, including Amplify, MapLibre, and Tangram.

Do one of the following to display a map in your application:
+ The most direct way to display a map in your web and mobile front end applications is to use MapLibre. You can follow the [MapLibre tutorials](tutorial-maplibre.md) or even the [Quick start tutorial](getting-started.md) to learn how to use MapLibre.
+ If you are an existing AWS Amplify developer, you may want to use the Amplify Geo SDK. To learn more, follow the [ Amplify tutorial](https://docs.aws.amazon.com/location/previous/developerguide/tutorial-map-amplify.html).
+ If you are an existing user of Tangram, and want to continue to use it to render your map, while moving to Amazon Location Service, follow the [Tangram tutorial](tutorial-tangram-js.md).

**Topics**
+ [Using the MapLibre library with Amazon Location Service](tutorial-maplibre.md)
+ [Using the Amplify library with Amazon Location Service](tutorial-map-amplify.md)
+ [Tutorial: using Tangram with Amazon Location Service](tutorial-tangram.md)

# Using the MapLibre library with Amazon Location Service
<a name="tutorial-maplibre"></a>

The following tutorials walk you through using the MapLibre Library with Amazon Location. 

**Topics**
+ [Using MapLibre GL JS with Amazon Location Service](tutorial-maplibre-gl-js.md)
+ [Using the MapLibre Native SDK for Android with Amazon Location Service](tutorial-maplibre-android.md)
+ [Using the MapLibre Native SDK for iOS with Amazon Location Service](tutorial-maplibre-ios.md)

# Using MapLibre GL JS with Amazon Location Service
<a name="tutorial-maplibre-gl-js"></a>

Use [MapLibre GL JS](https://github.com/maplibre/maplibre-gl-js) to embed client-side maps into web applications.

MapLibre GL JS is an open-source JavaScript library that's compatible with the styles and tiles provided by the Amazon Location Service Maps API. You can integrate MapLibre GL JS within a basic HTML or JavaScript application to embed customizable and responsive client-side maps.

This tutorial describes how to integrate MapLibre GL JS with Amazon Location within a basic HTML and JavaScript application. The same libraries and techniques presented in this tutorial also apply to frameworks, such as [React](https://reactjs.org/) and [Angular](https://angular.io/). 

The sample application for this tutorial is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

## Building the application: Scaffolding
<a name="tutorial-maplibre-js-scaffolding"></a>

This tutorial creates a web application that uses JavaScript to build a map on an HTML page.

Begin by creating an HTML page (`index.html`) that includes the map's container:
+ Enter a `div` element with an `id` of `map` to apply the map's dimensions to the map view. The dimensions are inherited from the viewport.

```
<html>
  <head>
    <style>
      body {
        margin: 0;
      }
 
      #map {
        height: 100vh; /* 100% of viewport height */
      }
    </style>
  </head>
  <body>
    <!-- map container -->
    <div id="map" />
  </body>
</html>
```

## Building the application: Adding dependencies
<a name="tutorial-maplibre-js-add-dependencies"></a>

Add the following dependencies to your application: 
+ MapLibre GL JS (v3.x), and its associated CSS.
+ The Amazon Location [JavaScript Authentication helper](loc-sdk-auth.md).

```
<!-- CSS dependencies -->
<link
  href="https://unpkg.com/maplibre-gl@3.x/dist/maplibre-gl.css"
  rel="stylesheet"
/>
<!-- JavaScript dependencies -->
<script src="https://unpkg.com/maplibre-gl@3.x/dist/maplibre-gl.js"></script>
<script src="https://unpkg.com/@aws/amazon-location-authentication-helper.js"></script>
<script>
  // application-specific code
</script>
```

This creates an empty page with the map's container. 

## Building the application: Configuration
<a name="tutorial-maplibre-js-configuration"></a>

To configure your application using JavaScript:

1. Enter the names and identifiers of your resources.

   ```
   // Cognito Identity Pool ID
   const identityPoolId = "us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd";
   // Amazon Location Service Map name
   const mapName = "ExampleMap";
   ```

1. Instantiate a credential provider using the unauthenticated identity pool you created in [Using maps - Step 2, Set up authentication](map-prerequisites.md#using-maps-set-up-authentication). We will put this in a function called `initializeMap`, that will also contain other map initialization code, added in the next step

   ```
   // extract the Region from the Identity Pool ID; this will be used for both Amazon Cognito and Amazon Location
   AWS.config.region = identityPoolId.split(":")[0];
    
   async function initializeMap() {
     // Create an authentication helper instance using credentials from Cognito
     const authHelper = await amazonLocationAuthHelper.withIdentityPoolId(identityPoolId);
   
     // ... more here, later
   }
   ```

## Building the application: Map initialization
<a name="tutorial-maplibre-js-request-map-init"></a>

For the map to display after the page is loaded, you must initialize the map. You can adjust the initial map location, add additional controls, and overlay data.

```
async function initializeMap() {
  // Create an authentication helper instance using credentials from Cognito
  const authHelper = await amazonLocationAuthHelper.withIdentityPoolId(identityPoolId);
 
  // Initialize the map
  const map = new maplibregl.Map({
    container: "map",
    center: [-123.1187, 49.2819], // initial map centerpoint
    zoom: 10, // initial map zoom
    style: `https://maps.geo.${region}.amazonaws.com/maps/v0/maps/${mapName}/style-descriptor`,
    ...authHelper.getMapAuthenticationOptions(), // authentication, using cognito
  });
 
  map.addControl(new maplibregl.NavigationControl(), "top-left");
}
 
initializeMap();
```

**Note**  
You must provide word mark or text attribution for each data provider that you use, either on your application or your documentation. Attribution strings are included in the style descriptor response under the `sources.esri.attribution`, `sources.here.attribution`, and `sources.grabmaptiles.attribution` keys. MapLibre GL JS will automatically provide attribution. When using Amazon Location resources with [data providers](https://docs.aws.amazon.com/location/previous/developerguide/what-is-data-provider.html), make sure to read the [service terms and conditions](https://aws.amazon.com/service-terms/).

## Running the application
<a name="tutorial-maplibre-js-writing-js"></a>

You can run this sample application by using it in a local web server, or opening it in a browser.

To use a local web server, you can use npx, because it's installed as part of Node.js. You can use `npx serve` from within the same directory as `index.html`. This serves the application on `localhost:5000`.

**Note**  
If the policy you created for your unauthenticated Amazon Cognito role includes a `referer` condition, you might be blocked from testing with `localhost:` URLs. In this case. you can test with a web server that provides a URL that is in your policy.

After completing the tutorial, the final application looks like the following example.

```
<!-- index.html -->
<html>
  <head>
    <link href="https://unpkg.com/maplibre-gl@3.x/dist/maplibre-gl.css" rel="stylesheet" />
    <style>
      body {
        margin: 0;
      }
      #map {
        height: 100vh;
      }
    </style>
  </head>

  <body>
    <!-- map container -->
    <div id="map" />
    <!-- JavaScript dependencies -->
    <script src="https://unpkg.com/maplibre-gl@3.x/dist/maplibre-gl.js"></script>
    <script src="https://unpkg.com/@aws/amazon-location-authentication-helper.js"></script>
    <script>
      // configuration
      const identityPoolId = "us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd"; // Cognito Identity Pool ID
      const mapName = "ExampleMap"; // Amazon Location Service Map Name

      // extract the region from the Identity Pool ID
      const region = identityPoolId.split(":")[0];

      async function initializeMap() {
        // Create an authentication helper instance using credentials from Cognito
        const authHelper = await amazonLocationAuthHelper.withIdentityPoolId(identityPoolId);

        // Initialize the map
        const map = new maplibregl.Map({
          container: "map",
          center: [-123.115898, 49.295868],
          zoom: 10,
          style: `https://maps.geo.${region}.amazonaws.com/maps/v0/maps/${mapName}/style-descriptor`,
          ...authHelper.getMapAuthenticationOptions(),
        });
        map.addControl(new maplibregl.NavigationControl(), "top-left");
      }

      initializeMap();
    </script>
  </body>
</html>
```

Running this application displays a full-screen map using your chosen map style. This sample is available in the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

# Using the MapLibre Native SDK for Android with Amazon Location Service
<a name="tutorial-maplibre-android"></a>

Use [MapLibre Native](https://github.com/maplibre/maplibre-gl-native) SDK to embed interactive maps into your Android applications.

The MapLibre Native SDK for Android is a library based on[ Mapbox Native](https://github.com/mapbox/mapbox-gl-native), and is compatible with the styles and tiles provided by the Amazon Location Service Maps API. You can integrate MapLibre Native SDK for Android to embed interactive map views with scalable, customizable vector maps in your Android applications.

This tutorial describes how to integrate the MapLibre Native SDK for Android with Amazon Location. The sample application for this tutorial is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

## Building the application: Initialization
<a name="tutorial-maplibre-android-initialization"></a>

To initialize your application:

1. Create a new Android Studio project from the **Empty Activity** template.

1. Ensure that **Kotlin** is selected for the project language.

1. Select a **Minimum SDK of API 14: Android 4.0 (Ice Cream Sandwich)** or newer.

1. Open **Project Structure**, then go to **File** > **Project Structure...** to choose the **Dependencies** section.

1. With **<All Modules>** selected,then choose the **\$1** button to add a new **Library Dependency**.

1. Add **AWS Android SDK** version 2.20.0 or later. For example: `com.amazonaws:aws-android-sdk-core:2.20.0`

1. Add the **MapLibre Native SDK for Android** version 9.4.0 or later. For example: `org.maplibre.gl:android-sdk:9.4.0`

1. At the project level of your **build.gradle** file, add the following maven repository to access the MapLibre packages for Android:

   ```
   allprojects {
       repositories {
           // Retain your existing repositories
           google()
           jcenter()
           
           //  Declare the repositories for MapLibre
           mavenCentral()
       }
   }
   ```

## Building the application: Configuration
<a name="tutorial-maplibre-android-configuration"></a>

To configure your application with your resources and AWS Region:   Create `app/src/main/res/values/configuration.xml`.   Enter the names and identifiers of your resource the AWS Region they were created in:   

```
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="identityPoolId">us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd</string>
    <string name="mapName">ExampleMap</string>
    <string name="awsRegion">us-east-1</string>
</resources>
```

## Building the application: Activity layout
<a name="tutorial-maplibre-android-activity-layout"></a>

Edit `app/src/main/res/layout/activity_main.xml`:
+ Add a `MapView`, which renders the map. This will also set the map's initial center point.
+ Add a `TextView`, which displays attribution.

```
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
    <com.mapbox.mapboxsdk.maps.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:mapbox_cameraTargetLat="49.2819"
        app:mapbox_cameraTargetLng="-123.1187"
        app:mapbox_cameraZoom="12"
        app:mapbox_uiAttribution="false"
        app:mapbox_uiLogo="false" />
 
    <TextView
        android:id="@+id/attributionView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#80808080"
        android:padding="5sp"
        android:textColor="@android:color/black"
        android:textSize="10sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        tools:ignore="SmallSp" />
</androidx.constraintlayout.widget.ConstraintLayout>
```

**Note**  
You must provide word mark or text attribution for each data provider that you use, either on your application or your documentation. Attribution strings are included in the style descriptor response under the `sources.esri.attribution`, `sources.here.attribution`, and `source.grabmaptiles.attribution` keys. When using Amazon Location resources with [data providers](https://docs.aws.amazon.com/location/previous/developerguide/what-is-data-provider.html), make sure to read the [service terms and conditions](https://aws.amazon.com/service-terms/).

## Building the application: Request transformation
<a name="tutorial-maplibre-android-request-transformation"></a>

Create a class named `SigV4Interceptor` to intercept AWS requests and sign them using [Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html). This will be registered with the HTTP client used to fetch map resources when the Main Activity is created.

```
package aws.location.demo.okhttp
 
import com.amazonaws.DefaultRequest
import com.amazonaws.auth.AWS4Signer
import com.amazonaws.auth.AWSCredentialsProvider
import com.amazonaws.http.HttpMethodName
import com.amazonaws.util.IOUtils
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import okio.Buffer
import java.io.ByteArrayInputStream
import java.net.URI
 
class SigV4Interceptor(
    private val credentialsProvider: AWSCredentialsProvider,
    private val serviceName: String
) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
 
        if (originalRequest.url().host().contains("amazonaws.com")) {
            val signer = if (originalRequest.url().encodedPath().contains("@")) {
                // the presence of "@" indicates that it doesn't need to be double URL-encoded
                AWS4Signer(false)
            } else {
                AWS4Signer()
            }
 
            val awsRequest = toAWSRequest(originalRequest, serviceName)
            signer.setServiceName(serviceName)
            signer.sign(awsRequest, credentialsProvider.credentials)
 
            return chain.proceed(toSignedOkHttpRequest(awsRequest, originalRequest))
        }
 
        return chain.proceed(originalRequest)
    }
 
    companion object {
        fun toAWSRequest(request: Request, serviceName: String): DefaultRequest<Any> {
            // clone the request (AWS-style) so that it can be populated with credentials
            val dr = DefaultRequest<Any>(serviceName)
 
            // copy request info
            dr.httpMethod = HttpMethodName.valueOf(request.method())
            with(request.url()) {
                dr.resourcePath = uri().path
                dr.endpoint = URI.create("${scheme()}://${host()}")
 
                // copy parameters
                for (p in queryParameterNames()) {
                    if (p != "") {
                        dr.addParameter(p, queryParameter(p))
                    }
                }
            }
 
            // copy headers
            for (h in request.headers().names()) {
                dr.addHeader(h, request.header(h))
            }
 
            // copy the request body
            val bodyBytes = request.body()?.let { body ->
                val buffer = Buffer()
                body.writeTo(buffer)
                IOUtils.toByteArray(buffer.inputStream())
            }
 
            dr.content = ByteArrayInputStream(bodyBytes ?: ByteArray(0))
 
            return dr
        }
 
        fun toSignedOkHttpRequest(
            awsRequest: DefaultRequest<Any>,
            originalRequest: Request
        ): Request {
            // copy signed request back into an OkHttp Request
            val builder = Request.Builder()
 
            // copy headers from the signed request
            for ((k, v) in awsRequest.headers) {
                builder.addHeader(k, v)
            }
 
            // start building an HttpUrl
            val urlBuilder = HttpUrl.Builder()
                .host(awsRequest.endpoint.host)
                .scheme(awsRequest.endpoint.scheme)
                .encodedPath(awsRequest.resourcePath)
 
            // copy parameters from the signed request
            for ((k, v) in awsRequest.parameters) {
                urlBuilder.addQueryParameter(k, v)
            }
 
            return builder.url(urlBuilder.build())
                .method(originalRequest.method(), originalRequest.body())
                .build()
        }
    }
}
```

## Building the application: Main activity
<a name="tutorial-maplibre-android-request-main-activity"></a>

The Main Activity is responsible for initializing the views that will be displayed to users. This involves:
+ Instantiating an Amazon Cognito `CredentialsProvider`.
+ Registering the Signature Version 4 interceptor.
+ Configuring the map by pointing it at a map style descriptor, and displaying appropriate attribution.

 `MainActivity` is also responsible for forwarding life cycle events to the map view, allowing it to preserve the active viewport between invocations.

```
package aws.location.demo.maplibre
 
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import aws.location.demo.okhttp.SigV4Interceptor
import com.amazonaws.auth.CognitoCachingCredentialsProvider
import com.amazonaws.regions.Regions
import com.mapbox.mapboxsdk.Mapbox
import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.module.http.HttpRequestUtil
import okhttp3.OkHttpClient
 
private const val SERVICE_NAME = "geo"
 
class MainActivity : AppCompatActivity() {
    private var mapView: MapView? = null
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
 
        // configuration
        val identityPoolId = getString(R.string.identityPoolId)
        val region = getString(R.string.awsRegion)
        val mapName = getString(R.string.mapName)
 
        // Credential initialization
        val credentialProvider = CognitoCachingCredentialsProvider(
            applicationContext,
            identityPoolId,
            Regions.fromName(identityPoolId.split(":").first())
        )
 
        // initialize MapLibre
        Mapbox.getInstance(this, null)
        HttpRequestUtil.setOkHttpClient(
            OkHttpClient.Builder()
                .addInterceptor(SigV4Interceptor(credentialProvider, SERVICE_NAME))
                .build()
        )
 
        // initialize the view
        setContentView(R.layout.activity_main)
 
        // initialize the map view
        mapView = findViewById(R.id.mapView)
        mapView?.onCreate(savedInstanceState)
        mapView?.getMapAsync { map ->
            map.setStyle(
                Style.Builder()
                    .fromUri("https://maps.geo.${region}.amazonaws.com/maps/v0/maps/${mapName}/style-descriptor")
            ) { style ->
                findViewById<TextView>(R.id.attributionView).text = style.sources.first()?.attribution
            }
        }
    }
 
    override fun onStart() {
        super.onStart()
        mapView?.onStart()
    }
 
    override fun onResume() {
        super.onResume()
        mapView?.onResume()
    }
 
    override fun onPause() {
        super.onPause()
        mapView?.onPause()
    }
 
    override fun onStop() {
        super.onStop()
        mapView?.onStop()
    }
 
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        mapView?.onSaveInstanceState(outState)
    }
 
    override fun onLowMemory() {
        super.onLowMemory()
        mapView?.onLowMemory()
    }
 
    override fun onDestroy() {
        super.onDestroy()
        mapView?.onDestroy()
    }
}
```

Running this application displays a full-screen map in the style of your choosing. This sample is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

# Using the MapLibre Native SDK for iOS with Amazon Location Service
<a name="tutorial-maplibre-ios"></a>

Use [MapLibre Native SDK for iOS](https://github.com/maplibre/maplibre-gl-native) to embed client-side maps into iOS applications. 

The MapLibre Native SDK for iOS is a library based on [Mapbox GL Native](https://github.com/mapbox/mapbox-gl-native), and is compatible with the styles and tiles provided by the Amazon Location Service Maps API. You can integrate MapLibre Native SDK for iOS to embed interactive map views with scalable, customizable vector maps into your iOS applications.

This tutorial describes how to integrate the MapLibre Native SDK for iOS with Amazon Location. The sample application for this tutorial is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

## Building the application: Initialization
<a name="tutorial-maplibre-ios-initialization"></a>

To initialize your application:

1. Create a new Xcode project from the **App** template.

1. Select **SwiftUI** for its interface.

1. Select **SwiftUI** application for its Life Cycle.

1. Select **Swift** for its language.

## Adding MapLibre dependencies using Swift Packages
<a name="tutorial-maplibre-add-dependencies"></a>

To add a package dependency to your Xcode project:

1. Navigate to **File** > **Swift Packages** > **Add Package Dependency**.

1. Enter the repository URL: **https://github.com/maplibre/maplibre-gl-native-distribution**
**Note**  
For more information about Swift Packages see [Adding Package Dependencies to Your App](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app) at Apple.com

1. In your terminal, install CocoaPods:

   ```
   sudo gem install cocoapods
   ```

1. Navigate to your application's project directory and initialize the **Podfile** with the CocoaPods package manager:

   ```
   pod init
   ```

1. Open the **Podfile** to add `AWSCore` as a dependency:

   ```
   platform :ios, '12.0'
    
   target 'Amazon Location Service Demo' do
     use_frameworks!
    
     pod 'AWSCore'
   end
   ```

1. Download and install dependencies:

   ```
   pod install --repo-update
   ```

1. Open the Xcode workspace that CocoaPods created:

   ```
   xed .
   ```

## Building the application: Configuration
<a name="tutorial-maplibre-ios-configuration"></a>

Add the following keys and values to **Info.plist** to configure the application:


| Key | Value | 
| --- | --- | 
| AWSRegion | us-east-1 | 
| IdentityPoolId | us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd | 
| MapName | ExampleMap | 

## Building the application: ContentView layout
<a name="tutorial-maplibre-ios-contentview-layout"></a>

To render the map, edit `ContentView.swift`:
+  Add a `MapView` which renders the map.
+ Add a `TextField` which displays attribution. 

This also sets the map's initial center point.

```
import SwiftUI
 
struct ContentView: View {
    @State private var attribution = ""
 
    var body: some View {
        MapView(attribution: $attribution)
            .centerCoordinate(.init(latitude: 49.2819, longitude: -123.1187))
            .zoomLevel(12)
            .edgesIgnoringSafeArea(.all)
            .overlay(
                TextField("", text: $attribution)
                    .disabled(true)
                    .font(.system(size: 12, weight: .light, design: .default))
                    .foregroundColor(.black)
                    .background(Color.init(Color.RGBColorSpace.sRGB, white: 0.5, opacity: 0.5))
                    .cornerRadius(1),
                alignment: .bottomTrailing)
    }
}
 
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```

**Note**  
You must provide word mark or text attribution for each data provider that you use, either on your application or your documentation. Attribution strings are included in the style descriptor response under the `sources.esri.attribution`, `sources.here.attribution`, and `source.grabmaptiles.attribution` keys. When using Amazon Location resources with [data providers](https://docs.aws.amazon.com/location/previous/developerguide/what-is-data-provider.html), make sure to read the [service terms and conditions](https://aws.amazon.com/service-terms/).

## Building the application: Request transformation
<a name="tutorial-maplibre-ios-request-transformation"></a>

Create a new Swift file named `AWSSignatureV4Delegate.swift` containing the following class definition to intercept AWS requests and sign them using [Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html). An instance of this class will be assigned as the offline storage delegate, which is also responsible for rewriting URLs, in the map view.

```
import AWSCore
import Mapbox
 
class AWSSignatureV4Delegate : NSObject, MGLOfflineStorageDelegate {
    private let region: AWSRegionType
    private let identityPoolId: String
    private let credentialsProvider: AWSCredentialsProvider
 
    init(region: AWSRegionType, identityPoolId: String) {
        self.region = region
        self.identityPoolId = identityPoolId
        self.credentialsProvider = AWSCognitoCredentialsProvider(regionType: region, identityPoolId: identityPoolId)
        super.init()
    }
 
    class func doubleEncode(path: String) -> String? {
        return path.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)?
            .addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)
    }
 
    func offlineStorage(_ storage: MGLOfflineStorage, urlForResourceOf kind: MGLResourceKind, with url: URL) -> URL {
        if url.host?.contains("amazonaws.com") != true {
            // not an AWS URL
            return url
        }
 
        // URL-encode spaces, etc.
        let keyPath = String(url.path.dropFirst())
        guard let percentEncodedKeyPath = keyPath.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else {
            print("Invalid characters in path '\(keyPath)'; unsafe to sign")
            return url
        }
 
        let endpoint = AWSEndpoint(region: region, serviceName: "geo", url: url)
        let requestHeaders: [String: String] = ["host": endpoint!.hostName]
 
        // sign the URL
        let task = AWSSignatureV4Signer
            .generateQueryStringForSignatureV4(
                withCredentialProvider: credentialsProvider,
                httpMethod: .GET,
                expireDuration: 60,
                endpoint: endpoint!,
                // workaround for https://github.com/aws-amplify/aws-sdk-ios/issues/3215
                keyPath: AWSSignatureV4Delegate.doubleEncode(path: percentEncodedKeyPath),
                requestHeaders: requestHeaders,
                requestParameters: .none,
                signBody: true)
        task.waitUntilFinished()
 
        if let error = task.error as NSError? {
            print("Error occurred: \(error)")
        }
 
        if let result = task.result {
            var urlComponents = URLComponents(url: (result as URL), resolvingAgainstBaseURL: false)!
            // re-use the original path; workaround for https://github.com/aws-amplify/aws-sdk-ios/issues/3215
            urlComponents.path = url.path
 
            // have Mapbox GL fetch the signed URL
            return (urlComponents.url)!
        }
 
        // fall back to an unsigned URL
        return url
    }
}
```

## Building the application: Map view
<a name="tutorial-maplibre-ios-request-map-view"></a>

The Map View is responsible for initializing an instance of `AWSSignatureV4Delegate` and configuring the underlying `MGLMapView`, which fetches resources and renders the map. It also handles propagating attribution strings from the style descriptor's source back to the `ContentView`.

Create a new Swift file named `MapView.swift` containing the following `struct` definition:

```
import SwiftUI
import AWSCore
import Mapbox
 
struct MapView: UIViewRepresentable {
    @Binding var attribution: String
 
    private var mapView: MGLMapView
    private var signingDelegate: MGLOfflineStorageDelegate
 
    init(attribution: Binding<String>) {
        let regionName = Bundle.main.object(forInfoDictionaryKey: "AWSRegion") as! String
        let identityPoolId = Bundle.main.object(forInfoDictionaryKey: "IdentityPoolId") as! String
        let mapName = Bundle.main.object(forInfoDictionaryKey: "MapName") as! String
 
        let region = (regionName as NSString).aws_regionTypeValue()
 
        // MGLOfflineStorage doesn't take ownership, so this needs to be a member here
        signingDelegate = AWSSignatureV4Delegate(region: region, identityPoolId: identityPoolId)
 
        // register a delegate that will handle SigV4 signing
        MGLOfflineStorage.shared.delegate = signingDelegate
 
        mapView = MGLMapView(
            frame: .zero,
            styleURL: URL(string: "https://maps.geo.\(regionName).amazonaws.com/maps/v0/maps/\(mapName)/style-descriptor"))
 
        _attribution = attribution
    }
 
    func makeCoordinator() -> Coordinator {
        Coordinator($attribution)
    }
 
    class Coordinator: NSObject, MGLMapViewDelegate {
        var attribution: Binding<String>
 
        init(_ attribution: Binding<String>) {
            self.attribution = attribution
        }
 
        func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
            let source = style.sources.first as? MGLVectorTileSource
            let attribution = source?.attributionInfos.first
            self.attribution.wrappedValue = attribution?.title.string ?? ""
        }
    }
 
    // MARK: - UIViewRepresentable protocol
 
    func makeUIView(context: UIViewRepresentableContext<MapView>) -> MGLMapView {
        mapView.delegate = context.coordinator
 
        mapView.logoView.isHidden = true
        mapView.attributionButton.isHidden = true
        return mapView
    }
 
    func updateUIView(_ uiView: MGLMapView, context: UIViewRepresentableContext<MapView>) {
    }
 
    // MARK: - MGLMapView proxy
 
    func centerCoordinate(_ centerCoordinate: CLLocationCoordinate2D) -> MapView {
        mapView.centerCoordinate = centerCoordinate
        return self
    }
 
    func zoomLevel(_ zoomLevel: Double) -> MapView {
        mapView.zoomLevel = zoomLevel
        return self
    }
}
```

Running this application displays a full-screen map in the style of your choosing. This sample is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

# Using the Amplify library with Amazon Location Service
<a name="tutorial-map-amplify"></a>

The following tutorial walks you through using AWS Amplify with Amazon Location. Amplify uses MapLibre GL JS to render maps in your JavaScript-based application.

Amplify is a set of open-source client libraries that provide interfaces to different categories of services, including Amplify Geo, which is powered by Amazon Location Service. [ Learn more about the AWS Amplify Geo JavaScript library](https://docs.amplify.aws/lib/geo/getting-started/q/platform/js/).

**Note**  
This tutorial assumes that you have already followed the steps in [Using maps - To add a map to your application](map-prerequisites.md#create-map-resource).

## Building the application: Scaffolding
<a name="tutorial-map-amplify-scaffolding"></a>

This tutorial creates a web application that uses JavaScript to build a map on an HTML page.

Begin by creating an HTML page (`index.html`) that includes the map's container:
+ Enter a `div` element with an `id` of `map` to apply the map's dimensions to the map view. The dimensions are inherited from the viewport.

```
<html>
  <head>
    <style>
      body { margin: 0; }
      #map { height: 100vh; } /* 100% of viewport height */
    </style>
  </head>

  <body>
    <!-- map container -->
    <div id="map" />
  </body>
</html>
```

## Building the application: Adding dependencies
<a name="tutorial-map-amplify-add-dependencies"></a>

Add the following dependencies to your application: 
+ AWS Amplify map and geo libraries.
+ AWS Amplify core library.
+ AWS Amplify auth library.
+ AWS Amplify stylesheet.

```
<!-- CSS dependencies -->
    <link href="https://cdn.amplify.aws/packages/maplibre-gl/1.15.2/maplibre-gl.css" rel="stylesheet" integrity="sha384-DrPVD9GufrxGb7kWwRv0CywpXTmfvbKOZ5i5pN7urmIThew0zXKTME+gutUgtpeD" crossorigin="anonymous" referrerpolicy="no-referrer"></link>

<!-- JavaScript dependencies -->
    <script src="https://cdn.amplify.aws/packages/maplibre-gl/1.15.2/maplibre-gl.js" integrity="sha384-rwYfkmAOpciZS2bDuwZ/Xa/Gog6jXem8D/whm3wnsZSVFemDDlprcUXHnDDUcrNU" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.amplify.aws/packages/core/4.3.0/aws-amplify-core.min.js" integrity="sha384-7Oh+5w0l7XGyYvSqbKi2Q7SA5K640V5nyW2/LEbevDQEV1HMJqJLA1A00z2hu8fJ" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.amplify.aws/packages/auth/4.3.8/aws-amplify-auth.min.js" integrity="sha384-jfkXCEfYyVmDXYKlgWNwv54xRaZgk14m7sjeb2jLVBtUXCD2p+WU8YZ2mPZ9Xbdw" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.amplify.aws/packages/geo/1.1.0/aws-amplify-geo.min.js" integrity="sha384-TFMTyWuCbiptXTzvOgzJbV8TPUupG1rA1AVrznAhCSpXTIdGw82bGd8RTk5rr3nP" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.amplify.aws/packages/maplibre-gl-js-amplify/1.1.0/maplibre-gl-js-amplify.umd.min.js" integrity="sha384-7/RxWonKW1nM9zCKiwU9x6bkQTjldosg0D1vZYm0Zj+K/vUSnA3sOMhlRRWAtHPi" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
  // application-specific code
</script>
```

This creates an empty page with the map's container. 

## Building the application: Configuration
<a name="tutorial-map-amplify-configuration"></a>

To configure your application using JavaScript:

1. Enter the identifiers of the unauthenticated identity pool that you created in [Using maps - Step 2, Set up authentication](map-prerequisites.md#create-map-resource).

   ```
   // Cognito Identity Pool ID
   const identityPoolId = "region:identityPoolID"; // for example: us-east-1:123example-1234-5678
   // extract the Region from the Identity Pool ID
   const region = identityPoolId.split(":")[0];
   ```

1. Configure AWS Amplify to use the resources you've created, including the identity pool and the Map resource (shown here with the default name of `explore.map`).

   ```
   // Configure Amplify
   const { Amplify } = aws_amplify_core;
   const { createMap } = AmplifyMapLibre;
   
   Amplify.configure({
     Auth: {
       identityPoolId,
       region,
     },
     geo: {
       AmazonLocationService: {
         maps: {
           items: {
             "explore.map": {
               style: "Default style"
             },
           },
           default: "explore.map",
         },
         region,
       },
     }
   });
   ```

## Building the application: Map initialization
<a name="tutorial-map-amplify-request-map-init"></a>

For the map to display after the page is loaded, you must initialize the map. You can adjust the initial map location, add additional controls, and overlay data.

```
async function initializeMap() {
  const map = await createMap(
    {
      container: "map",
      center: [-123.1187, 49.2819],
      zoom: 10,
      hash: true,
    }
  );

  map.addControl(new maplibregl.NavigationControl(), "top-left");
}

initializeMap();
```

**Note**  
You must provide word mark or text attribution for each data provider that you use, either on your application or your documentation. Attribution strings are included in the style descriptor response under the `sources.esri.attribution`, `sources.here.attribution`, and `sources.grabmaptiles.attribution` keys. Amplify will automatically provide attribution. When using Amazon Location resources with [data providers](https://docs.aws.amazon.com/location/previous/developerguide/what-is-data-provider.html), make sure to read the [service terms and conditions](https://aws.amazon.com/service-terms/).

## Running the application
<a name="tutorial-map-amplify-writing-js"></a>

You can run this sample application by using it in a local web server, or opening it in a browser.

To use a local web server, you can use npx, installed as part of Node.js, or any other web server of your choice. To use npx, type `npx serve` from within the same directory as `index.html`. This serves the application on `localhost:5000`.

**Note**  
If the policy that you created for your unauthenticated Amazon Cognito role includes a `referer` condition, you might be blocked from testing with `localhost:` URLs. In this case. you can test with a web server that provides a URL that is in your policy.

After completing the tutorial, the final application looks like the following example.

```
<html>
  <head>
    <!-- CSS dependencies -->
    <link href="https://cdn.amplify.aws/packages/maplibre-gl/1.15.2/maplibre-gl.css" rel="stylesheet" integrity="sha384-DrPVD9GufrxGb7kWwRv0CywpXTmfvbKOZ5i5pN7urmIThew0zXKTME+gutUgtpeD" crossorigin="anonymous" referrerpolicy="no-referrer"></link>

    <!-- JavaScript dependencies -->
    <script src="https://cdn.amplify.aws/packages/maplibre-gl/1.15.2/maplibre-gl.js" integrity="sha384-rwYfkmAOpciZS2bDuwZ/Xa/Gog6jXem8D/whm3wnsZSVFemDDlprcUXHnDDUcrNU" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.amplify.aws/packages/core/4.3.0/aws-amplify-core.min.js" integrity="sha384-7Oh+5w0l7XGyYvSqbKi2Q7SA5K640V5nyW2/LEbevDQEV1HMJqJLA1A00z2hu8fJ" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.amplify.aws/packages/auth/4.3.8/aws-amplify-auth.min.js" integrity="sha384-jfkXCEfYyVmDXYKlgWNwv54xRaZgk14m7sjeb2jLVBtUXCD2p+WU8YZ2mPZ9Xbdw" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.amplify.aws/packages/geo/1.1.0/aws-amplify-geo.min.js" integrity="sha384-TFMTyWuCbiptXTzvOgzJbV8TPUupG1rA1AVrznAhCSpXTIdGw82bGd8RTk5rr3nP" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.amplify.aws/packages/maplibre-gl-js-amplify/1.1.0/maplibre-gl-js-amplify.umd.min.js" integrity="sha384-7/RxWonKW1nM9zCKiwU9x6bkQTjldosg0D1vZYm0Zj+K/vUSnA3sOMhlRRWAtHPi" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

    <style>
      body { margin: 0; }
      #map { height: 100vh; }
    </style>
  </head>

  <body>
    <div id="map" />
    <script type="module">
      // Cognito Identity Pool ID
      const identityPoolId = "region:identityPoolId"; // for example: us-east-1:123example-1234-5678
      // extract the Region from the Identity Pool ID
      const region = identityPoolId.split(":")[0];

      // Configure Amplify
      const { Amplify } = aws_amplify_core;
      const { createMap } = AmplifyMapLibre;

      Amplify.configure({
        Auth: {
          identityPoolId,
          region,
        },
        geo: {
          AmazonLocationService: {
            maps: {
              items: {
                "explore.map": {
                  style: "Default style"
                },
              },
              default: "explore.map",
            },
            region,
          },
        }
      });

      async function initializeMap() {
        const map = await createMap(
          {
            container: "map",
            center: [-123.1187, 49.2819],
            zoom: 10,
            hash: true,
          }
        );

        map.addControl(new maplibregl.NavigationControl(), "top-left");
      }

      initializeMap();
    </script>
  </body>
</html>
```

Running this application displays a full-screen map using your chosen map style. This sample is also described on the **Embed map** tab of any Map resource page in the [Amazon Location Service console](https://console.aws.amazon.com/location/maps/home).

After you complete this tutorial, go to the [ Display a map](https://docs.amplify.aws/lib/geo/maps/q/platform/js#display-a-map) topic in the AWS Amplify documentation to learn more, including how to display markers on the map.

# Tutorial: using Tangram with Amazon Location Service
<a name="tutorial-tangram"></a>

This section provides the following tutorials on how to integrate Tangram with Amazon Location. 

**Important**  
The Tangram styles in the following tutorials are only compatible with Amazon Location map resources configured with the `VectorHereContrast` style.

The following is an example of an AWS CLI command to create a new map resource called *TangramExampleMap* using the *VectorHereContrast* style:

```
aws --region us-east-1 \
  location \
  create-map \
  --map-name "TangramExampleMap" \
  --configuration "Style=VectorHereContrast"
```

**Note**  
Billing is determined by your usage. You may incur fees for the use of other AWS services. For more information, see [Amazon Location Service pricing](https://aws.amazon.com/location/pricing/).

**Topics**
+ [Using Tangram with Amazon Location Service](tutorial-tangram-js.md)
+ [Using Tangram ES for Android with Amazon Location Service](tutorial-tangram-es-android.md)
+ [Using Tangram ES for iOS with Amazon Location Service](tutorial-tangram-es-ios.md)

# Using Tangram with Amazon Location Service
<a name="tutorial-tangram-js"></a>

[Tangram](https://tangrams.readthedocs.io/) is a flexible mapping engine, designed for real-time rendering of 2D and 3D maps from vector tiles. It can be used with Mapzen-designed styles and the HERE tiles provided by the Amazon Location Service Maps API. This guide describes how to integrate Tangram with Amazon Location within a basic HTML/JavaScript application, although the same libraries and techniques also apply when using frameworks like React and Angular.

Tangram is built atop [Leaflet](https://leafletjs.com/), an open-source JavaScript library for mobile-friendly interactive maps. This means that many Leaflet-compatible plugins and controls also work with Tangram.

Tangram styles built to work with the [Tilezen schema](https://tilezen.readthedocs.io/en/latest/layers/) are largely compatible with Amazon Location when using maps from HERE. These include:
+ [Bubble Wrap](https://github.com/tangrams/bubble-wrap) – A full-featured wayfinding style with helpful icons for points of interest
+ [Cinnabar](https://github.com/tangrams/cinnabar-style) – A classic look and go-to for general mapping applications
+ [Refill ](https://github.com/tangrams/refill-style) – A minimalist map style designed for data visualization overlays, inspired by the seminal Toner style by Stamen Design
+ [Tron](https://github.com/tangrams/tron-style) – An exploration of scale transformations in the visual language of TRON
+ [Walkabout ](https://github.com/tangrams/walkabout-style) – An outdoor-focused style that's perfect for hiking or getting out and about

This guide describes how to integrate Tangram with Amazon Location within a basic HTML/JavaScript application using the Tangram Style called [Bubble Wrap](https://github.com/tangrams/bubble-wrap). This sample is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

While other Tangram styles are best accompanied by raster tiles, which encode terrain information, this feature is not yet supported by Amazon Location.

**Important**  
The Tangram styles in the following tutorial are only compatible with Amazon Location map resources configured with the `VectorHereContrast` style.

## Building the application: Scaffolding
<a name="tutorial-tangram-js-scaffolding"></a>

The application is an HTML page with JavaScript to build the map on your web application. Create an HTML page (`index.html`) and create the map's container: 
+ Enter a `div` element with an `id` of map to apply the map's dimensions to the map view. 
+ The dimensions are inherited from the viewport.

```
<html>
  <head>
    <style>
      body {
        margin: 0;
      }
 
      #map {
        height: 100vh; /* 100% of viewport height */
      }
    </style>
  </head>
  <body>
    <!-- map container -->
    <div id="map" />
  </body>
</html>
```

## Building the application: Adding dependencies
<a name="tutorial-tangram-js-add-dependencies"></a>

Add the following dependencies: 
+ Leaflet and its associated CSS.
+ Tangram.
+ AWS SDK for JavaScript.

```
<!-- CSS dependencies -->
<link
  rel="stylesheet"
  href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
  integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
  crossorigin=""
/>
<!-- JavaScript dependencies -->
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<script src="https://unpkg.com/tangram"></script>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.784.0.min.js"></script>
<script>
  // application-specific code
</script>
```

This creates an empty page with the necessary prerequisites. The next step guides you through writing the JavaScript code for your application. 

## Building the application: Configuration
<a name="tutorial-tangram-js-configuration"></a>

To configure your application with your resources and credentials:

1. Enter the names and identifiers of your resources.

   ```
   // Cognito Identity Pool ID
   const identityPoolId = "us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd";
   // Amazon Location Service map name; must be HERE-backed
   const mapName = "TangramExampleMap";
   ```

1. Instantiate a credential provider using the unauthenticated identity pool you created in [Using maps - Step 2, Set up authentication](map-prerequisites.md#using-maps-set-up-authentication). Since this uses credentials outside the normal AWS SDK work flow, sessions expire after **one** hour.

   ```
   // extract the region from the Identity Pool ID; this will be used for both Amazon Cognito and Amazon Location
   AWS.config.region = identityPoolId.split(":", 1)[0];
    
   // instantiate a Cognito-backed credential provider
   const credentials = new AWS.CognitoIdentityCredentials({
     IdentityPoolId: identityPoolId,
   });
   ```

1. While Tangram allows you to override the URL(s) used to fetch tiles, it doesn't include the ability to intercept requests so that they can be signed. 

   To work around this, override `sources.mapzen.url` to point to Amazon Location using a synthetic host name `amazon.location`, which will be handled by a [service worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). The following is an example of scene configuration using [Bubble Wrap](https://github.com/tangrams/bubble-wrap):

   ```
   const scene = {
     import: [
       // Bubble Wrap style
       "https://www.nextzen.org/carto/bubble-wrap-style/10/bubble-wrap-style.zip",
       "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/label-7.zip",
       "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/bubble-wrap-road-shields-usa.zip",
       "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/bubble-wrap-road-shields-international.zip",
     ],
     // override values beneath the `sources` key in the style above
     sources: {
       mapzen: {
         // point at Amazon Location using a synthetic URL, which will be handled by the service
         // worker
         url: `https://amazon.location/${mapName}/{z}/{x}/{y}`,
       },
       // effectively disable raster tiles containing encoded normals
       normals: {
         max_zoom: 0,
       },
       "normals-elevation": {
         max_zoom: 0,
       },
     },
   };
   ```

## Building the application: Request transformation
<a name="tutorial-tangram-js-request-transformation"></a>

To register and initialize the service worker, create a `registerServiceWorker` function to be called before the map is initialized. This registers the JavaScript code provided in a separate file called `sw.js` as the service worker controlling `index.html`. 

Credentials are loaded from Amazon Cognito and are passed into the service worker alongside the Region to provide information to sign tile requests with [Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html). 

```
/**
 * Register a service worker that will rewrite and sign requests using Signature Version 4.
 */
async function registerServiceWorker() {
  if ("serviceWorker" in navigator) {
    try {
      const reg = await navigator.serviceWorker.register("./sw.js");
 
      // refresh credentials from Amazon Cognito
      await credentials.refreshPromise();
 
      await reg.active.ready;
 
      if (navigator.serviceWorker.controller == null) {
        // trigger a navigate event to active the controller for this page
        window.location.reload();
      }
 
      // pass credentials to the service worker
      reg.active.postMessage({
        credentials: {
          accessKeyId: credentials.accessKeyId,
          secretAccessKey: credentials.secretAccessKey,
          sessionToken: credentials.sessionToken,
        },
        region: AWS.config.region,
      });
    } catch (error) {
      console.error("Service worker registration failed:", error);
    }
  } else {
    console.warn("Service worker support is required for this example");
  }
}
```

The Service Worker implementation in `sw.js` listens for `message` events to pick up credential and Region configuration changes. It also acts as a proxy server by listening for `fetch` events. `fetch` events targeting the `amazon.location` synthetic host name will be rewritten to target the appropriate Amazon Location API and signed using Amplify Core's `Signer`.

```
// sw.js
self.importScripts(
  "https://unpkg.com/@aws-amplify/core@3.7.0/dist/aws-amplify-core.min.js"
);
 
const { Signer } = aws_amplify_core;
 
let credentials;
let region;
 
self.addEventListener("install", (event) => {
  // install immediately
  event.waitUntil(self.skipWaiting());
});
 
self.addEventListener("activate", (event) => {
  // control clients ASAP
  event.waitUntil(self.clients.claim());
});
 
self.addEventListener("message", (event) => {
  const {
    data: { credentials: newCredentials, region: newRegion },
  } = event;
 
  if (newCredentials != null) {
    credentials = newCredentials;
  }
 
  if (newRegion != null) {
    region = newRegion;
  }
});
 
async function signedFetch(request) {
  const url = new URL(request.url);
  const path = url.pathname.slice(1).split("/");
 
  // update URL to point to Amazon Location
  url.pathname = `/maps/v0/maps/${path[0]}/tiles/${path.slice(1).join("/")}`;
  url.host = `maps.geo.${region}.amazonaws.com`;
  // strip params (Tangram generates an empty api_key param)
  url.search = "";
 
  const signed = Signer.signUrl(url.toString(), {
    access_key: credentials.accessKeyId,
    secret_key: credentials.secretAccessKey,
    session_token: credentials.sessionToken,
  });
 
  return fetch(signed);
}
 
self.addEventListener("fetch", (event) => {
  const { request } = event;
 
  // match the synthetic hostname we're telling Tangram to use
  if (request.url.includes("amazon.location")) {
    return event.respondWith(signedFetch(request));
  }
 
  // fetch normally
  return event.respondWith(fetch(request));
});
```

To automatically renew credentials and send them to the service worker before they expire, use the following function within `index.html`:

```
async function refreshCredentials() {
  await credentials.refreshPromise();
 
  if ("serviceWorker" in navigator) {
    const controller = navigator.serviceWorker.controller;
 
    controller.postMessage({
      credentials: {
        accessKeyId: credentials.accessKeyId,
        secretAccessKey: credentials.secretAccessKey,
        sessionToken: credentials.sessionToken,
      },
    });
  } else {
    console.warn("Service worker support is required for this example.");
  }
 
  // schedule the next credential refresh when they're about to expire
  setTimeout(refreshCredentials, credentials.expireTime - new Date());
}
```

## Building the application: Map initialization
<a name="tutorial-tangram-js-request-map-init"></a>

For the map to display after the page is loaded, you must initialize the map. You have the option to adjust the initial map location, add additional controls, and overlay data. 

**Note**  
You must provide word mark or text attribution for each data provider that you use, either on your application or your documentation. Attribution strings are included in the style descriptor response under the `sources.esri.attribution`, `sources.here.attribution`, and `source.grabmaptiles.attribution` keys.   
Because Tangram doesn't request these resources, and is only compatible with maps from HERE, use "© 2020 HERE". When using Amazon Location resources with [data providers](https://docs.aws.amazon.com/location/previous/developerguide/what-is-data-provider.html), make sure to read the [service terms and conditions](https://aws.amazon.com/service-terms/).

```
/**
 * Initialize a map.
 */
async function initializeMap() {
  // register the service worker to handle requests to https://amazon.location
  await registerServiceWorker();
 
  // Initialize the map
  const map = L.map("map").setView([49.2819, -123.1187], 10);
  Tangram.leafletLayer({
    scene,
  }).addTo(map);
  map.attributionControl.setPrefix("");
  map.attributionControl.addAttribution("© 2020 HERE");
}
 
initializeMap();
```

## Running the application
<a name="tutorial-tangram-js-writing-js"></a>

To run this sample, you can:
+ Use a host that supports HTTPS, 
+ Use a local web server to comply with service worker security restrictions.

To use a local web server, you can use npx, because it's installed as a part of Node.js. You can use `npx serve` from within the same directory as `index.html` and `sw.js`. This serves the application on [localhost:5000](http://localhost:5000/).

The following is the `index.html` file:

```
<!-- index.html -->
<html>
  <head>
    <link
      rel="stylesheet"
      href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
      integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
      crossorigin=""
    />
    <style>
      body {
        margin: 0;
      }
 
      #map {
        height: 100vh;
      }
    </style>
  </head>
 
  <body>
    <div id="map" />
    <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
    <script src="https://unpkg.com/tangram"></script>
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.784.0.min.js"></script>
    <script>
      // configuration
      // Cognito Identity Pool ID
      const identityPoolId = "<Identity Pool ID>";
      // Amazon Location Service Map name; must be HERE-backed
      const mapName = "<Map name>";
 
      AWS.config.region = identityPoolId.split(":")[0];
 
      // instantiate a credential provider
      credentials = new AWS.CognitoIdentityCredentials({
        IdentityPoolId: identityPoolId,
      });
 
      const scene = {
        import: [
          // Bubble Wrap style
          "https://www.nextzen.org/carto/bubble-wrap-style/10/bubble-wrap-style.zip",
          "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/label-7.zip",
          "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/bubble-wrap-road-shields-usa.zip",
          "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/bubble-wrap-road-shields-international.zip",
        ],
        // override values beneath the `sources` key in the style above
        sources: {
          mapzen: {
            // point at Amazon Location using a synthetic URL, which will be handled by the service
            // worker
            url: `https://amazon.location/${mapName}/{z}/{x}/{y}`,
          },
          // effectively disable raster tiles containing encoded normals
          normals: {
            max_zoom: 0,
          },
          "normals-elevation": {
            max_zoom: 0,
          },
        },
      };
 
      /**
       * Register a service worker that will rewrite and sign requests using Signature Version 4.
       */
      async function registerServiceWorker() {
        if ("serviceWorker" in navigator) {
          try {
            const reg = await navigator.serviceWorker.register("./sw.js");
 
            // refresh credentials from Amazon Cognito
            await credentials.refreshPromise();
 
            await reg.active.ready;
 
            if (navigator.serviceWorker.controller == null) {
              // trigger a navigate event to active the controller for this page
              window.location.reload();
            }
 
            // pass credentials to the service worker
            reg.active.postMessage({
              credentials: {
                accessKeyId: credentials.accessKeyId,
                secretAccessKey: credentials.secretAccessKey,
                sessionToken: credentials.sessionToken,
              },
              region: AWS.config.region,
            });
          } catch (error) {
            console.error("Service worker registration failed:", error);
          }
        } else {
          console.warn("Service Worker support is required for this example");
        }
      }
 
      /**
       * Initialize a map.
       */
      async function initializeMap() {
        // register the service worker to handle requests to https://amazon.location
        await registerServiceWorker();
 
        // Initialize the map
        const map = L.map("map").setView([49.2819, -123.1187], 10);
        Tangram.leafletLayer({
          scene,
        }).addTo(map);
        map.attributionControl.setPrefix("");
        map.attributionControl.addAttribution("© 2020 HERE");
      }
 
      initializeMap();
    </script>
  </body>
</html>
```

The following is the `sw.js` file:

```
// sw.js
self.importScripts(
  "https://unpkg.com/@aws-amplify/core@3.7.0/dist/aws-amplify-core.min.js"
);
 
const { Signer } = aws_amplify_core;
 
let credentials;
let region;
 
self.addEventListener("install", (event) => {
  // install immediately
  event.waitUntil(self.skipWaiting());
});
 
self.addEventListener("activate", (event) => {
  // control clients ASAP
  event.waitUntil(self.clients.claim());
});
 
self.addEventListener("message", (event) => {
  const {
    data: { credentials: newCredentials, region: newRegion },
  } = event;
 
  if (newCredentials != null) {
    credentials = newCredentials;
  }
 
  if (newRegion != null) {
    region = newRegion;
  }
});
 
async function signedFetch(request) {
  const url = new URL(request.url);
  const path = url.pathname.slice(1).split("/");
 
  // update URL to point to Amazon Location
  url.pathname = `/maps/v0/maps/${path[0]}/tiles/${path.slice(1).join("/")}`;
  url.host = `maps.geo.${region}.amazonaws.com`;
  // strip params (Tangram generates an empty api_key param)
  url.search = "";
 
  const signed = Signer.signUrl(url.toString(), {
    access_key: credentials.accessKeyId,
    secret_key: credentials.secretAccessKey,
    session_token: credentials.sessionToken,
  });
 
  return fetch(signed);
}
 
self.addEventListener("fetch", (event) => {
  const { request } = event;
 
  // match the synthetic hostname we're telling Tangram to use
  if (request.url.includes("amazon.location")) {
    return event.respondWith(signedFetch(request));
  }
 
  // fetch normally
  return event.respondWith(fetch(request));
});
```

 This sample is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

# Using Tangram ES for Android with Amazon Location Service
<a name="tutorial-tangram-es-android"></a>

[Tangram ES](https://github.com/tangrams/tangram-es) is a C\$1\$1 library for rendering 2D and 3D maps from vector data using OpenGL ES. It's the native counterpart to [Tangram](https://github.com/tangrams/tangram).

Tangram styles built to work with the [Tilezen schema](https://tilezen.readthedocs.io/en/latest/layers/) are largely compatible with Amazon Location when using maps from HERE. These include:
+ [Bubble Wrap](https://github.com/tangrams/bubble-wrap) – A full-featured wayfinding style with helpful icons for points of interest.
+ [Cinnabar](https://github.com/tangrams/cinnabar-style) – A classic look and go-to for general mapping applications.
+ [Refill ](https://github.com/tangrams/refill-style)– A minimalist map style designed for data visualization overlays, inspired by the seminal Toner style by Stamen Design.
+ [Tron](https://github.com/tangrams/tron-style) – An exploration of scale transformations in the visual language of TRON.
+ [Walkabout ](https://github.com/tangrams/walkabout-style)– An outdoor-focused style that's perfect for hiking or getting out and about.

This guide describes how to integrate Tangram ES for Android with Amazon Location using the Tangram style called Cinnabar. This sample is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

While other Tangram styles are best accompanied by raster tiles, which encode terrain information, this feature isn't yet supported by Amazon Location.

**Important**  
The Tangram styles in the following tutorial are only compatible with Amazon Location map resources configured with the `VectorHereContrast` style.

## Building the application: Initialization
<a name="tutorial-tangram-es-android-initialization"></a>

To initialize your application:

1. Create a new Android Studio project from the **Empty Activity** template.

1. Ensure that **Kotlin** is selected for the project language.

1. Select a **Minimum SDK of API 16: Android 4.1 (Jelly Bean)** or newer.

1. Open **Project Structure** to select **File**, **Project Structure...**, and choose the **Dependencies** section.

1. With **<All Modules>** selected, choose the **\$1** button to add a new **Library Dependency**.

1. Add **AWS Android SDK** version 2.19.1 or later. For example: `com.amazonaws:aws-android-sdk-core:2.19.1`

1. Add **Tangram** version 0.13.0 or later. For example: `com.mapzen.tangram:tangram:0.13.0`. 
**Note**  
Searching for **Tangram**: `com.mapzen.tangram:tangram:0.13.0` will generate a message that it's "not found", but choosing **OK** will allow it to be added.

## Building the application: Configuration
<a name="tutorial-tangram-es-android-configuration"></a>

To configure your application with your resources and AWS Region:

1. Create `app/src/main/res/values/configuration.xml`.

1. Enter the names and identifiers of your resources, and also the AWS Region they were created in:

```
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="identityPoolId">us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd</string>
    <string name="mapName">TangramExampleMap</string>
    <string name="awsRegion">us-east-1</string>
    <string name="sceneUrl">https://www.nextzen.org/carto/cinnabar-style/9/cinnabar-style.zip</string>
    <string name="attribution">© 2020 HERE</string>
</resources>
```

## Building the application: Activity layout
<a name="tutorial-tangram-es-android-activity-layout"></a>

Edit `app/src/main/res/layout/activity_main.xml`:
+ Add a `MapView`, which renders the map. This will also set the map's initial center point. 
+ Add a `TextView`, which displays attribution. 

This will also set the map's initial center point.

**Note**  
You must provide word mark or text attribution for each data provider that you use, either on your application or your documentation. Attribution strings are included in the style descriptor response under the `sources.esri.attribution`, `sources.here.attribution`, and `source.grabmaptiles.attribution` keys.   
Because Tangram doesn't request these resources, and is only compatible with maps from HERE, use "© 2020 HERE". When using Amazon Location resources with [data providers](https://docs.aws.amazon.com/location/previous/developerguide/what-is-data-provider.html), make sure to read the [service terms and conditions](https://aws.amazon.com/service-terms/).

```
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
    <com.mapzen.tangram.MapView
        android:id="@+id/map"
        android:layout_height="match_parent"
        android:layout_width="match_parent" />
 
    <TextView
        android:id="@+id/attributionView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#80808080"
        android:padding="5sp"
        android:textColor="@android:color/black"
        android:textSize="10sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        tools:ignore="SmallSp" />
</androidx.constraintlayout.widget.ConstraintLayout>
```

## Building the application: Request transformation
<a name="tutorial-tangram-es-android-request-transformation"></a>

Create a class named `SigV4Interceptor` to intercept AWS requests and sign them using [Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html). This will be registered with the HTTP client used to fetch map resources when the Main Activity is created.

```
package aws.location.demo.okhttp
 
import com.amazonaws.DefaultRequest
import com.amazonaws.auth.AWS4Signer
import com.amazonaws.auth.AWSCredentialsProvider
import com.amazonaws.http.HttpMethodName
import com.amazonaws.util.IOUtils
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import okio.Buffer
import java.io.ByteArrayInputStream
import java.net.URI
 
class SigV4Interceptor(
    private val credentialsProvider: AWSCredentialsProvider,
    private val serviceName: String
) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
 
        if (originalRequest.url().host().contains("amazonaws.com")) {
            val signer = if (originalRequest.url().encodedPath().contains("@")) {
                // the presence of "@" indicates that it doesn't need to be double URL-encoded
                AWS4Signer(false)
            } else {
                AWS4Signer()
            }
 
            val awsRequest = toAWSRequest(originalRequest, serviceName)
            signer.setServiceName(serviceName)
            signer.sign(awsRequest, credentialsProvider.credentials)
 
            return chain.proceed(toSignedOkHttpRequest(awsRequest, originalRequest))
        }
 
        return chain.proceed(originalRequest)
    }
 
    companion object {
        fun toAWSRequest(request: Request, serviceName: String): DefaultRequest<Any> {
            // clone the request (AWS-style) so that it can be populated with credentials
            val dr = DefaultRequest<Any>(serviceName)
 
            // copy request info
            dr.httpMethod = HttpMethodName.valueOf(request.method())
            with(request.url()) {
                dr.resourcePath = uri().path
                dr.endpoint = URI.create("${scheme()}://${host()}")
 
                // copy parameters
                for (p in queryParameterNames()) {
                    if (p != "") {
                        dr.addParameter(p, queryParameter(p))
                    }
                }
            }
 
            // copy headers
            for (h in request.headers().names()) {
                dr.addHeader(h, request.header(h))
            }
 
            // copy the request body
            val bodyBytes = request.body()?.let { body ->
                val buffer = Buffer()
                body.writeTo(buffer)
                IOUtils.toByteArray(buffer.inputStream())
            }
 
            dr.content = ByteArrayInputStream(bodyBytes ?: ByteArray(0))
 
            return dr
        }
 
        fun toSignedOkHttpRequest(
            awsRequest: DefaultRequest<Any>,
            originalRequest: Request
        ): Request {
            // copy signed request back into an OkHttp Request
            val builder = Request.Builder()
 
            // copy headers from the signed request
            for ((k, v) in awsRequest.headers) {
                builder.addHeader(k, v)
            }
 
            // start building an HttpUrl
            val urlBuilder = HttpUrl.Builder()
                .host(awsRequest.endpoint.host)
                .scheme(awsRequest.endpoint.scheme)
                .encodedPath(awsRequest.resourcePath)
 
            // copy parameters from the signed request
            for ((k, v) in awsRequest.parameters) {
                urlBuilder.addQueryParameter(k, v)
            }
 
            return builder.url(urlBuilder.build())
                .method(originalRequest.method(), originalRequest.body())
                .build()
        }
    }
}
```

## Building the application: Main activity
<a name="tutorial-tangram-es-android-request-main-activity"></a>

The Main Activity is responsible for initializing the views that will be displayed to users. This involves:
+ Instantiating an Amazon Cognito `CredentialsProvider`.
+ Registering the Signature Version 4 interceptor.
+ Configuring the map by pointing it at a map style, overriding tile URLs, and displaying appropriate attribution. 

`MainActivity` is also responsible for forwarding life cycle events to the map view.

```
package aws.location.demo.tangram
 
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import aws.location.demo.okhttp.SigV4Interceptor
import com.amazonaws.auth.CognitoCachingCredentialsProvider
import com.amazonaws.regions.Regions
import com.mapzen.tangram.*
import com.mapzen.tangram.networking.DefaultHttpHandler
import com.mapzen.tangram.networking.HttpHandler
 
private const val SERVICE_NAME = "geo"
 
class MainActivity : AppCompatActivity(), MapView.MapReadyCallback {
    private var mapView: MapView? = null
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
 
        setContentView(R.layout.activity_main)
 
        mapView = findViewById(R.id.map)
 
        mapView?.getMapAsync(this, getHttpHandler())
        findViewById<TextView>(R.id.attributionView).text = getString(R.string.attribution)
    }
 
    override fun onMapReady(mapController: MapController?) {
        val sceneUpdates = arrayListOf(
            SceneUpdate(
                "sources.mapzen.url",
                "https://maps.geo.${getString(R.string.awsRegion)}.amazonaws.com/maps/v0/maps/${
                    getString(
                        R.string.mapName
                    )
                }/tiles/{z}/{x}/{y}"
            )
        )
 
        mapController?.let { map ->
            map.updateCameraPosition(
                CameraUpdateFactory.newLngLatZoom(
                    LngLat(-123.1187, 49.2819),
                    12F
                )
            )
            map.loadSceneFileAsync(
                getString(R.string.sceneUrl),
                sceneUpdates
            )
        }
    }
 
    private fun getHttpHandler(): HttpHandler {
        val builder = DefaultHttpHandler.getClientBuilder()
 
        val credentialsProvider = CognitoCachingCredentialsProvider(
            applicationContext,
            getString(R.string.identityPoolId),
            Regions.US_EAST_1
        )
 
        return DefaultHttpHandler(
            builder.addInterceptor(
                SigV4Interceptor(
                    credentialsProvider,
                    SERVICE_NAME
                )
            )
        )
    }
 
    override fun onResume() {
        super.onResume()
        mapView?.onResume()
    }
 
    override fun onPause() {
        super.onPause()
        mapView?.onPause()
    }
 
    override fun onLowMemory() {
        super.onLowMemory()
        mapView?.onLowMemory()
    }
 
    override fun onDestroy() {
        super.onDestroy()
        mapView?.onDestroy()
    }
}
```

Running this application displays a full-screen map in the style of your choosing. This sample is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

# Using Tangram ES for iOS with Amazon Location Service
<a name="tutorial-tangram-es-ios"></a>

[Tangram ES](https://github.com/tangrams/tangram-es) is a C\$1\$1 library for rendering 2D and 3D maps from vector data using OpenGL ES. It's the native counterpart to [Tangram](https://github.com/tangrams/tangram).

Tangram styles built to work with the [Tilezen schema](https://tilezen.readthedocs.io/en/latest/layers/) are largely compatible with Amazon Location when using maps from HERE. These include:
+ [Bubble Wrap](https://github.com/tangrams/bubble-wrap) – A full-featured wayfinding style with helpful icons for points of interest
+ [Cinnabar](https://github.com/tangrams/cinnabar-style) – A classic look and go-to for general mapping applications
+ [Refill ](https://github.com/tangrams/refill-style)– A minimalist map style designed for data visualization overlays, inspired by the seminal Toner style by Stamen Design
+ [Tron](https://github.com/tangrams/tron-style) – An exploration of scale transformations in the visual language of TRON
+ [Walkabout](https://github.com/tangrams/walkabout-style) – An outdoor-focused style that's perfect for hiking or getting out and about

This guide describes how to integrate Tangram ES for iOS with Amazon Location using the Tangram style called Cinnabar. This sample is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

While other Tangram styles are best accompanied by raster tiles, which encode terrain information, this feature isn't yet supported by Amazon Location. 

**Important**  
The Tangram styles in the following tutorial are only compatible with Amazon Location map resources configured with the `VectorHereContrast` style.

## Building the application: Initialization
<a name="tutorial-tangram-es-ios-initialization"></a>

To initialize the application:

1. Create a new Xcode project from the **App** template.

1. Select **SwiftUI** for its interface.

1. Select **SwiftUI** application for its Life Cycle.

1. Select **Swift** for its language.

## Building the application: Add dependencies
<a name="tutorial-tangram-es-ios-add-dependencies"></a>

To add dependencies, you can use a dependency manager, such as [CocoaPods](https://cocoapods.org/): 

1. In your terminal, install CocoaPods:

   ```
   sudo gem install cocoapods
   ```

1. Navigate to your application's project directory and initialize the **Podfile** with the CocoaPods package manager:

   ```
   pod init
   ```

1. Open the **Podfile** to add `AWSCore` and `Tangram-es` as dependencies:

   ```
   platform :ios, '12.0'
    
   target 'Amazon Location Service Demo' do
     use_frameworks!
    
     pod 'AWSCore'
     pod 'Tangram-es'
   end
   ```

1. Download and install dependencies:

   ```
   pod install --repo-update
   ```

1. Open the Xcode workspace that CocoaPods created:

   ```
   xed .
   ```

## Building the application: Configuration
<a name="tutorial-tangram-es-ios-configuration"></a>

Add the following keys and values to **Info.plist** to configure the application and disable telemetry:


| Key | Value | 
| --- | --- | 
| AWSRegion | us-east-1 | 
| IdentityPoolId | us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd | 
| MapName | ExampleMap | 
| SceneURL | https://www.nextzen.org/carto/cinnabar-style/9/cinnabar-style.zip | 

## Building the application: ContentView layout
<a name="tutorial-tangram-es-ios-activity-layout"></a>

To render the map, edit `ContentView.swift`:
+  Add a `MapView` which renders the map.
+ Add a `TextField` which displays attribution. 

This also sets the map's initial center point.

**Note**  
You must provide word mark or text attribution for each data provider that you use, either on your application or your documentation. Attribution strings are included in the style descriptor response under the `sources.esri.attribution`, `sources.here.attribution`, and `source.grabmaptiles.attribution` keys. When using Amazon Location resources with [data providers](https://docs.aws.amazon.com/location/previous/developerguide/what-is-data-provider.html), make sure to read the [service terms and conditions](https://aws.amazon.com/service-terms/).

```
import SwiftUI
import TangramMap
 
struct ContentView: View {
    var body: some View {
        MapView()
            .cameraPosition(TGCameraPosition(
                                center: CLLocationCoordinate2DMake(49.2819, -123.1187),
                                zoom: 10,
                                bearing: 0,
                                pitch: 0))
            .edgesIgnoringSafeArea(.all)
            .overlay(
                Text("© 2020 HERE")
                    .disabled(true)
                    .font(.system(size: 12, weight: .light, design: .default))
                    .foregroundColor(.black)
                    .background(Color.init(Color.RGBColorSpace.sRGB, white: 0.5, opacity: 0.5))
                    .cornerRadius(1),
                alignment: .bottomTrailing)
    }
}
 
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```

## Building the application: Request transformation
<a name="tutorial-tangram-es-ios-request-transformation"></a>

Create a new Swift file named `AWSSignatureV4URLHandler.swift` containing the following class definition to intercept AWS requests and sign them using [Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html). This will be registered as a URL handler within the Tangram `MapView`.

```
import AWSCore
import TangramMap
 
class AWSSignatureV4URLHandler: TGDefaultURLHandler {
    private let region: AWSRegionType
    private let identityPoolId: String
    private let credentialsProvider: AWSCredentialsProvider
 
    init(region: AWSRegionType, identityPoolId: String) {
        self.region = region
        self.identityPoolId = identityPoolId
        self.credentialsProvider = AWSCognitoCredentialsProvider(regionType: region, identityPoolId: identityPoolId)
        super.init()
    }
 
    override func downloadRequestAsync(_ url: URL, completionHandler: @escaping TGDownloadCompletionHandler) -> UInt {
        if url.host?.contains("amazonaws.com") != true {
            // not an AWS URL
            return super.downloadRequestAsync(url, completionHandler: completionHandler)
        }
 
        // URL-encode spaces, etc.
        let keyPath = String(url.path.dropFirst())
        guard let keyPathSafe = keyPath.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else {
            print("Invalid characters in path '\(keyPath)'; unsafe to sign")
            return super.downloadRequestAsync(url, completionHandler: completionHandler)
        }
 
        // sign the URL
        let endpoint = AWSEndpoint(region: region, serviceName: "geo", url: url)
        let requestHeaders: [String: String] = ["host": endpoint!.hostName]
        let task = AWSSignatureV4Signer
            .generateQueryStringForSignatureV4(
                withCredentialProvider: credentialsProvider,
                httpMethod: .GET,
                expireDuration: 60,
                endpoint: endpoint!,
                keyPath: keyPathSafe,
                requestHeaders: requestHeaders,
                requestParameters: .none,
                signBody: true)
        task.waitUntilFinished()
 
        if let error = task.error as NSError? {
            print("Error occurred: \(error)")
        }
 
        if let result = task.result {
            // have Tangram fetch the signed URL
            return super.downloadRequestAsync(result as URL, completionHandler: completionHandler)
        }
 
        // fall back to an unsigned URL
        return super.downloadRequestAsync(url, completionHandler: completionHandler)
    }
}
```

## Building the application: Map view
<a name="tutorial-tangram-es-ios-request-main-activity"></a>

The map view is responsible for initializing an instance of `AWSSignatureV4Delegate` and configuring the underlying `MGLMapView`, which fetches resources and renders the map. It also handles propagating attribution strings from the style descriptor's source back to the `ContentView`.

Create a new Swift file named `MapView.swift` containing the following `struct` definition:

```
import AWSCore
import TangramMap
import SwiftUI
 
struct MapView: UIViewRepresentable {
    private let mapView: TGMapView
 
    init() {
        let regionName = Bundle.main.object(forInfoDictionaryKey: "AWSRegion") as! String
        let identityPoolId = Bundle.main.object(forInfoDictionaryKey: "IdentityPoolId") as! String
        let mapName = Bundle.main.object(forInfoDictionaryKey: "MapName") as! String
        let sceneURL = URL(string: Bundle.main.object(forInfoDictionaryKey: "SceneURL") as! String)!
 
        let region = (regionName as NSString).aws_regionTypeValue()
 
        // rewrite tile URLs to point at AWS resources
        let sceneUpdates = [
            TGSceneUpdate(path: "sources.mapzen.url",
                          value: "https://maps.geo.\(regionName).amazonaws.com/maps/v0/maps/\(mapName)/tiles/{z}/{x}/{y}")]
 
        // instantiate a TGURLHandler that will sign AWS requests
        let urlHandler = AWSSignatureV4URLHandler(region: region, identityPoolId: identityPoolId)
 
        // instantiate the map view and attach the URL handler
        mapView = TGMapView(frame: .zero, urlHandler: urlHandler)
 
        // load the map style and apply scene updates (properties modified at runtime)
        mapView.loadScene(from: sceneURL, with: sceneUpdates)
    }
 
    func cameraPosition(_ cameraPosition: TGCameraPosition) -> MapView {
        mapView.cameraPosition = cameraPosition
 
        return self
    }
 
    // MARK: - UIViewRepresentable protocol
 
    func makeUIView(context: Context) -> TGMapView {
        return mapView
    }
 
    func updateUIView(_ uiView: TGMapView, context: Context) {
    }
}
```

Running this application displays a full-screen map in the style of your choosing. This sample is available as part of the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples).

# Drawing data features on a map
<a name="drawing-on-a-map"></a>

After you have an application that renders a map, using Amplify, MapLibre, or Tangram to render the map, a natural next step is to draw features on top of the map. For example, you might want to render your customer locations as markers on the map.

In general, you can use the [Places search functions](searching-for-places.md) to find locations from your data, and then use the functionality of Amplify, MapLibre, or Tangram to render the locations.

To see samples of rendering different types of objects on map, see the following MapLibre samples:
+ [Example: Draw markers](example-draw-markers.md)
+ [Example: Draw clustered points](example-draw-clusters.md)
+ [Example: Draw a polygon](example-draw-polygon.md)

For more samples and tutorials, see [Code examples and tutorials for working with Amazon Location Service](samples.md).

# Setting extents for a map using MapLibre
<a name="setting-map-extents"></a>

There are times that you do not want your users to be able to pan or zoom around the entire world. If you are using MapLibre's map control, you can limit the *extents*, or *bounds*, of the map control with the `maxBounds` option, and constrain the zoom with `minZoom` and `maxZoom` options.

The following code example shows how to initialize the map control to constrain panning to a specific boundary (in this case, the extents of the Grab data source).

**Note**  
These samples are in JavaScript, and work within the context of the [Create a web app to use Amazon Location Service](qs-web.md) tutorial.

```
// Set bounds to Grab data provider region 
var bounds = [
        [90.0, -21.943045533438166], // Southwest coordinates
        [146.25, 31.952162238024968] // Northeast coordinates
    ];

var mlglMap = new maplibregl.Map(
    {
    container: 'map',
    style: mapName,
    maxBounds: bounds // Sets bounds as max
    transformRequest,
    }
);
```

Similarly, you can set a minimum and maximum zoom level for the map. The values for both can be between 0 and 24, although the defaults are 0 for minimum zoom and 22 for maximum (data providers may not provide data at all zoom levels. Most map libraries handle this automatically). The following example initializes the `minZoom` and `maxZoom` options on the MapLibre Map control.

```
// Set the minimum and maximum zoom levels 
var mlglMap = new maplibregl.Map(
    {
    container: 'map',
    style: mapName,
    maxZoom: 12,
    minZoom: 5,
    transformRequest,
    }
);
```

**Tip**  
The MapLibre Map control also allows setting these options at runtime, rather than during initialization, with `get...` and `set...` functions. For example, use `getMaxBounds` and `setMaxBounds` to change the map bounds at runtime.

# Managing your map resources with Amazon Location
<a name="managing-maps"></a>

This topic covers the management and configuration of maps within the Amazon Location Service. It explains how to create and customize map resources, enabling you to tailor the mapping experience for your location-based applications.

You can manage your map resources using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

## List map resources
<a name="viewing-maps"></a>

You can view a list of your map resources using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To view a list of existing map resources using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Maps ** from the left navigation pane.

1. View a list of your map resources under **My maps**.

------
#### [ API ]

Use the `[ListMaps](https://docs.aws.amazon.com//location-maps/latest/APIReference/API_ListMaps.html)` operation from the Amazon Location Maps APIs.

The following example is an API request to get a list of map resources in the AWS account.

```
POST /maps/v0/list-maps
```

The following is an example response for `[ListMaps](https://docs.aws.amazon.com//location-maps/latest/APIReference/API_ListMaps.html)`:

```
{
   "Entries": [ 
      { 
         "CreateTime": 2020-10-30T01:38:36Z,
         "DataSource": "Esri",
         "Description": "string",
         "MapName": "ExampleMap",
         "UpdateTime": 2020-10-30T01:38:36Z
      }
   ],
   "NextToken": "1234-5678-9012"
}
```

------
#### [ CLI ]

Use the `[list-map](https://docs.aws.amazon.com/cli/latest/reference/location/list-maps.html)` command.

The following example is an AWS CLI to get a list of map resources in the AWS account. 

```
aws location list-maps
```

------

## Get map resource details
<a name="get-map-details"></a>

You can get details about any map resource in your AWS account using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To view the details of a map resource using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Maps ** from the left navigation pane.

1. Under **My maps**, select the name link of the target map resource. 

------
#### [ API ]

Use the `[DescribeMap](https://docs.aws.amazon.com/location-maps/latest/APIReference/API_DescribeMap.html)` operation from the Amazon Location Maps APIs. 

The following example is an API request to get the map resource details for *ExampleMap*.

```
GET /maps/v0/maps/ExampleMap
```

The following is an example response for `[DescribeMap](https://docs.aws.amazon.com/location-maps/latest/APIReference/API_DescribeMap.html)`:

```
{
   "Configuration": { 
      "Style": "VectorEsriNavigation"
   },
   "CreateTime": 2020-10-30T01:38:36Z,
   "DataSource": "Esri",
   "Description": "string",
   "MapArn": "arn:aws:geo:us-west-2:123456789012:maps/ExampleMap",
   "MapName": "ExampleMap",   
   "Tags": { 
      "Tag1" : "Value1" 
   },
   "UpdateTime": 2020-10-30T01:40:36Z
}
```

------
#### [ CLI ]

Use the `[describe-map](https://docs.aws.amazon.com/cli/latest/reference/location/describe-map.html)` command.

The following example is an AWS CLI to get the map resource details for *ExampleMap*.

```
aws location describe-map \
    --map-name "ExampleMap"
```

------

## Delete a map resource
<a name="delete-maps"></a>

You can delete a map resource from your AWS account using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

**Warning**  
This operation deletes the resource permanently.

 

------
#### [ Console ]

**To delete an existing map resource using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Maps ** from the left navigation pane.

1. Under **My maps** list, select the target map from the list.

1. Choose **Delete map**.

------
#### [ API ]

Use the `[DeleteMap](https://docs.aws.amazon.com/location-maps/latest/APIReference/API_DeleteMap.html)` operation from the Amazon Location Maps APIs. 

The following example is an API request to delete the map resource *ExampleMap*.

```
DELETE /maps/v0/maps/ExampleMap
```

The following is an example success response for `[DeleteMap](https://docs.aws.amazon.com/location-maps/latest/APIReference/API_DeleteMap.html)`:

```
HTTP/1.1 200
```

------
#### [ CLI ]

Use the `[delete-map](https://docs.aws.amazon.com/cli/latest/reference/location/delete-map.html)` command.

The following example is an AWS CLI command to delete the map resource *ExampleMap*.

```
aws location delete-map \
    --map-name "ExampleMap"
```

------

# Searching place and geolocation data using Amazon Location
<a name="searching-for-places"></a>

**Note**  
We released a new version of the Places API, see the updated [Places Developer Guide](https://docs.aws.amazon.com//location/latest/developerguide/places.html) or [Places API](https://docs.aws.amazon.com//location/latest/APIReference/API_Operations_Amazon_Location_Service_Places_V2.html) for revised information.

Amazon Location includes the ability to search the geolocation, or *place*, data of your chosen provider. There are several kinds of searching available.
+ **Geocoding** – Geocoding is the process of searching for addresses, regions, business names, or other points of interest, based on text input. It returns details and the location (in latitude and longitude) of the results found.
+ **Reverse geocoding** – Reverse geocoding allows you to find places near a given location.
+ **Autocomplete** – Autocomplete is the process of making automatic suggestions as the user types in a query. For example, if they type **Par** one suggestion might be `Paris, France`.

Amazon Location lets you choose a data provider for place search operations by creating and configuring a place index resource.

Once you create your resource, you can send requests using the AWS SDK for your preferred language, Amplify, or the REST API endpoints. You can use data from the response to mark locations on a map, enrich position data, and to convert positions into human-readable text.

**Note**  
For an overview of searching place concepts, see [Learn about Places search in Amazon Location Service](places-concepts.md).

**Topics**
+ [Places prerequisites using Amazon Location](places-prerequisites.md)
+ [Geocoding using Amazon Location](search-place-index-geocoding.md)
+ [Reverse geocoding using Amazon Location](search-place-index-reverse-geocode.md)
+ [Autocomplete using Amazon Location](search-place-index-autocomplete.md)
+ [Use place IDs with Amazon Location](search-using-placeids.md)
+ [Place categories and filtering results with Amazon Location](category-filtering.md)
+ [Amazon Aurora PostgreSQL user-defined functions for Amazon Location Service](database-address-validation.md)
+ [Managing your place index resources with Amazon Location](managing-place-indexes.md)

# Places prerequisites using Amazon Location
<a name="places-prerequisites"></a>

Before you begin geocoding, reverse geocoding or searching for places, follow the prerequisite steps:

**Topics**
+ [Creating a place index resource](#create-place-index-resource)
+ [Authenticating your requests](#places-identity-pool)

## Creating a place index resource
<a name="create-place-index-resource"></a>

Begin by creating a place index resource in your AWS account. 

When you create a place index resource, you can choose from the data providers available to support queries for geocoding, reverse geocoding, and searches:

1. **Esri **– For more information about Esri's coverage in your region of interest, see [Esri geocoding coverage](https://developers.arcgis.com/rest/geocode/api-reference/geocode-coverage.htm) in the Esri documentation.

1. **HERE Technologies** – For more information about HERE's coverage in your region of interest, see [HERE geocoding coverage](https://developer.here.com/documentation/geocoder/dev_guide/topics/coverage-geocoder.html) in the HERE documentation.

1. **Grab** – Grab provides data only for Southeast Asia. For more information about Grab's coverage, see [Countries/regions and area covered](grab.md#grab-coverage-area) in this guide.

You can do this using the Amazon Location Service console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To create a place index resource using the Amazon Location Service console**

1. Open the Amazon Location Service console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. In the left navigation pane, choose **Place indexes**.

1. Choose **Create place index**.

1. Fill out the following boxes:
   + ****Name **** – Enter a name for the place index resource. For example, *ExamplePlaceIndex*. Maximum 100 characters. Valid entries include alphanumeric characters, hyphens, periods, and underscores.
   + ****Description** ** – Enter an optional description.

1. Under **Data providers**, choose an available [data provider](https://aws.amazon.com/location/data-providers/) to use with your place index resource.
**Note**  
If your application is tracking or routing assets you use in your business, such as delivery vehicles or employees, you must not use Esri as your geolocation provider. See section 82 of the [AWS service terms](https://aws.amazon.com/service-terms) for more details.

1. Under **Data storage options**, specify if you intend to store search results from your place index resource.

1. (Optional) Under **Tags**, enter a tag **Key** and **Value**. This adds a tag your new place index resource. For more information, see [Tagging your resources](tagging.md).

1. Choose **Create place index**.

------
#### [ API ]

**To create a place index resource using the Amazon Location APIs**

Use the `[CreatePlaceIndex](https://docs.aws.amazon.com/location-places/latest/APIReference/API_CreatePlaceIndex.html)` operation from the Amazon Location Places APIs. 

The following example is an API request to create a place index resource called *ExamplePlaceIndex* using the data provider *Esri*.

```
POST /places/v0/indexes
Content-type: application/json

{
   "DataSource": "Esri",
   "DataSourceConfiguration": { 
      "IntendedUse": "SingleUse"
   },
   "Description": "string",
   "IndexName": "ExamplePlaceIndex",
   "Tags": { 
      "Tag1" : "Value1" 
   }
}
```

------
#### [ AWS CLI ]

**To create a place index resource using AWS CLI commands**

Use the `[create-place-index](https://docs.aws.amazon.com/cli/latest/reference/location/create-place-index.html)` command.

The following example creates a place index resource called *ExamplePlaceIndex* using *Esri* as the data provider. 

```
aws location \
  create-place-index \
  --data-source "Esri" \
  --description "Example place index" \
  --index-name "ExamplePlaceIndex" \
  --tags Tag1=Value1
```

------

**Note**  
Billing depends on your usage. You may incur fees for the use of other AWS services. For more information, see [Amazon Location Service pricing](https://aws.amazon.com/location/pricing/).

## Authenticating your requests
<a name="places-identity-pool"></a>

Once you create a place index resource and you're ready to begin building location features into your application, choose how you would authenticate your requests:
+ To explore ways you can access the services, see [Accessing Amazon Location Service](how-to-access.md).
+ If you have a website with anonymous users, you may want to use API Keys or Amazon Cognito.

  **Example**

  The following example shows using an API key for authorization, using [AWS JavaScript SDK v3](https://aws.amazon.com/sdk-for-javascript/), and the Amazon Location [JavaScript Authentication helper](loc-sdk-auth.md).

  ```
  import { LocationClient, SearchPlaceIndexForTextCommand } from "@aws-sdk/client-location";
  import { withAPIKey } from "@aws/amazon-location-utilities-auth-helper";
  
  const apiKey = "v1.public.your-api-key-value"; // API key
  
  // Create an authentication helper instance using an API key
  const authHelper = await withAPIKey(apiKey);
  
  const client = new LocationClient({
    region: "<region>", // region containing Cognito pool
    ...authHelper.getLocationClientConfig(), // Provides configuration required to make requests to Amazon Location
  });
  
  const input = {
    IndexName: "ExamplePlaceIndex",
    Text: "Anyplace",
    BiasPosition: [-123.4567, 45.6789]
  };
  
  const command = new SearchPlaceIndexForTextCommand(input);
  
  const response = await client.send(command);
  ```

# Geocoding using Amazon Location
<a name="search-place-index-geocoding"></a>

Geocoding is a process that converts text, such as an address, a region, a business name, or point of interest, into a set of geographic coordinates. You can use place index resources to submit geocoding requests and incorporate data retrieved from geocoding to display data on a map for your web or mobile application.

This section guides you through how to send a simple geocoding request, and how to send geocoding requests with optional specifications.

## Geocoding
<a name="geocoding"></a>

You can submit a simple request to geocode using the `[SearchPlaceIndexForText](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html)` operation to convert an address to a set of coordinates. A simple request contains the following required parameter:
+ `Text` – An address, name, city, or region to convert to a set of coordinates. For example, the string `Any Town`.

To specify a maximum number of results per pages, use the following optional parameter:
+ `MaxResults` – Limits the maximum number of results returned in the query response.

You can use the AWS CLI or the Amazon Location APIs.

------
#### [ API ]

The following example is a `[SearchPlaceIndexForText](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html)` request to search the place index resource, *ExamplePlaceIndex*, for an address, name, city or region called *Any Town*.

```
POST /places/v0/indexes/ExamplePlaceIndex/search/text 
Content-type: application/json

{
    "Text": "Any Town",
    "MaxResults": 10
}
```

------
#### [ AWS CLI ]

The following example is a `[search-place-index-for-text](https://docs.aws.amazon.com/cli/latest/reference/location/search-place-index-for-text.html)` command to search the place index resource, *ExamplePlaceIndex*, for an address, name, city or region called *Any Town*.

```
aws location \
    search-place-index-for-text \
        --index-name ExamplePlaceIndex \
        --text "Any Town" \
        --max-results 10
```

------

## Geocode near a position
<a name="geocoding-near"></a>

When geocoding, you can geocode near a given position with the following optional parameter:
+ `BiasPosition` – The position you want to search nearby. This narrows your search by searching for results closest to the given position. Defined as `[longitude, latitude]`

The following example is a `[SearchPlaceIndexForText](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html)` request to search the place index resource for an address, name, city or region called *Any Town* near the position [*-123.4567*,*45.6789*].

```
POST /places/v0/indexes/ExamplePlaceIndex/search/text 
Content-type: application/json

{
   "Text": "Any Town",
   "BiasPosition": [-123.4567,45.6789]
}
```

## Geocode within a bounding box
<a name="geocoding-bbox"></a>

You can geocode within a bounding box to narrow your results to coordinates within a given boundary using the following optional parameter:
+ `FilterBBox` – A bounding box that you specify to filter your results to coordinates within the box's boundaries. Defined as `[LongitudeSW, LatitudeSW, LongitudeNE, LatitudeNE]`
**Note**  
A request can't contain both the `FilterBBox` and `BiasPosition` parameters. Specifying both parameters in the request returns a `ValidationException` error.

The following example is a `[SearchPlaceIndexForText](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html)` request to search within a bounding box for an address, name, city or region called *Any Town*. The bounding box follows that:
+ The longitude of the southwest corner is *-124.1450*.
+ The latitude of the southwest corner is *41.7045*.
+ The longitude of the northeast corner is *-124.1387*.
+ The latitude of the northeast corner is *41.7096*.

```
POST /places/v0/indexes/ExamplePlaceIndex/search/text 
Content-type: application/json

{
   "Text": "Any Town",
   "FilterBBox":  [
        -124.1450,41.7045,
        -124.1387,41.7096
    ]
}
```

## Geocode within a country
<a name="geocoding-filtercountry"></a>

You can geocode within one or more countries you specify by using the following optional parameter:
+ `FilterCountries` – The country or region you want to geocode within. You can define up to 100 countries in one request using a [ISO 3166](https://www.iso.org/iso-3166-country-codes.html) three letter country code. For example, use `AUS` for Australia.

The following example is a `[SearchPlaceIndexForText](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html)` request to search for an address, name, city or region called *Any Town* in Germany and France. 

```
POST /places/v0/indexes/ExamplePlaceIndex/search/text 
Content-type: application/json

{
   "Text": "Any Town",
   "FilterCountries": ["DEU","FRA"]
}
```

## Filtering by category
<a name="geocoding-filtercategories"></a>

You can filter the categories that are returned in your geocode request by using the following optional parameter:
+ `FilterCategories` – The categories of results you want returned in your query. You can specify up to 5 categories in one request. You can find the list of Amazon Location Service categories in the [Categories](category-filtering.md) section. For example, you can specify `Hotel` to specify only returning hotels in your query.

The following example is a `[SearchPlaceIndexForText](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html)` request to search for an coffee shop called *Hometown Coffee* in the United States.

```
POST /places/v0/indexes/ExamplePlaceIndex/search/text 
Content-type: application/json

{
   "Text": "Hometown Coffee",
   "FilterCategories": ["Coffee Shop"],
   "FilterCountries": ["USA"]
}
```

For more details about filtering on categories, see [Place categories and filtering results with Amazon Location](category-filtering.md)

## Geocode in a preferred language
<a name="geocoding-language"></a>

You can set a language preference for results of your search by using the optional `Language` parameter. For example, a search for **100 Main St, Anytown, USA** may return `100 Main St, Any Town, USA` by default. But if you select `fr` as the `Language`, then the results may return `100 Rue Principale, Any Town, États-Unis` instead.
+ `Language` – A language code to use for rendering the results of your query. The value must be a valid [BCP 47](https://www.rfc-editor.org/info/bcp47) language code. For example, `en` for English.

**Note**  
If `Language` is not specified, or the specified language is not supported for a result, the partner's default language for that result will be used.

The following example is a `SearchPlaceIndexforText` request to search for a place called **Any Town** with the preferred language specified as `de`.

```
POST /places/v0/indexes/ExamplePlaceIndex/search/text 
Content-type: application/json
{
   "Text": "Any Town",
   "Language": "de"
}
```

## Example response
<a name="geocoding-example-response"></a>

**Example**  
The following is an example response when you call the `[SearchPlaceIndexForText](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html)` operation from the Amazon Location Places APIs. The results include relevant [places](https://docs.aws.amazon.com/location-places/latest/APIReference/API_Place.html) and the request [summary](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForTextSummary.html). Two responses are shown, based on selecting Esri or HERE as the partner.  

```
POST /places/v0/indexes/ExamplePlaceIndex/search/text 
Content-type: application/json

{
   "Text": "Amazon",
   "MaxResults": 1,
   "FilterCountries": ["USA"],
   "BiasPosition": [-112.10, 46.32]
}
```

```
{
    "Results": [
        {
            "Place": {
                "Country": "USA",
                "Geometry": {
                    "Point": [
                        -112.10667999999998,
                        46.319090000000074
                    ]
                },
                "Interpolated": false,
                "Label": "Amazon, MT, USA",
                "Municipality": "Amazon",
                "Region": "Montana",
                "SubRegion": "Jefferson County"
            },
            "Distance": 523.4619749879726,
            "Relevance": 1
        }
    ],
    "Summary": {
        "BiasPosition": [
            -112.1,
            46.32
        ],
        "DataSource": "Esri",
        "FilterCountries": [
            "USA"
        ],
        "MaxResults": 1,
        "ResultBBox": [
            -112.10667999999998,
            46.319090000000074,
            -112.10667999999998,
            46.319090000000074
        ],
        "Text": "Amazon"
    }
}
```

```
{
    "Summary": {
        "Text": "Amazon",
        "BiasPosition": [
            -112.1,
            46.32
        ],
        "FilterCountries": [
            "USA"
        ],
        "MaxResults": 1,
        "ResultBBox": [
            -112.10668,
            46.31909,
            -112.10668,
            46.31909
        ],
        "DataSource": "Here"
    },
    "Results": [
        {
            "Place": {
                "Label": "Amazon, Jefferson City, MT, United States",
                "Geometry": {
                    "Point": [
                        -112.10668,
                        46.31909
                    ]
                },
                "Neighborhood": "Amazon",
                "Municipality": "Jefferson City",
                "SubRegion": "Jefferson",
                "Region": "Montana",
                "Country": "USA",
                "Interpolated": false,
                "TimeZone": {
                    "Name": "America/Denver",
                    "Offset": -25200
                }
            },
            "PlaceId": "AQAAAIAADsn2T3KdrRWeaXLeVEyjNx_JfeTsMB0NVCEAnAZoJ-o3nqdlJZAdgcT2oWi1w9pS4wXXOk3O1vsKlGsPyHjV4EJxsu289i3hVO_BUPgP7SFoWAi8BW2v7LvAjQ5NfUPy7a1v9ajT3feIqcUZszWSTqKbJHFYvQqW7wdqhpQq3Wy-et39ZQDWSPLZUzgcjN-6VD2gyKkH0Po7gSm8YSJNSQ",            "Distance": 523.4619749905755
        }
    ]
}
```

# Reverse geocoding using Amazon Location
<a name="search-place-index-reverse-geocode"></a>

Reverse geocoding is a process that converts a set of coordinates into meaningful text, such as an address, a region, a business name, or point of interest. You can use place index resources to submit reverse geocoding requests and incorporate data retrieved from reverse geocoding to display data on a map for your web or mobile application.

This section guides you through how to send a simple reverse geocoding request.

## Reverse geocoding
<a name="reverse-geocode"></a>

You can submit a simple request to reverse geocode a set of coordinates and convert them to a meaningful address, a point of interest or a general location without an address using the `[SearchPlaceIndexForPosition](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForPosition.html)` operation. A simple request contains the following required parameter:
+ `Position` – A set of coordinates that you want to convert to an address, point of interest, or general location. Defined using the format `[longitude,latitude]`. 

To specify a maximum number of results per pages, add the following optional parameter:
+ `MaxResults` – Limits the maximum number of results returned in the query response.

If you want to specify a preferred language for the results of your query, use the following optional parameter:
+ `Language` – A language code to be used for rendering results. The value must be a valid [BCP 47](https://www.rfc-editor.org/info/bcp47) language code. For example, `en` for English.

**Note**  
If `Language` is not specified, or the specified language is not supported for a result, the partner's default language for that result will be used.

You can use the AWS CLI or the Amazon Location APIs.

------
#### [ API ]

The following example is a `[SearchPlaceIndexForPosition](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForPosition.html)` request to search the place index resource, *ExamplePlaceIndex*, for a meaningful address, point of interest or general location near the position [*122.3394*,*47.6159*].

```
POST /places/v0/indexes/ExamplePlaceIndex/search/position
Content-type: application/json

{
   "Position": [-122.3394,47.6159],
   "MaxResults": 5,
   "Language": "de"
}
```

------
#### [ AWS CLI ]

The following example is a `[search-place-index-for-position](https://docs.aws.amazon.com/cli/latest/reference/location/search-place-index-for-position.html)` command to search the place index resource, *ExamplePlaceIndex*, for a meaningful address, point of interest or general location near the position [*122.3394*,*47.6159*].

```
aws location \
    search-place-index-for-position \
        --index-name ExamplePlaceIndex \
        --position -122.3394 47.6159 \
        --max-results 5 \
        --language de
```

------

## Example response
<a name="reverse-geocoding-example-response"></a>

**Example**  
The following is an example response when calling the `[SearchPlaceIndexForPosition](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForPosition.html)` operation from the Amazon Location Places APIs. The results return relevant [places](https://docs.aws.amazon.com/location-places/latest/APIReference/API_Place.html) and the request [summary](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForPositionSummary.html). Two responses are shown, based on selecting Esri or Here as the partner.  

```
POST /places/v0/indexes/ExamplePlaceIndex/search/position
Content-type: application/json

{
   "Position": [-122.3394,47.6159],
   "MaxResults": 1
}
```

```
{
    "Results": [
        {
            "Place": {
                "AddressNumber": "2111",
                "Country": "USA",
                "Geometry": {
                    "Point": [
                        -122.33937999999995,
                        47.61591000000004
                    ]
                },
                "Interpolated": false,
                "Label": "The Spheres, 2111 7th Ave, Seattle, WA, 98121, USA",
                "Municipality": "Seattle",
                "Neighborhood": "Belltown",
                "PostalCode": "98121",
                "Region": "Washington",
                "SubRegion": "King County"
            },
            "Distance": 1.8685861313438727
        }
    ],
    "Summary": {
        "DataSource": "Esri",
        "MaxResults": 1,
        "Position": [
            -122.3394,
            47.6159
        ]
    }
}
```

```
{
    "Summary": {
        "Position": [
            -122.3394,
            47.6159
        ],
        "MaxResults": 1,
        "DataSource": "Here"
    },
    "Results": [
        {
            "Place": {
                "Label": "2111 7th Ave, Seattle, WA 98121-5114, United States",
                "Geometry": {
                    "Point": [
                        -122.33938,
                        47.61591
                    ]
                },
                "AddressNumber": "2111",
                "Street": "7th Ave",
                "Neighborhood": "Belltown",
                "Municipality": "Seattle",
                "SubRegion": "King",
                "Region": "Washington",
                "Country": "USA",
                "PostalCode": "98121-5114",
                "Interpolated": false,
                "TimeZone": {
                    "Name": "America/Los_Angeles",
                    "Offset": -28800
                }
            },
            "PlaceId": "AQAAAIAADsn2T3KdrRWeaXLeVEyjNx_JfeTsMB0NVCEAnAZoJ-o3nqdlJZAdgcT2oWi1w9pS4wXXOk3O1vsKlGsPyHjV4EJxsu289i3hVO_BUPgP7SFoWAi8BW2v7LvAjQ5NfUPy7a1v9ajT3feIqcUZszWSTqKbJHFYvQqW7wdqhpQq3Wy-et39ZQDWSPLZUzgcjN-6VD2gyKkH0Po7gSm8YSJNSQ",
            "Distance": 1.868586125090601
        }
    ]
}
```

# Autocomplete using Amazon Location
<a name="search-place-index-autocomplete"></a>

Autocomplete provides responsive feedback to end users as they are typing their search query. It provides suggestions for addresses and points of interest based on partial or misspelled free-form text. You can use place index resources to request autocomplete suggestions, and display the resulting suggestions in your application.

Amazon Location does not support storage of autocomplete suggestions. An error is returned if the place index used for an autocomplete call is configured for use with stored geocodes. To use stored geocodes and query for suggestions, create and configure multiple place indexes.

This section describes how to send an autocomplete request. It starts with the most basic form of the request, and then shows optional parameters that you can use to increase the relevance of autocomplete search results.

## Using autocomplete
<a name="autocomplete"></a>

You can submit a simple request for autocomplete suggestions by using the `[SearchPlaceIndexForSuggestions](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForSuggestions.html)` operation. The simplest form of the request has a single required parameter, the query `Text`: 
+ `Text` – The free-form partial text to use to generate place suggestions. For example, the string `eiffel tow`.

To limit the number of results returned, add the optional `MaxResults` parameter: 
+ `MaxResults` – Limits the number of results returned in the query response.

You can use the Amazon Location APIs or the AWS CLI.

------
#### [ API ]

The following example is a `[SearchPlaceIndexForSuggestions](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForSuggestions.html)` request to search the place index resource, *ExamplePlaceIndex*, for up to *5* suggestions based on the partial place name *kamp*. 

```
POST /places/v0/indexes/ExamplePlaceIndex/search/suggestions
Content-type: application/json

{
    "Text": "kamp",
    "MaxResults": 5
}
```

------
#### [ AWS CLI ]

The following example is a `[search-place-index-for-suggestions](https://docs.aws.amazon.com/cli/latest/reference/location/search-place-index-for-suggestions.html)` command to search the place index resource, *ExamplePlaceIndex*, for up to *5* suggestions based on the partial place name *kamp*. 

```
aws location \
              search-place-index-for-suggestions \
              --index-name ExamplePlaceIndex \
              --text kamp \
              --max-results 5
```

------

The call to `SearchPlaceIndexForSuggestions` results in a list of places with a name and an ID for each. You can use those results to present suggestions of what the user might be searching for, as they are typing, such as providing a dropdown list of choices underneath a text box. For example, here are the results for suggestions, based on a user typing *kamp*.

```
{
    "Summary": {
        "Text": "kamp",
        "MaxResults": 5,
        "DataSource": "Esri"
    },
    "Results": [
        {
            "Text": "Kampuchea",
            "PlaceId": "AQAAAIAADsn2T3KdrRWeaXLeVEyjNx_JfeTsMB0NVCEAnAZoJ-o3nqdlJZAdgcT2oWi1w9pS4wXXOk3O1vsKlGsPyHjV4EJxsu289i3hVO_BUPgP7SFoWAi8BW2v7LvAjQ5NfUPy7a1v9ajT3feIqcUZszWSTqKbJHFYvQqW7wdqhpQq3Wy-et39ZQDWSPLZUzgcjN-6VD2gyKkH0Po7gSm8YSJNSQ"
        },
        {
            "Text": "Kampoul, Kabul, AFG",
            "PlaceId": "AQAAAIAAA1mxl_-9ffzXD07rBgo9fh6E01Pd1YKvuT5rz2qBDxqBkhTlgkeiOPR2s5sa3YBLxUqQI8bhymsYcu9R-DkX3L9QSi3CB5LhNPu160iSFJo6H8S1CrxO3QsJALhrr9mdbg0R4R4YDywkhkeBlnbn7g5C5LI_wYx873WeQZuilwtsGm8jcMA0Ya5oK4netQC6piVx6zmnPdwBs-UeXcb_bg"
        },
        {
            "Text": "Kampala, UGA",
            "PlaceId": "AQAAAIAAzZfZt3qMruKGObyhP6MM0pqy2L8SULlVWT7a3ertLBRS6Q5n7I4s9D7E0nRHADAj7mL7kvX1Q8HD-mpuiATXNJ1Ix4_V_1B15zHe8jlYKMWvXbgbO8cMpgR2fqYqZMR1x-dfBOO8OoqujKZldvPIDK1kNe3GwcaqvvMWWPMeaGd203brFynubAe-MmFF-Gjz-WBMfUy9og6MV7bkk6NGCA"
        },
        {
            "Text": "Kampar, Riau, IDN",
            "PlaceId": "AQAAAIAAvbXXx-srOi111tHOkPdao0GF7WQ_KaZ444SEnevycp6Gtf_2JWgPfCE5bIQCYwya1uZQpX2a8YJoFm2K7Col4fLu7IK0yYOLhZx4kp6QzbG4xEAGzfWtWq6nfbb0lZfuHY6r0g1sRlN1aucvwim4AEcKRzckqaa93JI8064pj6Q59kN37pAa3JX4ayEzH1DzIL3m3oqxzd4O16yGfhAIgA"
        },
        {
            "Text": "Kampung Pasir Gudang Baru, Johor, MYS",
            "PlaceId": "AQAAAIAA4HLQHdjUDcaaXLE9wtNIT1cjQYLgkBnMoG2eNN0AaQ8PJoWabLRXmmPUaAj8MAD6vT0i6zqaun5Mixyj7vnYXrk2xp59cbgdqvQaPoWhSCVxBOX0WGs3cZ8TnIRn3c-6v8_UfmqC7es1gUyECfMGK04VBKiwpHwCzjNsqymkd9BC3A9K3QlMgd3dkrGjv_vV94iLlnFTbaecrckl2UDCkA"
        }
    ]
}
```

The next section explains how to use the `PlaceID` from these results.

## Using the autocomplete results
<a name="autocomplete-results"></a>

The call to `SearchPlaceIndexForSuggestions` results in a list of places with a name and an ID for each. You can use those results to present suggestions of what the user might be searching for, as they are typing, such as providing a dropdown list of choices underneath a text box. When the user chooses one of the results, you can then call the [GetPlace](https://docs.aws.amazon.com/location-places/latest/APIReference/API_GetPlace.html) operation with the ID of their selection to return the details of that place, including location, address, or other details.

**Note**  
A `PlaceId` is valid only if all of the following are the same in the original search request, and the call to `GetPlace`.  
Customer AWS account
AWS Region
Data provider specified in the place index resource

Typically, you use `GetPlace` with the Amazon Location APIs. The following example is a `[GetPlace](https://docs.aws.amazon.com/location-places/latest/APIReference/API_GetPlace.html)` request to find one of the suggestions from the previous section. This example is based on the partial place name *kamp*. 

```
POST /places/v0/indexes/ExamplePlaceIndex/places/AQAAAIAADsn2T3KdrRWeaXLeVEyjNx_JfeTsMB0NVCEAnAZoJ-o3nqdlJZAdgcT2oWi1w9pS4wXXOk3O1vsKlGsPyHjV4EJxsu289i3hVO_BUPgP7SFoWAi8BW2v7LvAjQ5NfUPy7a1v9ajT3feIqcUZszWSTqKbJHFYvQqW7wdqhpQq3Wy-et39ZQDWSPLZUzgcjN-6VD2gyKkH0Po7gSm8YSJNSQ
```

## Autocomplete near a position
<a name="autocomplete-near"></a>

 When you search for autocomplete place suggestions by using `[SearchPlaceIndexForSuggestions](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForSuggestions.html)`, you can get more locally-relevant suggestions by adding the following optional parameter:
+ `BiasPosition` – The position you want to search nearby. Defined as `[longitude, latitude]`.

The following example uses a `[SearchPlaceIndexForSuggestions](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForSuggestions.html)` request to search the place index resource *ExamplePlaceIndex* for place suggestions matching the partial query *kamp* near the position [*32.5827*,*0.3169*]. 

```
POST /places/v0/indexes/ExamplePlaceIndex/search/suggestions
Content-type: application/json

{
    "Text": "kamp",
    "BiasPosition": [32.5827,0.3169]
}
```

The suggestions returned for the same `Text` can be different if a different `BiasPosition` is chosen, such as [*-96.7977*, *32.7776*].

## Autocomplete within a bounding box
<a name="autocomplete-bbox"></a>

You can narrow your autocomplete search to receive only suggestions for places which are located within a given boundary by adding the following optional parameter: 
+ `FilterBBox` – A bounding box that you specify to filter your results to coordinates within the box's boundaries. Defined as `[LongitudeSW, LatitudeSW, LongitudeNE, LatitudeNE]`
**Note**  
A request can't contain both the `FilterBBox` and `BiasPosition` parameters. Specifying both parameters in the request returns a `ValidationException` error.

The following example uses a `[SearchPlaceIndexForSuggestions](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForSuggestions.html)` request to search the place index resource *ExamplePlaceIndex* for place suggestions matching the partial query *kamp*, and which are contained within the bounding box where: 
+ The longitude of the southwest corner of the bounding box is *32.5020*.
+ The latitude of the southwest corner of the bounding box is *0.2678*.
+ The longitude of the northeast corner of the bounding box is *32.6129*.
+ The latitude of the northeast corner of the bounding box is *0.3502*.

```
POST /places/v0/indexes/ExamplePlaceIndex/search/suggestions
Content-type: application/json

{
    "Text": "kamp",
    "FilterBBox": [
        32.5020, 0.2678,
        32.6129, 0.3502
    ]
}
```

 The suggestions returned for the same `Text` are different if a different `FilterBBox` is chosen, such as [*-97.9651*, *32.0640*, * -95.1196*, *34.0436*]. 

## Autocomplete within a country
<a name="autocomplete-country"></a>

You can narrow your autocomplete search to receive only suggestions for places which are located within a given country, or set of countries, by adding the following optional parameter: 
+ `FilterCountries` – The countries you want to search for place suggestions within. You can specify up to 100 countries in one request using a [ISO 3166](https://www.iso.org/iso-3166-country-codes.html) three-letter country code. For example, use `AUS` for Australia.

 The following example uses a `[SearchPlaceIndexForSuggestions](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForSuggestions.html)` request to search the place index resource *ExamplePlaceIndex* for place suggestions matching the partial query *kamp* and which are contained within Uganda, Kenya, or Tanzania:

```
POST /places/v0/indexes/ExamplePlaceIndex/search/suggestions
Content-type: application/json

{
    "Text": "kamp",
    "FilterCountries": ["UGA", "KEN", "TZA"]
}
```

 The suggestions returned for the same `Text` are different if a different `FilterCountries` list is chosen, such as ["*USA*"]. 

## Example response
<a name="autocomplete-basic-response"></a>

The following is an example response of suggested autocompletions for the `[SearchPlaceIndexForSuggestions](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForSuggestions.html)` operation, using the text *kamp*.

```
{
    "Summary": {
        "Text": "kamp",
        "MaxResults": 5,
        "DataSource": "Esri"
    },
    "Results": [
        {
            "Text": "Kampuchea",
            "PlaceId": "AQAAAIAADsn2T3KdrRWeaXLeVEyjNx_JfeTsMB0NVCEAnAZoJ-o3nqdlJZAdgcT2oWi1w9pS4wXXOk3O1vsKlGsPyHjV4EJxsu289i3hVO_BUPgP7SFoWAi8BW2v7LvAjQ5NfUPy7a1v9ajT3feIqcUZszWSTqKbJHFYvQqW7wdqhpQq3Wy-et39ZQDWSPLZUzgcjN-6VD2gyKkH0Po7gSm8YSJNSQ"
        },
        {
            "Text": "Kampoul, Kabul, AFG",
            "PlaceId": "AQAAAIAAA1mxl_-9ffzXD07rBgo9fh6E01Pd1YKvuT5rz2qBDxqBkhTlgkeiOPR2s5sa3YBLxUqQI8bhymsYcu9R-DkX3L9QSi3CB5LhNPu160iSFJo6H8S1CrxO3QsJALhrr9mdbg0R4R4YDywkhkeBlnbn7g5C5LI_wYx873WeQZuilwtsGm8jcMA0Ya5oK4netQC6piVx6zmnPdwBs-UeXcb_bg"
        },
        {
            "Text": "Kampala, UGA",
            "PlaceId": "AQAAAIAAzZfZt3qMruKGObyhP6MM0pqy2L8SULlVWT7a3ertLBRS6Q5n7I4s9D7E0nRHADAj7mL7kvX1Q8HD-mpuiATXNJ1Ix4_V_1B15zHe8jlYKMWvXbgbO8cMpgR2fqYqZMR1x-dfBOO8OoqujKZldvPIDK1kNe3GwcaqvvMWWPMeaGd203brFynubAe-MmFF-Gjz-WBMfUy9og6MV7bkk6NGCA"
        },
        {
            "Text": "Kampar, Riau, IDN",
            "PlaceId": "AQAAAIAAvbXXx-srOi111tHOkPdao0GF7WQ_KaZ444SEnevycp6Gtf_2JWgPfCE5bIQCYwya1uZQpX2a8YJoFm2K7Col4fLu7IK0yYOLhZx4kp6QzbG4xEAGzfWtWq6nfbb0lZfuHY6r0g1sRlN1aucvwim4AEcKRzckqaa93JI8064pj6Q59kN37pAa3JX4ayEzH1DzIL3m3oqxzd4O16yGfhAIgA"
        },
        {
            "Text": "Kampung Pasir Gudang Baru, Johor, MYS",
            "PlaceId": "AQAAAIAA4HLQHdjUDcaaXLE9wtNIT1cjQYLgkBnMoG2eNN0AaQ8PJoWabLRXmmPUaAj8MAD6vT0i6zqaun5Mixyj7vnYXrk2xp59cbgdqvQaPoWhSCVxBOX0WGs3cZ8TnIRn3c-6v8_UfmqC7es1gUyECfMGK04VBKiwpHwCzjNsqymkd9BC3A9K3QlMgd3dkrGjv_vV94iLlnFTbaecrckl2UDCkA"
        }
    ]
}
```

# Use place IDs with Amazon Location
<a name="search-using-placeids"></a>

Searching for places returns a list of results. Most results include a `PlaceId` for that result. You can use a `PlaceId` in a `[GetPlace](https://docs.aws.amazon.com/location-places/latest/APIReference/API_GetPlace.html)` operation to return the information about that place (including name, address, location, or other details).

**Note**  
Using [SearchPlaceIndexForSuggestions](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForSuggestions.html) will return `PlaceId` results for any place indexes created with any data source. Using [SearchPlaceIndexForText](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html) or [SearchPlaceIndexForPosition](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForPosition.html) will return a `PlaceId` only if the data source used is HERE.

Each `PlaceId` uniquely defines the place it refers to, but a single place can have more than one `PlaceId` over time, and based on the context. The following rules describe the uniqueness and longevity of a `PlaceId`.
+ The `PlaceId` returned in calls that you make is specific to your AWS account, to the AWS Region, and to the data provider in your `PlaceIndex` resource. `GetPlace` will find results only when these three attributes match the original call that created the `PlaceId`.
+ The `PlaceId` for a place will change when the data about that place changes. For example, when the business that it refers to moves location or changes names.
+ The `PlaceId` returned from a repeated search call may change when the backend service makes an update. The older `PlaceId` will continue to be found, but new calls to search may return a different ID.

The `PlaceId` is a string. There is no specific limit to the length of a `PlaceId`. The following is an example of a valid `PlaceId`. 

```
AQAAAIAADsn2T3KdrRWeaXLeVEyjNx_JfeTsMB0NVCEAnAZoJ-o3nqdlJZAdgcT2oWi1w9pS4wXXOk3O1vsKlGsPyHjV4EJxsu289i3hVO_BUPgP7SFoWAi8BW2v7LvAjQ5NfUPy7a1v9ajT3feIqcUZszWSTqKbJHFYvQqW7wdqhpQq3Wy-et39ZQDWSPLZUzgcjN-6VD2gyKkH0Po7gSm8YSJNSQ
```

Calling `GetPlace` with a `PlaceId` for a place whose data has changed (for example, a business location that has gone out of business), will result in a `404`, `ResourceNotFound` error. Calling `GetPlace` with a `PlaceId` that is not valid, or one out of context, such as from another AWS account, will return a `400`, `ValidationException` error.

While you can use PlaceID in subsequent requests, PlaceID is not intended to be a permanent identifier and the ID can change between consecutive API calls. Please see the following PlaceID behaviour for each data provider:
+ **Esri**: Place IDs will change every quarter at a minimum. The typical time period for these changes would be March, June, September, and December. Place IDs might also change between the typical quarterly change but that will be much less frequent.
+ **HERE**: We recommend that you cache data for no longer than a week to keep your data data fresh. You can assume that less than 1% ID shifts will release over release which is approximately 1 - 2 times per week.
+ **Grab**: Place IDs can expire or become invalid in the following situations.
  + **Data operations**: The POI may be removed from Grab POI database by Grab Map Ops based on the ground-truth, such as being closed in the real world, being detected as a duplicate POI, or having incorrect information. Grab will synchronize data to the Waypoint environment on weekly basis.
  + **Interpolated POI**: Interpolated POI is a temporary POI generated in real time when serving a request, and it will be marked as derived in the `place.result_type` field in the response. The information of interpolated POIs will be retained for at least 30 days, which means that within 30 days, you are able to obtain POI details by Place ID from Place Details API. After 30 days, the interpolated POIs(both Place ID and details) may expire and inaccessible from the Places Details API.

# Place categories and filtering results with Amazon Location
<a name="category-filtering"></a>

Places are categorized. If you search for a business, the business might be a `Restaurant`, for example. Even the results of a search for an address can be categorized by whether it was matched to an *address*, *street*, or *intersection*.

Broadly, Amazon Location Service categorizes places into *Place types*. Points of interest are further categorized into *Point of interest types*.

**Note**  
Not all results will have categories.

You can use the categories to filter your geocoding searches.

## Filtering results
<a name="place-filtering"></a>

When you are using `SearchPlaceIndexForText`, you can filter the results that are returned by the categories that you want to use. For example:
+ If you want to search for a place called "Hometown Coffee", and only return results that are categorized as coffee shops, you can do that by calling `SearchPlaceIndexForText` and include the *Point of interest category*, `Coffee Shop` in the `FilterCategories` parameter.
+ When searching for "123 Main St, Anytown, WA, 98123, USA", you can filter result to just addresses, so you don't get matches on, for example, the postal code. Filter to just addresses by including *Place type*, `AddressType` in the `FilterCategories` parameter.

**Note**  
Not all data providers support filtering, or support it in the same way. For more information, see [Filtering limitations by data provider](#filter-limitations).

The next section lists the categories that you can filter on.

## Categories
<a name="place-categories"></a>

The following lists show the categories that Amazon Location Service uses to categorize and filter. These categories are used in all languages, independent of the language parameter is set to a different language.

**Note**  
Amazon Location Service maps data provider categories to this set of categories. If a data provider puts a place into a category that is not part of the Amazon Location Service category list, the provider category will be included in the results as a *supplemental category*.

**Place types** – These types are used to indicate the type of match that was used to find the result.
+ `AddressType` – Returned when the result was matched to an address.
+ `StreetType` – Returned when the result was matched to a street.
+ `IntersectionType` – Returned when the result was matched to the intersection of two streets.
+ `PointOfInterestType` – Returned when the result was match to a point of interest, such as a business, or civic location.
+ `CountryType` – Returned when the result was matched to a country or major region.
+ `RegionType` – Returned when the result was matched to a region within a country, such as a state or province.
+ `SubRegionType` – Returned when the result was matched to a subregion within a country, such as a county or metropolitan area.
+ `MunicipalityType` – Returned when the result was matched to a city or town.
+ `NeighborhoodType` – Returned when the result was matched to a neighborhood or area within a city.
+ `PostalCodeType` – Returned when the result was matched to a postal code.

**Point of interest categories** – These categories are used to indicate the type of business or location for point of interest results.
+ `Airport`
+ `Amusement Park`
+ `Aquarium`
+ `Art Gallery`
+ `ATM`
+ `Bakery`
+ `Bank`
+ `Bar`
+ `Beauty Salon`
+ `Bus Station`
+ `Car Dealer`
+ `Car Rental`
+ `Car Repair`
+ `Car Wash`
+ `Cemetery`
+ `Cinema`
+ `City Hall`
+ `Clothing Store`
+ `Coffee Shop`
+ `Consumer Electronics Store`
+ `Convenience Store`
+ `Court House`
+ `Dentist`
+ `Embassy`
+ `Fire Station`
+ `Fitness Center`
+ `Gas Station`
+ `Government Office`
+ `Grocery`
+ `Higher Education`
+ `Hospital`
+ `Hotel`
+ `Laundry`
+ `Library`
+ `Liquor Store`
+ `Lodging`
+ `Market`
+ `Medical Clinic`
+ `Motel`
+ `Museum`
+ `Nightlife`
+ `Nursing Home`
+ `Park`
+ `Parking`
+ `Pet Store`
+ `Pharmacy`
+ `Plumbing`
+ `Police Station`
+ `Post Office`
+ `Religious Place`
+ `Restaurant`
+ `School`
+ `Shopping Mall`
+ `Sports Center`
+ `Storage`
+ `Taxi Stand`
+ `Tourist Attraction`
+ `Train Station`
+ `Veterinary Care`
+ `Zoo`

## Filtering limitations by data provider
<a name="filter-limitations"></a>

Not all providers have the same filtering functionality. The following table describes the differences.


| Provider | APIs with filter support | Categories supported for filtering | Return values | 
| --- | --- | --- | --- | 
|  Esri  |  `SearchPlaceIndexForText`, `SearchPlaceIndexForSuggestions`  |  Filter by *Place types* and *Point of interest categories*.  |  Categories are returned by `SearchPlaceIndexForText`, `SearchPlaceIndexForPosition`, and `GetPlace`  | 
|  Here  |  `SearchPlaceIndexForText`, `SearchPlaceIndexForSuggestions`  |  Filter by *Place types* only.  |  Categories are returned by `SearchPlaceIndexForText` and `SearchPlaceIndexForSuggestions`, `SearchPlaceIndexForPosition`, and `GetPlace`  | 
|  Grab  |  not supported  |  not supported  |  not supported  | 
|  Open Data  |  n/a (searching places not supported)  |  n/a  |  n/a  | 

# Amazon Aurora PostgreSQL user-defined functions for Amazon Location Service
<a name="database-address-validation"></a>

You can use Amazon Location Service to work with coordinates and addresses stored in database tables to clean and enrich your geospatial data.

For example:
+ You can use geocoding to convert addresses to coordinates to normalize and fill gaps in data for addresses stored in a database table. 
+ You can geocode addresses to obtain their positions and use the coordinates with database spatial functions, such as a function that shows rows in a specified area.
+ You can use enriched data to generate automated reporting, such as generating an automated report that illustrates all devices in a given area, or an automated report for machine learning that illustrates areas with higher failure rates when sending location updates.

This tutorial shows how to format and enrich addresses stored in an Amazon Aurora PostgreSQL database table using Amazon Location Service.
+ **Amazon Aurora PostgreSQL** – A fully managed relational database engine, compatible with MySQL and PostgreSQL, that outputs up to five times the throughput of MySQL and up to three times the throughput of PostgreSQL without changing most of your existing application. For more information, see [What is Amazon Aurora?](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_AuroraOverview.html) in the *Amazon Aurora User Guide*.

**Important**  
The resulting application in this tutorial uses a place index that stores geocoding results. For information about applicable charges for storing geocoding results, see [Amazon Location Service pricing](https://aws.amazon.com/location/pricing/). 

Sample code is available in the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples/tree/main/aurora-udfs), which includes [an AWS CloudFormation template](https://github.com/aws-samples/amazon-location-samples/tree/main/aurora-udfs/cloudformation/template.yaml). 

**Topics**
+ [Overview](#aurora-amazon-location-overview)
+ [Prerequisites](#aurora-amazon-location-prerequisites)
+ [Quick start](#aurora-amazon-location-quick-start)
+ [Create a place index resource](#aurora-create-place-index)
+ [Create an AWS Lambda function for geocoding](#aurora-create-lambda)
+ [Grant Amazon Aurora PostgreSQL access to AWS Lambda](#aurora-invoke-API)
+ [Invoke the AWS Lambda function](#aurora-setup-table)
+ [Enriching a database containing address data](#aurora-run-sql)
+ [Next steps](#aurora-amazon-location-next-steps)

## Overview
<a name="aurora-amazon-location-overview"></a>

![\[alt text not found\]](http://docs.aws.amazon.com/location/previous/developerguide/images/aurora_architecture.PNG)


The architecture involves the following integrations:
+  This solution uses an Amazon Location place index resource to support geocoding queries using the operation `SearchPlaceIndexForText`.
+ AWS Lambda uses a Python Lambda that geocodes addresses when an IAM policy gives permission to allow AWS Lambda to call the Amazon Location geocoding operation, `SearchPlaceIndexForText`.
+ Grant permission to Amazon Aurora PostgreSQL to invoke the geocoding Lambda function using an SQL user-defined function. 

## Prerequisites
<a name="aurora-amazon-location-prerequisites"></a>

Before you begin, you need the following prerequisites:
+ An Amazon Aurora PostgreSQL cluster. For more information about [Creating an Amazon Aurora DB cluster](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.CreateInstance.html), see the *Amazon Aurora User Guide*.
**Note**  
If your Amazon Aurora cluster isn't publicly available, you must also configure Amazon Aurora to connect to AWS Lambda in a virtual private cloud (VPC) in your AWS account. For more information, see [Grant Amazon Aurora PostgreSQL access to AWS Lambda](#aurora-invoke-API).
+ An SQL developer tool to connect to the Amazon Aurora PostgreSQL cluster.

## Quick start
<a name="aurora-amazon-location-quick-start"></a>

As an alternative to going through the steps in this tutorial, you can launch a quick stack to deploy an AWS Lambda function supporting the Amazon Location operation `[SearchPlaceIndexForText](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html)`. This automatically configures your AWS account to allow Amazon Aurora to call AWS Lambda.

Once you configure your AWS account, you will need to: 
+ Add the Lambda feature to Amazon Aurora. See Add the IAM role to a Amazon Aurora DB cluster in [Grant Amazon Aurora PostgreSQL access to AWS Lambda](#aurora-invoke-API).
+ Load the user-defined function into your database. See [Invoke the AWS Lambda function](#aurora-setup-table).

 

[https://console.aws.amazon.com/cloudformation/home#/stacks/quickcreate?templateUrl=https%3A%2F%2Famazon-location-cloudformation-templates.s3.us-west-2.amazonaws.com%2Faurora-udfs%2Ftemplate.yaml&stackName=AuroraUDFs](https://console.aws.amazon.com/cloudformation/home#/stacks/quickcreate?templateUrl=https%3A%2F%2Famazon-location-cloudformation-templates.s3.us-west-2.amazonaws.com%2Faurora-udfs%2Ftemplate.yaml&stackName=AuroraUDFs)

## Create a place index resource
<a name="aurora-create-place-index"></a>

Start by creating a place index resource to support geocoding queries. 

1. Open the Amazon Location Service console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home). 

1. In the left navigation pane, choose **Place indexes**. 

1. Fill out the following boxes:
   + ** Name** – Enter a name for the place index resource. For example, *AuroraPlaceIndex*. Maximum 100 characters. Valid entries include alphanumeric characters, hyphens, periods, and underscores.
   + ** Description** – Enter an optional description. For example, *Place index for Amazon Aurora*. 

1. Under **Data providers**, choose an available [data provider](https://aws.amazon.com/location/data-providers/) to use with your place index resource. If you have no preference, we recommend starting with *Esri*.

1. Under **Data storage options**, specify **Yes, results will be stored**. This indicates that you intend to save the geocoding results in a database.

1. (Optional) Under **Tags**, enter a tag **Key** and **Value**. This adds a tag your new place index resource. For more information, see [Tagging your resources](tagging.md).

1. Choose **Create place index**.

## Create an AWS Lambda function for geocoding
<a name="aurora-create-lambda"></a>

To create a connection between Amazon Aurora PostgreSQL and Amazon Location Service, you need an AWS Lambda function to handle requests from the database engine. This function translates the Lambda user-defined function event and calls the Amazon Location operation `SearchPlaceIndexForText`.

You can create the function using the AWS Lambda console, the AWS Command Line Interface, or the AWS Lambda APIs.

**To create a Lambda user-defined function using the console**

1. Open the AWS Lambda console at [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/home).

1. From the left navigation, choose **Functions**. 

1.  Choose **Create Function**, and make sure that **Author from scratch** is selected. 

1. Fill out the following boxes:
   + **Function name** – Enter a unique name for your function. Valid entries include alphanumeric characters, hyphens, and underscores with no spaces. For example, *AuroraGeocoder*.
   + **Runtime** – Choose *Python 3.8*.

1. Choose **Create function**. 

1. Choose the **Code** tab to open the editor.

1. Overwrite the placeholder code in `lambda_function.py` with the following:

   ```
   from os import environ
   
   import boto3
   from botocore.config import Config
   
   # load the place index name from the environment, falling back to a default
   PLACE_INDEX_NAME = environ.get("PLACE_INDEX_NAME", "AuroraPlaceIndex")
   
   location = boto3.client("location", config=Config(user_agent="Amazon Aurora PostgreSQL"))
   
   """
   This Lambda function receives a payload from Amazon Aurora and translates it to
   an Amazon Location `SearchPlaceIndex` call and returns the results as-is, to be
   post-processed by a PL/pgSQL function.
   """
   def lambda_handler(event, context):
       kwargs = {}
       
       if event.get("biasPosition") is not None:
           kwargs["BiasPosition"] = event["biasPosition"]
   
       if event.get("filterBBox") is not None:
           kwargs["FilterBBox"] = event["filterBBox"]
   
       if event.get("filterCountries") is not None:
           kwargs["FilterCountries"] = event["filterCountries"]
   
       if event.get("maxResults") is not None:
           kwargs["MaxResults"] = event["maxResults"]
       
       return location.search_place_index_for_text(
           IndexName=PLACE_INDEX_NAME,
           Text=event["text"],
           **kwargs)["Results"]
   ```

1. If you've named your place index something other than *AuroraPlaceIndex*, create an environment variable named `PLACE_INDEX_NAME` to assign the resource name to:
   + From the **Configuration** tab, choose **Environment Variables**.
   + Choose **Edit**, then choose **Add environment variable**.
   + For **Key**: Enter `PLACE_INDEX_NAME`.
   + For **Value**: Enter the name of your place index resource.

1. Choose **Deploy** to save the updated function.

1. From the **Test** drop-down menu, choose **Configure test Event**.

1. Choose **Create new test event**.

1. Enter the following test event:

   ```
   {
     "text": "Baker Beach",
     "biasPosition": [-122.483, 37.790],
     "filterCountries": ["USA"]
   }
   ```

1. Choose **Test** to test the Lambda function.

1. Choose the **Configuration** tab.

1. Under **General configuration**: Choose **Permissions**.

1. Under **Execution role**: Choose the hyper linked **Role name** to grant Amazon Location Service permissions to your Lambda function. 

1. Under the **Permissions** tab: Select the **Add permissions** drop down, then choose **Create inline policy**.

1. Choose the **JSON** tab.

1. Add the following IAM policy:
   + The following policy gives permission to send `SearchPlaceIndexForText` to the place index resource *AuroraPlaceIndex*.

     ```
     {
       "Version": "2012-10-17",		 	 	 
       "Statement": [
         {
           "Effect": "Allow",
           "Action": "geo:SearchPlaceIndexForText",
           "Resource": "arn:aws:geo:<Region>:<AccountId>:place-index/AuroraPlaceIndex"
         }
       ]
     }
     ```

1. Choose **Review policy**.

1. Enter a policy name. For example, *AuroraPlaceIndexReadOnly*.

1. Choose **Create policy**.

## Grant Amazon Aurora PostgreSQL access to AWS Lambda
<a name="aurora-invoke-API"></a>

Before Amazon Aurora PostgreSQL can invoke an AWS Lambda function, you must grant access permission.

If your Amazon Aurora PostgreSQL cluster isn't publicly accessible, you will need to first create a VPC endpoint for AWS Lambda in order for Amazon Aurora to call your Lambda function.

**Create a VPC Endpoint for AWS Lambda** 

**Note**  
This step is only required if your Amazon Aurora PostgreSQL cluster isn't publicly accessible. 

1. Open the [Amazon Virtual Private Cloud Console](https://console.aws.amazon.com/vpc/home).

1. In the left navigation, choose **Endpoints**.

1. Choose **Create endpoint**.

1. In the **Service Name** filter, enter "lambda", then choose `com.amazonaws.<region>.lambda`.

1. Choose the VPC containing your Aurora cluster.

1. Choose a subnet for each availability zone.

1. In the **Security group** filter, enter "default" or the name of the security group your Aurora cluster is a member of, then choose the security group.

1. Choose **Create endpoint**.

**Create an IAM policy to grant permission to invoke your AWS Lambda function**

1. Open the [IAM console](https://console.aws.amazon.com/iam/home#/home).

1. In the left navigation, expand **Access Management** to choose **Policies**.

1. Choose **Create policy**.

1. On the **JSON** tab, input the following policy:
   + The following is an example of an IAM policy that grants Amazon Aurora PostgreSQL permission to invoke the `AuroraGeocoder` AWS Lambda function.

   ```
   {
       "Version": "2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "lambda:InvokeFunction",
               "Resource": [
                   "arn:aws:lambda:<Region>:<AccountId>:function:AuroraGeocoder"
               ]
           }
       ]
   }
   ```

1. Choose **Next: Tags** to add optional tags.

1. Choose **Next: Review**. 

1. Review your policy and enter the following details for the policy:
   + **Name** – Use alphanumeric and '\$1=,.@-\$1' characters. Maximum 128 characters. For example, *AuroraGeocoderInvoke*.
   + **Description** – Enter an optional description. Use alphanumeric and '\$1=,.@-\$1' characters. Maximum 1000 characters. 

1. Choose **Create policy**. Note the ARN for this policy, which you use to attach the policy to an IAM role.

**Create an IAM role to give permission to Amazon Relational Database Service (Amazon RDS)**

By creating an IAM role, Amazon Aurora PostgreSQL can assume the role on your behalf to access your Lambda function. For more information, see [Creating a role to delegate permissions to an IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user.html) in the *IAM User Guide*.

The following example is an AWS CLI command that creates a role named *AuroraGeocoderInvokeRole*:

```
aws iam create-role  --role-name rds-lambda-role --assume-role-policy-document '{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
        "Effect": "Allow",
        "Principal": {
            "Service": "rds.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
        }
    ] 
}'
```

**Attach your IAM policy to the IAM role**

When you have an IAM role, attach the IAM policy that you've created. 

The following example is an AWS CLI command that attaches the policy *AuroraGeocoderInvoke* to the role *AuroraGeocoderInvokeRole*.

```
aws iam attach-role-policy  --policy-arn AuroraGeocoderInvoke  --role-name AuroraGeocoderInvokeRole
```

**Add the IAM role to a Amazon Aurora DB cluster**

The following example is an AWS CLI command to add an IAM role to a Amazon Aurora PostgreSQL DB cluster named *MyAuroraCluster*.

```
aws rds add-role-to-db-cluster \
--db-cluster-identifier MyAuroraCluster \
--feature-name Lambda \
--role-arn AuroraGeocoderInvokeRole   \
--region your-region
```

## Invoke the AWS Lambda function
<a name="aurora-setup-table"></a>

After you grant permission to Amazon Aurora PostgreSQL to invoke your geocoding Lambda function, you can create an Amazon Aurora PostgreSQL user-defined function to invoke the geocoding AWS Lambda function. For more information, see [Invoking an AWS Lambda function from an Amazon Aurora PostgreSQL DB cluster](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/PostgreSQL-Lambda.html) in the *Amazon Aurora User Guide*.

**Install the required PostgreSQL extensions**

To install the required PostgreSQL extensions `aws_lambda` and `aws _commons` extensions, see [Overview of using a Lambda function](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/PostgreSQL-Lambda.html#PostgreSQL-Lambda-overview) in the *Amazon Aurora User Guide*.

```
CREATE EXTENSION IF NOT EXISTS aws_lambda CASCADE;
```

**Install the required PostGIS extensions**

PostGIS is an extension to PostgreSQL for storing and managing spatial information. For more information, see [Working with the PostGIS extension](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.PostGIS.html) on the *Amazon Relational Database Service User Guide*.

```
CREATE EXTENSION IF NOT EXISTS postgis;
```

**Create an SQL user-defined function that invokes the Lambda function**

In an SQL editor, create a new user-defined function `f_SearchPlaceIndexForText` to invoke the function *AuroraGeocoder*:

```
CREATE OR REPLACE FUNCTION f_SearchPlaceIndexForText(
  text text,
  bias_position geometry(Point, 4326) DEFAULT NULL,
  filter_bbox box2d DEFAULT NULL,
  filter_countries text[] DEFAULT NULL,
  max_results int DEFAULT 1
)
 RETURNS TABLE (
   label text,
   address_number text,
   street text,
   municipality text,
   postal_code text,
   sub_region text,
   region text,
   country text,
   geom geometry(Point, 4326)
 )
 LANGUAGE plpgsql
 IMMUTABLE
AS $function$
begin
    RETURN QUERY
    WITH results AS (
      SELECT json_array_elements(payload) rsp
      FROM aws_lambda.invoke(
        aws_commons.create_lambda_function_arn('AuroraGeocoder'),
        json_build_object(
          'text', text,
          'biasPosition',
          CASE WHEN bias_position IS NOT NULL THEN
            array_to_json(ARRAY[ST_X(bias_position), ST_Y(bias_position)])
          END,
          'filterBBox',
          CASE WHEN filter_bbox IS NOT NULL THEN
            array_to_json(ARRAY[ST_XMin(filter_bbox), ST_YMin(filter_bbox), ST_XMax(filter_bbox), ST_YMax(filter_bbox)])
          END,
          'filterCountries', filter_countries,
          'maxResults', max_results
        )
      )
    )
    SELECT
      rsp->'Place'->>'Label' AS label,
      rsp->'Place'->>'AddressNumber' AS address_number,
      rsp->'Place'->>'Street' AS street,
      rsp->'Place'->>'Municipality' AS municipality,
      rsp->'Place'->>'PostalCode' AS postal_code,
      rsp->'Place'->>'SubRegion' AS sub_region,
      rsp->'Place'->>'Region' AS region,
      rsp->'Place'->>'Country' AS country,
      ST_GeomFromGeoJSON(
        json_build_object(
          'type', 'Point',
            'coordinates', rsp->'Place'->'Geometry'->'Point'
        )
      ) geom
    FROM results;
end;
$function$;
```

**Call the SQL function to geocode from Aurora**

Running the SQL statement invokes the Lambda function *AuroraGeocoder*, which takes address records from the database table in the Amazon Aurora PostgreSQL database and geocodes them using a place index resource.

**Note**  
Amazon Aurora PostgreSQL invokes the Lambda function for each call to the SQL user-defined function.   
If you are geocoding 50 rows, Amazon Aurora PostgreSQL invokes the Lambda function 50 times. One invocation for each row.

The following `f_SearchPlaceIndexForText` SQL function makes requests to Amazon Location's `[SearchPlaceIndexForText](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html)` API through the *AuroraGeocoder* Lambda function. The function returns a `geom` column that's a PostGIS geometry, which `ST_AsText(geom)` converts to text.

```
SELECT *, ST_AsText(geom)
FROM f_SearchPlaceIndexForText('Vancouver, BC');
```

By default, the return will contain one row. To request additional rows, up to the `MaxResults` limit, run the following SQL statement while providing a `BiasPosition` and limiting to results in Canada.

```
SELECT *
FROM f_SearchPlaceIndexForText('Mount Pleasant', ST_MakePoint(-123.113, 49.260), null, '{"CAN"}', 5);
```

To filter results using a bounding box, then pass a `[Box2D](https://postgis.net/docs/Box2D.html)` as `filter_bbox`:
+ `[FilterBBox](https://docs.aws.amazon.com/location-places/latest/APIReference/API_SearchPlaceIndexForText.html#locationplaces-SearchPlaceIndexForText-request-FilterBBox)` – Filters the results by returning places within a bounding box. This is an optional parameter. 

```
SELECT *
FROM f_SearchPlaceIndexForText('Mount Pleasant', null, 'BOX(-139.06 48.30, -114.03 60.00)'::box2d, '{"CAN"}', 5);
```

For more information on PostGIS types and functions, see the [PostGIS Reference](https://postgis.net/docs/reference.html).

## Enriching a database containing address data
<a name="aurora-run-sql"></a>

You can construct a formatted address and simultaneously normalize and geocode using the Amazon Location operation `SearchPlaceIndexForText` given a database table with the following data broken out into the following columns:
+ `id`
+ `address`
+ `city`
+ `state`
+ `zip`

```
WITH source_data AS (
  SELECT
    id,
    address || ', ' || city || ', ' || state || ', ' || zip AS formatted_address
  FROM addresses
),
geocoded_data AS (
  SELECT
    *,
    (f_SearchPlaceIndexForText(formatted_address)).*
  FROM source_data
)
SELECT
  id,
  formatted_address,
  label normalized_address,
  ST_Y(geom) latitude,
  ST_X(geom) longitude
FROM geocoded_data
-- limit the number of rows that will be geocoded; remove this to geocode the entire table
LIMIT 1;
```

The following example illustrates one resulting datatable row:

```
 id |      formatted_address         |            normalized_address              |     latitude     |     longitude
----+--------------------------------+--------------------------------------------+------------------+-------------------
 42 | 123 Anytown Ave N, Seattle, WA | 123 Anytown Ave N, Seattle, WA, 12345, USA | 47.6223000127926 | -122.336745971039
(1 row)
```

**Update the database table and populate columns**

The following example updates the table and populates columns with results of `SearchPlaceIndexForText` queries:

```
WITH source_data AS (
  -- select rows that have not been geocoded and created a formatted address for each
  SELECT
    id,
    address || ', ' || city || ', ' || state || ', ' || zip AS formatted_address
  FROM addresses
  WHERE label IS NULL
  -- limit the number of rows that will be geocoded; remove this to geocode the entire table
  LIMIT 1
),
geocoded_data AS (
  -- geocode each row and keep it linked to the source's ID
  SELECT
    id,
    (f_SearchPlaceIndexForText(formatted_address)).*
  FROM source_data
)
UPDATE addresses
-- populate columns
SET
  normalized_address = geocoded_data.label,
  latitude = ST_Y(geocoded_data.geom),
  longitude = ST_X(geocoded_data.geom)
FROM geocoded_data
-- ensure that rows match
WHERE addresses.id = geocoded_data.id;
```

## Next steps
<a name="aurora-amazon-location-next-steps"></a>

Sample code is available in the Amazon Location Service samples repository on [GitHub](https://github.com/aws-samples/amazon-location-samples/tree/main/aurora-udfs), which includes [an AWS CloudFormation template](https://github.com/aws-samples/amazon-location-samples/tree/main/aurora-udfs/cloudformation/template.yaml). 

# Managing your place index resources with Amazon Location
<a name="managing-place-indexes"></a>

You can manage your place index resources using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

## List your place index resources
<a name="viewing-place-indexes"></a>

You can view your place index resources list using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To view a list of place index resources using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Place indexes** from the left navigation pane.

1. View a list of your place index resources under the **My place indexes**.

------
#### [ API ]

Use the `[ListPlaceIndexes](https://docs.aws.amazon.com/location-places/latest/APIReference/API_ListPlaceIndexes.html)` operation from the Amazon Location Places APIs. 

The following example is an API request to get a list of place index resources in the AWS account. 

```
POST /places/v0/list-indexes
```

The following is an example response for `[ListPlaceIndexes](https://docs.aws.amazon.com/location-places/latest/APIReference/API_ListPlaceIndexes.html)`:

```
{
   "Entries": [ 
      { 
         "CreateTime": 2020-10-30T01:38:36Z,
         "DataSource": "Esri",
         "Description": "string",
         "IndexName": "ExamplePlaceIndex",
         "UpdateTime": 2020-10-30T01:40:36Z
      }
   ],
   "NextToken": "1234-5678-9012"
}
```

------
#### [ CLI ]

Use the `[list-place-indexes](https://docs.aws.amazon.com/cli/latest/reference/location/list-place-indexes.html)` command.

The following example is an AWS CLI to get a list of place index resources in the AWS account. 

```
aws location list-place-indexes
```

------

## Get place index resource details
<a name="get-place-index-details"></a>

You can get details about any place index resource in your AWS account using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To view the details of a place index resource using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Place indexes** from the left navigation pane.

1. Under **My place indexes**, select the name link of the target place index resource. 

------
#### [ API ]

Use the `[DescribePlaceIndex](https://docs.aws.amazon.com/location-places/latest/APIReference/API_DescribePlaceIndex.html)` operation from the Amazon Location Place APIs. 

The following example is an API request to get the place index resource details for *ExamplePlaceIndex*.

```
GET /places/v0/indexes/ExamplePlaceIndex
```

The following is an example response for `[DescribePlaceIndex](https://docs.aws.amazon.com/location-places/latest/APIReference/API_DescribePlaceIndex.html)`:

```
{
   "CreateTime": 2020-10-30T01:38:36Z,
   "DataSource": "Esri",
   "DataSourceConfiguration": { 
      "IntendedUse": "SingleUse"
   },
   "Description": "string",
   "IndexArn": "arn:aws:geo:us-west-2:123456789012:place-indexes/ExamplePlaceIndex",
   "IndexName": "ExamplePlaceIndex",
   "Tags": { 
      "string" : "string" 
   },
   "UpdateTime": 2020-10-30T01:40:36Z
}
```

------
#### [ CLI ]

Use the `[describe-place-index](https://docs.aws.amazon.com/cli/latest/reference/location/describe-place-index.html)` command.

The following example is an AWS CLI to get the place index resource details for *ExamplePlaceIndex*.

```
aws location describe-place-index \
    --index-name "ExamplePlaceIndex"
```

------

## Delete a place index resource
<a name="delete-place-index"></a>

You can delete a place index resource from your AWS account using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To delete a place index resource using the Amazon Location console**

**Warning**  
This operation deletes the resource permanently.

 

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Place indexes** from the left navigation pane.

1. Under **My place index**, select the target place index resource. 

1. Choose **Delete place index**.

------
#### [ API ]

Use the `[DeletePlaceIndex](https://docs.aws.amazon.com/location-places/latest/APIReference/API_DeletePlaceIndex.html)` operation from the Amazon Location Places APIs. 

The following example is an API request to delete the place index resource *ExamplePlaceIndex*.

```
DELETE /places/v0/indexes/ExamplePlaceIndex
```

The following is an example success response for `[DeletePlaceIndex](https://docs.aws.amazon.com/location-places/latest/APIReference/API_DeletePlaceIndex.html)`:

```
HTTP/1.1 200
```

------
#### [ CLI ]

Use the `[delete-place-index](https://docs.aws.amazon.com/cli/latest/reference/location/delete-place-index.html)` command.

The following example is an AWS CLI command to delete the place index resource *ExamplePlaceIndex*.

```
aws location delete-place-index \
    --index-name "ExamplePlaceIndex"
```

------

# Calculating routes using Amazon Location Service
<a name="calculating-routes"></a>

**Note**  
We released a new version of the Routes API, see the updated [Routes Developer Guide](https://docs.aws.amazon.com//location/latest/developerguide/routes.html) or [Routes API](https://docs.aws.amazon.com/location/latest/APIReference/API_Operations_Amazon_Location_Service_Routes_V2.html) for revised information.

Amazon Location lets you select a data provider for calculating a route by creating and configuring a route calculator resource.

You can use the route calculator resource to [calculate a route](calculate-route.md) given specific parameters using the AWS SDK, or the REST API endpoints. Use this route calculator resource to calculate routes between an origin, a destination and up to 23 waypoints for different modes of transportation, avoidances, and traffic conditions. 

You can also use the route calculator resource to create inputs for your route planning algorithms or products by [calculating a route matrix](calculate-route-matrix.md). Calculate the travel time and travel distance between a set of departure positions and a set of destination positions. Route planning software can use that time and distance data to optimize a route or a set of routes; for example, if you are planning multiple delivery routes, and want to find the best route and time for each stop. You can calculate a matrix of routes for different modes of transportation, avoidances, and traffic conditions.

**Note**  
For an overview of routing concepts, see [Learn about routing in Amazon Location Service](route-concepts.md).

**Topics**
+ [Prerequisites for calculating routes using Amazon Location](routes-prerequisites.md)
+ [Calculate a route with Amazon Location](calculate-route.md)
+ [Route planning with a route matrix in Amazon Location](calculate-route-matrix.md)
+ [Positions not located on a road in Amazon Location](snap-to-nearby-road.md)
+ [Departure time with Amazon Location](departure-time.md)
+ [Travel mode with Amazon Location](travel-mode.md)
+ [Managing your route calculator resources with Amazon Location](managing-route-calculators.md)

# Prerequisites for calculating routes using Amazon Location
<a name="routes-prerequisites"></a>

This page outlines prerequisites to get started with the service's routing features, which enable you to calculate optimized routes and travel times between multiple locations. It covers essential topics, such as configuring access permissions, setting up the required resources within your AWS account, and any additional dependencies or tools needed based on your specific use case or development environment. 

## Create a route calculator resource
<a name="create-route-calculator-resource"></a>

Before you can calculate a route, create a route calculator resource in your AWS account. 

When you create a route calculator resource, you can choose from the data providers available:

1. **Esri** – For more information about Esri's coverage in your region of interest, see [Esri details on street networks and traffic coverage](https://doc.arcgis.com/en/arcgis-online/reference/network-coverage.htm).

1. **HERE Technologies** – For more information about HERE's coverage in your region of interest, see [HERE car routing coverage](https://developer.here.com/documentation/routing-api/dev_guide/topics/coverage/car-routing.html) and [HERE truck routing coverage](https://developer.here.com/documentation/routing-api/dev_guide/topics/coverage/truck-routing.html).

1. **Grab** – For more information about Grab's coverage, see [Countries/regions and area covered](grab.md#grab-coverage-area).

**Note**  
If your application is tracking or routing assets you use in your business, such as delivery vehicles or employees, you must not use Esri as your geolocation provider. See section 82 of the [AWS service terms](https://aws.amazon.com/service-terms) for more details.

You can do this using the Amazon Location Service console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To create a route calculator resource using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. In the left navigation pane, choose **Route calculators**.

1. Choose **Create route calculator**.

1. Fill out the following boxes:
   + ****Name **** – Enter a name for the route calculator resource. For example, *ExampleCalculator*. Maximum 100 characters. Valid entries include alphanumeric characters, hyphens, periods, and underscores.
   + ****Description** ** – Enter an optional description.

1. For **Data providers**, choose a [data provider](https://aws.amazon.com/location/data-providers/) to use as a route calculator.

1. (Optional) Under **Tags**, enter a tag **Key** and **Value**. This adds a tag your new route calculator resource. For more information, see [Tagging your resources](tagging.md).

1. Choose **Create route calculator**.

------
#### [ API ]

**To create a route calculator resource using the Amazon Location APIs**

Use the `[CreateRouteCalculator](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_CreateRouteCalculator.html)` operation from the Amazon Location Places APIs. 

The following example is an API request to create a route calculator resource called *ExampleCalculator* using the data provider *Esri*. 

```
POST /routes/v0/calculators
Content-type: application/json

{
   "CalculatorName": "ExampleCalculator",
   "DataSource": "Esri",
   "Description": "string",
   "Tags": { 
      "Tag1" : "Value1" 
   }
}
```

------
#### [ AWS CLI ]

**To create a route calculator resource using AWS CLI commands**

Use the `create-route-calculator` command.

The following example creates a route calculator resource called *ExampleCalculator* using *Esri* as the data provider. 

```
aws location \
  create-route-calculator \
  --calculator-name "ExampleCalculator" \
  --data-source "Esri" \
  --tags Tag1=Value1
```

------

**Note**  
Billing depends on your usage. You may incur fees for the use of other AWS services. For more information, see [Amazon Location Service pricing](https://aws.amazon.com/location/pricing/).

## Authenticating your requests
<a name="routes-identity-pool"></a>

Once you create a route calculator resource and you're ready to begin building location features into your application, choose how you would authenticate your requests: 
+ To explore ways you can access the services, see [Accessing Amazon Location Service](how-to-access.md).
+ If you have a website with anonymous users, you may want to use API Keys or Amazon Cognito.

  **Example**

  The following example shows using an API key for authorization, using [AWS JavaScript SDK v3](https://aws.amazon.com/sdk-for-javascript/), and the Amazon Location [JavaScript Authentication helper](loc-sdk-auth.md).

  ```
  import { LocationClient, CalculateRouteCommand } from "@aws-sdk/client-location";
  import { withAPIKey } from "@aws/amazon-location-utilities-auth-helper";
  
  const apiKey = "v1.public.your-api-key-value"; // API key
  
  // Create an authentication helper instance using an API key
  const authHelper = await withAPIKey(apiKey);
  
  const client = new LocationClient({
    region: "<region>", // region containing Cognito pool
    ...authHelper.getLocationClientConfig(), // Provides configuration required to make requests to Amazon Location
  });
  
  const input = {
    CalculatorName: "ExampleCalculator",
    DeparturePosition: [-123.4567, 45.6789],
    DestinationPosition: [-123.123, 45.234],
  };
  
  const command = new CalculateRouteCommand(input);
  
  const response = await client.send(command);
  ```

# Calculate a route with Amazon Location
<a name="calculate-route"></a>

You can use Amazon Location Service to calculate routes between an origin and a destination, with up to 23 waypoints along the route, for different modes of transportation, avoidances, and traffic conditions.

**Note**  
You must first create a route calculator resource and set up authentication for your requests to Amazon Location. For more information, see [Prerequisites for calculating routes using Amazon Location](routes-prerequisites.md).

## Start calculating routes
<a name="start-calculate-route"></a>

Submit a simple request by using the `[CalculateRoute](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_CalculateRoute.html)` operation. A simple request contains the following required fields:
+ `DeparturePosition` – The starting position for which to calculate the route from. Defined as `[longitude, latitude]`
+ `DestinationPosition` – The end position to which to calculate the route. Defined as `[longitude, latitude]`. 

**Note**  
If you specify a departure or destination position that's not located on a road, Amazon Location [moves the position to the nearest road](snap-to-nearby-road.md).

You can optionally specify [waypoints](#waypoints), a [departure time](departure-time.md), and a [ travel mode](travel-mode.md) in your request.

You can use the AWS CLI or the Amazon Location APIs.

------
#### [ API ]

The following example is a `CalculateRoute` request using the route calculator resource *ExampleCalculator*. The request specifies calculating a route from a departure position [*-122.7565*, *49.0021*] to a destination position [*-122.3394*, *47.6159*].

```
POST /routes/v0/calculators/ExampleCalculator/calculate/route
Content-type: application/json
{
   "DeparturePosition": [-122.7565,49.0021],
   "DestinationPosition": [-122.3394, 47.6159]
}
```

------
#### [ AWS CLI ]

The following example is a `calculate-route` command using the route calculator resource *ExampleCalculator*. The request specifies calculating a route from a departure position [*-122.7565*, *49.0021*] to a destination position [*-122.3394*, *47.6159*].

```
aws location \
    calculate-route \
        --calculator-name ExampleCalculator \
        --departure-position -122.7565 49.0021 \
        --destination-position -122.3394 47.6159
```

------

By default, the response returns `Distance` in kilometers. You can change the unit of measurement to miles using the following optional parameter:
+ `DistanceUnit` – Specifies the unit system to use for the distance results.

**Example**  

```
POST /routes/v0/calculators/ExampleCalculator/calculate/route
Content-type: application/json
{
   "DeparturePosition": [-122.7565,49.0021],
   "DestinationPosition": [-122.3394, 47.6159],
   "DistanceUnit": "Miles"
}
```

## Setting waypoints
<a name="waypoints"></a>

When calculating a route, you can specify up to 23 intermediate stopover points between the departure position and the destination position using waypoint positions.
+ `WaypointPositions` – Specifies an ordered list of intermediate positions to include along a route between the departure position and destination position. 
**Note**  
If you specify a waypoint position that's not located on a road, Amazon Location moves the position to the nearest road.

**Example**  
The following `[CalculateRoute](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_CalculateRoute.html)` request calculates a route with 2 waypoints:  
+ The departure position is [-122.7565, 49.0021], and the destination position is [-122.3394, 47.6159].
+ For the request parameter `WaypointPositions`:
  + The first stop over position is [*-122.1884, 48.0936*]. 
  + The second stop over position is [*-122.3493, 47.6205*]. 
+ To include the leg linestring geometry between these two waypoints, set the following optional parameter to *true*:
  + `IncludeLegGeometry` – Includes the geometry of each path between a pair of positions in the response.

```
POST /routes/v0/calculators/ExampleCalculator/calculate/route
Content-type: application/json
{
   "DeparturePosition": [-122.7565,49.0021],
   "DestinationPosition": [-122.3394, 47.6159],
   "WaypointPositions":[
        [-122.1884,48.0936],
        [-122.3493,47.6205]
    ],
   "IncludeLegGeometry": true
}
```

## Example response
<a name="example-response-calculate-route"></a>

The following is an example request with the corresponding response when calling the `[CalculateRoute](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_CalculateRoute.html)` operation from the Amazon Location Routes API with the `IncludeLegGeometry` set to *true*, which includes the linestring geometry of each path between a pair of positions in the response.

------
#### [ Example request ]

```
POST /routes/v0/calculators/ExampleCalculator/calculate/route
Content-type: application/json
{
   "DeparturePosition": [-122.7565,49.0021],
   "DestinationPosition": [-122.3394, 47.6159],
   "IncludeLegGeometry": true
}
```

------
#### [ Example response ]

```
{
   "Legs": [ 
      { 
         "Distance": 178.5,
         "DurationSeconds": 6480,
         "EndPosition": [-122.3394,47.6159],
         "Geometry": { 
            "LineString": [ 
               [-122.7565,49.0021],
               [-122.3394,47.6159]
            ]
         },
         "StartPosition": [-122.7565,49.0021],
         "Steps": [ 
            { 
               "Distance": 178.5,
               "DurationSeconds": 6480,
               "EndPosition": [-122.3394,47.6159],
               "GeometryOffset": 0,
               "StartPosition": [-122.7565,49.0021]
            }
         ]
      }
   ],
   "Summary": { 
      "DataSource": "Esri",
      "Distance": 178.5,
      "DistanceUnit": "Kilometers",
      "DurationSeconds": 6480,
      "RouteBBox": [
        -122.7565,49.0021,
        -122.3394,47.6159
    ]
   }
}
```

------

# Route planning with a route matrix in Amazon Location
<a name="calculate-route-matrix"></a>

You can use Amazon Location Service to create inputs to your route planning and optimization software. You can create route results, including travel time and travel distance, for routes between a set of departure positions and a set of destination positions.

For example, given departure positions A and B, and destination positions X and Y, Amazon Location Service will return travel time and travel distance for routes from A to X, A to Y, B to X, and B to Y. 

You can calculate the routes with different modes of transportation, avoidances, and traffic conditions. For example, you can specify that the vehicle is a truck that is 35 feet long, and the route calculated will use those restrictions to determine the travel time and travel distance.

The number of results returned (and routes calculated) is the number of departure positions multiplied by the number of destination positions. You are charged for each route calculated, not each request to the service, so a route matrix with 10 departures and 10 destinations will be billed as 100 routes.

## Calculating a route matrix
<a name="calc-route-matrix-howto"></a>

You can calculate a matrix of routes between a set of departure positions and a set of destination positions. The route results will include travel time and travel distance.

**Prerequisite**
+ You must first create a route calculator resource and set up authentication for your requests to Amazon Location. For more information, see [Prerequisites for calculating routes using Amazon Location](routes-prerequisites.md).

Submit a request by using the `[CalculateRouteMatrix](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_CalculateRouteMatrix.html)` operation. A minimal request contains the following required fields:
+ `DeparturePositions` – The set of starting positions for which to calculate the routes. Defined as an array of `[longitude, latitude]`
+ `DestinationPositions` – The set of end positions for which to calculate the routes. Defined as an array of `[longitude, latitude]`. 

**Note**  
If you specify a departure or destination position that's not located on a road, Amazon Location [moves the position to the nearest road](snap-to-nearby-road.md).

You can optionally specify a [departure time](departure-time.md), and a [ travel mode](travel-mode.md) in your request.

You can use the AWS CLI or the Amazon Location APIs.

------
#### [ API ]

The following example is a `CalculateRouteMatrix` request using the route calculator resource *ExampleCalculator*. The request specifies calculating the matrix of routes from departure positions [*-122.7565*, *49.0021 *] and [*-122.2014*, *47.6101*] to destination positions [*-122.3394*, *47.6159 *] and [*-122.4813*, *48.7511*].

```
POST /routes/v0/calculators/ExampleCalculator/calculate/route-matrix
Content-type: application/json
{
   "DeparturePositions": [
       [-122.7565,49.0021],
       [-122.2014,47.6101]
   ],
   "DestinationPositions": [
       [-122.3394, 47.6159],
       [-122.4813,48.7511]
   ]
}
```

------
#### [ AWS CLI ]

The following example is a `calculate-route-matrix` command using the route calculator resource *ExampleCalculator*. The request specifies calculating the matrix of routes from departure positions [*-122.7565*, *49.0021 *] and [*-122.2014*, *47.6101*] to destination positions [*-122.3394*, *47.6159 *] and [*-122.4813*, *48.7511*].

```
aws location \
    calculate-route-matrix \
        --calculator-name ExampleCalculator \
        --departure-positions "[[-122.7565,49.0021],[-122.2014,47.6101]]" \
	    --destination-positions "[[-122.3394,47.6159],[-122.4813,48.7511]]"
```

------

By default, the response returns `Distance` in kilometers. You can change the unit of measurement to miles using the following optional parameter:
+ `DistanceUnit` – Specifies the unit system to use for the distance results.

**Example**  

```
POST /routes/v0/calculators/ExampleCalculator/calculate/route-matrix
Content-type: application/json
{
   "DeparturePositions": [
       [-122.7565,49.0021],
       [-122.2014,47.6101]
   ],
   "DestinationPositions": [
       [-122.3394, 47.6159],
       [-122.4813,48.7511]
   ],
   "DistanceUnit": "Miles"
}
```

## Restrictions on departure and destination positions
<a name="matrix-routing-position-limits"></a>

When calculating a route matrix, there are restrictions on the departure and destination positions. These restrictions vary depending on the provider used by the `RouteCalculator` resource.


****  

| Limitation | Esri | Grab | HERE | 
| --- | --- | --- | --- | 
| Number of positions | Up to 10 departure positions and 10 destination positions. | Up to 350 departure positions and 350 destination positions. |  Up to 350 departure positions and 350 destination positions. For longer routes, additional restrictions apply. See the [ section](#matrix-routing-longer-routes).  | 
| Distance between positions | Any pair of departure and destination positions must be within 400 km of each other (40km for walking routes). |  |  All departure and destination positions must fall within a 180 km diameter circle. For longer routes, additional restrictions apply. See the [ section](#matrix-routing-longer-routes).  | 
| Route length | Routes will not be completed if the total travel time for the route is over 400 minutes. |    |  Routes that deviate more than 10 km outside a circle around the departure and destination points will not be calculated. For longer routes, additional restrictions apply. See the [ section](#matrix-routing-longer-routes).  | 
| Regions | Calculating a route matrix is not supported in Korea. | Available in Southeast Asia. For a list of supported countries/regions and more information, see [Countries/regions and area covered](grab.md#grab-coverage-area). | No additional restrictions. | 

### Longer route planning
<a name="matrix-routing-longer-routes"></a>

Calculating a matrix of route results is useful for efficient route planning, but the calculation can take some time. All of the Amazon Location Service data providers put limitations on the number of routes or the distance of the routes that can be calculated. For example, HERE allows creating routes between 350 departure and destination positions, but those positions must fall within a 180km circle. What if you want to plan with longer routes?

You can calculate a matrix of routes with unrestricted lengths for a smaller numbers of routes, using, a `RouteCalculator` with HERE as the data provider. This does not change the way that you call the `[CalculateRouteMatrix](https://docs.aws.amazon.com/location/previous/APIReference/API_CalculateRouteMatrix.html)` API, Amazon Location simply allows longer routes when you meet the requirements.

The requirements for longer length route calculations are:
+ The `RouteCalculator` must use the HERE data provider.
+ The number of departure positions must not be greater than 15.
+ The total number of routes to calculate must not be greater than 100.
+ Long distance routing is not allowed for truck routing with toll avoidances when the routes are greater than 1,000 km. This combination is slower to calculate, and can cause the call to time out. You can calculate these routes individually with the [CalculateRoute](https://docs.aws.amazon.com/location/previous/APIReference/API_CalculateRoute.html) operation.

If your call does not meet these requirements (for example, you are requesting 150 route calculations in a single call), then `CalculateRouteMatrix` will revert to only allowing the shorter route rules. You can then calculate the routes, as long as the positions are within a 180km circle.

When calculating longer routes, keep these points in mind:
+ Longer routes can take longer to calculate, even longer than the maximum time for Amazon Location APIs. If you get frequent timeouts with specific routes, you can try a smaller number of routes in each call to `CalculateRouteMatrix`.
+ If you add more destination or departure positions to your `CalculateRouteMatrix` request, the operation can switch into the more restricted mode, and you can get an error for a route that can be calculated without issue when there are fewer routes to create. In this case, reduce the number of destination or departure positions, and make multiple requests to get the full set of route calculations that you need.

## Example response
<a name="example-response-route-matrix"></a>

The following is an example request with the corresponding response when calling the `[CalculateRouteMatrix](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_CalculateRouteMatrix.html)` operation from the Amazon Location Routes API.

------
#### [ Example request ]

```
POST /routes/v0/calculators/ExampleCalculator/calculate/route-matrix
Content-type: application/json
{
   "DeparturePositions": [
       [-122.7565,49.0021],
       [-122.2014,47.6101]
   ],
   "DestinationPositions": [
       [-122.3394, 47.6159],
       [-122.4813,48.7511]
   ]
}
```

------
#### [ Example response ]

```
{
    "RouteMatrix": [
        [
            {
                "Distance": 178.764,
                "DurationSeconds": 7565
            },
            {
                "Distance": 39.795,
                "DurationSeconds": 1955
            }
        ],
        [
            {
                "Distance": 15.31,
                "DurationSeconds": 1217
            },
            {
                "Distance": 142.506,
                "DurationSeconds": 6279
            }
        ]
    ],
    "Summary": {
        "DataSource": "Here",
        "RouteCount": 4,
        "ErrorCount": 0,
        "DistanceUnit": "Kilometers"
    }
}
```

------

# Positions not located on a road in Amazon Location
<a name="snap-to-nearby-road"></a>

When using `CalculateRoute` or `CalculateRouteMatrix`, if you specify a departure, destination, or waypoint position that's not located on a road Amazon Location moves the position to a nearby road.

The following `[CalculateRoute](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_CalculateRoute.html)` request specifies a departure position and destination position that's not located on a road:

```
POST /routes/v0/calculators/ExampleCalculator/calculate/route
Content-type: application/json
{
   "DeparturePosition": [-123.128014, 49.298472],
   "DestinationPosition": [-123.134701, 49. 294315]
}
```

The resulting response returns a position that's snapped to a nearby road:

```
{
   "Legs": [
      {
         "StartPosition": [-123.12815, 49.29717],
         "EndPosition":   [-123.13375, 49.2926],
         "Distance": 4.223,
         "DurationSeconds": 697,
         "Steps": [
            {
               "StartPosition": [ -123.12815, 49.29717 ],
               "EndPosition":   [ -123.12806, 49.29707 ],
               "Distance": 0.013,
               "DurationSeconds": 8
            },
            {
               "StartPosition": [ -123.12806, 49.29707 ],
               "EndPosition":   [ -123.1288, 49.29659 ],
               "Distance": 0.082,
               "DurationSeconds": 36
            },
            {
               "StartPosition": [ -123.1288, 49.29659 ],
               "EndPosition":   [ -123.12021, 49.29853 ],
               "Distance": 0.742,
               "DurationSeconds": 128
            },
            {
               "StartPosition": [ -123.12021, 49.29853 ],
               "EndPosition":   [ -123.1201, 49.29959 ],
               "Distance": 0.131,
               "DurationSeconds": 26
            },
            {
               "StartPosition": [ -123.1201, 49.29959 ],
               "EndPosition":   [ -123.13562, 49.30681 ],
               "Distance": 1.47,
               "DurationSeconds": 238
            },
            {
               "StartPosition": [ -123.13562, 49.30681 ],
               "EndPosition":   [ -123.13693, 49.30615 ],
               "Distance": 0.121,
               "DurationSeconds": 28
            },
            {
               "StartPosition": [ -123.13693, 49.30615 ],
               "EndPosition":   [ -123.13598, 49.29755 ],
               "Distance": 0.97,
               "DurationSeconds": 156
            },
            {
               "StartPosition": [ -123.13598, 49.29755 ],
               "EndPosition":   [ -123.13688, 49.29717 ],
               "Distance": 0.085,
               "DurationSeconds": 15
            },
            {
               "StartPosition": [ -123.13688, 49.29717 ],
               "EndPosition":   [ -123.13375, 49.2926 ],
               "Distance": 0.609,
               "DurationSeconds": 62
            }
         ]
      }
   ],
   "Summary": {
      "RouteBBox": [ -123.13693, 49.2926, -123.1201, 49.30681 ],
      "DataSource": "Here",
      "Distance": 4.223,
      "DurationSeconds": 697,
      "DistanceUnit": "Kilometers"
   }
}
```

# Departure time with Amazon Location
<a name="departure-time"></a>

By default, when you call `CalculateRoute` or `CalculateRouteMatrix`, if you don't provide a departure time in the request, the calculated routes reflects optimal traffic conditions.

You can set a specific a departure time to use live and predictive traffic conditions from your chosen data provider, by using one of the following options:
+ `DepartNow` – When set to *true*, it uses live traffic conditions to calculate the fastest travel path.
+ `DepartureTime` – When provided, it uses predictive and known traffic conditions for the requested time. Defined in the following [format](https://www.iso.org/iso-8601-date-and-time-format.html): `YYYY-MM-DDThh:mm:ss.sssZ`. 

**Example**  
The following `[CalculateRoute](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_CalculateRoute.html)` request sets the departure time to July 2, 2024, at 12:15:20 UTC.  

```
POST /routes/v0/calculators/ExampleCalculator/calculate/route
Content-type: application/json
{
   "DeparturePosition": [-122.7565,49.0021],
   "DestinationPosition": [-122.3394, 47.6159],
   "WaypointPositions":[
        [-122.1884,48.0936],
        [-122.3493,47.6205]
    ]
    "IncludeLegGeometry": true,
    "DepartureTime": 2024-07-02T12:15:20.000Z,
}
```

# Travel mode with Amazon Location
<a name="travel-mode"></a>

You can set a travel mode when using `CalculateRoute` or `CalculateRouteMatrix`. The mode of travel affects speed of travel and road compatibility. While the default mode of travel is by car, you can specify which mode of travel you're using while traveling along a route with the following optional parameter:
+ `TravelMode` – Specifies the mode of transport when calculating a route, such as: *`Bicycle`*, *`Car`*, *`Motorcycle`*, *`Truck`*, or *`Walking`*.

**Limitations**
+ If you specify `Walking` for the travel mode and your data provider is Esri, the start and destination must be within 40km.
+ `Bicycle` or `Motorcycle` are available only when using Grab as the data provider.
+ Grab provides only `Bicycle` and `Walking` routes in certain cities. For more information, see [Countries/regions and area covered](grab.md#grab-coverage-area).
+ `Truck` is not available when using Grab as the data provider.

**Additional preferences**

If you specify a `TravelMode` of *`Car`*, you can specify additional route preferences with the following optional parameter:
+ `CarModeOptions` – Specifies route preferences when traveling in a car, such as *`AvoidFerries`* or *`AvoidTolls`*.

If you specify a `TravelMode` of *`Truck`*, you can specify additional route preferences with the following optional parameter:
+ `TruckModeOptions` – Specifies route preferences when traveling in a truck, such as *`AvoidFerries`* or *`AvoidTolls`*, in addition to specifying routes that can accommodate the *`TruckDimensions`* and *`TruckWeight`*.

**Example**  
The following `[CalculateRoute](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_CalculateRoute.html)` request specifies *`Truck`* as the mode of travel. Additional route restrictions include: avoiding routes that use ferries and avoiding roads that can't accommodate the truck dimensions and weight.  

```
{
   "DeparturePosition": [-122.7565,49.0021],
   "DestinationPosition": [-122.3394, 47.6159],
   "DepartNow": true,
   "TravelMode": "Truck",
   "TruckModeOptions": { 
      "AvoidFerries": true,
      "AvoidTolls": false,
      "Dimensions": { 
         "Height": 4.5,
         "Length": 15.5,
         "Unit": "Meters",
         "Width": 4.5
      },
      "Weight": { 
         "Total": 7500,
         "Unit": "Pounds"
      }
   }
}
```

# Managing your route calculator resources with Amazon Location
<a name="managing-route-calculators"></a>

You can manage your route calculator resources using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

## List your route calculator resources
<a name="viewing-route-calculators"></a>

You can view your route calculator list using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To view a list of route calculators using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Route calculators** from the left navigation pane.

1. View the route calculator details under **My route calculators**.

------
#### [ API ]

Use the `[ListRouteCalculators](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_ListRouteCalculators.html)` operation from the Amazon Location Routes APIs. 

The following example is an API request to get a list of route calculators in the AWS account. 

```
POST /routes/v0/list-calculators
```

The following is an example response for `[ListRouteCalculators](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_ListRouteCalculators.html)`:

```
{
       "Entries": [ 
          { 
             "CalculatorName": "ExampleCalculator",
             "CreateTime": 2020-09-30T22:59:34.142Z,
             "DataSource": "Esri",
             "Description": "string",
             "UpdateTime": 2020-09-30T23:59:34.142Z
          }
       ],
       "NextToken": "1234-5678-9012"
    }
```

------
#### [ CLI ]

Use the `list-route-calculators` command.

The following example is an AWS CLI to get a list of route calculators in the AWS account. 

```
aws location list-route-calculators
```

------

## Get route calculator details
<a name="get-route-calculator-details"></a>

You can get details about any route calculator resource in your AWS account using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To view the details of a route calculator using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Route calculators** from the left navigation pane.

1. Under **My route calculators**, select the name link of the target route calculator. 

------
#### [ API ]

Use the `[DescribeRouteCalculator](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_DescribeRouteCalculator.html)` operation from the Amazon Location Routes APIs. 

The following example is an API request to get the route calculator details for *ExampleCalculator*.

```
GET /routes/v0/calculators/ExampleCalculator
```

The following is an example response for `[DescribeRouteCalculator](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_DescribeRouteCalculator.html)`:

```
{
       "CalculatorArn": "arn:aws:geo:us-west-2:123456789012:route-calculator/ExampleCalculator",
       "CalculatorName": "ExampleCalculator",
       "CreateTime": 2020-09-30T22:59:34.142Z,
       "DataSource": "Esri",
       "Description": "string",
       "Tags": { 
          "Tag1" : "Value1" 
       },
       "UpdateTime": 2020-09-30T23:59:34.142Z
    }
```

------
#### [ CLI ]

Use the `describe-route-calculator` command.

The following example is an AWS CLI to get the route calculator details for *ExampleCalculator*.

```
aws location describe-route-calculator \
        --calculator-name "ExampleCalculator"
```

------

## Delete a route calculator
<a name="delete-route-calculator"></a>

You can delete a route calculator from your AWS account using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To delete a route calculator using the Amazon Location console**

**Warning**  
This operation deletes the resource permanently. 

 

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Route calculators** from the left navigation pane.

1. Under **My route calculators**, select the target route calculator. 

1. Choose **Delete route calculator**.

------
#### [ API ]

Use the `[DeleteRouteCalculator](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_DeleteRouteCalculator.html)` operation from the Amazon Location Routes APIs. 

The following example is an API request to delete the geofence collection *ExampleCalculator*.

```
DELETE /routes/v0/calculators/ExampleCalculator
```

The following is an example response for `[DeleteRouteCalculator](https://docs.aws.amazon.com/location-routes/latest/APIReference/API_DeleteRouteCalculator.html)`:

```
HTTP/1.1 200
```

------
#### [ CLI ]

Use the `delete-route-calculator` command.

The following example is an AWS CLI command to delete the geofence collection *ExampleCalculator*.

```
aws location delete-route-calculator \
        --calculator-name "ExampleCalculator"
```

------

# Geofencing an area of interest using Amazon Location
<a name="geofence-an-area"></a>

A geofencing application evaluates a tracked device’s position relative to previously registered areas of interest. This enables actions to be taken based on position updates. For example, you can initiate an event that prompts a notification when a customer who ordered coffee on their mobile app is near a store.

**Note**  
For an overview of geofencing and tracker concepts, see [Learn about geofences and trackers in Amazon Location Service](geofence-tracker-concepts.md).

This section of the guide provides step-by-step instructions for creating a geofencing application using Amazon Location Service.

Overview of steps

1. Add geofences around areas of interest and store them in a geofence collection resource. 

1. Start tracking your target devices and store the device location history in a tracker resource.

1. Link your tracker resource to your geofence collection resource so that device location updates are automatically evaluated against all your geofences.

1. You can evaluate device positions directly against your geofence collection resources if you don’t want to use Amazon Location Trackers to keep your devices’ location history.

After you implement your geofencing solution, your geofence collection resource emits the following events:
+ `ENTER` — A tracked device enters a geofence within a geofence collection.
+ `EXIT` — A tracked device exits a geofence within a geofence collection.

You can use Amazon EventBridge to react to events by routing them elsewhere.

As an alternative to sending updates via the Amazon Location Service APIs from each device, you can use MQTT to send device updates.

The following topics describe these steps and alternatives in detail.

**Topics**
+ [Add geofences with Amazon Location](add-geofences.md)
+ [Start tracking with Amazon Location](start-tracking.md)
+ [Tutorial: Link a tracker to a geofence collection in Amazon Location](associate-consumer.md)
+ [Evaluate device positions against geofences in Amazon Location](evaluate-geofences.md)
+ [Tutorial: Verify device positions with Amazon Location](verify-device-positions.md)
+ [Reacting to Amazon Location Service events with Amazon EventBridge](location-events.md)
+ [Track with AWS IoT, MQTT, with Amazon Location Service](tracking-using-mqtt.md)
+ [Manage geofence collection resources with Amazon Location](managing-geofence-collections.md)
+ [Manage tracker resources with Amazon Location](managing-trackers.md)
+ [Sample Geofencing and Tracking mobile application](geofence-tracking-tutorials.md)

# Add geofences with Amazon Location
<a name="add-geofences"></a>

Geofences contain points and vertices that form a closed boundary, which defines an area of interest. Geofence collections store and manage one or multiple geofences. 

Amazon Location geofence collections stores geofences defined by using a standard geospatial data format called [GeoJSON (RFC 7946)](https://geojson.org/). You can use tools, such as [geojson.io](http://geojson.io/), at no charge to draw your geofences graphically and save the output GeoJSON file.

**Note**  
Amazon Location doesn't support polygons with holes, multipolygons, clockwise polygons, and geofences that cross the antimeridian.

**Topics**
+ [Create a geofence collection](#create-geofence-collection)
+ [Draw geofences](#draw-geofences)
+ [Adding polygon geofences](#draw-polygon-geofences)
+ [Adding circular geofences](#draw-circle-geofences)

## Create a geofence collection
<a name="create-geofence-collection"></a>

Create a geofence collection to store and manage geofences by using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To create a geofence collection using the Amazon Location console**

1. Open the Amazon Location Service console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. In the left navigation pane, choose **Geofence collections**.

1. Choose **Create geofence collection**.

1. Fill out the following boxes:
   + ****Name **** – Enter a unique name. For example, *ExampleGeofenceCollection*. Maximum 100 characters. Valid entries include alphanumeric characters, hyphens, periods, and underscores.
   + ****Description **** – Enter an optional description to differentiate your resources.

1. Under **EventBridge rule with CloudWatch as a target**, you can create an optional EventBridge rule to get started [reacting to geofence events.](location-events.md) This enables Amazon Location to publish events to Amazon CloudWatch Logs.

1. (Optional) Under **Tags**, enter a tag **Key** and **Value**. This adds a tag your new geofence collection. For more information, see [Tag your Amazon Location Service resources](tagging.md).

1. (Optional) Under **Customer managed key encryption**, you can choose to **Add a customer managed key**. This adds a symmetric customer managed key that you create, own, and manage over the default AWS owned encryption. For more information, see [Encrypting data at rest](encryption-at-rest.md).

1. Choose **Create geofence collection**.

------
#### [ API ]

**To create a geofence collection using the Amazon Location APIs**

Use the `[CreateGeofenceCollection](https://docs.aws.amazon.com/location-geofences/latest/APIReference/API_CreateGeofenceCollection.html)` operation from the Amazon Location Geofences APIs. 

The following example uses an API request to create a geofence collection called *ExampleGeofenceCollection*. The geofence collection is associated with a [customer managed AWS KMS key to encrypt customer data](encryption-at-rest.md).

```
POST /geofencing/v0/collections
Content-type: application/json

{
   "CollectionName": "ExampleGeofenceCollection",
   "Description": "Geofence collection 1 for shopping center",
   "KmsKeyId": "1234abcd-12ab-34cd-56ef-1234567890ab",
   "Tags": { 
      "Tag1" : "Value1"
   }
}
```

------
#### [ AWS CLI ]

**To create a geofence collection using AWS CLI commands**

Use the `[create-geofence-collection](https://docs.aws.amazon.com/cli/latest/reference/location/create-geofence-collection.html)` command.

The following example uses an AWS CLI to create a geofence collection called *ExampleGeofenceCollection*. The geofence collection is associated with a [customer managed AWS KMS key to encrypt customer data](encryption-at-rest.md).

```
aws location \
  create-geofence-collection \
  --collection-name "ExampleGeofenceCollection" \
  --description "Shopping center geofence collection" \
  --kms-key-id "1234abcd-12ab-34cd-56ef-1234567890ab" \
  --tags Tag1=Value1
```

------

**Note**  
Billing depends on your usage. You may incur fees for the use of other AWS services. For more information, see [Amazon Location Service pricing](https://aws.amazon.com/location/pricing/).

## Draw geofences
<a name="draw-geofences"></a>

Now that you've created your geofence collection, you can define your geofences. Geofences are defined either as a polygon or as a circle. To draw a polygon geofence you can use a GeoJSON editing tool, such as [geojson.io](http://geojson.io/).

To create a geofence as a circle, you must define the center point of the circle, and the radius. For example, if you want to create a geofence to be notified whenever a device comes within 50 meters of a specific location, you would use the latitude and longitude of that location and specify the radius as 50 meters.

Using the Amazon Location Service APIs, you can also add metadata to your geofence, in the form of key-value pairs. These can be useful for storing information about the geofence, such as its type, or other information that is specific to your application. You can use this metadata when [Reacting to Amazon Location Service events with Amazon EventBridge](location-events.md).

## Adding polygon geofences
<a name="draw-polygon-geofences"></a>

This section describes creating polygon geofences

### Draw geofences using a GeoJSON tool
<a name="draw-geofences-geojson"></a>

Now that you've created your geofence collection, you can define your geofences by using a GeoJSON editing tool, such as [geojson.io](http://geojson.io/).

**To create a GeoJSON file**

1. Open a GeoJSON editing tool. For example, geojson.io.

1. Choose the **Draw a polygon** icon and draw your area of interest.

1. Choose **Save**, then choose **GeoJSON** from the dropdown menu.

### Put GeoJSON geofences in a geofence collection
<a name="put-geofences"></a>

 You can use the resulting GeoJSON file to upload your geofences using the Amazon Location Service console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To add a geofence to a geofence collection using the Amazon Location Service console**

1. Open the Amazon Location Service console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. In the left navigation pane, choose **Geofence collections**.

1. From the **Geofence collections** list, select the name link for the target geofence collection.

1. Under **Geofences**, choose **Create geofences**.

1. In the **Add geofences** window, drag, and drop your GeoJSON into the window. 

1. Choose **Add geofences**.

------
#### [ API ]

**To add geofences using the Amazon Location APIs**

Use the `[PutGeofence](https://docs.aws.amazon.com/location-geofences/latest/APIReference/API_PutGeofence.html)` operation from the Amazon Location Geofences APIs. 

The following example uses an API request to add a geofence given the ID *GEOFENCE-EXAMPLE1* to a geofence collection called *ExampleGeofenceCollection*. It also specifies a single geofence metadata property with the key `Type` and value `loadingArea`.

```
PUT /geofencing/v0/collections/ExampleGeofenceCollection/geofence/GEOFENCE-EXAMPLE1
    Content-type: application/json
    
    {
       "GeofenceProperties": {
          "Type" : "loadingArea"
       },
       "Geometry": { 
          "Polygon": [   
            [
                [-5.716667, -15.933333],
                [-14.416667, -7.933333],
                [-12.316667, -37.066667],
                [-5.716667, -15.933333]
            ]
          ]
       }
    }
```

Alternatively, you can add more than one geofence using the `[BatchPutGeofence](https://docs.aws.amazon.com/location-geofences/latest/APIReference/API_BatchPutGeofence.html)` operation. 

```
POST /geofencing/v0/collections/ExampleGeofenceCollection/put-geofences
    Content-type: application/json
    
    {
       "Entries": [ 
          {
             "GeofenceProperties": {
                "Type" : "loadingArea"
             },
             "GeofenceId": "GEOFENCE-EXAMPLE1",
             "Geometry": { 
                "Polygon": [ 
                   [ 
                      [-5.716667, -15.933333],
                      [-14.416667, -7.933333],
                      [-12.316667, -37.066667],
                      [-5.716667, -15.933333]
                   ]
                ]
             }
          }
       ]
    }
```

------
#### [ AWS CLI ]

**To add a geofence to a geofence collection using AWS CLI commands**

Use the `[put-geofence](https://docs.aws.amazon.com/cli/latest/reference/location/put-geofence.html)` command.

The following example uses an AWS CLI to add a geofence to a geofence collection called *ExampleGeofenceCollection*.

```
$ aws location \
        put-geofence \
            --collection-name ExampleGeofenceCollection \
            --geofence-id ExampleGeofenceTriangle \
            --geofence-properties '{"Type": "loadingArea"}' \
            --geometry 'Polygon=[[[-5.716667, -15.933333],[-14.416667, -7.933333],[-12.316667, -37.066667],[-5.716667, -15.933333]]]'
    {
        "CreateTime": "2020-11-11T00:16:14.487000+00:00",
        "GeofenceId": "ExampleGeofenceTriangle",
        "UpdateTime": "2020-11-11T00:19:59.894000+00:00"
    }
```

------

## Adding circular geofences
<a name="draw-circle-geofences"></a>

This section describes creating circular geofences. You must know the latitude and longitude of the point that you want to be the center of the circle, and the radius in meters of the circle. You can create circular geofences with the Amazon Location APIs or the AWS CLI.

------
#### [ API ]

**To add circular geofences using the Amazon Location APIs**

Use the `[PutGeofence](https://docs.aws.amazon.com/location/previous/APIReference/API_PutGeofence.html)` operation from the Amazon Location Geofences APIs. 

The following example uses an API request to add a geofence given the ID *GEOFENCE-EXAMPLE2* to a geofence collection called *ExampleGeofenceCollection*:

```
PUT /geofencing/v0/collections/ExampleGeofenceCollection/geofence/GEOFENCE-EXAMPLE2
    Content-type: application/json
    
    {
       "Geometry": { 
          "Circle": {   
            "Center": [-5.716667, -15.933333],
            "Radius": 50
          }
       }
    }
```

------
#### [ AWS CLI ]

**To add a circular geofence to a geofence collection using AWS CLI commands**

Use the `[put-geofence](https://docs.aws.amazon.com/cli/latest/reference/location/put-geofence.html)` command.

The following example uses an AWS CLI to add a geofence to a geofence collection called *ExampleGeofenceCollection*.

```
$ aws location \
        put-geofence \
            --collection-name ExampleGeofenceCollection \
            --geofence-id ExampleGeofenceCircle \
            --geometry 'Circle={Center=[-5.716667, -15.933333], Radius=50}'
```

**Note**  
You can also put JSON for complex geometry into its own file as in the following example.  

```
$ aws location \
        put-geofence \
            --collection-name ExampleGeofenceCollection \
            --geofence-id ExampleGeofenceCircle \
            --geometry file:circle.json
```
In the example, the circle.json file includes JSON for the circle geometry.  

```
{
    "Circle": {
        "Center": [-74.006975, 40.717127],
        "Radius": 287.7897969218057
    }
}
```

------

# Start tracking with Amazon Location
<a name="start-tracking"></a>

This section guides you through building a tracking application that captures device locations.

**Topics**
+ [Create a tracker](#start-create-tracker)
+ [Authenticating your requests](#tracking-identity-pool)
+ [Update your tracker with a device position](#send-location-updates)
+ [Get a device's location history from a tracker](#get-location-history)
+ [List your device positions](#list-device-positions)

## Create a tracker
<a name="start-create-tracker"></a>

Create a tracker resource to store and process position updates from your devices. You can use the Amazon Location Service console, the AWS CLI, or the Amazon Location APIs. 

Each position update stored in your tracker resources can include a measure of position accuracy, and up to three fields of metadata about the position or device that you want to store. The metadata is stored as key-value pairs, and can store information such as speed, direction, tire pressure, or engine temperature.

Trackers filter position updates as they are received. This reduces visual noise in your device paths (called *jitter*), and reduces the number of false geofence entry and exit events. This also helps manage costs by reducing the number of geofence evaluations initiated.

Trackers offer three position filtering options to help manage costs and reduce jitter in your location updates.
+ **Accuracy-based** – *Use with any device that provides an accuracy measurement. Most mobile devices provide this information.* The accuracy of each position measurement is affected by many environmental factors, including GPS satellite reception, landscape, and the proximity of Wi-Fi and Bluetooth devices. Most devices, including most mobile devices, can provide an estimate of the accuracy of the measurement along with the measurement. With `AccuracyBased` filtering, Amazon Location ignores location updates if the device moved less than the measured accuracy. For example, if two consecutive updates from a device have an accuracy range of 5 m and 10 m, Amazon Location ignores the second update if the device has moved less than 15 m. Amazon Location neither evaluates ignored updates against geofences, nor stores them.

   When accuracy is not provided, it is treated as zero, and the measurement is considered perfectly accurate.
**Note**  
You can also use accuracy-based filtering to remove all filtering. If you select accuracy-based filtering, but override all accuracy data to zero, or omit the accuracy entirely, then Amazon Location will not filter out any updates.
+ **Distance-based** – *Use when your devices do not provide an accuracy measurement, but you still want to take advantage of filtering to reduce jitter and manage costs.* `DistanceBased` filtering ignores location updates in which devices have moved less than 30 m (98.4 ft). When you use `DistanceBased` position filtering, Amazon Location neither evaluates these ignored updates against geofences nor stores the updates.

  The accuracy of most mobile devices, including the average accuracy of iOS and Android devices, is within 15 m. In most applications, `DistanceBased` filtering can reduce the effect of location inaccuracies when displaying device trajectory on a map, and the bouncing effect of multiple consecutive entry and exit events when devices are near the border of a geofence. It can also help reduce the cost of your application, by making fewer calls to evaluate against linked geofences or retrieve device positions.
+ **Time-based** – (default) *Use when your devices send position updates very frequently (more than once every 30 seconds), and you want to achieve near real-time geofence evaluations without storing every update. *In `TimeBased` filtering, every location update is evaluated against linked geofence collections, but not every location update is stored. If your update frequency is more often than 30 seconds, only one update per 30 seconds is stored for each unique device ID.

**Note**  
Be mindful of the costs of your tracking application when deciding your filtering method and the frequency of position updates. You are billed for every location update and once for evaluating the position update against each linked geofence collection. For example, when using time-based filtering, if your tracker is linked to two geofence collections, every position update will count as one location update request and two geofence collection evaluations. If you are reporting position updates every 5 seconds for your devices and using time-based filtering, you will be billed for 720 location updates and 1,440 geofence evaluations per hour for each device.  
Your bill is not affected by the number of geofences in each collection. Since each geofence collection may contain up to 50,000 geofences, you may want to combine your geofences into fewer collections, where possible, to reduce your cost of geofence evaluations.

By default, you will get EventBridge events each time a tracked device enters or exits a linked geofence. For more information, see [Tutorial: Link a tracker to a geofence collection in Amazon Location](associate-consumer.md).

You can enable events for all filtered position updates for a tracker resource. For more information, see [Enable update events for a tracker](location-events.md#enable-update-events).

**Note**  
If you wish to encrypt your data using your own AWS KMS customer managed key, then the Bounding Polygon Queries feature will be disabled by default. This is because by using this Bounding Polygon Queries feature, a representation of your device positions will not be encrypted using the your AWS KMS managed key. However, the exact device position is still encrypted using your managed key.  
You can choose to opt-in to the Bounding Polygon Queries feature by setting the `KmsKeyEnableGeospatialQueries` parameter to true when creating or updating a Tracker.

------
#### [ Console ]

**To create a tracker using the Amazon Location console**

1. Open the Amazon Location Service console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. In the left navigation pane, choose **Trackers**.

1. Choose **Create tracker**.

1. Fill the following fields:
   + ****Name **** – Enter a unique name. For example, *ExampleTracker*. Maximum 100 characters. Valid entries include alphanumeric characters, hyphens, periods, and underscores.
   + ****Description** ** – Enter an optional description.

1. Under **Position filtering**, choose the option that best fits how you intend to use your tracker resource. If you do not set **Position filtering**, the default setting is `TimeBased`. For more information, see [Learn about trackers in Amazon Location Service](tracking-overview.md) in this guide, and `[PositionFiltering](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_CreateTracker.html#locationtrackers-CreateTracker-request-PositionFiltering)` in the Amazon Location Service Trackers API Reference.

1. (Optional) Under **Tags**, enter a tag **Key** and **Value**. This adds a tag your new geofence collection. For more information, see [Tagging your resources](tagging.md).

1. (Optional) Under **Customer managed key encryption**, you can choose to **Add a customer managed key**. This adds a symmetric customer managed key that you create, own, and manage over the default AWS owned encryption. For more information, see [Encrypting data at rest](encryption-at-rest.md).

1. (Optional) Under **KmsKeyEnableGeospatialQueries**, you can choose to enable **Geospatial Queries**. This allows you use the Bounding Polygon Queries feature, while encrypting your data using a customer AWS KMS managed key.
**Note**  
When you use the Bounding Polygon Queries feature a representation of your device positions is not be encrypted using the your AWS KMS managed key. However, the exact device position is still encrypted using your managed key.

1. (Optional) Under **EventBridge configuration**, you can choose to enable EventBridge events for filtered position updates. This will send an event each time a position update for a device in this tracker meets the position filtering evaluation.

1. Choose **Create tracker**.

------
#### [ API ]

**To create a tracker by using the Amazon Location APIs**

Use the `[CreateTracker](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_CreateTracker.html)` operation from the Amazon Location Trackers APIs.

The following example uses an API request to create a tracker called *ExampleTracker*. The tracker resource is associated with a [customer managed AWS KMS key to encrypt customer data](encryption-at-rest.md), and does not [enable position updates in EventBridge](location-events.md#enable-update-events).

```
POST /tracking/v0/trackers
Content-type: application/json

{
   
   "TrackerName": "ExampleTracker",
   "Description": "string",
   "KmsKeyEnableGeospatialQueries": false, 
   "EventBridgeEnabled": false,
   "KmsKeyId": "1234abcd-12ab-34cd-56ef-1234567890ab",
   "PositionFiltering": "AccuracyBased",
   "Tags": { 
      "string" : "string" 
   }
}
```

**Create a tracker with `KmsKeyEnableGeospatialQueries` enabled**

The following example has the parameter `KmsKeyEnableGeospatialQueries` set to true. This allows you use the Bounding Polygon Queries feature, while encrypting your data using a customer AWS KMS managed key.

For information on using the Bounding Polygon Queries feature, see [List your device positions](#list-device-positions)

**Note**  
When you use the Bounding Polygon Queries feature a representation of your device positions is not be encrypted using the your AWS KMS managed key. However, the exact device position is still encrypted using your managed key.

```
POST /tracking/v0/trackers
Content-type: application/json

{
   
   "TrackerName": "ExampleTracker",
   "Description": "string",
   "KmsKeyEnableGeospatialQueries": true, 
   "EventBridgeEnabled": false,
   "KmsKeyId": "1234abcd-12ab-34cd-56ef-1234567890ab",
   "PositionFiltering": "AccuracyBased",
   "Tags": { 
      "string" : "string" 
   }
}
```

------
#### [ AWS CLI ]

**To create a tracker using AWS CLI commands**

Use the `[create-tracker](https://docs.aws.amazon.com/cli/latest/reference/location/create-tracker.html)` command.

The following example uses the AWS CLI to create a tracker called *ExampleTracker*. The tracker resource is associated with a [customer managed AWS KMS key to encrypt customer data](encryption-at-rest.md), and does not [enable position updates in EventBridge](location-events.md#enable-update-events).

```
aws location \
  create-tracker \
  --tracker-name "ExampleTracker" \
  --position-filtering "AccuracyBased" \
  --event-bridge-enabled false \
  --kms-key-enable-geospatial-queries false \
  --kms-key-id "1234abcd-12ab-34cd-56ef-1234567890ab"
```

**Create a tracker with `KmsKeyEnableGeospatialQueries` enabled**

The following example has the parameter `KmsKeyEnableGeospatialQueries` set to true. This allows you use the Bounding Polygon Queries feature, while encrypting your data using a customer AWS KMS managed key.

For information on using the Bounding Polygon Queries feature, see [List your device positions](#list-device-positions)

**Note**  
When you use the Bounding Polygon Queries feature a representation of your device positions is not be encrypted using the your AWS KMS managed key. However, the exact device position is still encrypted using your managed key.

```
aws location \
  create-tracker \
  --tracker-name "ExampleTracker" \
  --position-filtering "AccuracyBased" \
  --event-bridge-enabled false \
  --kms-key-enable-geospatial-queries true \
  --kms-key-id "1234abcd-12ab-34cd-56ef-1234567890ab"
```

------

**Note**  
Billing depends on your usage. You may incur fees for the use of other AWS services. For more information, see [Amazon Location Service pricing](https://aws.amazon.com/location/pricing/).

You can edit the **Description**, **Position filtering**, and **EventBridge configuration** after the tracker is created by choosing **Edit tracker**.

## Authenticating your requests
<a name="tracking-identity-pool"></a>

Once you create a tracker resource and you're ready to begin evaluating device positions against geofences, choose how you would authenticate your requests:
+ To explore ways you can access the services, see [Accessing Amazon Location Service](how-to-access.md).
+ If you want to publish device positions with unauthenticated requests,you may want to use Amazon Cognito.

  **Example**

  The following example shows using an Amazon Cognito identity pool for authorization, using [AWS JavaScript SDK v3](https://aws.amazon.com/sdk-for-javascript/), and the Amazon Location [JavaScript Authentication helper](loc-sdk-auth.md).

  ```
  import { LocationClient, BatchUpdateDevicePositionCommand } from "@aws-sdk/client-location";
  import { withIdentityPoolId } from "@aws/amazon-location-utilities-auth-helper";
  
  // Unauthenticated identity pool you created
  const identityPoolId = "us-east-1:1234abcd-5678-9012-abcd-sample-id";
  
  // Create an authentication helper instance using credentials from Cognito
  const authHelper = await withIdentityPoolId(identityPoolId);
  
  const client = new LocationClient({
    region: "us-east-1", // The region containing both the identity pool and tracker resource
    ...authHelper.getLocationClientConfig(), // Provides configuration required to make requests to Amazon Location
  });
  
  const input = {
    TrackerName: "ExampleTracker",
    Updates: [
      {
        DeviceId: "ExampleDevice-1",
        Position: [-123.4567, 45.6789],
        SampleTime: new Date("2020-10-02T19:09:07.327Z"),
      },
      {
        DeviceId: "ExampleDevice-2",
        Position: [-123.123, 45.123],
        SampleTime: new Date("2020-10-02T19:10:32Z"),
      },
    ],
  };
  
  const command = new BatchUpdateDevicePositionCommand(input);
  
  // Send device position updates
  const response = await client.send(command);
  ```

## Update your tracker with a device position
<a name="send-location-updates"></a>

To track your devices, you can post device position updates to your tracker. You can later retrieve these device positions or the device position history from your tracker resource.

Each position update must include the device ID, a timestamp , and a position. You may optionally include other metadata, including accuracy and up to 3 key-value pairs for your own use.

If your tracker is linked to one or more geofence collections, updates will be evaluated against those geofences (following the filtering rules that you specified for the tracker). If a device breaches a geofenced area (by moving from inside the area to outside, or vice versa), you will receive events in EventBridge. These `ENTER` or `EXIT` events include the position update details, including the device ID, the timestamp, and any associated metadata.

**Note**  
For more information about position filtering, see [Create a tracker](#start-create-tracker).  
For more information about geofence events, see [Reacting to Amazon Location Service events with Amazon EventBridge](location-events.md).

Use either of these methods to send device updates:
+ [Send MQTT updates](https://docs.aws.amazon.com/location/previous/developerguide/tracking-using-mqtt.html) to an AWS IoT Core resource and link it to your tracker resource.
+ Send location updates using the Amazon Location Trackers API, by using the AWS CLI, or the Amazon Location APIs. You can use the [AWS SDKs](location-actions.md) to call the APIs from your iOS or Android application.

------
#### [ API ]

**To send a position update using the Amazon Location APIs**

Use the `[BatchUpdateDevicePosition](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_BatchUpdateDevicePosition.html)` operation from the Amazon Location Trackers APIs. 

The following example uses an API request to post a device position update for *ExampleDevice* to a tracker *ExampleTracker*.

```
POST /tracking/v0/trackers/ExampleTracker/positions
Content-type: application/json
{
 "Updates": [
    {
    "DeviceId": "1",
    "Position": [
   -123.12245146162303, 49.27521118043802
    ],
    "SampleTime": "2022-10-24T19:09:07.327Z",
     "PositionProperties": { 
            "name" : "device1" 
         },
         "Accuracy": { 
            "Horizontal": 10
         }
    },

    {
    "DeviceId": "2",
    "Position": [
   -123.1230104928471, 49.27752402723152
    ],
    "SampleTime": "2022-10-02T19:09:07.327Z"
    },
    {
    "DeviceId": "3",
    "Position": [
    -123.12325592118916, 49.27340530543111
    ],
    "SampleTime": "2022-10-02T19:09:07.327Z"
    },
    {
    "DeviceId": "4",
    "Position": [
    -123.11958813096311, 49.27774641063121
    ],
    "SampleTime": "2022-10-02T19:09:07.327Z"
    },
    {
    "DeviceId": "5",
    "Position": [
    -123.1277418058896, 49.2765989015285
    ],
    "SampleTime": "2022-10-02T19:09:07.327Z"
    },
    {
    "DeviceId": "6",
    "Position": [
   -123.11964267059481, 49.274188155916534
    ],
    "SampleTime": "2022-10-02T19:09:07.327Z"
    }
    ]
}
```

------
#### [ AWS CLI ]

**To send a position update using AWS CLI commands**

Use the `[batch-update-device-position](https://docs.aws.amazon.com/cli/latest/reference/location/batch-update-device-position.html)` command.

The following example uses an AWS CLI to post a device position update for *ExampleDevice-1* and *ExampleDevice-2* to a tracker *ExampleTracker*. 

```
aws location batch-update-device-position \
--tracker-name ExampleTracker \
--updates '[{"DeviceId":"ExampleDevice-1","Position":[-123.123,47.123],"SampleTime":"2021-11-30T21:47:25.149Z"},{"DeviceId":"ExampleDevice-2","Position":[-123.123,47.123],"SampleTime":"2021-11-30T21:47:25.149Z","Accuracy":{"Horizontal":10.30},"PositionProperties":{"field1":"value1","field2":"value2"}}]'
```

------

## Get a device's location history from a tracker
<a name="get-location-history"></a>

 Your Amazon Location tracker resource maintains the location history of all your tracked devices for a period of 30 days. You can retrieve device location history, including all associated metadata, from your tracker resource. The following examples use the AWS CLI, or the Amazon Location APIs.

------
#### [ API ]

**To get the device location history from a tracker using the Amazon Location APIs**

Use the `[GetDevicePositionHistory](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_GetDevicePositionHistory.html)` operation from the Amazon Location Trackers APIs. 

The following example uses an API URI request to get the device location history of *ExampleDevice* from a tracker called *ExampleTracker* starting from `19:05:07` (inclusive) and ends at `19:20:07` (exclusive) on `2020–10–02`.

```
POST /tracking/v0/trackers/ExampleTracker/devices/ExampleDevice/list-positions 
Content-type: application/json
{
  "StartTimeInclusive": "2020-10-02T19:05:07.327Z",
  "EndTimeExclusive": "2020-10-02T19:20:07.327Z"
}
```

------
#### [ AWS CLI ]

**To get the device location history from a tracker using AWS CLI commands**

Use the `[get-device-position-history](https://docs.aws.amazon.com/cli/latest/reference/location/get-device-position-history.html)` command.

The following example uses an AWS CLI to get the device location history of *ExampleDevice* from a tracker called *ExampleTracker* starting from `19:05:07` (inclusive) and ends at `19:20:07` (exclusive) on `2020–10–02`.

```
aws location \
    get-device-position-history \
        --device-id "ExampleDevice" \
        --start-time-inclusive "2020-10-02T19:05:07.327Z" \
        --end-time-exclusive "2020-10-02T19:20:07.327Z" \
        --tracker-name "ExampleTracker"
```

------

## List your device positions
<a name="list-device-positions"></a>

You can view a list device positions for a tracker using the AWS CLI, or the Amazon Location APIs, with the ListDevicePositions API. When you call the ListDevicePositions API, a list of the latest positions for all devices associated with a given tracker is returned. By default this API returns 100 of the latest device positions per page of results for a given tracker. To only return devices within a specific region use the `FilterGeometry` parameter to create a Bounding Polygon Query. This way when you call ListDevicePositions, only devices inside the polygon will be returned.

**Note**  
If you wish to encrypt your data using your own AWS KMS customer managed key, then the Bounding Polygon Queries feature will be disabled by default. This is because by using this feature, a representation of your device positions will not be encrypted using the your AWS KMS managed key. The exact device position, however; is still encrypted using your managed key.  
You can choose to opt-in to the Bounding Polygon Queries feature. This is done by setting the `KmsKeyEnableGeospatialQueries` parameter to true when creating or updating a Tracker.

------
#### [ API ]

Use the `[ListDevicePositions](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_ListDevicePositions.html)` operation from the Amazon Location Trackers APIs.

The following example is an API request to get a list of device positions in polygonal area, using the optional parameter `[FilterGeometry](https://docs.aws.amazon.com/)`. The example returns 3 device locations present in the area defined by the `Polygon` array.

```
POST /tracking/v0/trackers/TrackerName/list-positions HTTP/1.1
Content-type: application/json

{
   "FilterGeometry": {
        "Polygon": [
          [
            [
              -123.12003339442259,
              49.27425121147397
            ],
            [
              -123.1176984148229,
              49.277063620879744
            ],
            [
              -123.12389509145294,
              49.277954183760926
            ],
            [
              -123.12755921328647,
              49.27554025235713
            ],
            [
              -123.12330236586217,
              49.27211836076236
            ],
            [
              -123.12003339442259,
              49.27425121147397
            ]
          ]
        ]
    },
   "MaxResults": 3,
   "NextToken": "1234-5678-9012"
}
```

The following is an example response for `[ListDevicePositions](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_ListDevicePositions.html)`:

```
{
    "Entries": [
        {
            "DeviceId": "1",
            "SampleTime": "2022-10-24T19:09:07.327Z",
            "Position": [
                -123.12245146162303,
                49.27521118043802
            ],
            "Accuracy": {
                "Horizontal": 10
            },
            "PositionProperties": {
                "name": "device1"
            }
        },
        {
            "DeviceId": "3",
            "SampleTime": "2022-10-02T19:09:07.327Z",
            "Position": [
                -123.12325592118916,
                49.27340530543111
            ]
        },
        {
            "DeviceId": "2",
            "SampleTime": "2022-10-02T19:09:07.327Z",
            "Position": [
                -123.1230104928471,
                49.27752402723152
            ]
        }
    ],
   "NextToken": "1234-5678-9012"
}
```

------
#### [ CLI ]

Use the `[list-trackers](https://docs.aws.amazon.com/cli/latest/reference/location/list-trackers.html)` command.

The following example is an AWS CLI to get a list of devices in a polygonal area. 

```
aws location list-device-positions TODO: add arguments add props for filter geo
```

------

# Tutorial: Link a tracker to a geofence collection in Amazon Location
<a name="associate-consumer"></a>

Now that you have a geofence collection and a tracker, you can link them together so that location updates are automatically evaluated against all of your geofences. If you don’t want to evaluate all location updates, or alternatively, if you aren't storing some of your locations in a tracker resource, you can [evaluate device positions against geofences](https://docs.aws.amazon.com/location/previous/developerguide/evaluate-geofences.html) on demand.

When device positions are evaluated against geofences, events are generated. You can set an action to these events. For more information about actions that you can set for geofence events, see [Reacting to Amazon Location Service events with Amazon EventBridge](https://docs.aws.amazon.com/location/previous/developerguide/location-events.html).

An Amazon Location event includes the attributes of the device position update that generates it and some attributes of the geofence that is entered or exited. For more information about the data included in a geofence event, see [Amazon EventBridge event examples for Amazon Location Service](location-events.md#example-event).

The following examples link a tracker resource to a geofence collection using the console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To link a tracker resource to a geofence collection using the Amazon Location Service console**

1. Open the Amazon Location Service console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. In the left navigation pane, choose **Trackers**.

1. Under **Device trackers**, select the name link of the target tracker.

1. Under **Linked Geofence Collections**, choose **Link Geofence Collection**.

1. In the **Linked Geofence Collection** window, select a geofence collection from the dropdown menu.

1. Choose **Link**.

After you link the tracker resource, it will be assigned an **Active** status.

------
#### [ API ]

**To link a tracker resource to a geofence collection using the Amazon Location APIs**

Use the `[AsssociateTrackerConsumer](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_AssociateTrackerConsumer.html)` operation from the Amazon Location Trackers APIs. 

The following example uses an API request that associates *ExampleTracker* with a geofence collection using its [Amazon Resource Name ](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)(ARN).

```
POST /tracking/v0/trackers/ExampleTracker/consumers
Content-type: application/json

{
   "ConsumerArn": "arn:aws:geo:us-west-2:123456789012:geofence-collection/ExampleGeofenceCollection"
}
```

------
#### [ AWS CLI ]

**To link a tracker resource to a geofence collection using AWS CLI commands**

Use the `[associate-tracker-consumer](https://docs.aws.amazon.com/cli/latest/reference/location/associate-tracker-consumer.html)` command. 

The following example uses an AWS CLI to create a geofence collection called *ExampleGeofenceCollection*.

```
aws location \
    associate-tracker-consumer \
        --consumer-arn "arn:aws:geo:us-west-2:123456789012:geofence-collection/ExampleGeofenceCollection" \
        --tracker-name "ExampleTracker"
```

------

# Evaluate device positions against geofences in Amazon Location
<a name="evaluate-geofences"></a>

There are two ways to evaluate positions against geofences to generate geofence events: 
+ You can link Trackers and Geofence Collections. For more information, see the section: [Tutorial: Link a tracker to a geofence collection in Amazon Location](associate-consumer.md).
+ You can make a direct request to the geofence collection resource to evaluate one or more positions, using the [BatchEvaluateGeofences](https://docs.aws.amazon.com//location/previous/APIReference/API_BatchEvaluateGeofences.html) API.

Additionally, you can forecast incoming geofence events for a device entering, exiting, or remaining idle within a geofence. Use the [ForecastGeofenceEvents](https://docs.aws.amazon.com//location/previous/APIReference/API_ForecastGeofenceEvents.html) API to forecast events.

If you also want to track your device location history or display locations on a map, link the tracker with a geofence collection. Alternatively, you may not want to evaluate all location updates, or you don't intend to store location data in a tracker resource. If either of these is the case, you can make a direct request to the geofence collection and evaluate one or more device positions against its geofences.

Evaluating device positions against geofences generates events. You can react to these events and route them to other AWS services. For more information about actions that you can take when receiving geofence events, see [Reacting to Amazon Location Service events with Amazon EventBridge](https://docs.aws.amazon.com/location/previous/developerguide/location-events.html).

An Amazon Location event includes the attributes of the device position update that generates it, including the time, position, accuracy, and key-value metadata, and some attributes of the geofence that is entered or exited. For more information about the data included in a geofence event, see [Amazon EventBridge event examples for Amazon Location Service](location-events.md#example-event).

The following examples use the AWS CLI, or the Amazon Location APIs.

------
#### [ API ]

**To evaluate device positions against the position of geofences using the Amazon Location APIs**

Use the `[BatchEvaluateGeofences](https://docs.aws.amazon.com/location-geofences/latest/APIReference/API_BatchEvaluateGeofences.html)` operation from the Amazon Location Geofences APIs. 

The following example uses an API request to evaluate the position of device *ExampleDevice* to an associated geofence collection *ExampleGeofenceCollection*. Replace these values with your own geofence and device IDs.

```
POST /geofencing/v0/collections/ExampleGeofenceCollection/positions HTTP/1.1
Content-type: application/json

{
   "DevicePositionUpdates": [ 
      { 
         "DeviceId": "ExampleDevice",
         "Position": [-123.123, 47.123],
         "SampleTime": "2021-11-30T21:47:25.149Z",
         "Accuracy": {
            "Horizontal": 10.30
         },
         "PositionProperties": {
            "field1": "value1",
            "field2": "value2"
         }
      }
   ]
}
```

------
#### [ AWS CLI ]

**To evaluate device positions against the position of geofences using AWS CLI commands**

Use the `[batch-evaluate-geofences](https://docs.aws.amazon.com/cli/latest/reference/location/batch-evaluate-geofences.html)` command. 

The following example uses an AWS CLI to evaluate the position of *ExampleDevice* against an associated geofence collection *ExampleGeofenceCollection*. Replace these values with your own geofence and device IDs.

```
aws location \
    batch-evaluate-geofences \
        --collection-name ExampleGeofenceCollection \
        --device-position-updates '[{"DeviceId":"ExampleDevice","Position":[-123.123,47.123],"SampleTime":"2021-11-30T21:47:25.149Z","Accuracy":{"Horizontal":10.30},"PositionProperties":{"field1":"value1","field2":"value2"}}]'
```

------

Evaluating device positions against geofences generates events. Traditionally you can react to the events by using [Amazon EventBridge](https://docs.aws.amazon.com//location/previous/developerguide/evaluate-geofences.html), but this process only lets you react to events after then have happened. If you need to anticipate when a device enters or exits a geofence, for example if a device is crossing a border and will be subject to a different regulations as a consequence, then you can use the [ForecastGeofenceEvents](https://docs.aws.amazon.com//location/previous/APIReference/API_ForecastGeofenceEvents.html) API to predict future geofence events.

The [ForecastGeofenceEvents](https://docs.aws.amazon.com//location/previous/APIReference/API_ForecastGeofenceEvents.html) API uses criteria such as the device's time-to-breach, proximity, speed, and position to predict events. There API will return a ` ForecastedBreachTime`, which signals the estimated time the geofence event will occur.

The following example uses the Amazon Location APIs.

------
#### [ API ]

**To forecast geofence events using the Amazon Location APIs**

Use the ` [ForecastGeofenceEvents](https://docs.aws.amazon.com//location/previous/APIReference/API_ForecastGeofenceEvents.html)` operation from the Amazon Location Geofences APIs. 

The following example uses an API request to forecast geofence events for an *ExampleDevice* relative to an *ExampleGeofence*. Replace these values with your own geofence and device IDs.

```
POST /geofencing/v0/collections/CollectionName/forecast-geofence-events HTTP/1.1
Content-type: application/json

{
   "DeviceState": { 
      "Position": [ number ],
      "Speed": number
   },
   "DistanceUnit": "string",
   "MaxResults": number,
   "NextToken": "string",
   "SpeedUnit": "string",
   "TimeHorizonMinutes": number
}
```

------

# Tutorial: Verify device positions with Amazon Location
<a name="verify-device-positions"></a>

To check the integrity of a device position use the [VerifyDevicePosition](https://docs.aws.amazon.com//location/previous/APIReference/API_VerifyDevicePosition.html) API. This API returns information about the integrity of the device's position, by evaluating properties such as the device's cell signal, Wi-Fi access point, Ipv4 address, and if a proxy is in use.

## Prerequisites
<a name="verify-device-positions-pre-reqs"></a>

Before being able to use the listed APIs for device verification, make sure you have the following prerequisite:
+ You have created a tracker for the device or devices you want to check. For more information, see [Start tracking with Amazon Location](start-tracking.md).

The following example shows a request for the Amazon Location [VerifyDevicePosition](https://docs.aws.amazon.com//location/previous/APIReference/API_VerifyDevicePosition.html) API.

------
#### [ API ]

**To verify device positions using the Amazon Location APIs**

Use the `[VerifyDevicePosition](https://docs.aws.amazon.com/location/previous/APIReference/API_VerifyDevicePosition.html)` operation from the Amazon Location Tracking APIs.

The following example shows an API request to evaluate the integrity of the position of a device. Replace these values with your own device IDs.

```
POST /tracking/v0/trackers/TrackerName/positions/verify HTTP/1.1
Content-type: application/json

{
   "DeviceState": { 
      "Accuracy": { 
         "Horizontal": number
      },
      "CellSignals": { 
         "LteCellDetails": [ 
            { 
               "CellId": number,
               "LocalId": { 
                  "Earfcn": number,
                  "Pci": number
               },
               "Mcc": number,
               "Mnc": number,
               "NetworkMeasurements": [ 
                  { 
                     "CellId": number,
                     "Earfcn": number,
                     "Pci": number,
                     "Rsrp": number,
                     "Rsrq": number
                  }
               ],
               "NrCapable": boolean,
               "Rsrp": number,
               "Rsrq": number,
               "Tac": number,
               "TimingAdvance": number
            }
         ]
      },
      "DeviceId": "ExampleDevice",
      "Ipv4Address": "string",
      "Position": [ number ],
      "SampleTime": "string",
      "WiFiAccessPoints": [ 
         { 
            "MacAddress": "string",
            "Rss": number
         }
      ]
   },
   "DistanceUnit": "string"
}
```

------

**Note**  
The **Integrity SDK** provides enhanced features related to device verification, and it is available for use by request. To get access to the SDK, contact [Sales Support](https://aws.amazon.com/contact-us/sales-support/?pg=locationprice&cta=herobtn).

# Reacting to Amazon Location Service events with Amazon EventBridge
<a name="location-events"></a>

Amazon EventBridge is a serverless event bus that efficiently connects applications together using data from AWS services like Amazon Location. EventBridge receives events from Amazon Location and routes that data to targets like AWS Lambda. You can set up routing rules to determine where to send your data to build application architectures that react in real time.

Only geofence events (`ENTER` and `EXIT` events, as devices enter or leave the geofenced areas) are sent to EventBridge by default. You can also enable all filtered position update events for a tracker resource. For more information, see [Enable update events for a tracker](#enable-update-events).

For more information, see [the Events and Event Patterns](https://docs.aws.amazon.com/eventbridge/latest/userguide/eventbridge-and-event-patterns.html) in *the Amazon EventBridge User Guide*.

**Topics**
+ [Enable update events for a tracker](#enable-update-events)
+ [Create event rules for Amazon Location](#create-event-rule)
+ [Amazon EventBridge event examples for Amazon Location Service](#example-event)

## Enable update events for a tracker
<a name="enable-update-events"></a>

By default, Amazon Location sends only `ENTER` and `EXIT` geofence events to EventBridge. You can enable all filtered position `UPDATE` events for a tracker to be sent to EventBridge. You can do this when you [create](https://docs.aws.amazon.com/location/previous/APIReference/API_CreateTracker.html) or [update](https://docs.aws.amazon.com/location/previous/APIReference/API_UpdateTracker.html) a tracker.

For example, to update an existing tracker using the AWS CLI, you can use the following command (use the name of your tracker resource in place of *MyTracker*).

```
aws location update-tracker --tracker-name MyTracker --event-bridge-enabled
```

To turn off position events for a tracker, you must use the API or the Amazon Location Service console.

## Create event rules for Amazon Location
<a name="create-event-rule"></a>

You can create [up to 300 rules per event bus](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-quota.html) in EventBridge to configure actions taken in response to an Amazon Location event. 

For example, you can create a rule for geofence events where a push notification will be sent when a phone is detected within a geofenced boundary.

**To create a rule for Amazon Location events**

Using the following values, [create an EventBridge rule](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule.html) based on Amazon Location events:
+ For **Rule type**, choose **Rule with an event pattern**.
+ In the **Event pattern** box, add the following pattern:

  ```
  {
    "source": ["aws.geo"],
    "detail-type": ["Location Geofence Event"]
  }
  ```

  To create a rule for tracker position updates, you can instead use the following pattern:

  ```
  {
    "source": ["aws.geo"],
    "detail-type": ["Location Device Position Event"]
  }
  ```

  You can optionally specify only `ENTER` or `EXIT` events by adding a `detail` tag (if your rule is for tracker position updates, there is only a single `EventType`, so there is no need to filter on it):

  ```
  {
    "source": ["aws.geo"],
    "detail-type": ["Location Geofence Event"],
    "detail": {
      "EventType": ["ENTER"]
    }
  }
  ```

  You can also optionally filter on properties of the position or geofence:

  ```
  {
    "source": ["aws.geo"],
    "detail-type": ["Location Geofence Event"],
    "detail": {
      "EventType": ["ENTER"],
      "GeofenceProperties": {
        "Type": "LoadingDock"
      },
      "PositionProperties": {
        "VehicleType": "Truck"
      }
    }
  }
  ```
+ For **Select targets**, choose the target action to take when an event is received from Amazon Location Service.

  For example, use an Amazon Simple Notification Service (SNS) topic to send an email or text message when an event occurs. You first need to create an Amazon SNS topic using the Amazon SNS console. For more information, see [Using Amazon SNS for user notifications](https://docs.aws.amazon.com//sns/latest/dg/sns-user-notifications.html).

**Warning**  
It's best practice to confirm that the event rule was successfully applied or your automated action may not initiate as expected. To verify your event rule, initiate conditions for the event rule. For example, simulate a device entering a geofenced area. 

You can also capture all events from Amazon Location, by just excluding the `detail-type` section. For example:

```
{
  "source": [
    "aws.geo"
  ]
}
```

**Note**  
The same event may be delivered more than one time. You can use the event id to de-duplicate the events that you receive.

## Amazon EventBridge event examples for Amazon Location Service
<a name="example-event"></a>

The following is an example of an event for entering a geofence initiated by calling `BatchUpdateDevicePosition`.

```
{
  "version": "0",
  "id": "aa11aa22-33a-4a4a-aaa5-example",
  "detail-type": "Location Geofence Event",
  "source": "aws.geo",
  "account": "636103698109",
  "time": "2020-11-10T23:43:37Z",
  "region": "eu-west-1",
  "resources": [
    "arn:aws:geo:eu-west-1:0123456789101:geofence-collection/GeofenceEvents-GeofenceCollection_EXAMPLE",
    "arn:aws:geo:eu-west-1:0123456789101:tracker/Tracker_EXAMPLE"
  ],
  "detail": {
    "EventType": "ENTER",
    "GeofenceId": "polygon_14",
    "DeviceId": "Device1-EXAMPLE",
    "SampleTime": "2020-11-10T23:43:37.531Z",
    "Position": [
      -123.12390073297821,
      49.23433613216247
    ],
    "Accuracy": {
      "Horizontal": 15.3
    },
    "GeofenceProperties": {
      "ExampleKey1": "ExampleField1",
      "ExampleKey2": "ExampleField2"
    },
    "PositionProperties": {
      "ExampleKey1": "ExampleField1",
      "ExampleKey2": "ExampleField2"
    }
  }
}
```

The following is an example of an event for exiting a geofence initiated by calling `BatchUpdateDevicePosition`.

```
{
  "version": "0",
  "id": "aa11aa22-33a-4a4a-aaa5-example",
  "detail-type": "Location Geofence Event",
  "source": "aws.geo",
  "account": "123456789012",
  "time": "2020-11-10T23:41:44Z",
  "region": "eu-west-1",
  "resources": [
    "arn:aws:geo:eu-west-1:0123456789101:geofence-collection/GeofenceEvents-GeofenceCollection_EXAMPLE",
    "arn:aws:geo:eu-west-1:0123456789101:tracker/Tracker_EXAMPLE"
  ],
  "detail": {
    "EventType": "EXIT",
    "GeofenceId": "polygon_10",
    "DeviceId": "Device1-EXAMPLE",
    "SampleTime": "2020-11-10T23:41:43.826Z",
    "Position": [
      -123.08569321875426,
      49.23766166742559
    ],
    "Accuracy": {
      "Horizontal": 15.3
    },
    "GeofenceProperties": {
      "ExampleKey1": "ExampleField1",
      "ExampleKey2": "ExampleField2"
    },
    "PositionProperties": {
      "ExampleKey1": "ExampleField1",
      "ExampleKey2": "ExampleField2"
    }
  }
}
```

The following is an example of an event for a position update, initiated by calling `BatchUpdateDevicePosition`.

```
{
  "version": "0",
  "id": "aa11aa22-33a-4a4a-aaa5-example",
  "detail-type": "Location Device Position Event",
  "source": "aws.geo",
  "account": "123456789012",
  "time": "2020-11-10T23:41:44Z",
  "region": "eu-west-1",
  "resources": [
    "arn:aws:geo:eu-west-1:0123456789101:tracker/Tracker_EXAMPLE"
  ],
  "detail": {
    "EventType": "UPDATE",
    "TrackerName": "tracker_2",
    "DeviceId": "Device1-EXAMPLE",
    "SampleTime": "2020-11-10T23:41:43.826Z",
    "ReceivedTime": "2020-11-10T23:41:39.235Z",
    "Position": [
      -123.08569321875426,
      49.23766166742559
    ],
    "Accuracy": {
      "Horizontal": 15.3
    },
    "PositionProperties": {
      "ExampleKey1": "ExampleField1",
      "ExampleKey2": "ExampleField2"
    }
  }
}
```

# Track with AWS IoT, MQTT, with Amazon Location Service
<a name="tracking-using-mqtt"></a>

[MQTT](http://mqtt.org/) is a lightweight and widely adopted messaging protocol designed for constrained devices. AWS IoT Core supports device connections that use the MQTT protocol and MQTT over WebSocket Secure (WSS) protocol. 

[AWS IoT Core](https://aws.amazon.com/iot-core/) connects devices to AWS and enables you to send and receive messages between them. The AWS IoT Core rules engine stores queries about your devices' message topics and enables you to define actions for sending messages to other AWS services, such as Amazon Location Service. Devices that are aware of their location as coordinates can have their locations forwarded to Amazon Location through the rules engine.

**Note**  
Devices may know their own position, for example via built-in GPS. AWS IoT also has support for third party device location tracking. For more information, see [AWS IoT Core Device Location](https://docs.aws.amazon.com/iot/latest/developerguide/device-location.html) in the *AWS IoT Core Developer Guide*.

The following walkthrough describes tracking using AWS IoT Core rules. You can also send the device information to your own AWS Lambda function, if you need to process it before sending to Amazon Location. For more details about using Lambda to process your device locations, see [Tutorial: Use AWS Lambda with MQTT](tracking-using-mqtt-with-lambda.md).

**Topics**
+ [Prerequisites](#mqtt-prerequisite)
+ [Create an AWS IoT Core rule](#mqtt-create-iot-rule)
+ [Tutorial: Test your AWS IoT Core rule in the console](#mqtt-test-iot-rule)
+ [Tutorial: Use AWS Lambda with MQTT](tracking-using-mqtt-with-lambda.md)

## Prerequisites
<a name="mqtt-prerequisite"></a>

Before you can begin tracking, you must complete the following prerequisites:
+ [Create a tracker resource](start-tracking.md#start-create-tracker) that you will send the device location data to.
+ [Create an IAM role](https://docs.aws.amazon.com/iot/latest/developerguide/iot-create-role.html) for granting AWS IoT Core access to your tracker.

  When following those steps, use the following policy to give access to your tracker:

  ```
  {
    "Version": "2012-10-17",		 	 	 
    "Statement": [
      {
        "Sid": "WriteDevicePosition",
        "Effect": "Allow",
        "Action": "geo:BatchUpdateDevicePosition",
        "Resource": "arn:aws:geo:*:*:tracker/*"
      }
    ]
  }
  ```

## Create an AWS IoT Core rule
<a name="mqtt-create-iot-rule"></a>

Next, create an AWS IoT Core rule to forward your devices' positional telemetry to Amazon Location Service. For more information about creating rules, see the following topics in the *AWS IoT Core Developer Guide*:
+ [Creating an AWS IoT rule](https://docs.aws.amazon.com/iot/latest/developerguide/iot-create-rule.html) for information about creating a new rule.
+ [Location action](https://docs.aws.amazon.com/iot/latest/developerguide/location-rule-action.html) for information specific to creating a rule for publishing to Amazon Location 

## Tutorial: Test your AWS IoT Core rule in the console
<a name="mqtt-test-iot-rule"></a>

If no devices are currently publishing telemetry that includes location, you can test your rule using the AWS IoT Core console. The console has a test client where you can publish a sample message to verify the results of the solution.

1. Sign in to the AWS IoT Core console at [https://console.aws.amazon.com/iot/](https://console.aws.amazon.com/iot/home).

1. In the left navigation, expand **Test**, and choose **MQTT test client**.

1. Under **Publish to a topic**, set the **Topic name** to *iot/topic* (or the name of the topic that you set up in your AWS IoT Core rule, if different), and provide the following for the **Message payload**.

   ```
   {
     "payload": {
       "deviceid": "thing123",
       "timestamp": 1604940328,
       "location": { "lat": 49.2819, "long": -123.1187 },
       "accuracy": { "Horizontal": 20.5 },
       "positionProperties": { "field1": "value1", "field2": "value2" }
     }
   }
   ```

1. Choose **Publish** to topic to send the test message.

1. To validate that the message was received by Amazon Location Service, use the following AWS CLI command. If you modified it during setup, replace the tracker name with the one that you used.

   ```
   aws location batch-get-device-position --tracker-name MyTracker --device-ids thing123
   ```

# Tutorial: Use AWS Lambda with MQTT
<a name="tracking-using-mqtt-with-lambda"></a>

While using AWS Lambda is no longer required when sending device location data to Amazon Location for tracking, you may still want to use Lambda in some cases. For example, if you wish to process your device location data yourself, before sending it on to Amazon Location. The following topics describe how to use Lambda to process messages before sending them to your tracker. For more information about this pattern, see the [reference architecture](https://d1.awsstatic.com/architecture-diagrams/ArchitectureDiagrams/amazon-location-service-ra.pdf).

**Topics**
+ [Prerequisites](#mqtt-prerequisite-with-lambda)
+ [Create a Lambda function](#mqtt-with-lambda-create-lambda)
+ [Create an AWS IoT Core rule](#mqtt-create-iot-rule-with-lambda)
+ [Test your AWS IoT Core rule in the console](#mqtt-test-iot-rule-with-lambda)

## Prerequisites
<a name="mqtt-prerequisite-with-lambda"></a>

Before you can begin tracking, you must [create a tracker resource](start-tracking.md). To create a tracker resource, you can use the Amazon Location console, the AWS CLI, or the Amazon Location APIs. 

The following example uses the Amazon Location Service console to create the tracker resource:

1. Open the Amazon Location Service console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. In the left navigation pane, choose **Trackers**. 

1.  Choose **Create tracker**. 

1. Fill out the following boxes:
   + **Name** – Enter a unique name that has a maximum of 100 characters. Valid entries include alphanumeric characters, hyphens, and underscores. For example, *MyTracker*.
   + **Description** – Enter an optional description. For example, *Tracker for storing AWS IoT Core device positions*.
   + **Position filtering** – Select the filtering that you want to use for position updates. For example, **Accuracy-based filtering**.

1. Choose **Create tracker**. 

## Create a Lambda function
<a name="mqtt-with-lambda-create-lambda"></a>

To create a connection between AWS IoT Core and Amazon Location Service, you need an AWS Lambda function to process messages forwarded by AWS IoT Core. This function will extract any positional data, format it for Amazon Location Service, and submit it through the Amazon Location Tracker API. You can create this function through the AWS Lambda console, or you can use the AWS Command Line Interface (AWS CLI) or the AWS Lambda APIs. 

To create a Lambda function that publishes position updates to Amazon Location using the console:

1. Open the AWS Lambda console at [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/home).

1. From the left navigation, choose **Functions**. 

1.  Choose **Create Function**, and make sure that **Author from scratch** is selected. 

1. Fill out the following boxes:
   + **Function name** – Enter a unique name for your function. Valid entries include alphanumeric characters, hyphens, and underscores with no spaces. For example, *MyLambda*.
   + **Runtime** – Choose *Python 3.8*.

1. Choose **Create function**. 

1. Choose the **Code** tab to open the editor.

1. Overwrite the placeholder code in `lambda_function.py` with the following, replacing the value assigned to `TRACKER_NAME` with the name of the tracker that you created as a [prerequisite](#mqtt-prerequisite-with-lambda).

   ```
   from datetime import datetime
   import json
   import os
   
   import boto3
   
   # Update this to match the name of your Tracker resource
   TRACKER_NAME = "MyTracker"
   
   """
   This Lambda function receives a payload from AWS IoT Core and publishes device updates to 
   Amazon Location Service via the BatchUpdateDevicePosition API.
   
   Parameter 'event' is the payload delivered from AWS IoT Core.
   
   In this sample, we assume that the payload has a single top-level key 'payload' and a nested key
   'location' with keys 'lat' and 'long'. We also assume that the name of the device is nested in
   the payload as 'deviceid'. Finally, the timestamp of the payload is present as 'timestamp'. For
   example:
   
   >>> event
   { 'payload': { 'deviceid': 'thing123', 'timestamp': 1604940328,
     'location': { 'lat': 49.2819, 'long': -123.1187 },
     'accuracy': {'Horizontal': 20.5 },
     'positionProperties': {'field1':'value1','field2':'value2'} }
   }
   
   If your data doesn't match this schema, you can either use the AWS IoT Core rules engine to
   format the data before delivering it to this Lambda function, or you can modify the code below to
   match it.
   """
   def lambda_handler(event, context):
     update = {
         "DeviceId": event["payload"]["deviceid"],
         "SampleTime": datetime.fromtimestamp(event["payload"]["timestamp"]).strftime("%Y-%m-%dT%H:%M:%SZ"),
         "Position": [
           event["payload"]["location"]["long"],
           event["payload"]["location"]["lat"]
           ]
       }
     if "accuracy" in event["payload"]:
         update["Accuracy"] = event["payload"]['accuracy']
     if "positionProperties" in event["payload"]:
         update["PositionProperties"] = event["payload"]['positionProperties']
    
     client = boto3.client("location")
     response = client.batch_update_device_position(TrackerName=TRACKER_NAME, Updates=[update])
   
     return {
       "statusCode": 200,
       "body": json.dumps(response)
     }
   ```

1. Choose **Deploy** to save the updated function.

1. Choose the **Configuration** tab.

1. In the **Permissions** section, choose the hyperlinked Role name to grant Amazon Location Service permissions to your Lambda function.

1. From your role's **Summary** page, choose **Add permissions**, and then from the dropdown list, select **Create inline policy**.

1. Choose the **JSON** tab, and overwrite the policy with the following document. This allows your Lambda function to update device positions managed by all tracker resources across all Regions.

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "WriteDevicePosition",
         "Effect": "Allow",
         "Action": "geo:BatchUpdateDevicePosition",
         "Resource": "arn:aws:geo:*:*:tracker/*"
       }
     ]
   }
   ```

1. Choose **Review policy**.

1. Enter a policy name. For example, *AmazonLocationTrackerWriteOnly*.

1. Choose **Create policy**.

You can modify this function code, as necessary, to adapt to your own device message schema.

## Create an AWS IoT Core rule
<a name="mqtt-create-iot-rule-with-lambda"></a>

Next, create an AWS IoT Core rule to forward your devices' positional telemetry to the AWS Lambda function for transformation and publication to Amazon Location Service. The example rule provided assumes that any necessary transformation of device payloads is handled by your Lambda function. You can create this rule through the AWS IoT Core console, the AWS Command Line Interface (AWS CLI), or the AWS IoT Core APIs.

**Note**  
While the AWS IoT console handles the permission necessary to allow AWS IoT Core to invoke your Lambda function, if you are creating your rule from the AWS CLI or SDK, you must [configure a policy to grant permission to AWS IoT](https://docs.aws.amazon.com/iot/latest/developerguide/lambda-rule-action.html#lambda-rule-action-requirements).

**To create an AWS IoT Core using the console**

1. Sign in to the AWS IoT Core console at [https://console.aws.amazon.com/iot/](https://console.aws.amazon.com/iot/home).

1. In the left navigation, expand **Act**, and choose **Rules**.

1. Choose **Create a rule** to start the new rule wizard.

1. Enter a name and description for your rule.

1. For the **Rule query statement**, update the `FROM` attribute to refer to a topic where at least one device is publishing telemetry that includes location. If you are testing the solution, no modification is needed.

   ```
   SELECT * FROM 'iot/topic'
   ```

1. Under **Set one or more actions **, choose **Add action**.

1. Select **Send a message to a lambda function**.

1. Choose **Configure action**.

1. Find and select your Lambda function from the list.

1. Choose **Add action**.

1. Choose **Create rule**.

## Test your AWS IoT Core rule in the console
<a name="mqtt-test-iot-rule-with-lambda"></a>

If no devices are currently publishing telemetry that includes location, you can test your rule and this solution using the AWS IoT Core console. The console has a test client where you can publish a sample message to verify the results of the solution.

1. Sign in to the AWS IoT Core console at [https://console.aws.amazon.com/iot/](https://console.aws.amazon.com/iot/home).

1. In the left navigation, expand **Test**, and choose **MQTT test client**.

1. Under **Publish to a topic**, set the **Topic name** to *iot/topic* (or the name of the topic that you set up in your AWS IoT Core rule, if different), and provide the following for the **Message payload**. Replace the timestamp *1604940328* with a valid timestamp within the last 30 days (any timestamps older than 30 days are ignored).

   ```
   {
     "payload": {
       "deviceid": "thing123",
       "timestamp": 1604940328,
       "location": { "lat": 49.2819, "long": -123.1187 },
       "accuracy": { "Horizontal": 20.5 },
       "positionProperties": { "field1": "value1", "field2": "value2" }
     }
   }
   ```

1. Choose **Publish** to topic to send the test message.

1. To validate that the message was received by Amazon Location Service, use the following AWS CLI command. If you modified them during setup, replace the tracker name and device id with the ones that you used.

   ```
   aws location batch-get-device-position --tracker-name MyTracker --device-ids thing123
   ```

# Manage geofence collection resources with Amazon Location
<a name="managing-geofence-collections"></a>

Manage your geofence collections using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

Review and complete the following tutorials to manage your geofence collection resounces.

**Topics**
+ [Tutorial: List your geofence collection resources](viewing-geofence-collections.md)
+ [Tutorial: Get geofence collection details](get-geofence-collection-details.md)
+ [Tutorial: Delete a geofence collection](delete-geofence-collection.md)
+ [Tutorial: List stored geofences](viewing-geofences.md)
+ [Tutorial: Get geofence details](get-geofence-details.md)
+ [Tutorial: Delete geofences](delete-geofence.md)

# Tutorial: List your geofence collection resources
<a name="viewing-geofence-collections"></a>

You can view your geofence collection list using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To view a list of geofence collections using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Geofence collections** from the left navigation pane.

1. View a list of your geofence collections under **My geofence collections**.

------
#### [ API ]

Use the `[ListGeofenceCollections](https://docs.aws.amazon.com/location/previous/APIReference/API_ListGeofenceCollections.html)` operation from the Amazon Location Geofences APIs. 

The following example is an API request to get a list of geofence collections in the AWS account. 

```
POST /geofencing/v0/list-collections
```

The following is an example response for `ListGeofenceCollections`:

```
{
    "Entries": [ 
    { 
        "CollectionName": "ExampleCollection",
        "CreateTime": 2020-09-30T22:59:34.142Z,
        "Description": "string",
        "UpdateTime": 2020-09-30T23:59:34.142Z
    },
    "NextToken": "1234-5678-9012"
}
```

------
#### [ CLI ]

Use the `[list-geofence-collections](https://docs.aws.amazon.com/cli/latest/reference/location/list-geofence-collections.html)` command.

The following example is an AWS CLI to get a list of geofence collections in the AWS account. 

```
aws location list-geofence-collections
```

------

# Tutorial: Get geofence collection details
<a name="get-geofence-collection-details"></a>

You can get details about any geofence collection resource in your AWS account using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To view the details of a geofence collection using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Geofence collections** from the left navigation pane.

1. Under **My geofence collections**, select the name link of the target geofence collection. 

------
#### [ API ]

Use the `[DescribeGeofenceCollection](https://docs.aws.amazon.com/location/previous/APIReference/API_DescribeGeofenceCollection.html)` operation from the Amazon Location Geofences APIs. 

The following example is an API request to get the geofence collection details for *ExampleCollection*.

```
GET /geofencing/v0/collections/ExampleCollection
```

The following is an example response for `DescribeGeofenceCollection`:

```
{
    "CollectionArn": "arn:aws:geo:us-west-2:123456789012:geofence-collection/GeofenceCollection",
    "CollectionName": "ExampleCollection",
    "CreateTime": 2020-09-30T22:59:34.142Z,
    "Description": "string",
    "KmsKeyId": "1234abcd-12ab-34cd-56ef-1234567890ab",
    "Tags": { 
        "Tag1" : "Value1"
    },
    "UpdateTime": 2020-09-30T23:59:34.142Z
}
```

------
#### [ CLI ]

Use the `[describe-geofence-collection](https://docs.aws.amazon.com/cli/latest/reference/location/describe-geofence-collection.html)` command.

The following example is an AWS CLI to get the geofence collection details for *ExampleCollection*.

```
aws location describe-geofence-collection \
    --collection-name "ExampleCollection"
```

------

# Tutorial: Delete a geofence collection
<a name="delete-geofence-collection"></a>

You can delete a geofence collection from your AWS account using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To delete a geofence collection using the Amazon Location console**

**Warning**  
This operation deletes the resource permanently.

 

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Geofence collections** from the left navigation pane.

1. Under **My geofence collection**, select the target geofence collection.

1. Choose **Delete geofence collection**.

------
#### [ API ]

Use the `[DeleteGeofenceCollection](https://docs.aws.amazon.com/location/previous/APIReference/API_DeleteGeofenceCollection.html)` operation from the Amazon Location APIs. 

The following example is an API request to delete the geofence collection *ExampleCollection*.

```
DELETE /geofencing/v0/collections/ExampleCollection
```

The following is an example response for `DeleteGeofenceCollection`:

```
HTTP/1.1 200
```

------
#### [ CLI ]

Use the `[delete-geofence-collection](https://docs.aws.amazon.com/cli/latest/reference/location/delete-geofence-collection.html)` command.

The following example is an AWS CLI command to delete the geofence collection *ExampleCollection*.

```
aws location delete-geofence-collection \
    --collection-name "ExampleCollection"
```

------

# Tutorial: List stored geofences
<a name="viewing-geofences"></a>

You can list geofences stored in a specified geofence collection using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To view a list of geofences using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Geofence collections** from the left navigation pane.

1. Under **My geofence collection**, select the name link of the target geofence collection.

1. View geofences in the geofence collection under **Geofences**

------
#### [ API ]

Use the `[ListGeofences](https://docs.aws.amazon.com/location/previous/APIReference/API_ListGeofences.html)` operation from the Amazon Location Geofences APIs. 

The following example is an API request to get a list of geofences stored in the geofence collection *ExampleCollection*. 

```
POST /geofencing/v0/collections/ExampleCollection/list-geofences
```

The following is an example response for `ListGeofences`:

```
{
   "Entries": [ 
      { 
         "CreateTime": 2020-09-30T22:59:34.142Z,
         "GeofenceId": "geofence-1",
         "Geometry": { 
             "Polygon": [            
                 [-5.716667, -15.933333,
                 [-14.416667, -7.933333],
                 [-12.316667, -37.066667],
                 [-5.716667, -15.933333]
             ]
         },
         "Status": "ACTIVE",
         "UpdateTime": 2020-09-30T23:59:34.142Z
      }
   ],
   "NextToken": "1234-5678-9012"
}
```

------
#### [ CLI ]

Use the `[list-geofences](https://docs.aws.amazon.com/cli/latest/reference/location/list-geofences.html)` command.

The following example is an AWS CLI to get a list of geofences stored in the geofence collection *ExampleCollection*. 

```
aws location list-geofences \
    --collection-name "ExampleCollection"
```

------

# Tutorial: Get geofence details
<a name="get-geofence-details"></a>

You can get the details of a specific geofence, such as the create time, update time, geometry, and status, from a geofence collection using the Amazon Location console, AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To view the status of a geofence using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Geofence collections** from the left navigation pane.

1. Under **My geofence collection**, select the name link of the target geofence collection.

1. Under **Geofences**, you’ll be able to view the status of your geofences.

------
#### [ API ]

Use the `[GetGeofence](https://docs.aws.amazon.com/location/previous/APIReference/API_GetGeofence.html)` operation from the Amazon Location Geofences APIs. 

The following example is an API request to get the geofence details from a geofence collection *ExampleCollection*.

```
GET /geofencing/v0/collections/ExampleCollection/geofences/ExampleGeofence1
```

The following is an example response for `GetGeofence`:

```
{
   "CreateTime": 2020-09-30T22:59:34.142Z,
   "GeofenceId": "ExampleGeofence1",
   "Geometry": { 
      "Polygon": [            
          [-1,-1],
          [1,-1],
          [0,1],
          [-1,-1] 
      ]
   },
   "Status": "ACTIVE",
   "UpdateTime": 2020-09-30T23:59:34.142Z
}
```

------
#### [ CLI ]

Use the `[get-geofence](https://docs.aws.amazon.com/cli/latest/reference/location/get-geofence.html)` command.

The following example is an AWS CLI to get the geofence collection details for *ExampleCollection*.

```
aws location get-geofence \
    --collection-name "ExampleCollection" \
    --geofence-id "ExampleGeofence1"
```

------

# Tutorial: Delete geofences
<a name="delete-geofence"></a>

You can delete geofences from a geofence collection using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To delete a geofence using the Amazon Location console**

**Warning**  
This operation deletes the resource permanently. 

 

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Geofence collections** from the left navigation pane.

1. Under **My geofence collection**, select the name link of the target geofence collection.

1. Under **Geofences**, select the target geofence.

1. Choose **Delete geofence**.

------
#### [ API ]

Use the `[BatchDeleteGeofence](https://docs.aws.amazon.com//location/previous/APIReference/API_BatchDeleteGeofence.html)` operation from the Amazon Location Geofences APIs. 

The following example is an API request to delete geofences from the geofence collection *ExampleCollection*.

```
POST /geofencing/v0/collections/ExampleCollection/delete-geofences
Content-type: application/json

{
   "GeofenceIds": [ "ExampleGeofence11" ]
}
```

The following is an example success response for `[BatchDeleteGeofence](https://docs.aws.amazon.com//location/previous/APIReference/API_BatchDeleteGeofence.html)`. 

```
HTTP/1.1 200
```

------
#### [ CLI ]

Use the `[batch-delete-geofence](https://docs.aws.amazon.com/cli/latest/reference/location/batch-delete-geofence.html)` command.

The following example is an AWS CLI command to delete geofences from the geofence collection *ExampleCollection*.

```
aws location batch-delete-geofence \
    --collection-name "ExampleCollection" \
    --geofence-ids "ExampleGeofence11"
```

------

# Manage tracker resources with Amazon Location
<a name="managing-trackers"></a>

You can manage your trackers using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

Review and complete the following tutorials to manage tracker resounces.

**Topics**
+ [Tutorial: List your trackers](viewing-trackers.md)
+ [Tutorial: Disconnect a tracker from a geofence collection](disassociate-tracker.md)
+ [Tutorial: Get tracker details with Amazon Location](get-tracker-details.md)
+ [Tutorial: Delete a tracker with Amazon Location](delete-tracker.md)

# Tutorial: List your trackers
<a name="viewing-trackers"></a>

You can view your trackers list using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To view a list of existing trackers using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose** Trackers** from the left navigation.

1. View a list of your tracker resources under **My trackers**.

------
#### [ API ]

Use the `[ListTrackers](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_ListTrackers.html)` operation from the Amazon Location Trackers APIs. 

The following example is an API request to get a list of trackers in your AWS account. 

```
POST /tracking/v0/list-trackers
```

The following is an example response for `[ListTrackers](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_ListTrackers.html)`:

```
{
   "Entries": [ 
      { 
         "CreateTime": 2020-10-02T19:09:07.327Z,
         "Description": "string",
         "TrackerName": "ExampleTracker",
         "UpdateTime": 2020-10-02T19:10:07.327Z
      }
   ],
   "NextToken": "1234-5678-9012"
}
```

------
#### [ CLI ]

Use the `[list-trackers](https://docs.aws.amazon.com/cli/latest/reference/location/list-trackers.html)` command.

The following example is an AWS CLI to get a list of trackers in your AWS account. 

```
aws location list-trackers
```

------

# Tutorial: Disconnect a tracker from a geofence collection
<a name="disassociate-tracker"></a>

You can disconnect a tracker from a geofence collection using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To disassociate a tracker from an associated geofence collection using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Trackers** from the left navigation pane.

1. Under **My trackers**, select the name link of the target tracker.

1. Under **Linked Geofence Collections**, select a geofence collection with a **Linked** status.

1. Choose **Unlink**.

------
#### [ API ]

Use the `[DisassociateTrackerConsumer](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_DisassociateTrackerConsumer.html)` operation from the Amazon Location Trackers APIs. 

The following example is an API request to disassociate a tracker from an associated geofence collection. 

```
DELETE /tracking/v0/trackers/ExampleTracker/consumers/arn:aws:geo:us-west-2:123456789012:geofence-collection/ExampleCollection
```

The following is an example response for `[DisassociateTrackerConsumer](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_DisassociateTrackerConsumer.html)`: 

```
HTTP/1.1 200
```

------
#### [ CLI ]

Use the `[disassociate-tracker-consumer](https://docs.aws.amazon.com/cli/latest/reference/location/disassociate-tracker-consumer.html)` command.

The following example is an AWS CLI command to disassociate a tracker from an associated geofence collection. 

```
aws location disassociate-tracker-consumer \
    --consumer-arn "arn:aws:geo:us-west-2:123456789012:geofence-collection/ExampleCollection" \
    --tracker-name "ExampleTracker"
```

------

# Tutorial: Get tracker details with Amazon Location
<a name="get-tracker-details"></a>

You can get details about any tracker in your AWS account by using the Amazon Location console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To view tracker details by using the Amazon Location console**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Trackers** from the left navigation.

1. Under **My trackers**, select the name link of the target tracker.

1. View the tracker details under **Information**.

------
#### [ API ]

Use the `[DescribeTracker](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_DescribeTracker.html)` operation from the Amazon Location Tracker APIs.

The following example is an API request to get the tracker details for *ExampleTracker*.

```
GET /tracking/v0/trackers/ExampleTracker
```

The following is an example response for `[DescribeTracker](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_DescribeTracker.html)`:

```
{
   "CreateTime": 2020-10-02T19:09:07.327Z,
   "Description": "string",
   "EventBridgeEnabled": false,
   "KmsKeyId": "1234abcd-12ab-34cd-56ef-1234567890ab",
   "PositionFiltering": "TimeBased",
   "Tags": { 
      "Tag1" : "Value1" 
   },
   "TrackerArn": "arn:aws:geo:us-west-2:123456789012:tracker/ExampleTracker",
   "TrackerName": "ExampleTracker",
   "UpdateTime": 2020-10-02T19:10:07.327Z
}
```

------
#### [ CLI ]

Use the `[describe-tracker](https://docs.aws.amazon.com/cli/latest/reference/location/describe-tracker.html)` command.

The following example is an AWS CLI command to get tracker details for *ExampleTracker*.

```
aws location describe-tracker \
    --tracker-name "ExampleTracker"
```

------

# Tutorial: Delete a tracker with Amazon Location
<a name="delete-tracker"></a>

You can delete a tracker from your AWS account using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:

------
#### [ Console ]

**To delete an existing map resource using the Amazon Location console**

**Warning**  
This operation deletes the resource permanently. If the tracker resource is in use, you may encounter an error. Make sure that the target resource isn't a dependency for your applications. 

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home).

1. Choose **Trackers** from the left navigation pane.

1. Under **My trackers**, select the target tracker.

1. Choose **Delete tracker**.

------
#### [ API ]

Use the `[DeleteTracker](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_DeleteTracker.html)` operation from the Amazon Location Tracker APIs. 

The following example is an API request to delete the tracker *ExampleTracker*.

```
DELETE /tracking/v0/trackers/ExampleTracker
```

The following is an example response for `[DeleteTracker](https://docs.aws.amazon.com/location-trackers/latest/APIReference/API_DeleteTracker.html)`: 

```
HTTP/1.1 200
```

------
#### [ CLI ]

Use the `[delete-tracker](https://docs.aws.amazon.com/cli/latest/reference/location/delete-tracker.html)` command.

The following example is an AWS CLI command to delete the tracker *ExampleTracker*.

```
aws location delete-tracker \
    --tracker-name "ExampleTracker"
```

------

# Sample Geofencing and Tracking mobile application
<a name="geofence-tracking-tutorials"></a>

This topic covers tutorials designed to demonstrate the key features of using the Amazon Location geofences and trackers in a mobile application. The applications demonstrate how a tracker and geofence interact using a combination of Lambda, AWS IoT and Amazon Location features. There are two tutorials available.
+ [Sample tracking and geofencing application for Android](https://docs.aws.amazon.com//location/previous/developerguide/qs-android-tracking.html), and you can clone the project files from GitHub: [https://github.com/aws-geospatial/amazon-location-samples-android/tree/main/tracking-with-geofence-notifications](https://github.com/aws-geospatial/amazon-location-samples-android/tree/main/tracking-with-geofence-notifications).
+ [Sample tracking and geofencing application for iOS](https://docs.aws.amazon.com//location/previous/developerguide/qs-ios-tracking.html), and you can clone the project files from GitHub: [https://github.com/aws-geospatial/amazon-location-samples-ios/tree/main/tracking-with-geofence-notifications](https://github.com/aws-geospatial/amazon-location-samples-ios/tree/main/tracking-with-geofence-notifications).

# Sample tracking and geofence application for Android
<a name="qs-android-tracking"></a>

This topic covers the Android tutorial designed to demonstrate the key features of using the Amazon Location geofences and trackers in a mobile application. The applications demonstrate how a tracker and geonfence interact using a combination of Lambda, AWS IoT and Amazon Location features.

**Topics**
+ [Tutorial: Create Amazon Location resources for your app](qs-android-tracking-resources.md)
+ [Tutorial: Create a Geofence Collection](qs-android-tracking-geofence.md)
+ [Tutorial: Link a tracker to a geofence collection](qs-android-tracking-link-geofence.md)
+ [Tutorial: Use AWS Lambda with MQTT](qs-android-tracking-lambda.md)
+ [Tutorial: Set up the sample app code](qs-android-tracking-sample-app-code.md)
+ [Tutorial: Use the sample app](qs-android-tracking-use.md)

# Tutorial: Create Amazon Location resources for your app
<a name="qs-android-tracking-resources"></a>

To begin you will need to create the required Amazon Location resources. These resources will be essential for the functionality of the application and executing the provided code snippets.

**Note**  
If you haven't created an AWS account, follow the instructions in the [AWS account managment](https://docs.aws.amazon.com/accounts/latest/reference/welcome-first-time-user.html) user guide.

To begin you will need to create a Amazon Cognito Identity Pool Id, use the following procedure:

1. Open the [Amazon Cognito console](https://console.aws.amazon.com/cognito/v2/) and select **Identity pools** from the left side menu, then select **Create Identity pool**. 

1. Make sure **Guest Access** is checked, and press **Next** to contiue.

1. Next create a new IAM role or Use an existing IAM role.

1. Enter an Identity pool name, and make sure Identity Pool has access to Amazon Location `(geo)`resources for the map and tracker you will be creating nin the next procedure.

Next you need to create and style a map in the AWS Amazon Location console, use the following procedure:

1. Navigate to the [Maps section](https://console.aws.amazon.com/location/maps/home) of the Amazon Location console and select **Create Map**.

1. Give the new map a **Name** and **Description**. Record the name you assign, as it is used later in the tutorial.

1. When choosing a map style, consider the map data provider. Refer to section 82 of the [AWS service terms](http://aws.amazon.com/service-terms) for more details.

1. Accept the [Amazon Location Terms and Conditions](https://aws.amazon.com/service-terms/#:~:text=82.%20Amazon%20Location%20Service), then select **Create Map**, to finish the map creation process.

Next you need to create a tracker in the Amazon Location console, use the following procedure:

1.  Open the [Maps section](https://console.aws.amazon.com/location/trackers) in the Amazon Location console.

1. Choose **Create tracker**.

1. Fill in the required fields. Make note of the tracker's **Name** as it will be refrenced throughout this tutoiral.

1. Under the **Position filtering** field, choose the option that best fits how you intend to use your tracker resource. If you do not set Position filtering, the default setting is `TimeBased`. For more information, see [Trackers](), and [PositionFiltering]() in the Amazon Location API Reference.

1.  Choose **Create tracker** to finish creating the tracker.

# Tutorial: Create a Geofence Collection
<a name="qs-android-tracking-geofence"></a>

Now will you create a geofence collection. You can use either the console, API or CLI. The following procedures walk you through each option.
+ Create a geofence collection using the Amazon Location console:

  1.  Open the [Geofence Collections](https://console.aws.amazon.com/location/geofencing/home#/) section of the Amazon Location console.

  1. Choose **Create geofence collection**.

  1. Provide a name and description for the collection.

  1. Under the EventBridge rule with Amazon CloudWatch as a target, you can create an optional EventBridge rule to get started reacting to geofence events. This enables Amazon Location to publish events to Amazon CloudWatch Logs.

  1. Press the **Create geofence collection** to finish creating the collection.
+ Create a geofence collection using the Amazon Location API:

  Use the [CreateGeofenceCollection](https://docs.aws.amazon.com/location/previous/APIReference/API_CreateGeofenceCollection.html) operation from the Amazon Location Geofences APIs. The following example uses an API request to create a geofence collection called `GEOCOLLECTION_NAME`.

  ```
  POST /geofencing/v0/collections
  Content-type: application/json
  
  {
     "CollectionName": "GEOCOLLECTION_NAME",
     "Description": "Geofence collection 1 for shopping center",
     "Tags": { 
        "Tag1" : "Value1"
     }
  }
  ```
+ Create a geofence collection using AWS CLI commands:

  Use the `create-geofence-collection` command. The following example uses an AWS CLI to create a geofence collection called `GEOCOLLECTION_NAME`. For more information on using the AWS CLI, see the [AWS Command Line Interface Documentation](https://docs.aws.amazon.com/cli/).

  ```
  aws location \
    create-geofence-collection \
    --collection-name "ExampleGeofenceCollection" \
    --description "Shopping center geofence collection" \
    --tags Tag1=Value1
  ```

# Tutorial: Link a tracker to a geofence collection
<a name="qs-android-tracking-link-geofence"></a>

To link a tracker to a geofence collection you can use either the console, API, or CLI. The following procedures walk you through each option.

Link a tracker resource to a geofence collection using the Amazon Location Service console:

1.  Open the Amazon Location console.

1.  In the left navigation pane, choose **Trackers**.

1.  Under **Device Trackers**, select the name link of the target tracker.

1.  Under **Linked Geofence Collections**, choose **Link Geofence Collection**.

1.  In the **Linked Geofence Collection window**, select a geofence collection from the dropdown menu.

1.  Choose **Link**.

1.  After you link the tracker resource, it will be assigned an Active status.

Link a tracker resource to a geofence collection using the Amazon Location APIs:

Use the `AsssociateTrackerConsumer` operation from the Amazon Location Trackers APIs. The following example uses an API request that associates an `ExampleTracker` with a geofence collection using its Amazon Resource Name (ARN).

```
        POST /tracking/v0/trackers/ExampleTracker/consumers
        Content-type: application/json
        {
           "ConsumerArn": "arn:aws:geo:us-west-2:123456789012:geofence-collection/GOECOLLECTION_NAME"
            }
```

Link a tracker resource to a geofence collection using AWS CLI commands:

Use the `associate-tracker-consumer ` command. The following example uses an AWS CLI to create a geofence collection called `GOECOLLECTION_NAME`.

```
aws location \
associate-tracker-consumer \
    --consumer-arn "arn:aws:geo:us-west-2:123456789012:geofence-collection/GOECOLLECTION_NAME" \
    --tracker-name "ExampleTracker"
```

# Tutorial: Use AWS Lambda with MQTT
<a name="qs-android-tracking-lambda"></a>

In order to create a connection between AWS IoT and Amazon Location, you need a Lambda function to process messages forwarded by EventBridge CloudWatch events. This function will extract any positional data, format it for Amazon Location, and submit it through the Amazon Location Tracker API.

The following procedure shows you how to create this function through the Lambda console:

1. Open the [console](https://console.aws.amazon.com/lambda/).

1. From the left navigation, choose **Functions**.

1. Then choose **Create Function**, and make sure that the **Author from scratch** option is selected.

1.  provide a **Function name**, and for the **Runtime** option, choose Node.js 16.x.

1. Choose **Create function**.

1. Open the **Code tab** to access the editor.

1. Overwrite the placeholder code in the `index.js` file with the following:

   ```
               const AWS = require('aws-sdk')
               const iot = new AWS.Iot();
               exports.handler =  function(event) {
                 console.log("event===>>>", JSON.stringify(event));
                 var param = {
                   endpointType: "iot:Data-ATS"
                 };
                 iot.describeEndpoint(param, function(err, data) {
                   if (err) {
                     console.log("error===>>>", err, err.stack); // an error occurred
                   } else {
                     var endp = data['endpointAddress'];
                     const iotdata = new AWS.IotData({endpoint: endp});    
                     const trackerEvent = event["detail"]["EventType"];
                     const src = event["source"];
                     const time = event["time"];
                     const gfId = event["detail"]["GeofenceId"];
                     const resources = event["resources"][0];  
                     const splitResources = resources.split(".");  
                     const geofenceCollection = splitResources[splitResources.length - 1];
                     const coordinates = event["detail"]["Position"];                               
                     const deviceId = event["detail"]["DeviceId"]; 
                     console.log("deviceId===>>>", deviceId);
                     const msg =  {
                         "trackerEventType" : trackerEvent,
                         "source" : src,
                         "eventTime" : time,
                         "geofenceId" : gfId,
                         "coordinates": coordinates, 
                         "geofenceCollection": geofenceCollection
                       };
                     const params = {
                       topic: `${deviceId}/tracker`,
                       payload: JSON.stringify(msg),
                       qos: 0
                     };
                     iotdata.publish(params, function(err, data) {
                         if (err) {
                           console.log("error===>>>", err, err.stack); // an error occurred
                         } else {
                           console.log("Ladmbda triggered===>>>", trackerEvent);  // successful response 
                         }
                     }); 
                   }
                 });
               }
   ```

1. Press the **Deploy** to save the updated function.

1. Next open the **Configuration** tab.

1. In the **Triggers** section, press the **Add Trigger** button.

1. Select **EventBridge (CloudWatch Events)** in Source field.

1. Select the **Existing Rules** option.

1. Enter the rule name, for example `AmazonLocationMonitor-GEOFENCECOLLECTION_NAME`.

1. Press the **Add** button.

1.  This will also attach **Resource-based policy statements** in the permissions tab

Now you will set up the MQTT Test Client using AWS IoT, use the following procedure:

1. Open the [https://console.aws.amazon.com/iot/](https://console.aws.amazon.com/iot/).

1.  In the left navigation pane, select the **MQTT test client**.

1.  You'll see a section titled **MQTT test client** where you can configure your MQTT connection.

1.  After configuring the necessary settings, click on the **Connect** button to establish a connection to the MQTT broker using the provided parameters.

1.  Record endpoint, as it is used later in the tutoiral.

   Once connected to the test client, you can subscribe to MQTT topics or publish messages to topics using the respective input fields provided in the MQTT test client interface. Next you will create an AWS IoT policy.

1.  On the left side menu, under **Manage** expand **Security** option and click on **Policies**.

1.  Click on **Create Policy** button.

1.  Enter a policy name.

1.  On **Policy Document** select **JSON** tab.

1. Copy paste the policy shown below, but make sure to update all elements with your `REGION` and `ACCOUNT_ID`:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Action": [
           "iot:Connect",
           "iot:Publish",
           "iot:Subscribe",
           "iot:Receive"
         ],
         "Resource": [
           "arn:aws:iot:REGION:ACCOUNT_ID:client/${cognito-identity.amazonaws.com:sub}",
           "arn:aws:iot:REGION:ACCOUNT_ID:topic/${cognito-identity.amazonaws.com:sub}",
           "arn:aws:iot:REGION:ACCOUNT_ID:topicfilter/${cognito-identity.amazonaws.com:sub}/*",
           "arn:aws:iot:REGION:ACCOUNT_ID:topic/${cognito-identity.amazonaws.com:sub}/tracker"
         ],
         "Effect": "Allow"
       }
     ]
   }
   ```

1. Select the **Create** button to finish.

After completing the previous procedure, you will now update the permissions for the guest role as follows:

1. Navigate to Amazon Cognito and open your identity pool. Then, proceed to user access and select the guest role.

1. Click on permission policies to enable editing.

   ```
   {
       'Version': '2012-10-17		 	 	 ',
       'Statement': [
           {
               'Action': [
                   'geo:GetMap*',
                   'geo:BatchUpdateDevicePosition',
                   'geo:BatchEvaluateGeofences',
                   'iot:Subscribe',
                   'iot:Publish',
                   'iot:Connect',
                   'iot:Receive',
                   'iot:AttachPrincipalPolicy',
                   'iot:AttachPolicy',
                   'iot:DetachPrincipalPolicy',
                   'iot:DetachPolicy'
               ],
               'Resource': [
                   'arn:aws:geo:us-east-1:{USER_ID}:map/{MAP_NAME}',
                   'arn:aws:geo:us-east-1:{USER_ID}:tracker/{TRACKER_NAME}',
                   'arn:aws:geo:us-east-1:{USER_ID}:geofence-collection/{GEOFENCE_COLLECTION_NAME}',
                   'arn:aws:iot:us-east-1:{USER_ID}:client/${cognito-identity.amazonaws.com:sub}',
                   'arn:aws:iot:us-east-1:{USER_ID}:topic/${cognito-identity.amazonaws.com:sub}',
                   'arn:aws:iot:us-east-1:{USER_ID}:topicfilter/${cognito-identity.amazonaws.com:sub}/*',
                   'arn:aws:iot:us-east-1:{USER_ID}:topic/${cognito-identity.amazonaws.com:sub}/tracker'
               ],
               'Effect': 'Allow'
           },
           {
               'Condition': {
                   'StringEquals': {
                       'cognito-identity.amazonaws.com:sub': '${cognito-identity.amazonaws.com:sub}'
                   }
               },
               'Action': [
                   'iot:AttachPolicy',
                   'iot:DetachPolicy',
                   'iot:AttachPrincipalPolicy',
                   'iot:DetachPrincipalPolicy'
               ],
               'Resource': [
                   '*'
               ],
               'Effect': 'Allow'
           }
       ]
   }
   ```

1. With the above policy changes, all necessary AWS resources are now configured appropriately for the application.

# Tutorial: Set up the sample app code
<a name="qs-android-tracking-sample-app-code"></a>

This page provides a sample Android application code that demonstrates how to integrate the tracking capabilities of Amazon Location Service into your mobile applications. 

1. Clone this repository: [https://github.com/aws-geospatial/amazon-location-samples-android/tree/main/tracking-with-geofence-notifications](https://github.com/aws-geospatial/amazon-location-samples-android/tree/main/tracking-with-geofence-notifications) to your local machine.

1. Open the `AmazonSampleSDKApp` project in Android Studio.

1. Build and run the app on your Android device or emulator.

# Tutorial: Use the sample app
<a name="qs-android-tracking-use"></a>

This guide walks you through the process of setting up and using the sample Android tracking application. By following the step-by-step instructions outlined in this section, you'll learn how to configure the necessary AWS resources, integrate the tracking functionality into the sample app, and deploy it to your Android device. 

To use the sample follow these procedures:
+ **Create a `custom.properties`**:

  To configure your `custom.properties` file, follow these steps:

  1. Open your preferred text editor or IDE.

  1. Create a new file.

  1. Save the file with the name `custom.properties`.

  1. Update the `custom.properties` with the following code sample, and replace the `MQTT_END_POINT`, `POLICY_NAME`, `GEOFENCE_COLLECTION_NAME`, and `TOPIC_TRACKER` with your resoucre names:

     ```
     MQTT_END_POINT=YOUR_END_POINT.us-east-1.amazonaws.com
     POLICY_NAME=YOUR_POLICY
     GEOFENCE_COLLECTION_NAME=YOUR_GEOFENCE
     TOPIC_TRACKER=YOUR_TRACKER
     ```

  1. Clean and Rebuild the project. After this, you can run the project.
+ **Sign In**:

  To sign in to the application, follow the below steps:

  1. Press the **Sign In** button.

  1. Provide an **Identity Pool Id**, **Tracker name**, and a **Map name**.

  1. Press **Sign In** again to finish.
+ **Manage Filters**:

  Open the configuration screen, and perform the following:

  1. Toggle filters on or off using the switch UI.

  1. Update Time and Distance filters when needed.
+ **Tracking Operations:**

  Open the tracking screen and perform the following:
  + You can start and stop tracking in foreground, background, or in battery-saver mode by pressing the respective buttons.

# Sample tracking and geofencing application for iOS
<a name="qs-ios-tracking"></a>

This topic covers the iOS tutorial designed to demonstrate the key features of using the Amazon Location geofences and trackers in a mobile application. The applications demonstrate how a tracker and geonfence interact using a combination of Lambda, AWS IoT and Amazon Location features.

**Topics**
+ [Tutorial: Create Amazon Location resources for your app](qs-ios-tracking-resources.md)
+ [Tutorial: Create a Geofence Collection](qs-ios-tracking-geofence.md)
+ [Tutorial: Link a tracker to a geofence collection](qs-ios-tracking-link-geofence.md)
+ [Tutorial: Use AWS Lambda with MQTT](qs-ios-tracking-lambda.md)
+ [Tutorial: Set up sample app code](qs-ios-tracking-setup-sample.md)
+ [Tutorial: Use the sample app](qs-ios-tracking-usage.md)

# Tutorial: Create Amazon Location resources for your app
<a name="qs-ios-tracking-resources"></a>

To begin you will need to create the required Amazon Location resources. These resources will be essential for the functionality of the application and executing the provided code snippets.

**Note**  
If you haven't created an AWS account, follow the instructions in the [AWS account managment](https://docs.aws.amazon.com/accounts/latest/reference/welcome-first-time-user.html) user guide.

To begin you will need to create a Amazon Cognito Identity Pool Id, use the following procedure:

1. Open the [Amazon Cognito console](https://console.aws.amazon.com/cognito/v2/) and select **Identity pools** from the left side menu, then select **Create Identity pool**. 

1. Make sure **Guest Access** is checked, and press **Next** to contiue.

1. Next create a new IAM role or Use an existing IAM role.

1. Enter an Identity pool name, and make sure Identity Pool has access to Amazon Location `(geo)`resources for the map and tracker you will be creating nin the next procedure.

Next you need to create and style a map in the AWS Amazon Location console, use the following procedure:

1. Navigate to the [Maps section](https://console.aws.amazon.com/location/maps/home) of the Amazon Location console and select **Create Map**.

1. Give the new map a **Name** and **Description**. Record the name you assign, as it is used later in the tutorial.

1. When choosing a map style, consider the map data provider. Refer to section 82 of the [AWS service terms](http://aws.amazon.com/service-terms) for more details.

1. Accept the [Amazon Location Terms and Conditions](https://aws.amazon.com/service-terms/#:~:text=82.%20Amazon%20Location%20Service), then select **Create Map**, to finish the map creation process.

Next you need to create a tracker in the Amazon Location console, use the following procedure:

1.  Open the [Maps section](https://console.aws.amazon.com/location/trackers) in the Amazon Location console.

1. Choose **Create tracker**.

1. Fill in the required fields. Make note of the tracker's **Name** as it will be refrenced throughout this tutoiral.

1. Under the **Position filtering** field, choose the option that best fits how you intend to use your tracker resource. If you do not set Position filtering, the default setting is `TimeBased`. For more information, see [Start tracking](location/previous/developerguide/start-tracking.html), and start-tracking.html [PositionFiltering](https://docs.aws.amazon.com/location/previous/APIReference/API_BatchUpdateDevicePosition.html) in the Amazon Location API Reference.

1.  Choose **Create tracker** to finish creating the tracker.

# Tutorial: Create a Geofence Collection
<a name="qs-ios-tracking-geofence"></a>

Now will you create a geofence collection. You can use either the console, API or CLI. The following procedures walk you through each option.
+ Create a geofence collection using the Amazon Location console:

  1.  Open the [Geofence Collections](https://console.aws.amazon.com/location/geofencing/home#/) section of the Amazon Location console.

  1. Choose **Create geofence collection**.

  1. Provide a name and description for the collection.

  1. Under the EventBridge rule with Amazon CloudWatch as a target, you can create an optional EventBridge rule to get started reacting to geofence events. This enables Amazon Location to publish events to Amazon CloudWatch Logs.

  1. Press the **Create geofence collection** to finish creating the collection.
+ Create a geofence collection using the Amazon Location API:

  Use the [CreateGeofenceCollection](https://docs.aws.amazon.com/location/previous/APIReference/API_CreateGeofenceCollection.html) operation from the Amazon Location Geofences APIs. The following example uses an API request to create a geofence collection called `GEOCOLLECTION_NAME`.

  ```
  POST /geofencing/v0/collections
  Content-type: application/json
  
  {
     "CollectionName": "GEOCOLLECTION_NAME",
     "Description": "Geofence collection 1 for shopping center",
     "Tags": { 
        "Tag1" : "Value1"
     }
  }
  ```
+ Create a geofence collection using AWS CLI commands:

  Use the `create-geofence-collection` command. The following example uses an AWS CLI to create a geofence collection called `GEOCOLLECTION_NAME`. For more information on using the AWS CLI, see the [AWS Command Line Interface Documentation](https://docs.aws.amazon.com/cli/).

  ```
  aws location \
    create-geofence-collection \
    --collection-name "ExampleGeofenceCollection" \
    --description "Shopping center geofence collection" \
    --tags Tag1=Value1
  ```

# Tutorial: Link a tracker to a geofence collection
<a name="qs-ios-tracking-link-geofence"></a>

To link a tracker to a geofence collection you can use either the console, API, or CLI. The following procedures walk you through each option.

Link a tracker resource to a geofence collection using the Amazon Location Service console:

1.  Open the Amazon Location console.

1.  In the left navigation pane, choose **Trackers**.

1.  Under **Device Trackers**, select the name link of the target tracker.

1.  Under **Linked Geofence Collections**, choose **Link Geofence Collection**.

1.  In the **Linked Geofence Collection window**, select a geofence collection from the dropdown menu.

1.  Choose **Link**.

1.  After you link the tracker resource, it will be assigned an Active status.

Link a tracker resource to a geofence collection using the Amazon Location APIs:

Use the `AsssociateTrackerConsumer` operation from the Amazon Location Trackers APIs. The following example uses an API request that associates ExampleTracker with a geofence collection using its Amazon Resource Name (ARN).

```
POST /tracking/v0/trackers/ExampleTracker/consumers
Content-type: application/json
    {
       "ConsumerArn": "arn:aws:geo:us-west-2:123456789012:geofence-collection/GEOCOLLECTION_NAME"
    }
```

Llink a tracker resource to a geofence collection using AWS CLI commands:

Use the `associate-tracker-consumer ` command. The following example uses an AWS CLI to create a geofence collection called `GEOCOLLECTION_NAME`.

```
aws location \
    associate-tracker-consumer \
        --consumer-arn "arn:aws:geo:us-west-2:123456789012:geofence-collection/GEOCOLLECTION_NAME" \
        --tracker-name "ExampleTracker"
```

# Tutorial: Use AWS Lambda with MQTT
<a name="qs-ios-tracking-lambda"></a>

In order to create a connection between AWS IoT and Amazon Location, you need a Lambda function to process messages forwarded by EventBridge CloudWatch events. This function will extract any positional data, format it for Amazon Location, and submit it through the Amazon Location Tracker API.

The following procedure shows you how to create this function through the Lambda console:

1. Open the [console](https://console.aws.amazon.com/lambda/).

1. From the left navigation, choose **Functions**.

1. Then choose **Create Function**, and make sure that the **Author from scratch** option is selected.

1.  provide a **Function name**, and for the **Runtime** option, choose Node.js 16.x.

1. Choose **Create function**.

1. Open the **Code tab** to access the editor.

1. Overwrite the placeholder code in the `index.js` file with the following:

   ```
               const AWS = require('aws-sdk')
               const iot = new AWS.Iot();
               exports.handler =  function(event) {
                 console.log("event===>>>", JSON.stringify(event));
                 var param = {
                   endpointType: "iot:Data-ATS"
                 };
                 iot.describeEndpoint(param, function(err, data) {
                   if (err) {
                     console.log("error===>>>", err, err.stack); // an error occurred
                   } else {
                     var endp = data['endpointAddress'];
                     const iotdata = new AWS.IotData({endpoint: endp});    
                     const trackerEvent = event["detail"]["EventType"];
                     const src = event["source"];
                     const time = event["time"];
                     const gfId = event["detail"]["GeofenceId"];
                     const resources = event["resources"][0];  
                     const splitResources = resources.split(".");  
                     const geofenceCollection = splitResources[splitResources.length - 1];
                     const coordinates = event["detail"]["Position"];                               
                     const deviceId = event["detail"]["DeviceId"]; 
                     console.log("deviceId===>>>", deviceId);
                     const msg =  {
                         "trackerEventType" : trackerEvent,
                         "source" : src,
                         "eventTime" : time,
                         "geofenceId" : gfId,
                         "coordinates": coordinates, 
                         "geofenceCollection": geofenceCollection
                       };
                     const params = {
                       topic: `${deviceId}/tracker`,
                       payload: JSON.stringify(msg),
                       qos: 0
                     };
                     iotdata.publish(params, function(err, data) {
                         if (err) {
                           console.log("error===>>>", err, err.stack); // an error occurred
                         } else {
                           console.log("Ladmbda triggered===>>>", trackerEvent);  // successful response 
                         }
                     }); 
                   }
                 });
               }
   ```

1. Press the **Deploy** to save the updated function.

1. Next open the **Configuration** tab.

1. In the **Triggers** section, press the **Add Trigger** button.

1. Select **EventBridge (CloudWatch Events)** in Source field.

1. Select the **Existing Rules** option.

1. Enter the rule name, for example `AmazonLocationMonitor-GEOFENCECOLLECTION_NAME`.

1. Press the **Add** button.

1.  This will also attach **Resource-based policy statements** in the permissions tab

Now you will set up the AWS IoT MQTT Test Client, use the following procedure:

1. Open the [https://console.aws.amazon.com/iot/](https://console.aws.amazon.com/iot/).

1.  In the left navigation pane, select the **MQTT test client**.

1.  You'll see a section titled **MQTT test client** where you can configure your MQTT connection.

1.  After configuring the necessary settings, click on the **Connect** button to establish a connection to the MQTT broker using the provided parameters.

1.  Record endpoint, as it is used later in the tutoiral.

   Once connected to the test client, you can subscribe to MQTT topics or publish messages to topics using the respective input fields provided in the MQTT test client interface. Next you will create an AWS IoT policy.

1.  On the left side menu, under **Manage** expand **Security** option and click on **Policies**.

1.  Click on **Create Policy** button.

1.  Enter a policy name.

1.  On **Policy Document** select **JSON** tab.

1. Copy paste the policy shown below, but make sure to update all elements with your `REGION` and `ACCOUNT_ID`:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Action": [
           "iot:Connect",
           "iot:Publish",
           "iot:Subscribe",
           "iot:Receive"
         ],
         "Resource": [
           "arn:aws:iot:REGION:ACCOUNT_ID:client/${cognito-identity.amazonaws.com:sub}",
           "arn:aws:iot:REGION:ACCOUNT_ID:topic/${cognito-identity.amazonaws.com:sub}",
           "arn:aws:iot:REGION:ACCOUNT_ID:topicfilter/${cognito-identity.amazonaws.com:sub}/*",
           "arn:aws:iot:REGION:ACCOUNT_ID:topic/${cognito-identity.amazonaws.com:sub}/tracker"
         ],
         "Effect": "Allow"
       }
     ]
   }
   ```

1. Select the **Create** button to finish.

# Tutorial: Set up sample app code
<a name="qs-ios-tracking-setup-sample"></a>

In order to setup the sample code you must have the following tools installed:
+ Git
+ XCode 15.3 or Later
+ iOS Simulator 16 or later

Use this procedure to set up the sample app code:

1. Clone the git repository from this URL: [https://github.com/aws-geospatial/amazon-location-samples-ios/tree/main/tracking-with-geofence-notifications](https://github.com/aws-geospatial/amazon-location-samples-ios/tree/main/tracking-with-geofence-notifications).

1.  Open the `AWSLocationSampleApp.xcodeproj` project file.

1.  Wait for the package resolution process to finish.

1. On the project navigation menu rename `ConfigTemplate.xcconfig` to `Config.xcconfig` and fill in the following values:

   ```
   IDENTITY_POOL_ID = `YOUR_IDENTITY_POOL_ID`
   MAP_NAME = `YOUR_MAP_NAME`
   TRACKER_NAME = `YOUR_TRACKER_NAME`
   WEBSOCKET_URL = `YOUR_MQTT_TEST_CLIENT_ENDPOINT`
   GEOFENCE_ARN = `YOUR_GEOFENCE_COLLECTION_NAME`
   ```

# Tutorial: Use the sample app
<a name="qs-ios-tracking-usage"></a>

After setting up the sample code you can now run the app on an iOS simulator or a physical device.

1. Build and run the app.

1. The app will ask you for location and notification permissions. You need to allow them.

1. Press the **Cognito Configuration** button.

1. Save the configuration.

1. You can now see the Filter options for time, distance and accuracy. Use them as per your need.

1. Go to **Tracking** tab in the app and you will see the map and **Start Tracking** button.

1. If you have installed the app on a simulator you may want to simulate location changes. This can be done in **Features** under the **Location** menu option. For example select **Features**, then **Location**, then **Freeway Drive**.

1. Press the **Start Tracking** button. You should see the tracking points on the map.

1. The app is also tracking the locations in the background. So, when you move the app in the background it will ask for your permission to continue tracking in background mode.

1. You can stop the tracking by tapping on **Stop Tracking** button.

# Tag your Amazon Location Service resources
<a name="tagging"></a>

Use resource tagging in Amazon Location to create tags to categorize your resources by purpose, owner, environment, or criteria. Tagging your resources helps you manage, identify, organize, search, and filter your resources. 



For example, with AWS Resource Groups, you can create groups of AWS resources based on one or more tags or portions of tags. You can also create groups based on their occurrence in an CloudFormation stack. Using Resource Groups and Tag Editor, you can consolidate and view data for applications that consist of multiple services, resources, and Regions in one place. For more information on [Common Tagging Strategies](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html#tag-strategies), see the *AWS General Reference*.

Each tag is a label consisting of a key and value that you define:
+ **Tag key** – A general label that categorizes the tag values. For example, `CostCenter`.
+ **Tag value** – An optional description for the tag key category. For example, `MobileAssetTrackingResourcesProd`.

This topic helps you get started with tagging by reviewing tagging restrictions. It also shows you how to create tags and use tags to track your AWS cost for each active tag by using cost allocation reports. 

For more information about:
+ Tagging best practices, see [Tagging AWS resources](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html#tag-best-practices) in the *AWS General Reference*.
+ Using tags to control access to AWS resources, see [Controlling access to AWS resources using tags](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_tags.html) in the *AWS Identity and Access Management User Guide*. 

# Amazon Location tagging restrictions
<a name="tagging-restrictions"></a>

Tagging allows you to organize and manage your resources more effectively. This page outlines the specific rules and constraints that govern the use of tags within Amazon Location Service. By understanding these tagging restrictions, you can ensure compliance with best practices and avoid potential issues when implementing tagging strategies for your location-based resources and applications. 

The following basic restrictions apply to tags:
+ Maximum tags per resource – 50
+ For each resource, each tag key must be unique, and each tag key can have only one value. 
**Note**  
If you add a new tag with the same tag key as an existing tag, the new tag overwrites the existing tag. 
+ Maximum key length – 128 Unicode characters in UTF-8
+ Maximum value length – 256 Unicode characters in UTF-8
+ The allowed characters across services are: letters, numbers, and spaces representable in UTF-8, and the following characters: \$1 - = . \$1 : / @. 
+ Tag keys and values are case-sensitive.
+ The `aws:` prefix is reserved for AWS use. If a tag has a tag key with this prefix, then you can't edit or delete the tag's key or value. Tags with the `aws:` prefix don't count against your tags per resource limit. 

# Grant permission to tag resources
<a name="tag-permissions"></a>

You can use IAM policies to control access to your Amazon Location resources and grant permission to tag a resource on creation. In addition to granting permission to create resources, the policy can include `Action` permissions to allow tagging operations:
+ `geo:TagResource` – Allows a user to assign one or more tags to a specified Amazon Location resource.
+ `geo:UntagResource` – Allows a user to remove one or more tags from a specified Amazon Location resource.
+ `geo:ListTagsForResource` – Allows a user to list all the tags assigned to an Amazon Location resource.

The following is a policy example to allow a user to create a geofence collection and tag resources:

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowTaggingForGeofenceCollectionOnCreation",
            "Effect": "Allow",
            "Action": [
                "geo:CreateGeofenceCollection",
                "geo:TagResource"
            ],
            "Resource": "arn:aws:geo:region:accountID:geofence-collection/*"
    ]
}
```

# Add a tag to an Amazon Location Service resource
<a name="create-tag"></a>

You can add tags when creating your resources using the Amazon Location console, the AWS CLI, or the Amazon Location APIs:
+ [Create a map resource ](map-prerequisites.md#create-map-resource)
+ [Create a place index resource](places-prerequisites.md#create-place-index-resource)
+ [Create a route calculator resource](routes-prerequisites.md#create-route-calculator-resource)
+ [Create a geofence collection](add-geofences.md#create-geofence-collection)
+ [Create a tracker resource](start-tracking.md#start-create-tracker)

**To tag existing resources, edit or delete tags**

1. Open the Amazon Location console at [https://console.aws.amazon.com/location/](https://console.aws.amazon.com/location/home). 

1. In the left navigation pane, choose the resource you want to tag. For example, **Maps**.

1. Choose a resource from the list.

1. Choose **Manage tags** to add, edit, or delete your tags.

# Track resource cost by tag
<a name="cost-by-tag"></a>

You can use tags for cost allocation to track your AWS cost in detail. After you activate the cost allocation tags, AWS uses the cost allocation tags to organize your resource billing on your cost allocation report. This helps you categorize and track your usage costs.

There are two types of cost allocation tags you can activate:
+ [AWS-generated](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/aws-tags.html) – These tags are generated by AWS. AWS tags use the `aws:` prefix, for example, `aws:createdBy`.
+ [User-defined](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/custom-tags.html) – These are custom tags that you create. The user-defined tags use the `user:` prefix, for example, `user:CostCenter`.

You must activate each tag type individually. After your tags are activated, you can [enable AWS Cost Explorer](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/ce-enable.html) or view your monthly cost allocation report.

------
#### [ AWS-generated tags ]

**To activate AWS-generated tags**

1. Open the Billing and Cost Management console at [https://console.aws.amazon.com/billing/](https://console.aws.amazon.com/billing/home#/.).

1. In the left navigation pane, choose **Cost Allocation Tags**.

1. Under the **AWS-Generated Cost Allocation Tags** tab, select the tag keys that you want to activate.

1. Choose **Activate**. 

------
#### [ User-defined tags ]

**To activate user-defined tags**

1. Open the Billing and Cost Management console at [https://console.aws.amazon.com/billing/](https://console.aws.amazon.com/billing/home#/.).

1. In the left navigation pane, choose **Cost Allocation Tags**.

1. Under the **User-Defined Cost Allocation Tags** tab, select the tag keys you want to activate.

1. Choose **Activate**. 

------

After you activate your tags, AWS generates a [monthly Cost Allocation Report](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/configurecostallocreport.html) for your resource usage and cost. This cost allocation report includes all of your AWS costs for each billing period, including tagged and untagged resources. For more information, see [Using Cost Allocation Tags](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html) in the *AWS Billing and Cost Management User Guide*.

# Control access to Amazon Location Service resources using tags
<a name="access-by-tag"></a>

AWS Identity and Access Management (IAM) policies support tag-based conditions, which enables you to manage authorization for your resources based on specific tags key and values. For example, an IAM role policy can include conditions to limit access to specific environments, such as development, test, or production, based on tags.

For more information, see the topic on [control resource access based on tags](security_iam_id-based-policy-examples.md#security_iam_tag-based-policy-example). 

# Grant access to Amazon Location Service
<a name="how-to-access"></a>

To use Amazon Location Service, a user must be granted access to the resources and APIs that make up Amazon Location. There are three strategies you can use to grant access to your resources.
+ **Use IAM** – To grant access to users authenticated with AWS IAM Identity Center or AWS Identity and Access Management (IAM), create an IAM policy that allows access to the resources that you want. For more information about IAM and Amazon Location, see [Identity and Access Management for Amazon Location Service](security-iam.md).
+ **Use API keys** – To grant access to unauthenticated users, you can create API Keys that give read-only access to your Amazon Location Service resources. This is useful in a case where you do not want to authenticate every user. For example, a web application. For more information about API keys, see [Allow unauthenticated guest access to your application using API keys](using-apikeys.md).
+ **Use Amazon Cognito** – An alternative to API keys is to use Amazon Cognito to grant anonymous access. Amazon Cognito allows you to create a richer authorization with policy to define what can be done by the unauthenticated users. For more information about using Amazon Cognito, see [Allow unauthenticated guest access to your application using Amazon Cognito](authenticating-using-cognito.md).
**Note**  
You can also use Amazon Cognito to use your own authentication process or to combine multiple authentication methods, using Amazon Cognito Federated Identities. For more information, see [Getting Started with Federated Identities](https://docs.aws.amazon.com/cognito/latest/developerguide/getting-started-with-identity-pools.html) in the *Amazon Cognito Developer Guide*.

**Topics**
+ [Use API keys](using-apikeys.md)
+ [Use Amazon Cognito](authenticating-using-cognito.md)

# Allow unauthenticated guest access to your application using API keys
<a name="using-apikeys"></a>

When you call Amazon Location Service APIs in your applications, you typically make this call as an *authenticated user* who is authorized to make the API calls. However, there are some cases where you do not want to authenticate every user of your application. For example, you might want a web application that shows your business location to be available to anyone using the website, whether they are logged in or not. In this case, one alternative is to use API keys to make the API calls.

*API keys* are a key value that is associated with specific Amazon Location Service resources in your AWS account, and specific actions that you can perform on those resources. You can use an API key in your application to make unauthenticated calls to the Amazon Location APIs for those resources. For example, if you associate an API key with the map resource *myMap*, and the `GetMap*` actions, then an application that uses that API key will be able to view maps created with that resource, and your account will be charged as any other usage from your account. That same API key would not give permissions to change or update the map resource—only using the resource is allowed.

**Note**  
API keys are available to use only with **map**, **place**, and **route** resources, and you cannot modify or create those resources. If your application needs access to other resources or actions for unauthenticated users, you can use Amazon Cognito to provide access along with, or instead of, API keys. For more information, see [Allow unauthenticated guest access to your application using Amazon Cognito](authenticating-using-cognito.md).

API keys include a plain text *value* that gives access to one or more resources in your AWS account. If someone copies your API key, they can access those same resources. To avoid this, you can specify the domains where the API key can be used when you create the key. These domains are called referers. If needed, you can also create short term API Keys by setting expiration times for your API Keys.

**Topics**
+ [API keys compared to Amazon Cognito](#using-apikeys-vs-cognito)
+ [Create API keys](#using-apikeys-create)
+ [Use an API key to call an Amazon Location API](#using-apikeys-in-api)
+ [Use an API key to render a map](#using-apikeys-in-maps)
+ [Manage API key lifetimes](#using-apikeys-expirations)

## API keys compared to Amazon Cognito
<a name="using-apikeys-vs-cognito"></a>

API keys and Amazon Cognito are used in similar ways for similar scenarios, so why would you use one over the other? The following list highlights some of the differences between the two.
+ API keys are available only for map, place, and route resources, and only for certain actions. Amazon Cognito can be used to authenticate access to most Amazon Location Service APIs.
+ The performance of map requests with API keys is typically faster than similar scenarios with Amazon Cognito. Simpler authentication means fewer round trips to the service and cached requests when getting the same map tile again in a short time period.
+ With Amazon Cognito, you can use your own authentication process or combine multiple authentication methods, using Amazon Cognito Federated Identities. For more information, see [Getting Started with Federated Identities](https://docs.aws.amazon.com/cognito/latest/developerguide/getting-started-with-identity-pools.html) in the *Amazon Cognito Developer Guide*.

## Create API keys
<a name="using-apikeys-create"></a>

You can create an API key, and associate it with one or more resources in your AWS account.

You can create an API key using the Amazon Location Service console, the AWS CLI, or the Amazon Location APIs.

------
#### [ Console ]

**To create an API key using the Amazon Location Service console**

1. In the [https://console.aws.amazon.com/location](https://console.aws.amazon.com/location), choose **API keys** from the left menu.

1. On the **API keys** page, choose **Create API key**.

1. On the **Create API key **page, fill in the following information:
   + **Name** – A name for your API key, such as `MyWebAppKey`.
   + **Description** – An optional description for your API key.
   + **Resources** – Choose the Amazon Location resources to give access to with this API key from the dropdown. You can add more than one resource by choosing **Add resource**.
   + **Actions** – Specify the actions you want to authorize with this API key. You must select at least one action to match each resource type you have selected. For example, if you selected a place resource, you must select at least one of the choices under **Places Actions**.
   + **Expiration time** – Optionally, add an expiration date and time for your API key. For more information, see [Manage API key lifetimes](#using-apikeys-expirations).
   + **Referers** – Optionally, add one or more domains where you can use the API key. For example, if the API key is to allow an application running on the website `example.com`, then you could put `*.example.com/` as an allowed referer.
   + **Tags** – Optionally, add tags to the API key.

1. Choose **Create API key** to create the API key.

1. On the detail page for the API key, you can see information about the API key that you have created. Choose **Show API key** to see the key value that you use when calling Amazon Location APIs. The key value will have the format `v1.public.a1b2c3d4...`. For more information about using the API key to render maps, see [Use an API key to render a map](#using-apikeys-in-maps).

------
#### [ API ]

**To create an API key using the Amazon Location APIs**

Use the `[CreateKey](https://docs.aws.amazon.com/location/previous/APIReference/API_CreateKey.html)` operation from the Amazon Location APIs.

The following example is an API request to create an API key called *ExampleKey* with no expiration date, and access to a single map resource. 

```
POST /metadata/v0/keys HTTP/1.1
Content-type: application/json

{
   "KeyName": "ExampleKey"
   "Restrictions": { 
      "AllowActions": [
         "geo:GetMap*"
      ],
      "AllowResources": [
         "arn:aws:geo:region:account:map/mapname"
      ]
   },
   "NoExpiry": true
   }
}
```

The response includes the API key value to use when accessing resources in your applications. The key value will have the format `v1.public.a1b2c3d4...`. To learn more about using the API key to render maps, see [Use an API key to render a map](#using-apikeys-in-maps).

You can also use the `[DescribeKey](https://docs.aws.amazon.com/location/previous/APIReference/API_DescribeKey.html)` API to find the key value for a key at a later time.

------
#### [ AWS CLI ]

**To create an API key using AWS CLI commands**

Use the `[create-key](https://docs.aws.amazon.com/cli/latest/reference/location/create-key.html)` command.

The following example creates an API key called *ExampleKey* with no expiration date, and access to a single map resource. 

```
aws location \
  create-key \
  --key-name ExampleKey \
  --restrictions '{"AllowActions":["geo:GetMap*"],"AllowResources":["arn:aws:geo:region:account:map/mapname"]}' \
  --no-expiry
```

The response includes the API key value to use when accessing resources in your applications. The key value will have the format `v1.public.a1b2c3d4...`. To learn more about using the API key to render maps, see [Use an API key to render a map](#using-apikeys-in-maps). The response to `create-key` looks like the following.

```
{
    "Key": "v1.public.a1b2c3d4...",
    "KeyArn": "arn:aws:geo:region:account:api-key/ExampleKey",
    "KeyName": "ExampleKey",
    "CreateTime": "2023-02-06T22:33:15.693Z"
}
```

You can also use `describe-key` to find the key value at a later time. The following example shows how to call `describe-key` on an API key named *ExampleKey*.

```
aws location describe-key \
    --key-name ExampleKey
```

------

## Use an API key to call an Amazon Location API
<a name="using-apikeys-in-api"></a>

After you create an API key, you can use the key value to make calls to Amazon Location APIs in your application.

The APIs that support API keys have an additional parameter that takes the API key value. For example, if you call the `GetPlace` API, you can fill in the [key](https://docs.aws.amazon.com/location/previous/APIReference/API_GetPlace.html#API_GetPlace_RequestSyntax) parameter, as follows

```
GET /places/v0/indexes/IndexName/places/PlaceId?key=KeyValue
```

If you fill in this value, you do not need to authenticate the API call with AWS Sig v4 as you normally would.

For JavaScript developers, you can use the Amazon Location [JavaScript Authentication helper](loc-sdk-auth.md) to help with authenticating API operations with API keys.

For mobile developers, you can use the following Amazon Location mobile authentication SDKs:
+ [Amazon Location Service Mobile Authentication SDK for iOS](https://github.com/aws-geospatial/amazon-location-mobile-auth-sdk-ios/)
+ [Amazon Location Service Mobile Authentication SDK for Android](https://github.com/aws-geospatial/amazon-location-mobile-auth-sdk-android/)

For AWS CLI users, when you use the `--key` parameter, you should also use the `--no-sign-request` parameter, to avoid signing with Sig v4.

**Note**  
If you include both a `key` and an AWS Sig v4 signature in a call to Amazon Location Service, only the API key is used.

## Use an API key to render a map
<a name="using-apikeys-in-maps"></a>

You can use the API key value to render a map in your application using MapLibre. This is a little bit different than using the API keys in other Amazon Location APIs that you are calling directly, because MapLibre makes those calls for you.

The following sample code shows using the API key to render a map in a simple webpage by using the MapLibre GL JS map control. For this code to work properly, replace the *v1.public.your-api-key-value*, *us-east-1*, and *ExampleMap* strings with values that match your AWS account.

```
<!-- index.html -->
<html>
  <head>
    <link href="https://unpkg.com/maplibre-gl@1.14.0/dist/maplibre-gl.css" rel="stylesheet" />
    <style>
      body { margin: 0; }
      #map { height: 100vh; }
    </style>
  </head>
  <body>
    <!-- Map container -->
    <div id="map" />
    <!-- JavaScript dependencies -->
    <script src="https://unpkg.com/maplibre-gl@1.14.0/dist/maplibre-gl.js"></script>
    <script>
      const apiKey = "v1.public.your-api-key-value"; // API key
      const region = "us-east-1"; // Region
      const mapName = "ExampleMap"; // Map name
      // URL for style descriptor
      const styleUrl = `https://maps.geo.${region}.amazonaws.com/maps/v0/maps/${mapName}/style-descriptor?key=${apiKey}`;
      // Initialize the map
      const map = new maplibregl.Map({
        container: "map",
        style: styleUrl,
        center: [-123.1187, 49.2819],
        zoom: 11,
      });
      map.addControl(new maplibregl.NavigationControl(), "top-left");
    </script>
  </body>
</html>
```

## Manage API key lifetimes
<a name="using-apikeys-expirations"></a>

You can create API keys that work indefinitely. However, if you want to create a temporary API key, rotate API keys on a regular basis, or revoke an existing API key, you can use *API key expiration*.

When creating a new API key, or updating an existing one, you can set the expiration time for that API key.
+ When an API key reaches its expiration time, the key is automatically deactivated. Inactive keys can no longer be used to make maps requests.
+ You can delete an API key 90 days after deactivating it. 
+ If you have an inactive key that you haven't yet deleted, you can restore it by updating the expiration time to a future time.
+ To create a permanent key, you can remove the expiration time.
+ If you attempt to deactivate an API key that has been used within the last 7 days, you'll be prompted to confirm that you want to make the change. If you are using the Amazon Location Service API, or the AWS CLI, you will receive an error, unless you set `ForceUpdate` parameter to true.

# Allow unauthenticated guest access to your application using Amazon Cognito
<a name="authenticating-using-cognito"></a>

You can use Amazon Cognito authentication as an alternative to directly using AWS Identity and Access Management (IAM) with both front end SDKs and direct HTTPS requests. 

You may want to use this form of authentication for the following reasons:
+ **Unauthenticated users** – If you have a website with anonymous users, you can use Amazon Cognito identity pools. For more information, see the section on [Allow unauthenticated guest access to your application using Amazon Cognito](#authenticating-using-cognito). 
+ **Your own authentication** – If you would like to use your own authentication process, or combine multiple authentication methods, you can use Amazon Cognito Federated Identities. For more information, see [Getting Started with Federated Identities](https://docs.aws.amazon.com/cognito/latest/developerguide/getting-started-with-identity-pools.html) in the *Amazon Cognito Developer Guide*.

Amazon Cognito provides authentication, authorization, and user management for web and mobile apps. You can use Amazon Cognito unauthenticated identity pools with Amazon Location as a way for applications to retrieve temporary, scoped-down AWS credentials.

For more information, see [Getting Started with User Pools](https://docs.aws.amazon.com/cognito/latest/developerguide/getting-started-with-cognito-user-pools.html) in the *Amazon Cognito Developer Guide*.

**Note**  
For mobile developers, Amazon Location provides mobile authentication SDKs for both iOS and Android, see the following GitHub repositories for more information:  
[Amazon Location Service Mobile Authentication SDK for iOS](https://github.com/aws-geospatial/amazon-location-mobile-auth-sdk-ios/)
[Amazon Location Service Mobile Authentication SDK for Android](https://github.com/aws-geospatial/amazon-location-mobile-auth-sdk-android/)

## Create an Amazon Cognito identity pool
<a name="cognito-create-user-pool"></a>

You can create Amazon Cognito identity pools to allow unauthenticated guest access to your application through the Amazon Cognito console, the AWS CLI, or the Amazon Cognito APIs.

**Important**  
The pool that you create must be in the same AWS account and AWS Region as the Amazon Location Service resources that you're using.

You can use IAM policies associated with unauthenticated identity roles with the following actions: 
+ `geo:GetMap*`
+ `geo:SearchPlaceIndex*`
+ `geo:GetPlace`
+ `geo:CalculateRoute*`
+ `geo:GetGeofence`
+ `geo:ListGeofences`
+ `geo:PutGeofence`
+ `geo:BatchDeleteGeofence`
+ `geo:BatchPutGeofence`
+ `geo:BatchEvaluateGeofences`
+ `geo:GetDevicePosition*`
+ `geo:ListDevicePositions`
+ `geo:BatchDeleteDevicePositionHistory`
+ `geo:BatchGetDevicePosition`
+  `geo:BatchUpdateDevicePosition`

Including other Amazon Location actions will have no effect, and unauthenticated identities will be unable to call them.

**Example**  
**To create an identity pool using the Amazon Cognito console**  

1. Go to the [Amazon Cognito console](https://console.aws.amazon.com/cognito/home).

1. Choose **Manage Identity Pools.**

1. Choose **Create new identity pool**, then enter a name for your identity pool.

1. From the **Unauthenticated identities** collapsible section, choose **Enable access to unauthenticated identities**.

1. Choose **Create Pool**.

1. Choose which IAM roles you want to use with your identity pool.

1. Expand **View Details**. 

1. Under **Unauthenticated identities**, enter a role name.

1. Expand the **View Policy Document** section, then choose **Edit** to add your policy.

1. Add your policy to grant access to your resources.

   The following are policy examples for Maps, Places, Trackers, and Routes. To use the examples for your own policy, replace the *region* and *accountID* placeholders: 

------
#### [ Maps policy example ]

   The following policy grants read-only access to a map resource named *ExampleMap*.

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "MapsReadOnly",
         "Effect": "Allow",
         "Action": [
           "geo:GetMapStyleDescriptor",
           "geo:GetMapGlyphs",
           "geo:GetMapSprites",
           "geo:GetMapTile"
         ],
         "Resource": "arn:aws:geo:region:accountID:map/ExampleMap"
       }
     ]
   }
   ```

   Adding an [IAM condition](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html) that matches `aws:referer` lets you limit browser access to your resources to a list of URLs or URL prefixes. The following example allows access to a map resource named `RasterEsriImagery` from only the website `example.com`:

**Warning**  
 While `aws:referer` can limit access, it is not a security mechanism. It is dangerous to include a publicly known referer header value. Unauthorized parties can use modified or custom browsers to provide any `aws:referer` value that they choose. As a result, `aws:referer` should not be used to prevent unauthorized parties from making direct AWS requests. It is offered only to allow customers to protect their digital content, such as content stored in Amazon S3, from being referenced on unauthorized third-party sites. For more information, see [AWS:referer](https://docs.aws.amazon.com//IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-referer).

   ```
   {
       "Version": "2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "geo:GetMap*",
               "Resource": "arn:aws:geo:us-west-2:111122223333:map/RasterEsriImagery",
               "Condition": {
                   "StringLike": {
                       "aws:referer": [
                           "https://example.com/*",
                           "https://www.example.com/*"
                       ]
                   }
               }
           }
       ]
   }
   ```

   If you're [using Tangram](https://docs.aws.amazon.com/location/previous/developerguide/tutorial-tangram.html) to display a map, it doesn't use the style descriptors, glyphs, or sprites returned by the Maps API. Instead, it's configured by pointing to a .zip file that contains style rules and necessary assets. The following policy grants read-only access to a map resource named *ExampleMap* for the `GetMapTile` operation.

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "MapsReadOnly",
         "Effect": "Allow",
         "Action": [
           "geo:GetMapTile"
         ],
         "Resource": "arn:aws:geo:region:accountID:map/ExampleMap"
       }
     ]
   }
   ```

------
#### [ Places policy example ]

   The following policy grants read-only access to a place index resource named *ExamplePlaceIndex* to search for places by text or positions.

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "PlacesReadOnly",
         "Effect": "Allow",
         "Action": [
             "geo:SearchPlaceIndex*",
             "geo:GetPlace"
         ],
         "Resource": "arn:aws:geo:region:accountID:place-index/ExamplePlaceIndex"
       }
     ]
   }
   ```

   Adding an [IAM condition](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html) that matches `aws:referer` lets you limit browser access to your resources to a list of URLs or URL prefixes. The following example denies access to a place index resource named *ExamplePlaceIndex* from all referring websites, except `example.com`.

**Warning**  
 While `aws:referer` can limit access, it is not a security mechanism. It is dangerous to include a publicly known referer header value. Unauthorized parties can use modified or custom browsers to provide any `aws:referer` value that they choose. As a result, `aws:referer` should not be used to prevent unauthorized parties from making direct AWS requests. It is offered only to allow customers to protect their digital content, such as content stored in Amazon S3, from being referenced on unauthorized third-party sites. For more information, see [AWS:referrer](https://docs.aws.amazon.com//IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-referer).

   ```
   {
       "Version": "2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "geo:*",
               "Resource": "arn:aws:geo:us-west-2:111122223333:place-index/ExamplePlaceIndex",
               "Condition": {
                   "StringLike": {
                       "aws:referer": [
                           "https://example.com/*",
                           "https://www.example.com/*"
                       ]
                   }
               }
           }
       ]
   }
   ```

------
#### [ Trackers policy example ]

   The following policy grants access to a tracker resource named *ExampleTracker* to update device positions.

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "UpdateDevicePosition",
         "Effect": "Allow",
         "Action": [
           "geo:BatchUpdateDevicePosition"
         ],
         "Resource": "arn:aws:geo:region:accountID:tracker/ExampleTracker"
       }
     ]
   }
   ```

   Adding an [IAM condition](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html) that matches `aws:referrer` lets you limit browser access to your resources to a list of URLs or URL prefixes. The following example denies access to a tracker resource named *ExampleTracker* from all referring websites, except `example.com`.

**Warning**  
 While `aws:referrer` can limit access, it is not a security mechanism. It is dangerous to include a publicly known referrer header value. Unauthorized parties can use modified or custom browsers to provide any `aws:referrer` value that they choose. As a result, `aws:referrer` should not be used to prevent unauthorized parties from making direct AWS requests. It is offered only to allow customers to protect their digital content, such as content stored in Amazon S3, from being referenced on unauthorized third-party sites. For more information, see [AWS:referrer](https://docs.aws.amazon.com//IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-referer).

   ```
   {
       "Version": "2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "geo:GetDevice*",
               "Resource": "arn:aws:geo:us-west-2:111122223333:tracker/ExampleTracker",
               "Condition": {
                   "StringLike": {
                       "aws:referer": [
                           "https://example.com/*",
                           "https://www.example.com/*"
                       ]
                   }
               }
           }
       ]
   }
   ```

------
#### [ Routes policy example ]

   The following policy grants access to a route calculator resource named *ExampleCalculator* to calculate a route.

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "RoutesReadOnly",
         "Effect": "Allow",
         "Action": [
           "geo:CalculateRoute"
         ],
         "Resource": "arn:aws:geo:region:accountID:route-calculator/ExampleCalculator"
       }
     ]
   }
   ```

   Adding an [IAM condition](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html) that matches `aws:referrer` lets you limit browser access to your resources to a list of URLs or URL prefixes. The following example denies access to a route calculator named *ExampleCalculator* from all referring websites, except `example.com`.

**Warning**  
 While `aws:referrer` can limit access, it is not a security mechanism. It is dangerous to include a publicly known referrer header value. Unauthorized parties can use modified or custom browsers to provide any `aws:referrer` value that they choose. As a result, `aws:referrer` should not be used to prevent unauthorized parties from making direct AWS requests. It is offered only to allow customers to protect their digital content, such as content stored in Amazon S3, from being referenced on unauthorized third-party sites. For more information, see [AWS:referrer](https://docs.aws.amazon.com//IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-referer).

   ```
   {
       "Version": "2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "geo:*",
               "Resource": "arn:aws:geo:us-west-2:111122223333:route-calculator/ExampleCalculator",
               "Condition": {
                   "StringLike": {
                       "aws:referer": [
                           "https://example.com/*",
                           "https://www.example.com/*"
                       ]
                   }
               }
           }
       ]
   }
   ```

------
**Note**  
While unauthenticated identity pools are intended for exposure on unsecured internet sites, note that they will be exchanged for standard, time-limited AWS credentials.  
It's important to scope the IAM roles associated with unauthenticated identity pools appropriately.

1. Choose** Allow** to create your identity pools.

The resulting identity pool follows the syntax `<region>:<GUID>.` 

For example:

```
us-east-1:1sample4-5678-90ef-aaaa-1234abcd56ef
```

For more policy examples specific to Amazon Location, see [Identity-based policy examples for Amazon Location Service](security_iam_id-based-policy-examples.md).

## Use the Amazon Cognito identity pools in JavaScript
<a name="identity-pool-js"></a>

The following example exchanges the unauthenticated identity pool that you've created for credentials that are then used to fetch the style descriptor for your map resource *ExampleMap*.

```
const AWS = require("aws-sdk");

const credentials = new AWS.CognitoIdentityCredentials({
   IdentityPoolId: "<identity pool ID>" // for example, us-east-1:1sample4-5678-90ef-aaaa-1234abcd56ef
});

const client = new AWS.Location({
   credentials,
   region: AWS.config.region || "<region>"
});

console.log(await client.getMapStyleDescriptor("ExampleMap").promise());
```

**Note**  
Retrieved credentials from unauthenticated identities are valid for **one hour**.

The following is an example of a function that automatically renews credentials before they expire.

```
async function refreshCredentials() {
  await credentials.refreshPromise();
  // schedule the next credential refresh when they're about to expire
  setTimeout(refreshCredentials, credentials.expireTime - new Date());
}
```

To simplify this work, you can use the Amazon Location [JavaScript Authentication helper](loc-sdk-auth.md). This is in place of both getting the credentials, and refreshing them. This example uses the AWS SDK for JavaScript v3.

```
import { LocationClient, GetMapStyleDescriptorCommand } from "@aws-sdk/client-location";
import { withIdentityPoolId } from "@aws/amazon-location-utilities-auth-helper";

const identityPoolId = "<identity pool ID>"; // for example, us-east-1:1sample4-5678-90ef-aaaa-1234abcd56ef

// Create an authentication helper instance using credentials from Cognito
const authHelper = await withIdentityPoolId(identityPoolId);

const client = new LocationClient({
  region: "<region>", // The region containing both the identity pool and tracker resource
  ...authHelper.getLocationClientConfig(), // Provides configuration required to make requests to Amazon Location
});

const input = {
  MapName: "ExampleMap",
};

const command = new GetMapStyleDescriptorCommand(input);

console.log(await client.send(command));
```

## Next steps
<a name="access-next-steps"></a>
+ To modify your roles, go to the [IAM console](https://console.aws.amazon.com/iam/).
+ To manage your identity pools, go to the [Amazon Cognito console](https://console.aws.amazon.com/cognito/home). 

# Monitor Amazon Location Service
<a name="monitoring"></a>

When using Amazon Location Service, you can monitor your usage and resources over time by using: 
+ **Amazon CloudWatch**. Monitors your Amazon Location Service resources, and provides metrics with statistics in near-real time.
+ **AWS CloudTrail**. Provides event tracking of all calls to Amazon Location Service APIs.

Monitoring is an important part of maintaining the reliability, availability, and performance of Amazon Location Service and your AWS solutions. We recommend that you collect monitoring data from the resources that make up your AWS solution so that you can more easily debug a multi-point failure if one occurs. Before you start monitoring Amazon Location Service, however, you should create a monitoring plan that includes answers to the following questions:
+ What are your monitoring goals?
+ What resources will you monitor?
+ How often will you monitor these resources?
+ What monitoring tools will you use?
+ Who will perform the monitoring tasks?
+ Who should be notified when something goes wrong?

This section provides information about using these services.

**Topics**
+ [Monitor Amazon Location Service with Amazon CloudWatch](monitoring-using-cloudwatch.md)
+ [Log and monitor with AWS CloudTrail](logging-using-cloudtrail.md)

# Monitor Amazon Location Service with Amazon CloudWatch
<a name="monitoring-using-cloudwatch"></a>

Amazon CloudWatch monitors your AWS resources and the applications that you run on AWS in near-real time. You can monitor Amazon Location resources using CloudWatch, which collects raw data and processes metrics into meaningful statistics in near-real time. You can view historical information for up to 15 months, or search metrics to view in the Amazon CloudWatch console for more perspective about your Amazon Location resources. You can also set alarms by defining thresholds, and send notifications or take actions when those thresholds are met. 

 For more information, see the [Amazon CloudWatch User Guide](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/)

**Topics**
+ [Amazon Location Service metrics exported to Amazon CloudWatch](#metrics-exported-to-cloudwatch)
+ [View Amazon Location Service metrics](#view-metrics)
+ [Create CloudWatch alarms for Amazon Location Service metrics](#create-alarms)
+ [Use CloudWatch to monitor usage against quotas](#alarms-on-quotas)
+ [CloudWatch metric examples for Amazon Location Service](#example-alarms)

## Amazon Location Service metrics exported to Amazon CloudWatch
<a name="metrics-exported-to-cloudwatch"></a>

Metrics are time-ordered data points that are exported to CloudWatch. A dimension is a name/value pair that identifies the metric. For more information, see [Using CloudWatch metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/working_with_metrics.html) and [CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html#Dimension) dimensions in the Amazon CloudWatch User Guide.

The following are metrics that Amazon Location Service exports to CloudWatch in the `AWS/Location` namespace.


| Metric | Description | 
| --- | --- | 
|  `CallCount`  |  The number of calls made to a given API endpoint.  Valid Dimensions: Amazon Location Service API names Valid Statistic: Sum Units: Count  | 
|  `ErrorCount`  |  The number of error responses from calls made to a given API endpoint. Valid Dimensions: Amazon Location Service API names Valid Statistic: Sum Units: Count  | 
|  `SuccessCount`  |  The number of successful calls made to a given API endpoint.  Valid Dimensions: Amazon Location Service API names Valid Statistic: Sum Units: Count  | 
|  `CallLatency`  | The amount of time the operation takes to process and return a response when a call is made to a given API endpoint. Valid Dimensions: Amazon Location Service API names Valid Statistic: AverageUnits: Milliseconds | 

## View Amazon Location Service metrics
<a name="view-metrics"></a>

You can view metrics for Amazon Location Service on the Amazon CloudWatch console or by using the Amazon CloudWatch API.

**To view metrics using the CloudWatch console**

**Example**  

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Metrics**.

1. On the **All metrics tab**, choose the Amazon Location namespace.

1. Select the type of metric to view.

1. Select the metric and add it to the chart.
For more information, see [View Available Metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/viewing_metrics_with_cloudwatch.html) in the *Amazon CloudWatch User Guide*. 

## Create CloudWatch alarms for Amazon Location Service metrics
<a name="create-alarms"></a>

You can use CloudWatch to set alarms on your Amazon Location Service metrics. For example, you can create an alarm in CloudWatch to send an email whenever an error count spike occurs. 

The following topics give you a high-level overview of how to set alarms using CloudWatch. For detailed instructions, see [Using Alarms](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html) in the *Amazon CloudWatch User Guide*. 

**To set alarms using the CloudWatch console**

**Example**  

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Alarm**.

1. Choose **Create Alarm**.

1. Choose **Select metric**.

1. On the **All metrics** tab, select the Amazon Location namespace.

1. Select a metric category.

1. Find the row with the metric you want to create an alarm for, then select the check box next to this row.

1. Choose **Select metric**.

1. Under **Metric**, fill in the values .

1. Specify the alarm **Conditions** .

1. Choose **Next**.

1. If you want to send a notification when the alarm conditions are met:
   + Under **Alarm state trigger**, select the alarm state to prompt a notification to be sent.
   + Under **Select an SNS topic**, choose **Create new topic** to create a new Amazon Simple Notification Service (Amazon SNS) topic. Enter the topic name and the email to send the notification to. 
   + Under **Send a notification to** enter additional email addresses to send the notification to.
   + Choose** Add notification**. This list is saved and appears in the field for future alarms.

1. When done, choose **Next**.

1. Enter a name and description for the alarm, then choose **Next**.

1. Confirm the alarm details, then choose **Next**.

**Note**  
When creating a new Amazon SNS topic, you must verify the email address before a notification can be sent. If the email is not verified, the notification will not be received when an alarm is initiated by a state change.

For more information about how to set alarms using the CloudWatch console, see [Create an Alarm that Sends Email](https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/AlarmThatSendsEmail.html) in the *Amazon CloudWatch User Guide*. 

## Use CloudWatch to monitor usage against quotas
<a name="alarms-on-quotas"></a>

You can create Amazon CloudWatch alarms to notify you when your utilization of a given quota exceeds a configurable threshold. This enables you to recognize when you are close to your quota limits, and either adapt your utilization to avoid cost overruns, or request a quota increase, if needed. For information about how to use CloudWatch to monitor quotas, see [ Visualizing your service quotas and setting alarms](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Quotas-Visualize-Alarms.html) in the * Amazon CloudWatch User Guide*.

## CloudWatch metric examples for Amazon Location Service
<a name="example-alarms"></a>

You can use the [GetMetricData](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetMetricData.html) API to retrieve metrics for Amazon Location. 
+ For example, you can monitor `CallCount` and set an alarm for when a drop in number occurs. 

  Monitoring the `CallCount` metrics for `SendDeviceLocation` can help give you perspective on tracked assets. If the `CallCount` drops, it means that tracked assets, such as a fleet of trucks, have stopped sending their current locations. Setting an alarm for this can help notify you an issue has occurred.
+ For another example, you can monitor `ErrorCount` and set an alarm for when a spike in number occurs.

  Trackers must be associated with geofence collections in order for device locations to be evaluated against geofences. If you have a device fleet that requires continuous location updates, seeing the `CallCount` for `BatchEvaluateGeofence` or `BatchPutDevicePosition` drop to zero indicates that updates are no longer flowing.

The following is an example output for [GetMetricData](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetMetricData.html) with the metrics for `CallCount` and `ErrorCount` for creating map resources.

```
{
  "StartTime": 1518867432,
  "EndTime": 1518868032,
  "MetricDataQueries": [
    {
      "Id": "m1",
      "MetricStat": {
        "Metric": {
          "Namespace": "AWS/Location",
          "MetricName": "CallCount",
          "Dimensions": [
            {
              "Name": "SendDeviceLocation",
              "Value": "100"
            }
          ]
        },
        "Period": 300,
        "Stat": "SampleCount",
        "Unit": "Count"
      }
    },
    {
      "Id": "m2",
      "MetricStat": {
        "Metric": {
          "Namespace": "AWS/Location",
          "MetricName": "ErrorCount",
          "Dimensions": [
            {
              "Name": "AssociateTrackerConsumer",
              "Value": "0"
            }
          ]
        },
        "Period": 1,
        "Stat": "SampleCount",
        "Unit": "Count"
      }
    }
  ]
}
```

# Log and monitor with AWS CloudTrail
<a name="logging-using-cloudtrail"></a>

AWS CloudTrail is a service that provides a record of actions taken by a user, role, or an AWS service. CloudTrail records all API calls as events. You can use Amazon Location Service with CloudTrail to monitor your API calls, which include calls from the Amazon Location Service console and AWS SDK calls to the Amazon Location Service API operations. 

When you create a trail, you can enable continuous delivery of CloudTrail events to an S3 bucket, including events for Amazon Location Service. If you don't configure a trail, you can still view the most recent events in the CloudTrail console in **Event history**. Using the information collected by CloudTrail, you can determine the request that was made to Amazon Location Service, the IP address from which the request was made, who made the request, when it was made, and additional details. 

For more information about CloudTrail, see the [AWS CloudTrail User Guide](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/).

**Topics**
+ [Amazon Location Service Information in CloudTrail](#service-name-info-in-cloudtrail)
+ [Learn about Amazon Location Service log file entries](#understanding-service-name-entries)

## Amazon Location Service Information in CloudTrail
<a name="service-name-info-in-cloudtrail"></a>

CloudTrail is enabled on your AWS account when you create the account. When activity occurs in Amazon Location Service, that activity is recorded in a CloudTrail event along with other AWS service events in **Event history**. You can view, search, and download recent events in your AWS account. For more information, see [Viewing Events with CloudTrail Event History](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/view-cloudtrail-events.html). 

For an ongoing record of events in your AWS account, including events for Amazon Location Service, create a trail. A *trail* enables CloudTrail to deliver log files to an S3 bucket. By default, when you create a trail in the console, the trail applies to all AWS Regions. The trail logs events from all Regions in the AWS partition and delivers the log files to the S3 bucket that you specify. Additionally, you can configure other AWS services to further analyze and act upon the event data collected in CloudTrail logs. 

For more information, see the following: 
+ [Overview for Creating a Trail](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-create-and-update-a-trail.html)
+ [CloudTrail Supported Services and Integrations](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-aws-service-specific-topics.html#cloudtrail-aws-service-specific-topics-integrations)
+ [Configuring Amazon SNS Notifications for CloudTrail](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/getting_notifications_top_level.html)
+ [Receiving CloudTrail Log Files from Multiple Regions](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html) and [Receiving CloudTrail Log Files from Multiple Accounts](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-receive-logs-from-multiple-accounts.html)

All Amazon Location Service actions are logged by CloudTrail and are documented in the [Amazon Location Service API references](https://docs.aws.amazon.com/location/previous/APIReference/index.html). For example, calls to the `CreateTracker`, `UpdateTracker` and `DescribeTracker` actions generate entries in the CloudTrail log files. 

Every event or log entry contains information about who generated the request. The identity information helps you determine whether the request was made: 
+ With root or AWS Identity and Access Management (IAM) user credentials.
+ With temporary security credentials for a role or federated user.
+ By another AWS service.

For more information, see the [CloudTrail userIdentity Element](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-user-identity.html).

## Learn about Amazon Location Service log file entries
<a name="understanding-service-name-entries"></a>

A trail is a configuration that enables delivery of events as log files to an S3 bucket that you specify, or to Amazon CloudWatch Logs. For more information, see [Working with CloudTrail log files](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-working-with-log-files.html) in the *AWS CloudTrail User Guide*. 

CloudTrail log files contain one or more log entries. An event represents a single request from any source and includes information about the requested operation, the date and time of the operation, request parameters, and so on. 

**Note**  
CloudTrail log files aren't an ordered stack trace of the public API calls, so they don't appear in any specific order. To determine the order of operations, use `[eventTime](https://docs.aws.amazon.com/awscloudtrail/latest/APIReference/API_Event.html)`.

The following example shows a CloudTrail log entry that demonstrates the `CreateTracker` operation, which creates a tracker resource.

```
{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "123456789012",
        "arn": "arn:aws:geo:us-east-1:123456789012:tracker/ExampleTracker"
        "accountId": "123456789012",
        "accessKeyId": "123456789012",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "123456789012",
                "arn": "arn:aws:geo:us-east-1:123456789012:tracker/ExampleTracker",
                "accountId": "123456789012",
                "userName": "exampleUser",
            },
            "webIdFederationData": {},
            "attributes": {
                "mfaAuthenticated": "false",
                "creationDate": "2020-10-22T16:36:07Z"
            }
        }
    },
    "eventTime": "2020-10-22T17:43:30Z",
    "eventSource": "geo.amazonaws.com",
    "eventName": "CreateTracker",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "192.0.2.0/24—TEST-NET-1",
    "userAgent": "aws-internal/3 aws-sdk-java/1.11.864 Linux/4.14.193-110.317.amzn2.x86_64 OpenJDK_64-Bit_Server_VM/11.0.8+10-LTS java/11.0.8 kotlin/1.3.72 vendor/Amazon.com_Inc. exec-env/AWS_Lambda_java11",
    "requestParameters": {
        "TrackerName": "ExampleTracker",
        "Description": "Resource description"
    },
    "responseElements": {
        "TrackerName": "ExampleTracker",
        "Description": "Resource description"
        "TrackerArn": "arn:partition:service:region:account-id:resource-id",
        "CreateTime": "2020-10-22T17:43:30.521Z"
    },
    "requestID": "557ec619-0674-429d-8e2c-eba0d3f34413",
    "eventID": "3192bc9c-3d3d-4976-bbef-ac590fa34f2c",
    "readOnly": false,
    "eventType": "AwsApiCall",
    "recipientAccountId": "123456789012",
}
```

The following shows a log entry for the `DescribeTracker` operation, which returns the details of a tracker resource.

```
{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "123456789012",
        "arn": "arn:partition:service:region:account-id:resource-id",
        "accountId": "123456789012",
        "accessKeyId": "123456789012",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "123456789012",
                "arn": "arn:partition:service:region:account-id:resource-id",
                "accountId": "123456789012",
                "userName": "exampleUser",
            },
            "webIdFederationData": {},
            "attributes": {
                "mfaAuthenticated": "false",
                "creationDate": "2020-10-22T16:36:07Z"
            }
        }
    },
    "eventTime": "2020-10-22T17:43:33Z",
    "eventSource": "geo.amazonaws.com",
    "eventName": "DescribeTracker",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "192.0.2.0/24—TEST-NET-1",
    "userAgent": "aws-internal/3 aws-sdk-java/1.11.864 Linux/4.14.193-110.317.amzn2.x86_64 OpenJDK_64-Bit_Server_VM/11.0.8+10-LTS java/11.0.8 kotlin/1.3.72 vendor/Amazon.com_Inc. exec-env/AWS_Lambda_java11",
    "requestParameters": {
        "TrackerName": "ExampleTracker"
    },
    "responseElements": null,
    "requestID": "997d5f93-cfef-429a-bbed-daab417ceab4",
    "eventID": "d9e0eebe-173c-477d-b0c9-d1d8292da103",
    "readOnly": true,
    "eventType": "AwsApiCall",
    "recipientAccountId": "123456789012",
}
```

# Create Amazon Location Service resources with AWS CloudFormation
<a name="creating-resources-with-cloudformation"></a>

Amazon Location Service is integrated with AWS CloudFormation, a service that helps you to model and set up your AWS resources so that you can spend less time creating and managing your resources and infrastructure. You create a template that describes all the AWS resources that you want (such as Amazon Location resources), and CloudFormation provisions and configures those resources for you. 

When you use CloudFormation, you can reuse your template to set up your Amazon Location resources consistently and repeatedly. Describe your resources once, and then provision the same resources over and over in multiple AWS accounts and Regions. 

## Amazon Location and CloudFormation templates
<a name="working-with-templates"></a>

To provision and configure resources for Amazon Location and related services, you must understand [CloudFormation templates](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-guide.html). Templates are formatted text files in JSON or YAML. These templates describe the resources that you want to provision in your CloudFormation stacks. If you're unfamiliar with JSON or YAML, you can use CloudFormation Designer to help you get started with CloudFormation templates. For more information, see [What is CloudFormation Designer?](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/working-with-templates-cfn-designer.html) in the *AWS CloudFormation User Guide*.

Amazon Location supports creating the following resource types in CloudFormation:
+ [AWS::Location::Map](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-location-map.html)
+ [AWS::Location::PlaceIndex](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-location-placeindex.html)
+ [AWS::Location::RouteCalculator](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-location-routecalculator.html)
+ [AWS::Location::Tracker](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-location-tracker.html)
+ [AWS::Location::TrackerConsumer](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-location-trackerconsumer.html)
+ [AWS::Location::GeofenceCollection](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-location-geofencecollection.html)

 For more information, including examples of JSON and YAML templates for Amazon Location resources, see the [Amazon Location Service resource type reference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Location.html) in the *AWS CloudFormation User Guide*.

## Learn more about CloudFormation
<a name="learn-more-cloudformation"></a>

To learn more about CloudFormation, see the following resources:
+ [AWS CloudFormation](https://aws.amazon.com/cloudformation/)
+ [AWS CloudFormation User Guide](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html)
+ [CloudFormation API Reference](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/Welcome.html)
+ [AWS CloudFormation Command Line Interface User Guide](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/what-is-cloudformation-cli.html)