Convert Oklahoma Section, Township, Range to Lat/Long for Power BI, Excel, and Google Sheets
Convert Oklahoma section, township, and range to lat/long for Power BI, Excel, and Google Sheets — Power Query, LAMBDA, and the add-on, with a SCOOP example.
Your Oklahoma well table has a column called legal_description. Every row reads something like T11N R8W Sec 14 NE¼, Indian Meridian — a string the Power BI map visual cannot plot, the Excel chart wizard cannot graph, and the Google Sheets MAP chart will not accept. There is no built-in geocoder anywhere in the Microsoft or Google data analytics stack that understands the Public Land Survey System.
This is the gap. You have hundreds — sometimes thousands — of SCOOP and STACK well records keyed by PLSS legal description, and you need them as latitude/longitude before any map, distance calculation, or spatial join will work. The fix is the same in all three tools: call a PLSS API once per row, expand the response, and keep going. Here is the workflow for each.
Power BI: convert PLSS to lat/long in Power Query
Power BI is where most production O&G dashboards live, and Power Query is the right place to do the conversion. Adding a custom column that calls the Township America Search API gives you a clean, refreshable column of latitude/longitude that travels with the rest of the model.
Start with a table that has your PLSS legal descriptions in one column:
well_id | legal_description |
|---|---|
| OK-00187 | T11N R8W Sec 14 NE¼, Indian Meridian |
| OK-00188 | T12N R8W Sec 22 SW¼, Indian Meridian |
| OK-00189 | T10N R7W Sec 6 NW¼NW¼, Indian Meridian |
Add a Power Query step that calls the API for each row. Read the key from a Power BI parameter named TA_API_KEY so it never lands in your .pbix:
let
apiKey = TA_API_KEY,
Source = #"Wells",
Geocoded = Table.AddColumn(Source, "geo", each
let
body = Json.FromValue([description = [legal_description]]),
response = Web.Contents(
"https://developer.townshipamerica.com/v1/search",
[
Headers = [
#"Content-Type" = "application/json",
#"x-api-key" = apiKey
],
Content = body
]
),
parsed = Json.Document(response),
point = parsed[features]{0}[geometry][coordinates]
in
[longitude = point{0}, latitude = point{1}]
),
Expanded = Table.ExpandRecordColumn(Geocoded, "geo", {"latitude", "longitude"})
in
Expanded
latitude and longitude land in two new numeric columns. Drop them straight onto the Map visual or use them as the spatial join key against any other geometry layer — lease boundaries, gathering pipelines, fault traces. Refresh runs Power Query again and re-geocodes any new rows.
For tables of more than a few hundred wells, swap the per-row pattern for the Batch API, which accepts up to 100 PLSS descriptions in a single POST. The same Power Query M language handles it — chunk the column into groups of 100, post each chunk, and append the results.
Excel: PLSS to lat/long with LAMBDA or Power Query
Excel gives you two paths. For a one-off workbook with a handful of legal descriptions, a LAMBDA in the Name Manager is the lightest option. Define it once, call it like a built-in function:
=PLSS_TO_LAT(legalDescription) =
LAMBDA(desc,
LET(
url, "https://developer.townshipamerica.com/v1/search",
body, "{""description"":""" & desc & """}",
response, WEBSERVICE(url & "?body=" & ENCODEURL(body) & "&key=" & TA_API_KEY),
coord, MID(response, FIND("[", response) + 1, FIND("]", response) - FIND("[", response) - 1),
VALUE(TRIM(MID(coord, FIND(",", coord) + 1, 20)))
)
)(legalDescription)
Define a matching PLSS_TO_LNG for longitude and you can write =PLSS_TO_LAT(B2) next to any PLSS cell. The same trick lets you build distance formulas — for example, kilometers from each well to a central gathering plant — without ever leaving the workbook.
For anything larger than a few dozen rows, use Power Query inside Excel. The M script above is identical to the Power BI version. Load it from Data → Get & Transform → From Other Sources → Blank Query, paste, and refresh. Excel writes the latitude/longitude back into a connected table so the geocoded rows update in place whenever the source PLSS column changes.
Watch the rate limits. Build-tier API keys allow one request per second; a 5,000-row workbook calling the Search API once per row will hit a 429 response inside a minute. Power Query handles this by buffering, but the cleaner answer is to route anything past 100 rows through the Batch endpoint.
Google Sheets: the PLSS converter add-on
Google Sheets needs no Power Query equivalent because the Township America PLSS Converter add-on installs from the Workspace Marketplace and registers two custom functions plus a column-mode sidebar.
The custom functions read like any other Sheets formula:
=PLSS_TO_LAT("T11N R8W Sec 14 NE¼, Indian Meridian")
=PLSS_TO_LNG(A2)
For the production dashboard pattern — converting an entire column of legal descriptions to lat/long pairs — open Extensions → Township America → Open Converter, set the input range (e.g. A2:A500) and the first output cell (B2), and click Convert Column. Latitude lands in B, longitude in C, errors in the cell next to whatever row could not be parsed.
Free accounts get 10 conversions per calendar month. Paste a Township America API key in Settings to remove the limit; the same key works in Power BI and Excel.
Scaling to a full Oklahoma well table
A SCOOP/STACK production dashboard typically pulls from a few thousand active wells across Grady, Stephens, Canadian, Kingfisher, and Blaine counties. Per-row Search API calls work for development, but a refreshable production model wants the Batch API.
The Batch API accepts up to 100 PLSS descriptions per request. A Build subscription is rated for 1,000 requests per month, which works out to up to 100,000 PLSS descriptions per month at full batch size — enough for a daily refresh of an STACK operator's full Anadarko Basin position with room to spare. Scale ($200/mo) and Enterprise ($1,000/mo) raise the monthly quota by 10× and 100× respectively, in case you are converting historical production data alongside the active well list.
The request body is a flat array of descriptions:
{
"descriptions": [
"T11N R8W Sec 14 NE¼, Indian Meridian",
"T12N R8W Sec 22 SW¼, Indian Meridian",
"T10N R7W Sec 6 NW¼NW¼, Indian Meridian"
]
}
The response is a GeoJSON FeatureCollection where each Feature.geometry.coordinates is a [longitude, latitude] pair in the same order as the input. Join it back to your well table on row index and you have a geocoded production model — ready for the Power BI map visual, the Excel 3D Map, or a Sheets GEO_DISTANCE calculation against the Cushing tank battery.
Worked example: an Oklahoma STACK production dashboard
Start with a CSV exported from a production accounting system. It has 1,400 rows — every active STACK well operated by a single company across Kingfisher and Blaine counties, with daily oil and gas volumes alongside a legal_description column. The goal is a Power BI dashboard with a county-level map, a production trend by section, and a distance-weighted average to the operator's central gathering facility at the Hennessey gas plant.
Build it in four steps:
- Load the CSV into Power Query.
- Add the geocoding step from the Power Query snippet above, pointed at the Batch endpoint with 100-row chunks. Total runtime on a Build-tier key: about 14 minutes for the full 1,400 rows, one chunk per 50 seconds with built-in backoff.
- Add a calculated column
distance_to_hennessey_kmusing the Haversine formula against the gathering plant's coordinates (36.1184, -97.8959). - Drop
latitudeandlongitudeonto a Map visual sliced by section and pipedistance_to_hennessey_kminto a stacked bar by quarter.
The same dashboard built without an API geocoder usually involves a hand-maintained township-range lookup table, a copy-paste workflow with a public PLSS converter web tool, or a vendor delivering coordinates back as a spreadsheet two days later. None of those refresh.
For one-off lookups against a known Indian Meridian township, use the Oklahoma PLSS converter directly. For everything that needs to live inside Power BI, Excel, or Sheets, the API is the join column you have been missing.
Pick the right tier
The Search API ($20/mo Build, $100/mo Scale, $500/mo Enterprise) covers single-record lookups. The Batch API ($40/mo Build, $200/mo Scale, $1,000/mo Enterprise) covers production data pipelines. Subscribe to either from the in-app developer portal — full quotas, code samples, and request logs are on the API documentation page.
Try the Search API — paste a SCOOP or STACK legal description, get back a GeoJSON Feature with the lat/long centroid, and drop the response into your Power Query, LAMBDA, or Sheets add-on workflow.