Revit to ETABS - cannot import shell elements into ETABS

Hi all,

I am getting started with Speckle and I’m very excited to see what can be done on this platform!

I have made a very basic Revit model (and applied the analytical model) to try and export it to ETABS to familiarize myself with the process. I have created some columns, walls and a floor/slab. When I try and receive the model in ETABS the columns are there but walls and floors are not.

I noticed that when sending the model from Revit I get some errors:

I’m not able to tell what kind of elements are failing to send, I assume the wall and floor elements.

Also, in my Revit model I have given the columns properties of a 450x450 square concrete column, however when ETABS receives these elements, they are imported with a default material property of a steel column.

My questions are:

  1. How come wall and floors are not able to be sent from Revit? Is there a certain property or setting I need to apply in Revit for this to work?

  2. Is applying default properties to column (or any other element) intended behaviour from Speckle? Or should properties translate between models? Also, if properties are not intended to be sent/received, is this something that can be solved with the Speckle API?

Would appreciate some help as I see huge potential benefit in this. Please let me know if there is any more info I need to provide.


Hey @ZStructural welcome to the community!

Feel free to Introduce yourself :person_gesturing_ok: if you’d like.

The ETABS connector is still in its early days, but we’re actively working to support and improve the Rvit<>ETABS workflow properly.

I believe walls and floors should be supported and we’ll investigate to see what’s up cc @connor . In the meantime, you should be able to receive them as meshes from ETABS’s Connector receive settings.

In regards to “mapping properties”, this is a bit more complicated. Which ones did you have in mind? What’s the workflow you’re trying to achieve?

1 Like

hey @ZStructural thanks for reaching out.

It looks like the elements that you are showing in the report are all of type “View3D”. Currently, you’ll get a few of those that try to convert but fail when you send everything, but it shouldn’t hurt anything. I would check what your commit looks like at and make sure it contains all the elements that you are interested in.

The important thing about importing 2D elements into ETABS is that they are analytical elements instead of the typical floors / walls. It sounds like you did send analytical elements though so I’m not sure why they are not showing up. Do you think you’d be able to provide the stream (or a portion of it that has the failing elements) so we can try to reproduce this issue on our end?

1 Like

Hi Connor, thanks for the response. I have just tried to add you to the stream.

I think everything is importing into ETABS just fine, I think the problem is exporting out of Revit. When importing into ETABS, the walls and slabs aren’t in the list of items imported at all.

Thanks teocomi! By mapping properties I meant in Revit if, for example I have a concrete column with a certain dimension, should that import into ETABS with a new section property of the same dimension? Or is the intention that it only imports the location/start/end of the column and then defining other properties is up to the user?

Hey @ZStructural - gotcha, thanks for the clarification!
Mapping properties is not yet supported in the Revit > Etabs workflow, but we have a basic implementation going on when doing Tekla>Revit (and ETABS>Revit I belive).

We’ll investigate a bit more your issue and let you know!

Thanks. I haven’t delved too deep into the Speckle API, but my understanding is you can create Speckle objects, so in theory would it be possible to just create my own object that sends from Revit with its own properties, that I can translate into ETABS section properties with some Python code?

Yes, you could totally do that too :slight_smile:
From the viewer you can easily explore elements as see what properties are being sent from Revit, if anything is missing we’d be happy to include it in.

Hi @teocomi

I have been playing around with the Python SDK, its making sense but the one thing I cant figure out is how to just grab all the levels with names and elevations. Is that possible? I can see it in the Speckle viewer in my browser but not from the transport.

Hey @ZStructural ,

Could you share a sample stream? It should be just a matter of iterating through the elements and their properties…

Hi @teocomi ,

I have figured it out by iterating through Revit categories. Not sure if that’s the most efficient way.

Could I give a few suggestions for the ETABS connector? I am based in Australia and work on mostly concrete buildings with irregular floor plans and column/wall layouts. I assume other parts of the world would be the same, but please let me know and I can give some comments on what would be extremely useful for us here. I could provide my stream and code if you would like as well, as an example of what I would need the end product (Revit to ETABS) to look like.

Hey @ZStructural absolutely, any suggestion and feedback are welcome - we’re actually currently investigating how to improve our structural connector workflows and your input would be great!
@Pavol will reach out to schedule a quick call/exchange :slight_smile:

Hey @ZStructural, a bit more on the Python retrieval of the Levels data. The GraphQL API is your friend here. In the context of Speckle, you can retrieve exactly the data you need in a single request, reducing the amount of data transferred over the network and speeding up your application.

Here, we can add a GQL client directly:

from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport

Before we proceed, let’s initialize some variables. The commit_referenced_object is an identifier for the specific data set you’re interested in, which you would have obtained when you retrieved the commit object. The HOST_SERVER is the URL of the Speckle server from which you are querying data. Make sure both of these variables are set before running the code.

commit_referenced_object = commit.referencedObject

gql_client = Client(
    transport=RequestsHTTPTransport( url=f"{HOST_SERVER}/graphql" )

The GraphQL query is designed to fetch specific data from the server. Here, we are interested in a stream identified by stream_id , and within that, an object identified by commit_referenced_object . The limit: 1000 specifies that we want to retrieve a maximum of 1000 records. The select array outlines the data fields we want to fetch: the level names and their elevations. 100 used is arbitrarily large, the default is lower than this, which means you may not capture all the levels as you haven’t parsed all the commit objects.

query = gql(
    query Commit( $stream_id: String!, $commit_referenced_object: String! ) { 
        stream(id: $stream_id) { 
            object(id: $commit_referenced_object) {
                children( limit:1000, 
                    select: [
                ) { objects { data } } } } } """

params = {
    "stream_id": stream_id, 
    "commit_referenced_object": commit_referenced_object

Once the query and parameters are set, the gql_client.execute() function sends the query to the server and fetches the data. The received data is stored in the received_data variable for further processing.

received_data = gql_client.execute(query, variable_values=params)

Now if you inspect received_data, you’ll see something like:

  "stream": {
    "object": {
      "children": {
        "objects": [
            "data": {
              "level": {
                "name": "Foundation",
                "parameters": {
                  "LEVEL_ELEV": {
                    "value": -1200
              "id": "00413ddd05759bd08a6c8123ca85bd5f"
          # ... snipped for all objects

Which is the response from the server that matches the query made. The payload and transaction is much quicker and smaller than getting all the data.

While the query parameter on the children could work to limit the Revit types queried, the Levels are not available as they are a property of the filtered objects. You may notice that the levels might appear multiple times in the data retrieved. This happens because different objects can reference the same level. Duplicate levels can make understanding the structure difficult, so we’ll filter them out in the next step.

A simple Pythonic job to clear that up:

# Initialize an empty set to store unique levels
unique_levels = set()

# Navigate through the nested structure to extract level names and elevations
if (received_data and 'stream' in received_data and 
        'object' in received_data['stream']):
    objects = received_data['stream']['object']\
        .get('children', {}).get('objects', [])
    for obj in objects:
        level_data = obj.get('data', {}).get('level', {})
        name = level_data.get('name', 'Unknown')
        elevation = level_data.get('parameters', {})\
            .get('LEVEL_ELEV', {}).get('value', 'Unknown')
        unique_levels.add((name, elevation))

Sorting the levels by elevation can provide a more transparent, more intuitive view of the building structure. This sorted list can be more easily interpreted and valuable for downstream applications or analyses.

sorted_unique_levels = sorted(list(unique_levels), key=lambda x: x[1])

Using this GraphQL query significantly reduces the amount of data you need to fetch from the server. This speeds up the data retrieval process and minimizes the load on both the client and server, making the operation more efficient and cost-effective.