# Zwift .zwo Format Reference (condensed) Offline copy of the essentials from . A `.zwo` file is XML; there is **no official Zwift schema**. This is the subset Zwift reliably accepts. ## Document structure ```xml IT Guy VO2 Max 5x3 5 × 3 min @ 115 % FTP bike ``` ## Conventions - **Power** is a fraction of FTP (`0.50` = 50 %, `1.15` = 115 %). `units="power"` is the implicit default. - **Duration** is always in **seconds**. - `` values seen: `bike` (61 %), `run` (37 %), `swim`, `ride`. We use `bike`. - Text cues are children of a step: ``. ## Step elements (child of ``) | Element | Attributes (relevant) | Meaning | |---|---|---| | `Warmup` | `Duration`, `PowerLow`, `PowerHigh`, `Cadence` | linear ramp Low→High | | `Cooldown` | `Duration`, `PowerLow`, `PowerHigh`, `Cadence` | linear ramp High→Low | | `SteadyState` | `Duration`, `Power`, (`PowerLow`,`PowerHigh`), `Cadence` | constant target | | `SolidState` | `Duration`, `Power` | constant power, no ERG variation | | `Ramp` | `Duration`, `PowerLow`, `PowerHigh` | explicit ramp | | `IntervalsT` | `Repeat`, `OnDuration`, `OffDuration`, `OnPower`, `OffPower`, `Cadence`, `CadenceResting`, `OverUnder` | N repeated on/off pairs | | `FreeRide` | `Duration`, `FlatRoad` | ERG off, rider's choice | | `MaxEffort` | `Duration` | all-out, ERG off | | `RestDay` | — | placeholder | | `textevent` | `timeoffset`, `message`, `duration` | on-screen cue | ## Top-level metadata elements (child of ``) `activitySaveName`, `author`, `author_alias`, `authorIcon`, `category`, `categoryIndex`, `description`, `durationType`, `entid`, `ftpOverride`, `ftpMaleOverride`, `ftpFemaleOverride`, `name`, `nameImperial`, `nameMetric`, `painIndex`, `setFtpAtPercentage`, `ShowCP20`, `Skippable`, `sportType`, `subcategory`, `tags`, `test_details`, `visibleAfterTime`, `visibleOutsidePlan`, `workout`, `workoutLength`, `WorkoutPlan`. **Minimal viable set we emit:** `author`, `name`, `description`, `sportType`, `tags`, `workout`. ## Importing a .zwo into Zwift 1. Copy the file into `~/Documents/Zwift/Workouts//` (folder name is your numeric Zwift ID), **or** 2. Use the Custom Workouts import on zwift.com, **or** 3. Drop it into the Zwift folder sync (Dropbox/OneDrive) if configured. Then restart Zwift; the workout appears under **Custom Workouts**. ## Gotchas - Malformed XML or unescaped `&`/quotes → Zwift silently ignores the file. - Power outside ~0.20–1.50 FTP is almost always a unit mistake. - Duplicate/unknown attributes are tolerated but ignored; keep it minimal.