A self-updating data dictionary for ArcGIS Online
Every GIS team is asked for a data dictionary, and almost none have a current one. What are all our hosted services? Which fields, which coded-value domains, how many records, what spatial reference? The honest answer is usually “let me click through forty item pages.” You can generate the whole thing in one run instead — a multi-sheet Excel inventory of your entire ArcGIS Online account — with the ArcGIS API for Python.
Watch: build the data dictionary and the toolbox tool (5:13)
Here’s how the crawl works, the part everyone gets wrong (domains), and the one design choice that makes the logic testable without a portal at all — plus a free notebook and Pro tool that produce the workbook.
Crawl the account, not the item pages
The ArcGIS API for Python gives you the whole account through your active sign-in. Walk the root plus every folder, keep the feature services, de-dup by item id — no credentials in code, just the session you’re already in:
from arcgis.gis import GIS gis = GIS("home") # active ArcGIS sign-in (or GIS("pro") in a Pro notebook) me = gis.users.me services = {} for folder in [None] + me.folders: # root + each folder for item in me.items(folder=folder): if item.type in ("Feature Service", "Feature Layer"): services[item.id] = item # de-dup by item id
That covers the “everything I own” case. The tool also takes a single item id or service URL to
pinpoint one service (a URL resolves to its item via the layer collection’s
serviceItemId), or a search-text scope that runs
gis.content.search('title:"<text>" owner:me', item_type="Feature *"). Same crawl,
four ways in.
The part everyone gets wrong: domains
A field’s domain is the most useful thing in a data dictionary and the most commonly dropped. There are two kinds and they have different shapes — flatten both, or your dictionary is lying by omission:
def domain_text(field): d = field.get("domain") if not d: return "" if d.get("codedValues"): # coded-value domain return "; ".join(f'{c["code"]}={c["name"]}' for c in d["codedValues"]) if "range" in d: # range domain lo, hi = d["range"] return f"min={lo}, max={hi}" return ""
Coded-value domains become readable code=label pairs; range domains become
min/max. Now “status field, 1=Active, 2=Retired” actually appears in
the dictionary instead of a bare integer column nobody can interpret
(attribute domains overview).
One accessor that makes it all testable
The ArcGIS API hands you layer metadata as a PropertyMap (attribute access),
but a plain JSON fixture is a dict (key access). Route every read through one tiny
tolerant accessor and the entire describe / serialize / write path runs against ordinary dicts — which
means you can unit-test it with no portal connection at all:
def g(obj, key, default=None): # tolerate both a dict (fixture) and an arcgis PropertyMap (live) if isinstance(obj, dict): return obj.get(key, default) return getattr(obj, key, default)
That one helper is the difference between “works on my machine against the live org” and a function you can actually test in CI with synthetic coded- and range-domain fixtures.
The output: three sheets that read like a dictionary
For each service the tool reads every layer and table’s properties, optionally fires one
return_count_only query per layer for record counts, and pulls the spatial
reference. It writes a multi-sheet workbook with auto-sized columns:
| Sheet | One row per… | Carries |
|---|---|---|
| Services | item | title, id, owner, type, URL, item metadata |
| Layers | layer / table | name, geometry type, record count, spatial reference |
| Fields | field | name, alias, type, length, nullable, and the flattened domain |
Counting is one query per layer, so it’s the slow part — turn it off for a fast
metadata-only pass on large services, and counts that fail degrade to n/a rather
than crashing the run.
Grab the tool — free
Same logic, two ways to run it. The notebook has a single
CONFIG cell — choose scope and output, Run All. The
Pro tool is the geoprocessing-dialog version — drop the
.pyt in a toolbox, no code. Both authenticate with your active ArcGIS sign-in;
neither stores a credential.
MIT-licensed. Needs the ArcGIS API for Python (ships with Pro); the XLSX writer uses openpyxl (CSV / TXT are dependency-free). The .zip contains the toolbox and its ArcGIS Pro documentation.
| Tool parameter | Notebook variable | What it controls | Default |
|---|---|---|---|
| Scope | SCOPE | Entire account / selected folders / single service / search | Entire account |
| Folders | FOLDERS | Folder titles to walk when scope = folders | [] |
| Item ID or service URL | ID_OR_URL | Pinpoint one service | — |
| Search text | SEARCH_TEXT | Title phrase, scoped to your items | — |
| Output folder | OUTPUT_DIR | Where the output files are written | required |
| Output format | OUTPUT_FORMAT | XLSX (one workbook, three sheets) / CSV (the fields table as one flat file) / TXT (an indented report) | XLSX |
| Count records | COUNT_RECORDS | One count query per layer (slow on big services) | true |
| Max services | MAX_ITEMS | Safety cap | 500 |
Keep it current: schedule it in ArcGIS Online
The same dictionary can run by itself every week. The scheduled version runs as an ArcGIS Online notebook task and overwrites one Microsoft Excel item, so the item ID and its link never change. The video below walks through every step.
Watch: schedule the notebook in ArcGIS Online (6:59)
- Upload the notebook: in ArcGIS Online open Content, choose New item, drop the .ipynb file in and save it to a folder. Open it in the notebook editor.
- Read the settings cell.
SCOPEpicks what to describe: the entire account, chosen folders, one service or a title search.OUTPUT_ITEM_IDstarts blank.OUTPUT_DIRis a full path under/arcgis/home, because a scheduled run has nobody at the keyboard and Esri's guidance is to use full paths. - Check the tags (command palette > Edit Notebook Metadata). The settings cell is tagged
parameters; the empty cell below it is taggedinjected-parameters. When a task runs, ArcGIS Online puts the task's values into that cell, so they override the defaults: one notebook, many schedules, no code changes. - First run by hand: set the scope, then Run > Run All Cells. The notebook adds the workbook as a new Excel item and prints its item ID. Copy it.
- Create the task: Tasks on the ribbon > Create task. Add parameters as key and value:
OUTPUT_ITEM_ID= the ID from the first run,SCOPE=folders,FOLDERS= your folder name. Values typed here can arrive as text, so the notebook converts them before it uses them. - Schedule it: repeat type Week and the days you want, with a start time. Start times are approximate and follow your browser's time zone.
- Advanced: lower the maximum run time (it defaults to 1425 minutes) to 15, turn Use workspace on so the workbook is kept between steps, and leave Update notebook on completion off.
Each run gets a status: Succeeded, Executing, Failed or Skipped (Skipped means the run before it was still going). Results opens the notebook exactly as it ran. Pause keeps the run history; Delete removes the task and its history; deleting the notebook also deletes its tasks.
Why Update notebook on completion stays off: In our testing, a run with it on saved itself back into the notebook and the empty tagged cell disappeared, so the next task run had nowhere to put its values.
Credits and limits, at the time of writing
As of October 2026, Esri's Understand credits page lists scheduled notebook tasks at 1.5 credits per hour on the Standard runtime, calculated per minute, and notes that with credit budgeting enabled these tasks need a 30-credit minimum balance. In our own account, three short scheduled runs were billed as 3.00 minutes (0.08 credits), so each run counted as a whole minute. At that rate a half-minute weekly run is about 0.025 credits a run, or roughly 1.3 credits a year. Rates change, so check Esri's page for the current figures.
Per Esri's Schedule a notebook task page (October 2026), each person can have 10 active tasks and an organization 50, and ArcGIS Online stops a task that fails five times.
References
- ArcGIS API for Python — Esri Developer documentation
- Accessing and managing content — ArcGIS API for Python
- An overview of attribute domains — ArcGIS Pro
- Understand credits (notebook task rates) — ArcGIS Online
- Schedule a notebook task — ArcGIS Online
- Using the GIS — ArcGIS API for Python
- Scheduled mode for ArcGIS Notebooks in ArcGIS Online is here — ArcGIS Blog
- The ArcGIS Notebooks beta in ArcGIS Online comes to a close (2020; interactive-notebook rates of that time) — ArcGIS Blog
Need your ArcGIS data documented — and kept that way?
We build the inventory and the automation that keeps it current — data dictionaries, service audits, and governance reporting across your whole ArcGIS Online account. Stop clicking through item pages.
Book a free intro call