Five levels of automation. Most people skip straight to the hardest one and regret it.
The decision rule
| Reach for | When |
|---|---|
| Schedule export | Somebody wants numbers out of the model. This is genuinely most requests. |
| Dynamo | One-off bulk data work, Excel round-trips, generative geometry. Ships in the box. |
| pyRevit | A repeatable tool for you or your team. Real code, no compile, hot reload, ribbon button in minutes. |
| Compiled add-in (C#) | It must ship, be versioned, have real UI, integrate external services, or perform at scale. |
| Cloud APIs (APS / AEC Data Model) | The data needs to be available without a Revit session — dashboards, web apps, pipelines. |
The failure mode is skipping the first two rows. A 200-line C# add-in to fix parameter values on 40 elements is a bad trade.
Schedule export
File → Export → Reports → Schedule writes a delimited text file. Crude and effective.
Also: ODBC export for a full relational dump, and File → Export → Reports → Room/Area for area documentation.
Before you write any code, ask whether a schedule solves it. See schedules — filters, calculated values, and key schedules cover more ground than people expect, and a schedule is bidirectional, so bulk data entry is often faster in a schedule than in a script.
Dynamo
Visual programming, bundled with Revit. Manage → Dynamo.
What it's genuinely good at
- Excel round-trips.
Data.ImportExcel→ set parameters. This is why most people open Dynamo. - Bulk parameter operations across categories where a schedule can't reach.
- Generative geometry — panelized façades, structural framing patterns, anything where the geometry follows a rule.
- One-off cleanups you'll throw away afterwards.
What it's bad at
- Anything you need to maintain. Graphs are hard to diff, review, and reason about after a month.
- Anything with real error handling or user interaction.
- Performance at scale.
- Being distributed to a team reliably.
The five things to learn first
- Run mode: switch to Manual immediately. Automatic re-runs on every edit, which on a real model means modifying the document while you're still building the graph.
Categories→All Elements of Category— your query. ThenElement.GetParameterValueByName/Element.SetParameterByName.- Lacing — shortest / longest / cross product. Controls how two input lists pair up. Right-click a node to set it.
- List levels — the
@L2controls on a node's input ports. Controls which nesting depth the node operates on. - The
Python Scriptnode — the escape hatch when the visual graph gets silly. Same API, and you choose IronPython or CPython.
Lacing and list levels are the entire source of "why did I get one result instead of fifty". Learn them before anything else.
Dynamo Player
Manage → Dynamo Player runs a saved graph with exposed inputs, without opening Dynamo.
This is how you hand a graph to a colleague who shouldn't be editing it. Mark inputs and
outputs with Is Input / Is Output on the nodes.
Packages
Packages → Search for a Package. The ecosystem is genuinely useful:
- Clockwork — general-purpose Revit utilities, the most-used package.
- archi-lab — a large grab bag, especially for documentation tasks.
- Rhythm — quality-of-life Revit nodes.
- Data-Shapes — build real input UI for Dynamo Player graphs.
- BimorphNodes — geometry and MEP-focused, good clash/intersection nodes.
- Genius Loci — a broad collection with excellent coverage of niche Revit APIs.
Version caution: once a package migrates to .NET 8 for Dynamo 3.x, it stops loading in older Dynamo. Check the package's stated compatibility against your Revit release.
pyRevit
Free, open source, and the pragmatic middle ground. It gives you:
- A scripting environment with hot reload — edit
script.py, click the button, done. No compile, no Revit restart. - A large library of ready-made tools that are worth having even if you never write a line yourself.
- A fast way to publish your own buttons to the ribbon.
- An interactive console for poking at the model live, which is the best way to learn the API.
Extension structure
The folder layout is the ribbon:
MyExtension.extension/
RB.tab/
Tools.panel/
Renumber.pushbutton/
script.py
icon.png
Audit.pulldown/
Warnings.pushbutton/
script.py
Orphans.pushbutton/
script.pyRegister the extension folder in pyRevit's settings and the ribbon builds itself. Naming
conventions do all the work — .tab, .panel, .pushbutton, .pulldown, .stack,
.smartbutton.
Script metadata goes in the file itself:
"""Renumber selected doors sequentially in selection order."""
__title__ = "Renumber\nDoors"
__author__ = "Zach"The docstring becomes the tooltip.
The ergonomics worth knowing
from pyrevit import revit, DB, UI, forms, script
doc = revit.doc # active Document
uidoc = revit.uidoc # active UIDocument
selection = revit.get_selection() # wrapped, iterable, settable
out = script.get_output() # rich HTML output window
out.print_md("## Heading")
out.print_table(data, columns=["A", "B"])
out.linkify(element.Id) # a clickable element link in the output!
forms.alert("message")
forms.ask_for_string(default="101", prompt="Number:")
forms.SelectFromList.show(items, multiselect=True)
with revit.Transaction("My change"): # commits on success, rolls back on error
...out.linkify() is worth calling out — it prints a link in the output window that selects
and zooms to the element. For any audit script, that turns a list of Element IDs into
something someone will actually use.
Also in this family
- RevitPythonShell — a lighter interactive shell, the original of the genre.
- RevitLookup — not scripting, but essential: a database explorer that shows you every property and parameter of a selected element. Install it before you write your first script. You cannot navigate the API efficiently without it.
Compiled add-ins
C# (or VB/F#) against RevitAPI.dll and RevitAPIUI.dll. See the
API primer.
Reach for this when:
- It needs to be versioned and distributed — an installer, an internal package feed.
- It needs real UI — a dockable panel, WPF windows, a settings dialog.
- It needs to integrate external services — a database, a web API, an auth flow.
- It needs to perform on a large model, or run on application events (document opened, element changed, sync completed).
- It needs to run headless via Design Automation.
Set expectations: the tooling overhead is real. A .csproj multi-targeting several Revit
versions, a .addin manifest per version, and a debug loop that involves restarting Revit
unless you use an add-in hot-reload shim.
Worth knowing:
- Nuget
Autodesk.Revit.SDKgives you version-pinned reference assemblies without installing every Revit release. IExternalApplicationfor startup/shutdown hooks and building ribbon UI;IExternalCommandfor a single button.IUpdaterfor reacting to model changes — powerful and easy to misuse; it runs inside other people's transactions.- Design Automation for Revit (part of Autodesk Platform Services) runs add-ins server-side with no Revit UI. This is how you build a service that processes models.
Cloud APIs
When the data needs to live outside Revit entirely:
- Autodesk Platform Services (APS) — the umbrella for Data Management, Model Derivative (translate models to a viewable/queryable form), the Viewer, and Design Automation.
- AEC Data Model API — GraphQL access to Revit model data hosted in ACC, without a Revit session. Query elements and parameters from a web app. Still maturing but this is the strategic direction for model data.
- ACC APIs — issues, RFIs, submittals, files.
Use these when the consumer is a dashboard, a web app, or a pipeline — not when the consumer is a person sitting in Revit.
On the Revit 2027 AI Assistant and MCP
Revit 2027 shipped a built-in AI assistant as a tech preview, described as an agentic assistant that can answer product questions, query the model, and automate tasks through prompts. It includes an MCP client, and Autodesk has stated an intent to support both local and cloud MCP servers.
The Revit MCP server — the thing that would let an external agent drive Revit — is announced rather than shipped. Treat it as a direction, not a platform to build on today. There are community MCP servers for Revit built on top of the regular API; they work the way any add-in works, with all the same single-threaded, transaction-bound constraints.
The stable surfaces remain the desktop API, the export formats, and the cloud APIs.