USGS National Map API in Python#

By Sebastian Shirk and Avery Fernandez

The USGS National Map API provides developers with access to a suite of geospatial datasets, including elevation, hydrography, boundaries, transportation, and more. This API facilitates the retrieval of topographic information essential for various applications such as mapping, analysis, and decision-making.

This tutorial content is intended to help facilitate academic research.

Please see the following resources for more information on API usage:

NOTE: The USGS National Map API does not impose a strict limit on requests. However, users are encouraged to use the service responsibly to ensure equitable access for all. This API is only for the United States and that if too many requests are being made nationwide, the API may not work as expected.

These recipe examples were tested on May 7, 2025.

Setup#

The following external libraries need to be installed into your enviornment to run the code examples in this tutorial:

We import the libraries used in this tutorial below:

import requests
from pprint import pprint

1. Requesting the API#

We start by adding all the variables that we can use to specify what kind of data we want to retrieve:

BASE_URL = "https://tnmaccess.nationalmap.gov/api/v1/"
endpoint = "products"

# Parameters
params = {
    "bbox": "",
    "polygon": "",
    "datasets": "",
    "prodExtents": "",
    "prodFormats": "",
    "q": "",
    "dataType": "",
    "start": "",
    "end": "",
    "offset": "0",
    "max": "1",
    "outputFormat": "JSON",
    "polyType": "",
    "polyCode": "",
    "extentQuery": ""
}

This will start as an empty query that gives us the first sets of data on the API database. We can modify our output with the variables above.

Then we query the API with the requests library and print the results.

# This sends a query that looks like this: 
# https://tnmaccess.nationalmap.gov/api/v1/products?&offset=0&max=1&outputFormat=JSON
try:
    response = requests.get(BASE_URL + endpoint, params=params)
    # Raise an error for bad responses
    response.raise_for_status()  
    data = response.json()
except requests.exceptions.RequestException as e:
    print(f"Error: {e}")
    data = None

if data:
    for item in data["items"]:
        # Print the first item in the response
        print("---------------------------------------------")
        pprint(item, compact=False, sort_dicts=False)
        print("---------------------------------------------\n")

        # This stops the loop after the first item is printed.
        # Remove this break statement to print all items in the response.
        break
---------------------------------------------
{'title': '18TWK610820',
 'moreInfo': 'Lidar (Light detection and ranging) discrete-return point cloud '
             'data are available in the American Society for Photogrammetry '
             'and Remote Sensing (ASPRS) LAS format. The LAS format is a '
             'standardized binary format for storing 3-dimensional point cloud '
             'data and point attributes along with header information and '
             'variable length records specific to the data. Millions of data '
             'points are stored as a 3-dimensional data cloud as a series of x '
             '(longitude), y (latitude) and z (elevation) points. A few older '
             'projects in this collection are in ASCII format. Please refer to '
             'http://www.asprs.org/Committee-General/LASer-LAS-File-Format-Exchange-Activities.html '
             'for additional information. This data set is a LAZ (compressed '
             'LAS) format file containing [...]',
 'sourceId': '6338596ad34e900e86cdbfd3',
 'sourceName': 'ScienceBase',
 'sourceOriginId': None,
 'sourceOriginName': 'gda',
 'metaUrl': 'https://www.sciencebase.gov/catalog/item/6338596ad34e900e86cdbfd3',
 'vendorMetaUrl': 'https://prd-tnm.s3.amazonaws.com/index.html?prefix=StagedProducts/Elevation/metadata/NJ_New_Jersey_SANDY_LiDAR_15/NJ_SdL5_2014',
 'publicationDate': '2015-05-03',
 'lastUpdated': '2022-10-01T09:14:53.711-06:00',
 'dateCreated': '2022-10-01T09:14:50.910-06:00',
 'sizeInBytes': 31830199,
 'extent': 'Varies',
 'format': 'LAZ',
 'downloadURL': 'https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/laz/18TWK610820.laz',
 'downloadURLRaster': None,
 'previewGraphicURL': 'https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/browse/18TWK610820.jpg',
 'downloadLazURL': 'https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/laz/18TWK610820.laz',
 'urls': {'LAZ': 'https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/laz/18TWK610820.laz'},
 'datasets': [],
 'boundingBox': {'minX': -74.2802466122605,
                 'maxX': -74.2624014212519,
                 'minY': 40.4863433374492,
                 'maxY': 40.4999672066248},
 'bestFitIndex': 0.0,
 'body': 'Lidar (Light detection and ranging) discrete-return point cloud data '
         'are available in the American Society for Photogrammetry and Remote '
         'Sensing (ASPRS) LAS format. The LAS format is a standardized binary '
         'format for storing 3-dimensional point cloud data and point '
         'attributes along with header information and variable length records '
         'specific to the data. Millions of data points are stored as a '
         '3-dimensional data cloud as a series of x (longitude), y (latitude) '
         'and z (elevation) points. A few older projects in this collection '
         'are in ASCII format. Please refer to '
         'http://www.asprs.org/Committee-General/LASer-LAS-File-Format-Exchange-Activities.html '
         'for additional information. This data set is a LAZ (compressed LAS) '
         'format file containing lidar point cloud data. Compression to an LAZ '
         "file was done with the LAStools 'laszip' program and can be unzipped "
         'with the same free program (laszip.org).',
 'processingUrl': 'processingUrl',
 'modificationInfo': '2022-10-01'}
---------------------------------------------

2. Specifying Variables#

All variables (except for max and offset) should be strings that start with the variable name and end with the variable value.

The variable max and offset will be set as a string that represents the maximum number of results and pagination respectively. If max or offset are null, the API will not run. The variable max is set to 1 by default and offset is set to 0 by default. These variables can have up to a combined total of 50.

Any variable that you do not want to specify should be left as an empty string ("").

For more information on using variables, please refer to the USGS National Map Documentation.

endpoint = "products"

# Parameters
params = {
    "bbox": "-122.5,37.5,-122,38",
    "polygon": "",
    "datasets": "National Elevation Dataset (NED) 1 arc-second",
    "prodExtents": "",
    "prodFormats": "GeoTIFF",
    "q": "",
    "dataType": "dateCreated",
    "start": "1996-01-22",
    "end": "2025-01-22",
    "offset": "0",
    "max": "1",
    "outputFormat": "JSON",
    "polyType": "",
    "polyCode": "",
    "extentQuery": ""
}

bbox Variable#

The bbox variable is used to specify the bounding box of the area you want to retrieve data from or a single point you would like to see around. The format is as follows:

Box

bbox = “minX,minY,maxX,maxY”

bbox = "-122.5,37.5,-122,38"

Gives back in an area inside or around -122.5,37.5,-122,38

Point

bbox = “minX,minY,maxX,maxY”

bbox = "-106,39,-106,39"

Gives back the area around the point -106,39

dataset Variable#

The dataset variable is used to specify what kind of data you want to retrieve. Here are all of the possible values you can use:

National Boundary Dataset (NBD):

datasets = "National Boundary Dataset (NBD)"

National Elevation Dataset (NED) 1 arc-second:

datasets = "National Elevation Dataset (NED) 1 arc-second"

Digital Elevation Model (DEM) 1 meter:

datasets = "Digital Elevation Model (DEM) 1 meter"

q Variable#

The q variable is used to specify a query string to search for data. This is useful if you want to search for a specific area or type of data. Here are all of the possible values you can use:

7.5:

q="7.5"

Airports:

q="Airports"

Bend:

q="Bend"

Using q = "Bridge" will give back something like this:

{
    'title': 'US Topo 7.5-minute map for Apishapa Bridge, CO',
    'format': 'Geospatial PDF, Geospatial PDF',
    'downloadURL': 'https://prd-tnm.s3.amazonaws.com/StagedProducts/Maps/USTopo/PDF/CO/CO_Apishapa_Bridge_20220308_TM_geo.pdf',
}

More information on Variables#

For more information on the variables, queries, and datasets, please refer to the USGS National Map API Documentation.

3. Querying and Parsing the API#

We can parse the API to get all the provided information on any given data piece. The most useful information in this data is the download URL to get the image, but there are other pieces of information that can be useful as well.

For example, we can get the title of the data, the download URL, and any other present information:

endpoint = "products"
# Parameters
params = {
    "bbox": "",
    "polygon": "",
    "datasets": "",
    "prodExtents": "",
    "prodFormats": "",
    "q": "",
    "dataType": "",
    "start": "",
    "end": "",
    "offset": "0",
    "max": "1",
    "outputFormat": "JSON",
    "polyType": "",
    "polyCode": "",
    "extentQuery": ""
}

# Query:
try:
    response = requests.get(BASE_URL + endpoint, params=params)
    # Raise an error for bad responses
    response.raise_for_status()  
    data = response.json()
except requests.exceptions.RequestException as e:
    print(f"Error: {e}")
    data = None

# Add any variable to the end of item
# Title Example:
# Add ["title"] to the end of item
if data:
    for item in data["items"]:
        # Print the first item in the response
        print("---------------------------------------------")
        pprint(item["title"], compact=False, sort_dicts=False)
        print("---------------------------------------------\n")

        # This stops the loop after the first item is printed.
        # Remove this break statement to print all items in the response.
        break

# DownloadURL Example: 
# Add ["downloadURL"] to the end of item
if data:
    for item in data["items"]:
        # Print the first item in the response
        print("---------------------------------------------")
        pprint(item["downloadURL"], compact=False, sort_dicts=False)
        print("---------------------------------------------\n")

        # This stops the loop after the first item is printed.
        # Remove this break statement to print all items in the response.
        break

# Usable Variables include:
# (This is also the order that data will be printed when not specified)
# ["title"]
# ["moreInfo"]
# ["sourceId"]
# ["sourceName"]
# ["sourceOriginName"]
# ["metaUrl"]
# ["vendorMetaUrl"]
# ["publicationDate"]
# ["lastUpdated"]
# ["dateCreated"]
# ["sizeInBytes"]
# ["extent"]
# ["format"]
# ["downloadURL"]
# ["previewGraphicURL"]
# ["urls"]
# ["datasets"]
# ["boundingBox"]
# ["bestFitIndex"]
# ["body"]
# ["processingUrl"]
# ["modificationInfo"]

# To get multiple variables, duplicate the pprint line and change the variable
if data:
    for item in data["items"]:
        # Print the first item in the response
        print("---------------------------------------------")
        pprint(item["title"], compact=False, sort_dicts=False)
        pprint(item["downloadURL"], compact=False, sort_dicts=False)
        pprint(item["sourceName"], compact=False, sort_dicts=False)
        print("---------------------------------------------\n")

        # This stops the loop after the first item is printed.
        # Remove this break statement to print all items in the response.
        break

# To go back and get all the variables, remove the variable from the pprint line
if data:
    for item in data["items"]:
        # Print the first item in the response
        print("---------------------------------------------")
        pprint(item, compact=False, sort_dicts=False)
        print("---------------------------------------------\n")

        # This stops the loop after the first item is printed.
        # Remove this break statement to print all items in the response.
        break
---------------------------------------------
'18TWK610820'
---------------------------------------------

---------------------------------------------
'https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/laz/18TWK610820.laz'
---------------------------------------------

---------------------------------------------
'18TWK610820'
'https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/laz/18TWK610820.laz'
'ScienceBase'
---------------------------------------------

---------------------------------------------
{'title': '18TWK610820',
 'moreInfo': 'Lidar (Light detection and ranging) discrete-return point cloud '
             'data are available in the American Society for Photogrammetry '
             'and Remote Sensing (ASPRS) LAS format. The LAS format is a '
             'standardized binary format for storing 3-dimensional point cloud '
             'data and point attributes along with header information and '
             'variable length records specific to the data. Millions of data '
             'points are stored as a 3-dimensional data cloud as a series of x '
             '(longitude), y (latitude) and z (elevation) points. A few older '
             'projects in this collection are in ASCII format. Please refer to '
             'http://www.asprs.org/Committee-General/LASer-LAS-File-Format-Exchange-Activities.html '
             'for additional information. This data set is a LAZ (compressed '
             'LAS) format file containing [...]',
 'sourceId': '6338596ad34e900e86cdbfd3',
 'sourceName': 'ScienceBase',
 'sourceOriginId': None,
 'sourceOriginName': 'gda',
 'metaUrl': 'https://www.sciencebase.gov/catalog/item/6338596ad34e900e86cdbfd3',
 'vendorMetaUrl': 'https://prd-tnm.s3.amazonaws.com/index.html?prefix=StagedProducts/Elevation/metadata/NJ_New_Jersey_SANDY_LiDAR_15/NJ_SdL5_2014',
 'publicationDate': '2015-05-03',
 'lastUpdated': '2022-10-01T09:14:53.711-06:00',
 'dateCreated': '2022-10-01T09:14:50.910-06:00',
 'sizeInBytes': 31830199,
 'extent': 'Varies',
 'format': 'LAZ',
 'downloadURL': 'https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/laz/18TWK610820.laz',
 'downloadURLRaster': None,
 'previewGraphicURL': 'https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/browse/18TWK610820.jpg',
 'downloadLazURL': 'https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/laz/18TWK610820.laz',
 'urls': {'LAZ': 'https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/laz/18TWK610820.laz'},
 'datasets': [],
 'boundingBox': {'minX': -74.2802466122605,
                 'maxX': -74.2624014212519,
                 'minY': 40.4863433374492,
                 'maxY': 40.4999672066248},
 'bestFitIndex': 0.0,
 'body': 'Lidar (Light detection and ranging) discrete-return point cloud data '
         'are available in the American Society for Photogrammetry and Remote '
         'Sensing (ASPRS) LAS format. The LAS format is a standardized binary '
         'format for storing 3-dimensional point cloud data and point '
         'attributes along with header information and variable length records '
         'specific to the data. Millions of data points are stored as a '
         '3-dimensional data cloud as a series of x (longitude), y (latitude) '
         'and z (elevation) points. A few older projects in this collection '
         'are in ASCII format. Please refer to '
         'http://www.asprs.org/Committee-General/LASer-LAS-File-Format-Exchange-Activities.html '
         'for additional information. This data set is a LAZ (compressed LAS) '
         'format file containing lidar point cloud data. Compression to an LAZ '
         "file was done with the LAStools 'laszip' program and can be unzipped "
         'with the same free program (laszip.org).',
 'processingUrl': 'processingUrl',
 'modificationInfo': '2022-10-01'}
---------------------------------------------

4. Downloading URLs and Images#

If you want to download any of the URLs, you can easily do this by copying the URL into any browser and it will download it.

If you want to do this strictly in the python script you can add and call this function:

def get_file(file_url):
    file_name = file_url.split("/")[-1]
    with open(file_name, "wb") as f:
        file_url_content = requests.get(file_url)
        f.write(file_url_content.content)
for item in data["items"]:
    # Print the first item in the response
    print("---------------------------------------------")
    pprint(item["downloadURL"], compact=False, sort_dicts=False)
    print("---------------------------------------------\n")
---------------------------------------------
'https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/LPC/Projects/USGS_Lidar_Point_Cloud_NJ_SdL5_2014_LAS_2015/laz/18TWK610820.laz'
---------------------------------------------

The get_file function downloads the file and saves it to the specified path.

get_file(data["items"][int(params["offset"])]["downloadURL"])