Hey,
I’d like to convert text addresses into coordinates from within the pipeline, either via transforms or pipeline builder.
I’m thinking of treating it as an External Transform in Transforms or via an UDF in Pipeline Builder, that would make the external call.
I was wondering if there’s a smarter way to do it, given there are mentions of Mapbox integrations for geospatial workflows in the doc, but I couldn’t find anything for geocoding.
AFAIK, there is currently no way of doing this in a first class way!
We did it a few times by now and here are some recommendations I have from my experience doing this with regular Transforms:
Use an incremental pipeline that caches geocoding results: In an incremental pipeline you can read the previous output and add new geocoding results to the output.
This way you won’t need to constantly geocode the same adresses multiple times if they reappear.
Don’t use UDF’s: From my experience UDF’s create a ton of overhead and take up multiple workers. It’s much easer to just take a limited amount of Rows from dataframes and iterate through them with regular python code.
If you need parallelisation you can use Threads instead.
If you need to geocode more rows at once you can just run the pipeline more frequently and it will fill up you cache over time.
If anyone is interested I can search through some previous code and share some snippets!
Very interested in seeing some past examples! I am working through this problem now. Echo the sentiment that this would be a first-class platform feature
I know this is not immediately helpful, and we (pipeline builder) have heard this is an important workflow. We are building out a first class solution coming soon (~months)!
I wanted to share a small snippet that might help others get started with geocoding in Foundry, especially if you’re looking to first test things locally before turning them into a pipeline or multi-threaded transformation. This approach uses the Nominatim API (OpenStreetMap), and can be a handy base to build on.
Here’s a Python example I’ve used to geocode U.S.-based addresses from a CSV file:
import pandas as pd
import requests
import time
import os
from tqdm import tqdm
tqdm.pandas()
def geocode(address, city, state):
search_address = f"{address}, {city}, {state}, USA".strip().strip(',')
if not search_address or search_address == "USA":
return [None, None]
base_url = "https://nominatim.openstreetmap.org/search"
params = {
"q": search_address,
"format": "json",
"limit": 1,
"addressdetails": 1,
"countrycodes": "us"
}
headers = {
"User-Agent": "OSMGeoCode",
"email" : "your_email" # Replace with your contact email
}
try:
response = requests.get(base_url, params=params, headers=headers)
if response.status_code == 200:
data = response.json()
if data:
lat = float(data[0]["lat"])
lon = float(data[0]["lon"])
time.sleep(1) # Respect Nominatim rate limit
return [lat, lon]
time.sleep(1)
return [None, None]
except Exception:
time.sleep(1)
return [None, None]
While Nominatim works technically, please remember it’s a free service run by volunteers. Respecting their rate limits is essential (1 request / second + need to specify an identifiable user-agent / email so they can contact you if something goes wrong).
For higher throughput geocoding, consider these alternatives:
Mapbox (https://www.mapbox.com/geocoding)
Google maps (https://developers.google.com/maps/documentation/geocoding/overview)
Self-hosting Nominatim (possible in Foundry but challenging; only worthwhile for processing millions of addresses)
There is no native geocoding transform in Foundry — the Mapbox integration covers **Mapbox Boundaries** (choropleth region data) and the **Find Locations** UI feature in the Map application, both of which are visualization-layer features rather than pipeline-level geocoding capabilities. Your instinct to use an external call is the right approach, and Foundry supports this in two well-documented ways.
This is the most flexible approach for batch geocoding. You write a Python transform that calls a geocoding API (Mapbox Geocoding, Google Maps, etc.) using the `@use_external_systems` decorator with a network egress policy.
The recommended modern pattern is **source-based external transforms**. The legacy @use_external_systems approach still works but is in legacy status.
A minimal example calling an external geocoding endpoint:
An Information Security Officer must enable **Allow access to external systems** in the repository settings.
A network egress policy covering the geocoding API endpoint must be created in Control Panel and imported into the repository.
If your addresses dataset contains sensitive markings, those markings must be explicitly allowed under **Configure use of Foundry inputs with external systems**.
Option 2: Python UDF in Pipeline Builder
If you prefer to stay in Pipeline Builder, you can author a **Python function** that calls the geocoding API and use it as a UDF transform node in your pipeline.
The function runs as a sidecar container alongside the pipeline and scales dynamically. To make external API calls from it, you publish a Python function with access to external systems, then configure the source in Data Connection under **Connection settings > Code import configuration** to allow it to be imported into pipelines.
Once published and configured, you import the UDF into your pipeline via **Reusables > User-defined functions**, then wire it up as a transform node like any other.
Yes, via Python function with external system access
Governance
Egress policy + export controls
Source must be configured as pipeline-importable
Maturity
Fully supported (use source-based, not legacy)
Supported; runs as sidecar container
Both are valid. If geocoding is one step in a larger Pipeline Builder graph, the Python UDF route keeps everything in one place. If it is a standalone scheduled sync or you need incremental processing, the external transform in Code Repositories gives you more control.