Install ckanext-gztr
Learn how to install ckanext-gztr to your CKAN instance.

Installation and setup
Prerequisite knowledge
In this installation guide, we assume you are already familiar with setting up CKAN extensions on a CKAN instance.
The following resources can be helpful for additional info as a reference. We recommend first try going through this page's installation guide for your CKAN instance, and then refer to these documentation sources as needed:
Support
If you ever have any issues installing ckanext-gztr, please:
- Read through the troubleshooting section
- Search the GitHub issues or create an issue
- Search the GitHub discussions or create a discussion
If you need further support reach out to datHere at support.dathere.com.
✨️ Try out the ckanext-gztr Docker Compose demo!
Want to explore ckanext-gztr on your local device first before going through the installation? Check out the ckanext-gztr Docker Compose demo at github.com/dathere/gztr-docker-demo! Clone the repo, update the environment variables, & launch a local CKAN instance with ckanext-gztr installed. Follow the steps in the README to get started.
In this installation guide we'll use a CKAN source install set up for development on Ubuntu 24.04 and we'll refer to the default installation location of /usr/lib/ckan/default/src/ckan during these steps along with the configuration file at /etc/ckan/default/ckan.ini.
You can also adapt the installation steps for your setup, such as modifying your Docker Compose or Kubernetes and Helm setup.
Minimum CKAN version 2.12
Activate your virtual environment and navigate to your CKAN extensions installation directory
Ensure your terminal is running in your instance's virtual environment before continuing and that you're in the /usr/lib/ckan/default/src directory so that we may install extensions here.
cd /usr/lib/ckan/default/src
. ../bin/activateInstall ckanext-scheming
The ckanext-gztr extension relies on ckanext-scheming to add the interactive gazetteer to the new dataset form.
Not using ckanext-scheming?
Run the following in /usr/lib/ckan/default/src to install the ckanext-scheming extension:
pip install -e "ckanext-scheming@git+https://github.com/ckan/ckanext-scheming.git"Then in your CKAN config file (e.g., /etc/ckan/default/ckan.ini) for ckan.plugins add scheming_datasets. For example:
ckan.plugins = activity scheming_datasetsWhat is scheming_datasets?
scheming_datasets to your ckan.plugins value enables ckanext-scheming features for datasets. In particular ckanext-gztr can expose the dataset publisher gazetteer through this.Add the preset ckanext.gztr:schemas/presets.yaml to the end of your scheming.presets config value:
scheming.presets = ckanext.scheming:presets.json ckanext.gztr:schemas/presets.yamlWhat is a scheming preset?
If you already have a running CKAN instance with ckanext-scheming installed and a custom dataset schema then you'll want to add the following fields to your schema YAML file for the dataset publisher gazetteer to appear in the dataset metadata form:
# ckanext-gztr fields
# Interactive React gazetteer widget
- field_name: gazetteer
label: Indicate Spatial Coverage
form_snippet: gazetteer_widget.html
display_snippet: null
validators: ignore_missing gazetteer_validator
output_validators: scheming_load_json
# Full GeoJSON (without geometries for selected features)
# as a STAC ItemCollection (based on GeoJSON FeatureCollection)
# from user's selection in data publisher gazetteer
- field_name: spatial_full
label: Geospatial metadata
display_snippet: gazetteer_preview.html
form_snippet: text.html
form_placeholder: Filled in automatically as you select areas above.If you do not have an existing dataset schema configured for your CKAN instance, then you can add the following demo dataset schema to try out the gazetteer (e.g. right below the line with ckan.plugins) in the dataset metadata form:
scheming.dataset_schemas = ckanext.gztr:schemas/dataset.yamlCustomize for your use case!
dataset.yaml file however may not fit your use case, so ensure you use a separate schema as needed.Install ckanext-gztr
Install ckanext-gztr and its dependencies in your activated virtual environment:
cd /usr/lib/ckan/default/src
git clone https://github.com/dathere/ckanext-gztr.git
cd ckanext-gztr
pip install -e .
pip install -r requirements.txtThen add gztr to your ckan.plugins in your /etc/ckan/default/ckan.ini file:
ckan.plugins = activity scheming_datasets gztrInstall JTS and update the Solr schema file
Brief overview of why we're going to install JTS and update schema.xml
With ckanext-gztr, one of the main features for public usage is geospatial search on the /dataset page of a CKAN web app by drawing a bounding box over a region.
CKAN uses the open-source Apache Solr for multi-modal search. With Apache Solr there are various ways to run a spatial search. ckanext-gztr uses a similar approach to ckanext-spatial for spatial search, attempting to run a geospatial intersection filter by intersecting the user's drawn bounding box against each dataset's simplified spatial geometry field which is indexed. This spatial field is a geometry, often a Polygon or MultiPolygon, and is necessary to have the dataset searchable by location by having it indexed in Solr.
The dataset's spatial_full field is transformed into WKT geometry using the shapely Python library and named as spatial_geom in Solr as an indexed field. Then a geospatial search query is ran through the following Intersects operation against spatial_geom and the bounds of the user's drawn bounding box (mimicing the filter used by ckanext-spatial):
{{!field f=spatial_geom}}Intersects(ENVELOPE({minx}, {maxx}, {maxy}, {miny}))Installation
However to run this geospatial search against polygons we need to install the JTS library for Solr and to configure it properly.
It may be a bit tricky to get JTS running with CKAN and Solr as intended. The CKAN development team provides preconfigured Solr Docker images for CKAN which you can refer to as an example.
To install JTS, follow the steps listed in the following admonition.
Complete these steps in particular!
Follow the Solr docs here, including these steps in particular:
- Install the JTS JAR file
- Place the installed JTS JAR file in a specific location as mentioned in the linked docs (e.g.
$SOLR_INSTALL/server/solr-webapp/webapp/WEB-INF/lib/where$SOLR_INSTALLin the official CKAN Solr spatial images is/opt/solr/).
For additional information see the Solr documentation for the latest documentation on how to install JTS here.
Now you'll need to update your Solr schema file. Find the relevant sections as shown in the top-level tags below and add the sub-level content to them:
<!-- ... -->
<types>
<!-- ... -->
<!-- RPT field type for searching polygons with ckanext-gztr -->
<fieldType
name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType"
spatialContextFactory="JTS"
autoIndex="true"
validationRule="repairBuffer0"
distErrPct="0.025"
maxDistErr="0.001"
distanceUnits="kilometers">
</fieldType>
</types>
<fields>
<!-- ... -->
<!-- Allow ckanext-gztr to index simplified geometry and place keywords -->
<field name="spatial_geom" type="location_rpt" indexed="true" stored="true" multiValued="true" />
<field name="place_keywords" type="string" indexed="true" stored="true" multiValued="true"/>
<!-- ... -->
</fields>
<!-- ... -->
<!-- Allows for searching by place keywords in the dataset search page by ckanext-gztr -->
<copyField source="place_keywords" dest="text" />Set ckan.search.solr_allowed_query_parsers to field in your CKAN config
First check if ckan.search.solr_allowed_query_parsers exists in your CKAN config file (e.g. /etc/ckan/default/ckan.ini). Update or add it with field as the value.
ckan.search.solr_allowed_query_parsers = fieldThis is necessary to ensure the public bounding box spatial search works. Otherwise you may get the following error:
Dataset search error: ("Local parameters are not supported in param 'fq'.",)Configure your CKAN instance and set up the gztr storage
There are a plethora of configuration options with ckanext-gztr for your CKAN instance. We've divded them into mandatory, recommended, and optional.
Add the following lines to your CKAN configuration and customize it as needed. Ensure that you provide the configuration values labeled as mandatory.
You might be able to skip some sections!
If you have been following the steps so far then you've already filled out the ckanext-scheming and SOLR options sections at the top of the following code block which you can skip.
# ckanext-gztr configuration (more info at https://gztr.dathere.com/docs/configuration)
# == ckanext-gztr | ckanext-scheming options ==
# (mandatory)
ckan.scheming.presets = ckanext.scheming:presets.json ckanext.gztr:schemas/presets.yaml
# (mandatory)
ckan.scheming.dataset.schemas = ckanext.gztr:schemas/dataset.yaml
# == ckanext-gztr | SOLR options ==
# (mandatory)
ckan.search.solr_allowed_query_parsers = field
# == ckanext-gztr | Storage options (more info at https://docs.ckan.org/en/latest/maintaining/filestore.html#setup-file-storages) ==
# The gztr storage type, in this case based on the filesystem.
# (mandatory)
ckan.files.storage.gztr.type = ckan:fs
# The path to the gztr storage on the filesystem.
# (mandatory)
ckan.files.storage.gztr.path = /var/lib/ckan/storage/uploads/gztr
# Creates the `gztr` directory if it doesn't exist.
# (mandatory)
ckan.files.storage.gztr.initialize = true
# Makes all gztr storage files publicly downloadable.
# (mandatory)
ckan.files.storage.gztr.public = true
# == ckanext-gztr | Dataset publisher gazetteer options ==
# Vector tile server URL.
# Raster tiles and PMTiles are not currently supported.
# (mandatory)
ckanext.gztr.dataset_publisher.tiles_url =
# The default center latitude of the map.
# (recommended)
ckanext.gztr.dataset_publisher.default_latitude = 34.307144
# The default center longitude of the map.
# (recommended)
ckanext.gztr.dataset_publisher.default_longitude = -106.018066
# The initial zoom level of the map.
# (recommended)
ckanext.gztr.dataset_publisher.default_zoom = 5
# The space-separated boundaries of the map (e.g. continental USA)
# (recommended)
ckanext.gztr.dataset_publisher.max_bounds = -134.428711 14.349548 -61.611328 52.536273
# Disable drawing custom polygons for dataset publishers.
# Set this to true if you want data publishers to only use preset features provided by the sysadmin.
# (optional)
ckanext.gztr.dataset_publisher.disable_drawn_features = false
# Modify the height of the map shown in the modal (note that there is already a fullscreen button if needed).
# (optional)
ckanext.gztr.dataset_publisher.dialog_map_height = 60vh
# Disable the address search feature which uses the external Nominatim API.
# (optional)
ckanext.gztr.dataset_publisher.disable_address_search = false
# Select an engine for parsing GeoParquet for usage in the gazetteers.
# - hyparquet: recommended (enabled by default) for lowest bandwidth costs through cloud-native geospatial methodology
# - duckdb: downloads DuckDB WASM from jsdelivr.com which is slow on first request then cached on subsequent requests
# - sedonadb: not recommended, slowest implementation as it converts GeoParquet to GeoJSON and the user downloads GeoJSON
# (recommended)
ckanext.gztr.dataset_publisher.geoparquet_engine = hyparquet
# In a geospatial collection's info modal, display a clickable JSON file icon button to open the corresponding STAC collection page.
# (optional)
ckanext.gztr.dataset_publisher.enable_stac_collection_json_button = true
# In a geospatial collection's info modal, display a clickable download icon button to download the collection as a file (e.g. GeoParquet).
# (optional)
ckanext.gztr.dataset_publisher.enable_stac_collection_download_button = true
# == ckanext-gztr | Public search gazetteer options ==
# Vector tile server URL.
# Raster tiles and PMTiles are not currently supported.
# (mandatory)
ckanext.gztr.public_search.tiles_url =
# The default center latitude of the maps.
# (recommended)
ckanext.gztr.public_search.default_latitude = 34.307144
# The default center longitude of the maps.
# (recommended)
ckanext.gztr.public_search.default_longitude = -106.018066
# The initial zoom level of the maps.
# (recommended)
ckanext.gztr.public_search.default_zoom = 5
# The space-separated boundaries of the map (e.g. continental USA)
# (recommended)
ckanext.gztr.public_search.max_bounds = -134.428711 14.349548 -61.611328 52.536273
# Disable the address search feature which uses Nominatim.
# (optional)
ckanext.gztr.public_search.disable_address_search = false
# Allow public users to click a JSON info icon button to open the STAC collection info JSON page.
# (optional)
ckanext.gztr.public_search.enable_stac_collection_json_button = false
# Allow public users to click a download icon button to download a geospatial collection (e.g. GeoParquet file).
# (optional)
ckanext.gztr.public_search.enable_stac_collection_download_button = true
# == ckanext-gztr | Public search minimap options ==
# MapLibre-specific config about the source data
# Refer to https://maplibre.org/maplibre-style-spec/sources for more info
# Vector, Raster, or PMTiles (using the pmtiles:// protocol) server URL.
# (mandatory)
ckanext.gztr.public_search_minimap.tiles_url =
# The type of the source, either vector or raster
# (mandatory)
ckanext.gztr.public_search_minimap.tiles_type = vector
# Attribution HTML (e.g. an HTML anchor tag with a link using href)
# NOTE: As a sysadmin, make sure this is safe HTML!
# (recommended)
ckanext.gztr.public_search_minimap.attribution_html =
# The space-separated boundaries of the minimap (e.g. continental USA)
# (recommended)
ckanext.gztr.public_search_minimap.max_bounds = -134.428711 14.349548 -61.611328 52.536273
# The maximum zoom level that the tiles would be retrieved for
# (optional)
ckanext.gztr.public_search_minimap.max_zoom = 19
# == ckanext-gztr | Geoconnex options (more info at https://gztr.dathere.com/docs/geoconnex-integration) ==
# (optional)
ckanext.gztr.geoconnex.enabled = false
# The namespace that should exist in the namespaces/bulk/ckan directory at https://github.com/internetofwater/geoconnex.us
# (optional)
ckanext.gztr.geoconnex.namespace =
# Embeds Geoconnex-compatible JSON-LD within each compatible CKAN dataset's landing page
# (optional)
ckanext.gztr.geoconnex.enable_dataset_jsonld = falseThe new gztr directory should be made in your filesystem at /var/lib/ckan/storage/uploads/gztr once you run your CKAN instance. This is where the GeoParquet files will be stored, along with the catalog.json and collections.json files we'll set up soon. They'll also be publicly available at {your_instance_domain}/file/public-download/gztr/{file_location} such as http://localhost:5000/file/public-download/gztr/catalog.json.
You can view other available configuration options in the Configuration section of this documentation. If you're installing ckanext-gztr on your CKAN instance, make sure to stay notified of new releases published to the ckanext-gztr GitHub repository that may mention any new or updated configuration options by "watching" it.
Using S3 instead of the filesystem
gztr storage with an S3-compatible cloud storage adapter on the CKAN file storages documentation (you may need to scroll down a bit) which uses the ckanext-file-keeper-cloud CKAN extension. You'll want to monitor your S3 usage though when using ckanext-gztr, especially if you have large geospatial collections. You may want to instead periodically sync from an external S3 bucket to the filesystem storage to remove the calls from your CKAN instance's server to the external S3 storage and instead read from the filesystem to reduce potential bandwidth costs and latency.Prepare your STAC and GeoJSON files

SpatioTemporal Asset Catalogs (STAC) with ckanext-gztr
The STAC specification is a common language to describe geospatial information, which can help make geospatial data easier to use, index, and discover.
We make use of the STAC specification throughout ckanext-gztr, including both how data models are organized and for the STAC API endpoints that get added to your CKAN instance.
Helpful STAC resources
If you're new to the STAC specification, here are a few resources you could get started with:
Upload your preset GeoJSON FeatureCollection files
As a sysadmin you'll provide GeoJSON files that are used throughout ckanext-gztr including for the public search gazetteer, the dataset publisher gazetteer, and the place keywords search functionality.
Geospatial data sources
We provide guides (e.g. using Jupyter Lab) on how to download and format data from various geospatial data sources in the geospatial data section of this documentation. However we still recommend reading through this section first to understand how you can add custom geospatial collections for your CKAN instance.
The GeoJSON files must be in a specific format so that ckanext-gztr can properly use them. Here are the conditions followed by an example GeoJSON file:
- A GeoJSON file must be a
FeatureCollectionusing WGS84 as its geographic coordinate reference system. - Each
Featuremust have a uniqueidentry. The value of theidentry is unique across allFeatures in theFeatureCollection. Therefore we do not recommend using a label such as a name for the ID, but rather a unique string or number such as basing theidon an existing unique ID system for theFeatureCollection. - Each
Featuremust also have atitleentry in itspropertiesdictionary where the value oftitleis a human-readable name for theFeature, such as a county name.
Unique ID is required!
Feature in a FeatureCollection has a unique ID. This is required for ckanext-gztr to work properly. If you have multiple geospatial Polygon Features that are meant to be selected as one feature (e.g. a group of cities) then you may need to consolidate them into one Feature with a MultiPolygon geometry.Let's view part of a GeoJSON file NM_HUC8_Sub_Basins.geojson for NMWDC with data provided by Geoconnex (we omit the value for geometry here as it would be too long):
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": "13020203",
"geometry": null,
"properties": {
"geoconnex_pid": "https://geoconnex.us/ref/hu08/13020203",
"title": "Rio Grande-Albuquerque"
}
}
]
}Notice that the ID is based on an existing ID system for HUC8 Sub Basins in the USA provided by the USGS as described in collections.json. We also have title in the properties of the Feature which is a human-readable name describing the feature. You can add other common metadata such as a description. There is also a geoconnex_pid as described in the Geoconnex integration documentation.
You'll now need to upload the GeoJSON file to your gztr storage through the gztr_collection_create custom CKAN API Action endpoint which converts your GeoJSON file into a GeoParquet file. Since we're using the CKAN API, you should ensure your CKAN instance is running.
Here is an example of uploading a GeoJSON file NM_HUC8_Sub_Basins.geojson through the CKAN API using curl in a Bash shell:
read -p 'CKAN sysadmin API Token: ' api_token
curl -H "Authorization: $api_token" -X POST -F upload=@./NM_HUC8_Sub_Basins.geojson -F storage=gztr http://localhost:5000/api/3/action/gztr_collection_createHere is the output that is returned:
{
"help": "http://localhost:5000/api/3/action/help_show?name=gztr_collection_create",
"success": true,
"result": {
"name": "nm_huc8_sub_basins.parquet",
"location": "nm_huc8_sub_basins.parquet",
"storage": "gztr",
"content_type": "application/octet-stream",
"size": 6394247,
"hash": "91437835777a3e23633d36a0021c004e",
"algorithm": "md5",
"created": "2026-08-18T09:32:52.751045+00:00",
"storage_data": {},
"id": "a13a09bc-8694-40f8-a082-bc6bca0c21a7",
"owner_type": "user",
"owner_id": "255d924c-f5fc-4dc1-9204-1e9bfa899219",
"pinned": false
}
}Now copy the location stem that is returned after uploading because we will use it for later, for example nm_huc8_sub_basins (case-sensitive! notice the file name is not exactly the same as the original GeoJSON file). Do this for each file you upload, as you'll need the value for when you define your STAC Catalog and STAC Collections in the next steps.
STAC Catalog (catalog.json) and STAC Collections (collections.json)
We need to define metadata about the geospatial data that is being stored by the CKAN instance and exposed through the STAC API. You'll need to define a STAC Catalog as a catalog.json file which is a top-level description of your the geospatial data available from your CKAN instance using STAC. You'll also need to define a file collections.json that defines the STAC Collections available from your STAC API.
We provide examples you can customize in the clickable accordions below.
You should refer to the STAC Catalog specification and the STAC Collection specification to guide your creation of the data for catalog.json and collection.json. You may also refer to the STAC best practices file.
For the catalog.json file we also provide a form below that generates basic STAC Catalog JSON that you can start with for your catalog.json file. For collections.json refer to example above and the specification.
Note that the generator below only works for a single STAC Collection, so you'll want to add more STAC Collections manually.
{
"id": "nmwdc",
"stac_version": "1.1.0",
"type": "Catalog",
"title": "New Mexico Water Data Catalog",
"description": "Geospatial collections and features used for dataset publishing and search by the , organized through the SpatioTemporal Asset Catalogs (STAC) specification suite.",
"links": [
{
"href": "/gztr/stac",
"rel": "self",
"type": "application/json"
},
{
"href": "/gztr/stac",
"rel": "root",
"type": "application/json"
},
{
"href": "/gztr/stac/collections",
"rel": "collections",
"type": "application/json"
},
{
"href": "/gztr/stac/collections/nm_huc8_sub_basins",
"rel": "child",
"type": "application/json",
"title": "HUC8 Sub Basins"
}
]
}
Remember to also set up a collections.json file.
Upload catalog.json and collections.json to the gztr storage
Now that you have your STAC Catalog and STAC Collections files prepared, you'll need to upload them to the gztr storage.
Here is an example of uploading the catalog.json and collections.json files through the CKAN API using curl in a Bash shell (make sure you use a sysadmin's API token):
read -p 'CKAN sysadmin API Token: ' api_token
curl -H "Authorization: $api_token" -X POST -F upload=@./catalog.json -F storage=gztr http://localhost:5000/api/3/action/file_create
curl -H "Authorization: $api_token" -X POST -F upload=@./collections.json -F storage=gztr http://localhost:5000/api/3/action/file_createVerify ckanext-gztr works as expected
Now the interactive gazetteer should be available on the form for adding and editing a dataset along with a public search map gazetteer.
For example you can run a local CKAN instance by running the following in your activated virtual environment:
cd /usr/lib/ckan/default/src/ckan
ckan -c /etc/ckan/default/ckan.ini runThen you should have your local CKAN instance running which you can open in your web browser at http://localhost:5000. If you visit the Datasets page at http://localhost:5000/dataset then you should see an interactive search gazetteer to search by bounding box intersections and a dataset publisher gazetteer in the new dataset form.
If you visit http://localhost:5000/api/3/action/status_show then there should be a JSON response where gztr is present in the result.extensions array.
You can also now explore your STAC API at http://localhost:5000/gztr/stac.
What next?
There's plenty more to explore with ckanext-gztr. In particular you'll want to customize your configuration such as setting the default map location, zoom, and your map tiles. We also recommend "watching" the GitHub repository to ensure you get notified when a new release is made and learn steps for updating your extension.
Configuration
Customize ckanext-gztr with configuration options.
Geospatial data
Learn how geospatial data is organized along with tutorials to ingest data from various data sources.
Geoconnex integration
Learn how to sync your water data with Geoconnex.
Software architecture
Learn about how ckanext-gztr is innovatively organized.