Export stage history

An export can include the full workflow history of each item: every stage the item went through, in order, and its annotations as they were when it left each stage. Use it to see what was delivered at a given stage, measure how much review changed, or put an item back the way it was at an earlier stage.

Turn it on

  • Export dialog: tick Include full stage history.
  • API: set include_stage_history: true on Create an export.
  • darwin-py:
    darwin dataset export <dataset> <release> --version 2.0 --include-stage-history
    darwin dataset pull <dataset>:<release> --only-annotations

Stage history needs Darwin JSON 2.0. Turn on worker metadata (include_authorship in the API) to also get names, emails, annotators and reviewers.

What you get

Next to the usual annotation files, the export has one folder per item:

stage_history/
  <item id>/
    visits.json                  # every stage visit of the item, in order
    <stage instance id>.json     # annotations at the end of that visit (Darwin JSON 2.0)

After darwin dataset pull, it's under <dataset>/releases/<release>/stage_history/.

visits.json

{
  "version": "1.1",
  "item_id": "0191...",
  "visits": [
    {
      "stage_instance_id": "8f2c...",
      "parent_stage_id": null,
      "stage": {"id": "...", "name": "Annotate", "type": "annotate"},
      "status": "completed",
      "entered_at": "2026-11-02T09:14:03Z",
      "exited_at": "2026-11-02T10:02:41Z",
      "exited_by": {"type": "user", "id": 123},
      "exit_snapshot": {"status": "exported", "file": "8f2c....json"}
    },
    {
      "stage_instance_id": "a71d...",
      "parent_stage_id": null,
      "stage": {"id": "...", "name": "Consensus", "type": "consensus_entrypoint"},
      "status": "completed",
      "entered_at": "2026-11-02T10:02:41Z",
      "exited_at": "2026-11-02T10:02:41Z",
      "exited_by": {"type": "system", "id": null},
      "exit_snapshot": {"status": "none", "file": null, "reason": "pass_through"}
    }
  ]
}
FieldMeaning
parent_stage_idFor an annotator's visit inside a consensus stage, the consensus stage it belongs to; otherwise null.
statuscompleted (left through the workflow), overriden (moved with set stage) or current (the item is still there)
exited_byWho ended the visit: user, model or system, with its id. With include_authorship, users also have email and full_name.
exit_snapshot.statusexported: file holds the annotations at exit. none: no snapshot; see reason.
exit_snapshot.reasoncurrent: the visit is still open. pass_through: a stage that never changes annotations (consensus entry, AI review). not_recorded: no snapshot was stored, typically older visits.

Snapshot files

Each <stage instance id>.json is a normal Darwin JSON 2.0 file with the item's annotations at the end of that visit: all frames, classes, properties and item properties, including classes and properties deleted since. With include_authorship, each annotation lists the annotators and reviewers it had at that point.

Restore an item to an earlier stage

  1. Export and pull with stage history (above).
  2. Open stage_history/<item id>/visits.json and pick the visit to go back to.
  3. Import its snapshot over the item:
    darwin dataset import <dataset> darwin stage_history/<item id>/<stage instance id>.json --overwrite --yes

The item's annotations, annotation properties and item properties now match that snapshot. Annotations are recreated with new IDs.

In Python:

from darwin.dataset.stage_history import read_stage_history

visits = read_stage_history(release_path / "stage_history" / item_id)
for visit in visits:
    print(visit.stage["name"], visit.exited_at, visit.exit_snapshot["status"], visit.reason)
    annotations = visit.snapshot()  # parsed Darwin JSON, or None

Good to know

  • History starts when snapshots were recorded. Moves made with set stage (UI or API) have snapshots from 19 October 2026. Earlier visits moved that way show not_recorded. Annotators and reviewers in snapshots start with snapshots taken after the November 2026 release.
  • Size. A clip with a long history can add tens of MB to the export. Filter the export to the items you need.
  • IDs across visits. An import with --overwrite gives every annotation a new ID, so matching annotations between visits by ID only works between overwrite imports.

Did this page help you?