Skip to main content

ezesri

Extract data from Esri REST API endpoints. Available as a web app, Python library and CLI.

Web app

Don't have Python installed? Use the web app at ezesri.com to extract GeoJSON directly in your browser. No installation required.

Public Data Directory

Browse 24,000+ public ArcGIS Feature Services from government agencies worldwide at ezesri.com/directory. Find parcels, zoning, elections, crime, weather, sports facilities, wildlife data and more — all searchable and filterable by 32 categories.

Python package

ezesri is also a lightweight Python package for extracting data and metadata from Esri REST API endpoints. It provides a modular API and optional CLI for exporting feature layers and metadata to common formats, with robust handling of Esri-specific pagination and filtering.

Why use the Python package?

Many tools exist for interacting with Esri services, but they often come with trade-offs:

  • pysridump/esridump: Simple and widely used, but not modular, lacks modern export formats, and is not actively maintained.
  • ArcGIS API for Python: A full-featured Esri SDK, but its heavy dependencies make it overkill for simple data extraction.
  • ogr2ogr (GDAL): Extremely powerful, but can be complex to use and is not a native Python library.

Key features

  • Multiple export formats: GeoJSON, Shapefile, GeoPackage, File Geodatabase, GeoParquet, Parquet, NDJSON
  • Readable output: Coded values become labels and Esri's epoch-millisecond dates become timestamps, by default
  • Automatic pagination: Handles Esri's record limits seamlessly
  • Filtering: Filter by bounding box, geometry, or SQL where clause
  • Bulk exports: Download all layers from a MapServer or FeatureServer
  • CLI: Command-line interface for quick extraction
  • Clean metadata: Human-readable layer summaries

Installation

pip install ezesri

Quickstart

Here's a simple example of how to use ezesri as a library to extract data and metadata.

import ezesri

# URL for Riverside County, CA parcels layer
url = "https://gis.countyofriverside.us/arcgis/rest/services/mmc/mmc_mSrvc_v12_prod/MapServer/8"

# Get layer metadata
metadata = ezesri.get_metadata(url)
print("## Layer Metadata Summary")
print(ezesri.summarize_metadata(metadata))

# Extract layer to a GeoDataFrame
print("\n## Extracting Layer to GeoDataFrame")
gdf = ezesri.extract_layer(url, where="APN LIKE '750%'")
print(f"Successfully extracted {len(gdf)} features.")
print(gdf.head())

Documentation

Full documentation is available at ezesri.com/docs

Usage

Python library

ezesri is designed to be used as a library for integration with your Python scripts.

  • get_metadata(url): Fetches the raw metadata for a layer.
  • summarize_metadata(metadata): Returns a human-readable summary of the metadata.
  • get_count(url, where, bbox, geometry, spatial_rel): Asks the server how many features match a query, without downloading them.
  • get_codebook(url): Returns a record of the layer's coded-value domains and date fields.
  • decode_dataframe(df, metadata, decode_domains, parse_dates): Decodes an already-fetched DataFrame, returning (df, report).
  • extract_layer(url, where, bbox, geometry, spatial_rel, out_sr, decode_domains, parse_dates): Extracts a layer to a GeoDataFrame, with optional filters.
  • bulk_export(service_url, output_dir, output_format, ...): Downloads all layers from a MapServer or FeatureServer.

geometry accepts a GeoJSON geometry, Feature or FeatureCollection, as either a dict or a JSON string, and is converted to Esri JSON before the query is sent.

Command-line interface (CLI)

ezesri also provides a command-line tool for quick data extraction.

Fetch metadata

Get a clean, human-readable summary of a layer's metadata.

ezesri metadata "https://gis.countyofriverside.us/arcgis/rest/services/mmc/mmc_mSrvc_v12_prod/MapServer/8"

To get the raw JSON output, use the --json flag:

ezesri metadata <YOUR_ESRI_LAYER_URL> --json

Fetch layer data

You can fetch a layer and save it to a file in various formats.

  • GeoJSON

    ezesri fetch <URL> --format geojson --out output.geojson
    
  • Shapefile

    ezesri fetch <URL> --format shapefile --out output.shp
    
  • GeoPackage

    ezesri fetch <URL> --format gpkg --out output.gpkg
    
  • File Geodatabase

    ezesri fetch <URL> --format gdb --out output.gdb
    
  • GeoParquet (spatial)

    ezesri fetch <URL> --format geoparquet --out output.parquet
    
  • Parquet (tabular)

    ezesri fetch <URL> --format parquet --out output.parquet
    
  • NDJSON (streaming)

    # to stdout
    ezesri fetch <URL> --format ndjson
    # to file
    ezesri fetch <URL> --format ndjson --out output.ndjson
    

Count features before downloading

Check how big a layer is before committing to a download. count takes the same filters as fetch.

ezesri count <URL>
ezesri count <URL> --where "STATUS = 'ACTIVE'"

Filtering

You can filter by a bounding box (in WGS84 coordinates), an attribute query or a GeoJSON geometry:

ezesri fetch <URL> --bbox <xmin,ymin,xmax,ymax> --out <FILE>
ezesri fetch <URL> --where "STATUS = 'ACTIVE'" --out <FILE>
ezesri fetch <URL> --geometry boundary.geojson --out <FILE>

Reprojecting output

Output is WGS84 (EPSG:4326) by default. Use --out-sr with any WKID the server supports:

ezesri fetch <URL> --out-sr 3857 --format geojson --out output.geojson

Large or fragile layers

Object ID queries page past the ArcGIS 1,000,000-ID transfer limit automatically, so layers larger than 1M features extract in full. Feature batches default to the lesser of the server's advertised maxRecordCount and 1,000, and halve on failure before retrying — servers often advertise a maxRecordCount they cannot actually serialize with geometry attached. Override it if you need to:

ezesri fetch <URL> --batch-size 250 --format geojson --out output.geojson

Coded values and dates

Esri layers routinely store a status as 3, with a domain elsewhere in the metadata that maps 3 to "Under construction". Dates come back as epoch milliseconds, so a filing date arrives as 1735689600000. ezesri decodes both by default:

Field Raw Esri value ezesri output
STATUS 3 Under construction
FILED 1735689600000 2025-01-01 00:00:00+00:00

Codes with no matching label are left alone and reported, rather than silently blanked. Layers that use subtypes are handled too, where the same code can mean different things depending on the subtype.

To keep the raw values:

ezesri fetch <URL> --raw-codes --raw-dates --out output.csv --format csv

Write a codebook alongside the export so the original codes stay recoverable:

ezesri fetch <URL> --format csv --out output.csv --codebook codebook.json

# or inspect a layer's codes without downloading anything
ezesri codebook <URL>

Bulk-fetch all layers from a service

You can discover and export all layers from a MapServer or FeatureServer to a specified directory.

ezesri bulk-fetch <YOUR_ESRI_SERVICE_URL> <YOUR_OUTPUT_DIRECTORY> --format gdb

Or use GeoPackage as an open, broadly supported alternative:

ezesri bulk-fetch <YOUR_ESRI_SERVICE_URL> <YOUR_OUTPUT_DIRECTORY> --format gpkg

You can also write per-layer files in these formats:

ezesri bulk-fetch <YOUR_ESRI_SERVICE_URL> <YOUR_OUTPUT_DIRECTORY> --format geoparquet
ezesri bulk-fetch <YOUR_ESRI_SERVICE_URL> <YOUR_OUTPUT_DIRECTORY> --format parquet
ezesri bulk-fetch <YOUR_ESRI_SERVICE_URL> <YOUR_OUTPUT_DIRECTORY> --format ndjson

Speed and politeness options:

# use 4 parallel workers
ezesri bulk-fetch <SERVICE_URL> <OUT_DIR> --format geoparquet --workers 4
# apply a global rate limit of 2 requests/second across all workers
ezesri bulk-fetch <SERVICE_URL> <OUT_DIR> --format geoparquet --workers 4 --rate 2

Bulk export takes the same filters as fetch, applied to every layer:

ezesri bulk-fetch <SERVICE_URL> <OUT_DIR> --format gpkg --where "STATE = 'CA'"
ezesri bulk-fetch <SERVICE_URL> <OUT_DIR> --format gpkg --bbox <xmin,ymin,xmax,ymax>

Examples

For a detailed, real-world example of using ezesri to acquire, process, and visualize data, see the scripts in the examples/ directory. These examples demonstrate how to download data, merge it, and create a map.

To run these examples, you will first need to install the required dependencies:

pip install geopandas matplotlib

Then, you can run the scripts directly:

python examples/00_palm_springs_fetch.py
python examples/01_palm_springs_pools_map.py

Testing

This project uses pytest for unit testing. For details on how to run the test suite, please see the testing guide.

Deploying the Web App

The web app consists of two parts:

Frontend (Next.js on Vercel)

The frontend auto-deploys to Vercel on push to main. No manual steps required.

Backend (AWS Lambda)

The API backend requires manual deployment via AWS SAM:

cd web/lambda
sam build && sam deploy

Prerequisites:

  • AWS CLI configured with credentials
  • AWS SAM CLI installed (brew install aws-sam-cli on Mac)

See web/lambda/README.md for more details.

Contributing

Contributions are welcome! Please see the contributing guide for more information.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ezesri-0.4.0.tar.gz (32.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ezesri-0.4.0-py3-none-any.whl (24.4 kB view details)

Uploaded Python 3

File details

Details for the file ezesri-0.4.0.tar.gz.

File metadata

  • Download URL: ezesri-0.4.0.tar.gz
  • Upload date:
  • Size: 32.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.18

File hashes

Hashes for ezesri-0.4.0.tar.gz
Algorithm Hash digest
SHA256 f260ecb9ea90b48d6983ec7d13ccefa687e77ae0d0e46e75f72efc37d0b2b502
MD5 955bf9d0aed1bf7669cff108d1e58cca
BLAKE2b-256 cc01442c4d557f0693b6aa6a5dc9a24baae319ee8bbb832fac36ac733db1670d

See more details on using hashes here.

File details

Details for the file ezesri-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: ezesri-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 24.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.18

File hashes

Hashes for ezesri-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7b9b08cb82cb886be2bb2f3a1d8b9f8a7b904e070bfd049c589ce5e8913bdebb
MD5 b1445436365d2167ed365c0f660d30e4
BLAKE2b-256 cea2a62703e81f5c11a8d386b2d621a461a99362c6947c33bcdd358140708b71

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 files

0.3.5

2 files

0.3.4

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page