Skip to content
PyPath

Learning Python for Revit: where do you start?

An honest step-by-step plan, from your first line of Python to your own pyRevit button. With real example code and the mistakes almost everyone makes.

7 min readUpdated October 10, 2026Checked against the Revit API 2025 documentation

Short answer: start with plain Python, not with Revit. First learn variables, lists, loops, conditions, dictionaries and functions. Then learn how a Revit model is structured (elements, categories, parameters) and write a first pyRevit button that only reads something. Once that works, move on to changing the model inside a transaction. At ten minutes a day you can be writing your own tools in about twelve weeks.

Why Python for Revit?

Revit has an extensive programming interface: the Revit API. With it you can do in code everything you do with the mouse, and above all: a thousand times in a row without mistakes. Counting elements, filling in parameters in bulk, checking a model, exporting schedules. Exactly the boring work that costs hours today.

There are three common ways to use that API:

  • C# and Visual Studio: the way to build full add-ins. Powerful, but you have to compile, and the learning curve is steep.
  • Dynamo: visual programming with nodes. Handy for geometry, but larger logic quickly gets messy. Dynamo also has Python nodes.
  • pyRevit: a free add-in that turns Python scripts into buttons on the Revit ribbon. Save the script, press the button, done. No compiling.

If you want to learn automation yourself, Python with pyRevit is the shortest path from idea to working button. And what you learn carries over to Dynamo.

References worth keeping at hand: the pyRevit documentation and the searchable Revit API documentation at revitapidocs.com.

What do you need?

To learn you need almost nothing: no programming experience and no expensive software. To run your scripts for real later on, you need:

  • Revit on a Windows PC;
  • pyRevit, the free open-source add-in;
  • a code editor, for example Visual Studio Code;
  • and ideally RevitLookup, a free add-in that shows all properties and parameters of the element you click.

Step 1: learn plain Python first

The biggest mistake is starting with the Revit API straight away. Then you are fighting two things at once: the language and the model. So learn the Python basics first, in this order:

  1. variables, numbers and text (strings);
  2. lists and for loops;
  3. decisions with if, elif and else;
  4. dictionaries, to count and group things;
  5. functions, and later classes and modules.

Dictionaries in particular are worth their weight in gold. This is the pattern you will use in Revit over and over: adding up per group.

practice.py
pipes = [
    {"system": "Heating supply", "length": 6.0},
    {"system": "Heating return", "length": 6.0},
    {"system": "Heating supply", "length": 4.5},
]

per_system = {}
for pipe in pipes:
    name = pipe["system"]
    per_system[name] = per_system.get(name, 0) + pipe["length"]

print(per_system)
Output
{'Heating supply': 10.5, 'Heating return': 6.0}

Later the pipes will not come from a list, but from your Revit model. Everything else stays the same.

What you can skip at first: web frameworks, data science, and well-known libraries such as pandas and NumPy. Those do not work in pyRevit's default engine anyway.

Step 2: understand how a Revit model is structured

Before you write code for Revit, it helps to see the model the way the API sees it:

  • Everything is an element. A wall, a pipe, a door, a view: all of them are an Element with its own ElementId.
  • Elements belong to a category, such as walls, doors or pipes. In code: BuiltInCategory.OST_Walls, OST_Doors or OST_PipeCurves.
  • Types and instances are different things. A wall type is not the wall you draw. That is why you often see WhereElementIsNotElementType(): only the actual instances.
  • Parameters hold the data: length, mark, comments, system name. You read them with get_Parameter(...) or LookupParameter("name").
  • Revit works in feet internally. A length of 1 means 304.8 mm. Convert with UnitUtils.ConvertFromInternalUnits.

Step 3: your first pyRevit button

A pyRevit button is simply a folder with a script.py in it. The folder names decide where the button appears on the ribbon:

folders
MyTools.extension/
  MyTools.tab/
    Count.panel/
      CountDoors.pushbutton/
        script.py

Add the MyTools.extension folder in the pyRevit settings (under the folders for custom extensions) and choose Reload. Your button is now on the ribbon; the full walkthrough is in pyRevit tutorial: your first button. Start with a script that only reads:

CountDoors.pushbutton/script.py
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory

doc = __revit__.ActiveUIDocument.Document

doors = (FilteredElementCollector(doc)
         .OfCategory(BuiltInCategory.OST_Doors)
         .WhereElementIsNotElementType()
         .ToElements())

print("Number of doors: {}".format(len(doors)))

Press the button and pyRevit opens a window with the output of print(). Reading can never break anything, so this is the place to experiment freely. Everything about finding elements is in the FilteredElementCollector explained.

Step 4: change something with a transaction

As soon as you want to change something in the model, it has to happen inside a transaction. That is also your safety net: if something goes wrong halfway, Revit rolls everything back. With pyRevit's helper module it looks like this:

MarkPipes.pushbutton/script.py
from pyrevit import revit, DB

pipes = (DB.FilteredElementCollector(revit.doc)
         .OfCategory(DB.BuiltInCategory.OST_PipeCurves)
         .WhereElementIsNotElementType())

with revit.Transaction("Mark pipes"):
    for pipe in pipes:
        comment = pipe.get_Parameter(
            DB.BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS)
        comment.Set("Checked")

Leave out the with line and Revit stops with the message Attempt to modify the model outside of transaction. You will definitely see that one at some point; here is how to fix it. More on reading and writing is in Read and set Revit parameters.

Step 5: bundle it into your own library

After a few buttons you notice you keep writing the same bits of code. Put them in your own module in the lib folder of your extension. pyRevit automatically makes that folder available to all your buttons.

MyTools.extension/lib/mylib.py
from Autodesk.Revit.DB import FilteredElementCollector, UnitUtils, UnitTypeId


def elements(doc, category):
    """All instances (no types) of one category."""
    return (FilteredElementCollector(doc)
            .OfCategory(category)
            .WhereElementIsNotElementType()
            .ToElements())


def to_mm(value):
    """Revit works in feet internally; this returns millimetres."""
    return UnitUtils.ConvertFromInternalUnits(value, UnitTypeId.Millimeters)

In every button you then simply write from mylib import elements, to_mm. That is the start of your own library, and the moment you really start saving time.

Six mistakes almost everyone makes

  1. Changing the model outside a transaction. Every change belongs in a transaction; otherwise you get the error from step 4.
  2. Forgetting that Revit works in feet. A diameter of 0.164 is not a bug, it is roughly 50 mm.
  3. Mixing up types and instances. Without WhereElementIsNotElementType() you count the types as well.
  4. Looking up parameters by name in a localised Revit. LookupParameter("Length") searches for the name you see in Revit, which differs per language. For built-in parameters, get_Parameter(BuiltInParameter...) is more reliable.
  5. f-strings in the default engine. pyRevit uses IronPython 2.7 by default, which has no f-strings. Use "{}".format(value), or choose the Python 3 engine with #! python3 on the first line.
  6. Testing straight away in a live project. Always try a new script on a copy of your model first.

A realistic learning plan

You do not need to free up whole evenings. Short daily sessions work better than one long session a week, because you see the material more often. A plan that works:

  • Month 1, Python basics: variables, lists, loops, conditions and dictionaries.
  • Month 2, intermediate: functions, classes, modules, handling errors and files.
  • Month 3, towards Revit: pyRevit, collecting elements, changing parameters and your own library.

With ten minutes a day, and a quick daily review of what you did before, that takes you from your first line of code to your first own tool in twelve weeks.