Changed Elements

Diffing plan overview

The Changed Elements API provides built-in strategies — Basic, VersionCompare, and Full — that cover most common comparison needs. As a developer, you can start with these predefined strategies to quickly enable element comparison in your application. If your use case requires more control — such as filtering, custom enrichment, or shaping the response — you can define your own strategy using a pipeline of processing steps.

When to create a custom strategy?

  • You need to minimize response size by including only specific fields.
  • You want to exclude certain types of changes from the results.
  • You need to add extra metadata to the comparison output.
  • You require custom processing rules to fit your workflow or business logic.

Best practice: Begin with a built-in strategy. Only define a custom strategy if the existing options and output configuration cannot deliver the data your application needs.

See the Full Strategy Reference for the full details on each strategy.

Diffing plan

A diffing plan defines how the Changed Elements API processes and returns comparison results. It is provided as the diffingPlan JSON object in a diff request and controls both the processing logic and the response structure. (The output can vary greatly depending on the strategy or plan that you provide.)

A diffing plan can be defined in one of two ways:

  • Strategy-based: Use a predefined strategy such as Basic, VersionCompare, or Full. This is the recommended approach for most applications.

    { "diffingPlan": { "strategy": "Basic" } }
    
  • Pipeline-based: Define a custom sequence of processing steps when you need specialized filtering, enrichment, or output shaping.

    { "diffingPlan": { "pipeline": [{ "name": "compute-changes" }] } }
    

Choosing a strategy

A strategy is a predefined diffing plan that creates a specific, supported result format. Using a strategy is the quickest way to set up a comparison and is recommended for most developers. Pick the strategy that best fits the data your application or workflow needs. For a comparison of available strategies, see the overview table.

Strategy
What you get
When to use it
VersionCompare
Full change-detection results: changed elements with their change type, operation, model, parent, and property changes. Matches the Version Compare API output.
Design review and version-comparison workflows where you need complete change data.
Basic
A lightweight list of changed elements with their ids and class names.
Simple workflows that only need to know what changed, such as lightweight visualization use cases.
Full
Like Basic but retains full property data and metadata. Geometry data is excluded to keep the payload smaller.
When you need property-level detail without the extra structure of VersionCompare.

Note: Strategy names are case-insensitive (e.g.,"VersionCompare" and "versioncompare" are equivalent).

See the Full Strategy Reference for the full details on each strategy.

Configuring output

Strategies can include a default output format. You can optionally add an output configuration to control (or override) how results are returned, including the response format, element id encoding, and which fields are included in the final payload.

Note: If you add an output configuration to an existing strategy, it will override the default output configuration for that strategy.

{
  "strategy": "VersionCompare",
  "output": {
    "format": "versionCompare",
    "idEncoding": "decimal",
    "dropFields": ["parentId"],
    "renameFields": { "modelId": "model" }
  }
}

Output options

Field
Type
Notes
format
string
Shape of the payload: basic or versionCompare (case-insensitive). Omit to keep the strategy's default. See Output formats.
idEncoding
string
How element ids are encoded: hex (e.g. 0x1) or decimal. Defaults to hex when not set.
renameFields
object
Maps an original field name to a new output name. Applied last.
keepFields
string[]
Allow-list of fields to retain. Cannot be used together with dropFields.
dropFields
string[]
Deny-list of fields to remove. Cannot be used together with keepFields.

Notes:

  • The element id field is always preserved, even if not listed in keepFields.
  • keepFields and dropFields are mutually exclusive — supply at most one.
  • When both drop/keep and renameFields are used, fields are dropped or kept first, then renamed.

Output formats

Supported formats for the output.format field.

Format
Shape
(omitted)
The results exactly as the strategy or pipeline produces them, with every field intact.
"basic"
A JSON array of minimal records: { id, classFullName?, operation? }. classFullName and operation appear only when present.
"versionCompare"
A columnar envelope of parallel arrays indexed per element (elements, class ids, operations, type, model ids, parent ids, parent class ids, and properties). Matches the Changed Elements V2 API contract.

Custom diffing pipelines

With a custom pipeline, you control exactly how change data is processed before you get the results. Instead of picking a built-in strategy, you create a step-by-step sequence that lets you filter, enrich, transform, and shape the output your way.

Use a custom pipeline when the built-in strategies and output options cannot give you the data that you need.

A pipeline is a sequence of processing steps executed in order. Each step performs a specific operation on the comparison data. Each pipeline step has a name and an optional step-specific config.

In the example below, the pipeline computes changes, removes duplicate updates to the same elements, and filters the output to include only the ECInstanceId, ECClassId, and $meta properties. It also applies basic formatting and displays ECInstanceId as a hexadecimal value.

{
  "pipeline": [
    { "name": "compute-changes" },
    { "name": "drop-duplicate-updates" },
    { "name": "filter-fields", "config": { "keepOnly": ["ECInstanceId", "ECClassId", "$meta"] } }
  ],
  "output": { "format": "basic", "idEncoding": "hex" }
}

A strategy can serve as a "shortcut" within a pipeline and then be extended with additional processing steps. In other words, a strategy can also be step in a custom pipeline.

{
  "pipeline": [
    { "strategy": "Basic" },
    { "name": "add-model-id" }
  ]
}

For more information on the Basic strategy, see its full documentation.

Notes:

  • Each step must specify either name or strategy, but not both.
  • The order in which the steps are listed determines the order in which they are executed.
  • Dependencies are resolved automatically. Missing prerequisite steps are automatically added as needed. Redundant steps are skipped.

Available pipeline steps

Pipeline steps define the operations performed in a custom diffing workflow. You can combine steps to compute changes, filter results, enrich data, and control the final output.

See the in-depth Pipeline Steps documentation for a more detailed description of each step and its behavior.

Technical details: Each step reads and writes fields as it processes changed instances. When building a custom pipeline, ensure that steps that require specific fields come after the steps that produce it.

The table below describes the contract for each step.

  • Reads — fields that must already exist before the step runs (if any).
  • Adds — fields that the step always adds to each instance. Some steps may also add additional fields dynamically.
  • Removes — fields removed from each instance. * indicates all fields. Steps that remove entire instances (rows) are described in What it does instead.
  • Config — optional configuration supported by the step.
  • Prerequisites — other steps that must run earlier in the pipeline. Missing prerequisites are automatically added during validation.
Step
What it does
Reads
Adds
Removes
Config
Prerequisites
compute-changes
Groups together changesets and outputs their raw change data, including metadata and changed properties. Every pipeline should start with this.
ECInstanceId, ECClassId, $meta
{ "skipOldStageRecords": boolean } — default false; when true, drops the "old" copy of each updated instance at the source.
drop-duplicate-updates
For updated instances, keeps the new version and drops the redundant old version (removes those rows).
$meta.op, $meta.stage
None
compute-changes
add-class-full-name
Adds the full class name for each changed instance.
ECClassId
classFullName
None
filter-fields
Keeps or removes fields per instance.
The fields named in keepOnly
The fields named in remove, or all fields except those in keepOnly
{ "keepOnly": string[] } to whitelist fields, or { "remove": string[] } to remove specific fields. Provide at most one.
drop-non-elements
Keeps only element rows, removing relationships and other non-element changes (removes those rows).
ECClassId
None
drop-non-geometric-elements
Keeps only elements that derive from BisCore:GeometricElement, removing all other rows.
ECClassId
None
add-model-id
Resolves the model each changed instance belongs to, filling in modelId where it is missing.
ECInstanceId, ECClassId
None

Notes:

  • ECInstanceId is always preserved by field-removal steps, even when it is not included in a keepOnly allow-list
  • A custom pipeline is validated when submitted. If a step name is unknown or the pipeline configuration is invalid, the request is rejected before the job is created.

Choosing pipeline steps

A common pattern for building custom strategies is:

  1. Generate change data with compute-changes.
  2. Remove unnecessary records with drop-duplicate-updates, drop-non-elements, or drop-non-geometric-elements.
  3. Enrich results with add-class-full-name or add-model-id.
  4. Reduce the final payload with filter-fields.
  5. Optionally apply output configuration to control the final response format.

This approach keeps pipelines easy to understand while producing results tailored to your application's needs.

Rules and gotchas

  • Provide exactly one of strategy or pipeline. Supplying both, or neither, fails validation.
  • Strategy names are case-insensitive, but pipeline step names are case-sensitive — match them exactly as listed above.
  • keepFields and dropFields cannot both be set in the same output block.
  • Invalid plans are rejected up front. An unknown strategy name, unknown step name, or a plan that breaks any of the rules above is rejected before the job starts.

Use cases and examples

Use case 1: Detailed change comparison in a viewer

{
  "diffingPlan": {
    "strategy": "VersionCompare"
  }
}

Use VersionCompare when an application needs change type, operation, model, parent, and changed-property information. This is the richest of the strategy outputs and matches the Version Compare V2 API output.

Use case 2: Lightweight set of element changes optimized for visualization

A facilities management application wants to highlight only physical asset changes in a digital twin. Relationship changes and duplicate update records are not relevant to the user experience.

Goal: Return a lightweight set of element changes optimized for visualization.

{
  "diffingPlan": {
    "pipeline": [
      { "name": "compute-changes" },
      { "name": "drop-duplicate-updates" },
      { "name": "drop-non-elements" }
    ],
    "output": {
      "format": "basic"
    }
  }
}

Why use a custom pipeline? The application only needs to know which elements changed so they can be highlighted in the viewer. Removing duplicate update records and non-element changes reduces the amount of data that must be transferred and rendered.

Use case 3: Change data integration with enterprise systems

A user needs to synchronize engineering changes with an external asset management platform. The target system only supports a small subset of fields and requires ids in a specific format.

Goal: Produce a clean, integration-ready dataset containing only the required fields.

{
  "diffingPlan": {
    "pipeline": [
      { "name": "compute-changes" },
      {
        "name": "filter-fields",
        "config": {
          "keepOnly": [
            "ECInstanceId",
            "ECClassId",
            "$meta"
          ]
        }
      }
    ],
    "output": {
      "idEncoding": "decimal"
    }
  }
}

Why use a custom pipeline? Most downstream systems do not need the complete changed-elements payload. Reducing the result to only the required fields simplifies data mapping, lowers integration costs, and reduces data transfer volumes.

Tutorial

To learn more about using custom pipelines, see the Configurable Pipelines Tutorial for additional examples.

Was this page helpful?