Looking for experienced SketchUp Ruby developer for lightweight data-extractor extension

Hi everyone,

I’m new here — hello to the SketchUp developer community.

I’m looking for an experienced SketchUp Ruby extension developer for a small paid task, and I would also appreciate general guidance from people who know the SketchUp plugin ecosystem well.

My background is in architecture / interiors / renovation. I’m working on a broader project that helps design software send structured project/model data into an external coordination system, so project information can continue into cost, time, procurement, approvals, and project memory instead of staying trapped inside separate design files.

For SketchUp, the first version is intentionally lightweight.

V1 goal:
Build a SketchUp Ruby extension that reads useful model data and sends structured JSON to an HTTPS endpoint.

Rough V1 scope:

  • installable .rbz extension
  • Windows + Mac support if practical
  • run on manual save / save trigger
  • recursively traverse groups and component instances
  • preserve parent/child hierarchy
  • include persistent IDs where available
  • extract object names
  • extract tags/layers
  • extract object type
  • extract bounding box / dimensions
  • extract existing attribute dictionaries / metadata where available
  • separate component definition data from placed component instance data where practical
  • POST structured JSON to an HTTPS endpoint
  • save a local JSON/log file if POST fails
  • include sample JSON output and basic install/config instructions

For V1, I do not need live sync, writeback, model editing, or a complex UI.

Later, there may be a V2 with bidirectional features, such as:

  • writing project IDs/status back into SketchUp attribute dictionaries
  • detecting meaningful changes after an object is linked
  • selecting/highlighting objects from backend-provided IDs
  • sending selected object information back to the backend
  • placing components from a library file with metadata attached

I am trying to be careful not to build V1 in a way that blocks V2 later.

If you are an experienced SketchUp Ruby extension developer and this sounds like something you can help with, please reply or message me.

I would also appreciate advice from the community on:

  1. whether this should be built purely as a SketchUp Ruby extension
  2. any important limitations around persistent_id, entityID, attribute dictionaries, or save observers
  3. what a good V1 architecture should include so V2 does not require a rewrite
  4. where experienced SketchUp Ruby developers usually look for this kind of paid work

Thank you — I appreciate any guidance.

I would first advise do not “recreate the wheel” if it exists. Check first if what you need is already exported by SketchUp with it’s IFC or DAE exporters (or the glTF export extensions.)


Re (2), you should not use entityID as they are not persistent between sessions.

Re (3) and “writing project IDs/status back into SketchUp attribute dictionaries”. If the save is triggered by an observer callback, it is unwise to attempt changing the model data during most observer callback operations. Worse, could be a crash, most likely a vicious loop of observer callbacks firing.

Re “POST structured JSON to an HTTPS endpoint”, … Keep in mind that the API web interface is asynchronous, which might cause issues if done during a save operation. The data collection and JSON building could happen synchronously during the onPostSaveModel callback and then sent transparently and asynchronously afterward.

Hi Dan,

Thank you — this is exactly the kind of guidance I was hoping for from the community. Very helpful.

On your suggestion about IFC or DAE exporters — I should clarify what we are actually trying to do, because it is slightly different from a standard export.

The goal is not to export geometry or BIM data for viewing or exchange. The goal is for SketchUp objects to continue existing as governed entities outside the model — with persistent identity, state, and workflow memory — and eventually for that identity to travel back into SketchUp too.

So the element does not get exported and forgotten. It travels — first one way, later both ways.

That is why standard exporters do not solve this. We need the plugin to understand which object is which across sessions, carry that identity into an external system, and later receive governed identity back into the model’s attribute dictionaries.

Your points on entityID and observer callbacks are very important and directly relevant to our architecture. Specifically:

On persistent IDs — we had already suspected entityID was session-only. Based on your advice, our approach will be to generate a stable UUID on first encounter and store it in the object’s attribute dictionary, then read it back on all subsequent extractions. Does that sound like the right approach to you?

On writeback during save callbacks — we have decided that V1 writeback will be manual-trigger only, not automatic during save. A simple menu command the user runs when they want to apply confirmed identities from the external system back into the model. This avoids the callback mutation risk entirely. V2 can explore a deferred queue approach.

On the async POST — the pattern you described is exactly what we planned: collect and build JSON synchronously during onPostSaveModel, then POST asynchronously afterward using the native SketchUp HTTP API.

One thing I should mention that is specific to our use case: one of the V2 requirements is writing governed visible names back into SketchUp object names and attribute dictionaries after the user confirms an identity in the external system. Given the callback constraints you described, does the manual-trigger approach sound safe for this? Or are there other SketchUp-side constraints on renaming objects and writing attributes outside of a save callback context?

If you are open to it, I would love to know whether this is something you would consider taking on as a paid build, or whether you can point me toward someone in the community who would be the right fit.

Thank you again for taking the time.

Brian Sia

No. Use the persistent_id property.

But keep in mind that some geometric operation are destructive and destroy and recreate entity objects which cause loss of attribute dictionaries and a new persistent id being assigned. The Boolean operations are some that do this.

Manual can work. But changes can trigger observer change callbacks (in other extensions.)

What you do not want is your saves triggering changes which trigger saves which trigger changes which trigger saves, … etc.

There also perhaps should be some guard against triggering updates when the user is shutting down and is prompted by SketchUp to save first.

Hi Dan,

Thank you again — your second reply is very helpful, and the points about manual writeback triggering other extension callbacks and the shutdown save guard are exactly the kind of edge cases I would not have thought to ask about.

Based on your guidance so far, our current architecture plan for the plugin is:

  • Stable ID: generate UUID using SecureRandom.uuid on first encounter, store in attribute dictionary under a registered key, read back on all subsequent extractions — never use entityID

  • Extraction: collect synchronously during onPostSaveModel, POST asynchronously afterward using Sketchup::Http::Request

  • Writeback: manual menu command only, never in any observer callback, with a re-entrance lock flag to prevent cascade

  • Shutdown guard: detect shutdown/closing state before writeback triggers

Before we find the right developer to build this, I have a few more questions if you are open to it — purely to brief the developer properly and avoid surprises:

  1. For UUID generation inside a SketchUp Ruby extension — is SecureRandom.uuid the right approach, or is there a more standard pattern used in the community?

  2. When a component instance is copied and pasted, does the copy inherit the instance’s attribute dictionary, the component definition’s attribute dictionary, or both? We need to know whether our stable UUID stored in the instance dictionary would be duplicated on copy-paste, and how best to detect and handle that.

  3. For detecting closed room boundaries in a typical architectural SketchUp model — what is the most reliable approach? Face loops, group naming conventions, tag/layer names, or something else?

  4. For the shutdown state guard — is there a reliable Ruby API call or flag to detect that SketchUp is in a closing sequence before our writeback runs?

  5. For the observer cascade risk on manual writeback — is there a recommended community pattern for preventing our attribute dictionary writes from triggering callbacks in other installed extensions?

I know you are not looking to take on the build, and I completely respect that. Your community contributions have already saved us from several significant architectural mistakes. If you happen to know a SketchUp Ruby developer who would be a good fit for this kind of project — someone who thinks carefully about extension architecture rather than just getting something working — I would genuinely value an introduction.

Thank you again for your time.

Brian Sia

Without knowing exactly where you are moving data between , some of the things may already be handled by existing software.

Where are you wanting to traverse model data to and from?

I’m not mainly looking for a geometry export format. I’m trying to preserve object identity and naming/context signals.

The external system is not another design/modeling tool. It is a project coordination layer that needs structured object signals from SketchUp.

Have a look at https://speckle.systems

that system is preserving model data as part of an intermediate server system (either hosted locally or online)

Everything is then a accessible from this via web interfaces (ala GitHub) and via API

They have plugins for a number of DCCs and BIM systems.

I’ve only dabbled with it in the past , but I think it may be an entry point into some of the things you are trying to achieve.

I have already said no. Why introduce the use of this when SketchUp entity subclass objects already have a persistent ID built in?

In addition, the SketchUp API has ModelObserver#onPidChanged which can help keep the data hash PID sync’d for entities that get changed in such a way that their PID is regenerated.

Also, SecureRandom.uuid has been known to have a strange delay the first time it is used in a session. [Not sure if this was ever resolved.] This also requires that external Ruby libraries be loaded (SecureRandom which loads Random::Formatter.)

So a “run of the mill” component instance (and likely as a group which are just “special” component instances,) the copy inherits the source instance’s attribute dictionaries with values from the copied instance.

This can be changed via observer such as DefinitionObserver#onComponentInstanceAdded to modify the standard behavior.

For example, Dynamic Components is an extension that uses this mechanism to modify instance attributes and use default attribute values that are actually stored in the definition’s "dynamic_attributes" attribute dictionary.
It also means that it is probable that any Dynamic or Live Component Instances will require extra diligence in data handling.

Your extension would likely also use this callback to make changes to your attribute dictionary for the copy’s values, post copy.

Very complex. There is no “pre-canned” method or standard. Yet.

There is a Labs feature in public Beta that you can try. (I have not yet done so.)
I am also unsure if it adds anything to the Ruby Objectspace that other extensions can leverage.

This would hopefully be AppObserver#onQuit, but this callback has been bugged. Even though API Release Notes claim it was fixed for Mac platform in 2014, there have still been issues with it, mostly concerning coordination with UI::HtmlDialog processes.

It all depends upon what order the various observer callbacks are called during a shutdown. I would suspect that AppObserver#onQuit would perhaps be last in the queue after the ModelObserver save callbacks.

It would take some testing, as the danger might be that SketchUp closes before updated data can be sent to the cloud server, because the web interfaces are asynchronous.

NO. Each extension code is separate. We cannot prevent other extensions’ observers from doing their things. However, risk is minimal for attribute dictionary objects. Read on …

Each extension should fully qualify it’s attribute dictionary name(s) so their is no clashing. I.e., don’t use a simple generic name like “Properties”. I always suggest using the module nesting as a dictionary name prefix which should end up being unique if you chose a unique top-level company module name anyway.

So in most cases other extensions will not be specifically watching your attribute dictionaries. They might be watching their own, but you will not be watching theirs.
The takeaway is that changing an attribute dictionary attached to a model entity does not trigger the onChangeEntity callback for the attached entity (which is what most other observer would be watching for.) Instead, because an attribute dictionary is an Entity subclass, onChangeEntity will fire for the dictionary object itself, and of course only for observers attached specifically to your dictionary object. It would be a very rare thing for an extension to be watching all attribute dictionaries attached to all objects for changes.

The main thing to worry about is that the model.modified? flag should be set true and either another extension or SketchUp’s autosave will want to save the model at some time following.

So you can also see that there are others interested in some of these aspects you mention.

With regard to time / scheduling see this topic thread:

SketchUp 4D Timeliner Concept – Looking for Ruby Development Support - Developers / Ruby API - SketchUp Community which has links to 2 existing extensions.

With regard to Material Requirements Planning (MRP) look at what OpenCutList has achieved so far:

Approvals / Inspections would vary by jurisdiction. I could see a Boolean field, perhaps a date and a link to external documents being helpful. But a quick search shows nothing in the Trimble Extension Warehouse.

Re Cost / Procurement, there have been quite a few attampts:

You can’t. Since you start a transaction and modify objects (definitions and/or containers), all the relevant observers will be triggered and possibly intercepted by other extensions (including your own extension).

This is tricky but seems to improve as of SU2026.1. However, you need t check that at the time observer callbacks are tiggered the model is still ‘alive’.

You may take a look in 5D+ Auto Info new version 2.0, which introduced new features “Data Bridge” and “Custom Attributes” for similar concepts.

These not only extract data from SketchUp but also help you write data from external source (with formats: xlsx, csv and json) over SketchUp objects attributes.

Dan, thank you for taking the time to share those references — the OpenCutList thread in particular is exactly the kind of serious community work I needed to understand what’s been achieved and where the real complexity lives.

I have a few more specific questions about the writeback architecture that I don’t want to clutter this thread with. Would you be open to continuing in PM?

Fredo6, thank you — that is exactly the kind of honest answer that actually helps.

The ‘you can’t’ on observer cascade is clarifying. It tells me the right design response is not to try to prevent interception, but to make the writeback operation itself resilient to it.

Which leads to my follow-up question, if you’re willing: since cascade prevention isn’t fully achievable, is the correct mitigation to design writeback operations to be idempotent — so that even if other extensions intercept and re-trigger the operation, the end state remains consistent and corruption-safe?

And on the shutdown guard — noted on SU2026.1. For earlier versions still in active use, is the practical approach simply to check model validity before any writeback fires, and abort cleanly if the model is no longer in a safe state?

Please again refer to the answer I gave for #5 in my post above. I.e., other extensions are very unlikely to attach any observer to your extension’s attribute dictionaries. Anyway, if they did, their observer callback would fire after your extension made the changes so they cannot intercept or prevent the change to the dictionaries.

Otherwise to this question it of course doesn’t hurt to write the same attribute data more than once. Depending upon the size of the model, the user may or may not notice a delay in getting back mouse control associated with a save or manually triggered writeback from the cloud.

Yes you can PM me. I won’t see it until tomorrow though.