twin.recordings.list() and twin.recordings.get() fetch the same recordings for local analysis.
In the lab, recordings become training episodes and datasets for your custom VLAs. In production, they let you learn from real-world data and improve your workflows and automations over time.
Cyberwave ships the whole pipeline out of the box: capture, upload, indexing and signed-URL playback. You don’t configure anything.
What gets recorded
Every twin in an environment records by default. The Cyberwave Edge buffers and uploads everything for you:- Live video from every paired camera (MP4, range-requested on playback)
- Joint states, positions, velocities, gripper status (Parquet, time-windowed reads)
- Mobile-base telemetry: GPS, odometry, IMU
- Point clouds from depth and LiDAR sensors (FlatBuffer chunks)
- Audio from on-device microphones
- Workflow runs: every node execution, input and output, bound to the same timeline
record / replay in the SDK data layer for the edge-side mechanics.
Record a simulation run
- Start a backend simulation in Simulate. Recording starts once the simulation is ready.
- Select Stop & save next to the mode buttons at the top of the 3D view, or stop the simulation. The run is added to Replay.
Find a recording
Saved runs
In Replay, the left sidebar lists recent saved runs:- Select a run’s name to load it without playing.
- Select its Play icon to open it and start playback.
- Open the ⋯ menu for Execution & evidence.
?mode=replay&run=<run-uuid>. It reopens that run for anyone with access to the environment.
Recordings by date
- Switch the environment to Replay.
- Click the calendar button.
- Pick the date: the day you recorded, or May 8, 2026 if you use the suggested demo environment.
- Click Load sessions. You don’t need filters. The timeline fills in.
- Twin
- Data source: live or simulation
- Replay stream: robot, camera, audio, depth, point cloud
Replay in the environment editor
When a recording loads, the whole scene rewinds together:- 3D twins snap to their historical poses: robot joints, base position, attached objects.
- Live video tiles scrub frame-accurately alongside the 3D view.
- Point clouds render at the right pose for every frame.
- Audio plays back in sync with the timeline.
- Workflow runs that fired during the window show up as markers. Click one to see node-level inputs, outputs and errors (env editor reference).
Camera and audio sidebar
The right-hand Camera & audio tab plays media available at the Replay cursor. Robot motion plays in the 3D scene and timeline, not in this tab, so a motion-only recording can replay without camera or audio tracks. If media exists elsewhere in the recording, move the cursor onto its timeline clip to view or hear it.Scene labels
Scene labels are off by default. Hover an object or its scene-tree row to see its name, or turn on labels from View or the labels toolbar button. Agent overview previews include labels by default. Sensor imagery excludes editor labels.Playback timing
A recording can keep both the wall-clock time each sample arrived and the producer’s own clock.- Source clock is the default when the producer’s clock is available. Robot motion, camera media, audio and events follow that one timeline, so a slow simulation step or an acquisition pause does not stretch the mission’s playback.
- Wall clock, in timeline settings, lets you inspect those pauses.
How playback loads data
Playback loads signed URLs from the API instead of inlined samples. Nothing is fully loaded into the browser, so scrubbing stays fast even on multi-hour recordings.
The
GET /api/v1/environments/{uuid}/recordings/{recording_uuid}/data endpoint returns compact source descriptors (URLs, bounds, column hints), not dense per-frame JSON.
The replay timeline
The Replay timeline shows everything an environment recorded over a time window, left to right. Each kind of data gets its own labeled row. Filled bars show where data exists. Dots in the Events row mark things that happened.Rows
A row only appears when it has something in it.
When two sources of the same kind overlap in time, such as two cameras recording the same minute, their bars stack inside the row. The row gets taller, but the bars keep the same thickness, so a bar never looks different just because something overlaps it. If more overlap than fit, the row label shows +N. Hovering still lists every one of them.
Episodes stack the same way. Two episodes covering the same stretch, or one nested inside another, each get their own line in the Episodes row, so you can hover and click either. Each line down the stack is a deeper shade of green, so you can follow one episode from start to end where others cross it. When more episodes overlap than there are lines, the ones sharing a line get a diagonal hatch. They cover each other, so hover any of them to list what is there.
Color legend
Open the Legend popover in the toolbar at any time. A color can mean only three things: a recording, an episode or an event.
Every recording bar is the same cyan, whatever data it holds. The row label tells you the kind, so you never have to tell two similar shades apart.
Event dots use a separate scale, so you can’t mistake an event for a recording:
A solid dot is an alert. A hollow dot is a workflow step or telemetry. When several events land too close together to draw apart, they merge into one wider dot that shows their count. Hover it to see each event.
Hover and pin
Hover any row and a card appears next to the cursor. Each row only tells you about its own contents, so a card never mixes recordings and events. If nothing is there, the card says so.- Recording bar: the kind of data, the twin’s name, and the twin’s UUID (click to copy). The bar’s position and width already show when it starts and how long it runs. When sources overlap, hover the specific stacked bar you want.
- Events row: the events at that moment, in this order: the twin (name, plus UUID to copy), the severity (Info, Warning or Critical), then the event’s name and message. The timestamp is in the card’s header.
Keyboard
Timeline controls
The row above the timeline holds what you use while watching: playback speed, Play / Pause, Create Episode, the calendar. Settings that change how the timeline reads sit under the Settings gear beside the Legend: time reference, 3D rendered mode, and the Events filter. A setting only appears there when there is something to choose.- Scrub and play back at 1× or 2×. Click anywhere on a row to jump there.
- Zoom into a stretch of the timeline for frame-level detail.
- Filter the Events row by twin with Settings → Events for. Recording rows are unaffected.
- Pick the 3D rendered mode, Depth or Point cloud, under Settings when a recording holds both. It sets which one the 3D view draws and highlights the matching row.
- Browse sessions by date with the calendar picker.
- Minimize the rows with the chevron at the right of the timeline. Playback controls stay available. Select it again to expand.
Create an episode
An episode marks a window you label as a training or dataset segment.- Click Create Episode. A short panel opens next to the button and tells you which point it wants next.
- Click the timeline twice. The playhead jumps to each click and turns green once the first mark lands.
- The two marks are ruled across every row, and the range between them fills in green with its duration.
- Name the episode in the dialog that opens.
Export an MP4
- In Replay, select Export MP4 in the playback toolbar beneath the 3D view.
- Choose the start and end time.
- Select Download MP4.
Use Chrome or Edge with video encoding support. Each export can be up to two minutes long. The MP4 holds the 3D scene without audio. Camera videos, microphone recordings and execution evidence stay available in Replay. The file metadata links back to the run, subject to the environment’s normal access rules.
Slice runs into episodes and export datasets
A recording isn’t just for watching. From the timeline you can create episodes and group them into a dataset you can train on. When you’re ready to leave the cloud, or hand data to an external tool, export to the format you need:
See the Dataset export reference for the full matrix and the Datasets API. Your data leaves in open formats whenever you want it to.
Work with recordings in Python
List and fetch recordings for a twin or an environment, then inspect the fetched artifacts locally.- Twin-scoped
- Environment-scoped
Defaults at a glance
recordings.list() narrows a request on purpose before it downloads catalog pages. The defaults are the same for twin.recordings.list() and cw.environments.recordings.list(). Twin-scoped calls also apply the twin filter on the server.
Pass both
start and end to select an older or wider UTC date range.
Date filtering
start and end accept a date, a datetime, or an ISO 8601 string (date-only or full datetime, with or without a Z or offset suffix). Provide both bounds together. A one-sided window is rejected.
start or end, list() checks which days have recordings and lists the most recent one, not the environment’s whole history. Pass an explicit window to reach older recordings.
Paging
list() fetches recordings in pages of 50 and returns at most limit (default 200). Use limit=0 to keep following pages until the window is exhausted.
filter= only narrows the recordings that were fetched. Widen limit or the date window instead of relying on filter to search further back.
Like the replay picker, list() excludes materializing or failed recordings by default. Pass include_unready=True only when you need those rows.
list() warns when it returns a partial view, so a truncated result never looks complete:
logging.getLogger("cyberwave.managers.recordings").setLevel(logging.ERROR).
Types and viewers
Recording types arecamera, robot, pointcloud (colored or lidar points), depth (raw depth maps) and audio. A depth camera typically matches camera and depth, and also pointcloud when it produces colored points.
get() downloads every artifact to a temp directory. The readers need the data extra:
data extra installs headless OpenCV, for decoding only. For GUI video playback with show_video(), also install a non-headless build: pip install opencv-python.
Contextual accessors
A fetched recording exposes only the accessors that apply to its streams.dir(rec) and autocomplete list just the relevant ones. info() is always available.
read_* raises with a “retry in a few minutes” hint.
Point clouds as Parquet
When youget() a recording, the SDK downloads point-cloud data as a single Parquet file, not the FlatBuffer chunks the browser streams. Each row is one frame: timestamp_us, rows, cols, dtype, and the raw frame data. read_depth() and read_pointcloud() rebuild the frames. To read the file directly with pyarrow:
get() logs a notice (“being generated / updated, retry in a few minutes”). Call get() again shortly to get the complete file.
Playback readiness
Each recording returned byGET /api/v1/environments/{uuid}/recordings includes an optional playback_readiness object. Its top-level state tells you whether the recording is ready, materializing or failed. Its streams list gives the same detail for each available camera, robot, audio, depth or point-cloud stream.
HTTP API defaults
GET /api/v1/environments/{uuid}/recordings and GET /api/v1/environments/{uuid}/recordings/availability share the same filters, but their defaults differ on purpose from Python recordings.list():
To apply a date window, send both
start_date and end_date (or both legacy start_timestamp and end_timestamp aliases). A one-sided date query does not produce a date-window filter. Repeated twin_uuid, context and source_type values are ORed within each kind and ANDed across kinds.
Include recordings that are not ready
Passinclude_unready=false for ready recordings only. Pass include_unready=true to include recordings that are still materializing or have failed. That value needs staff or administrator access:
Browse a large catalog or populate a calendar
Passlimit to get a stable page ordered newest-first. Follow the opaque next_cursor while has_more is true. Cursors are signed and bound to the current filters, so a 400 Invalid recording catalog cursor means you should restart the query. limit is capped at 100.
twin_uuid, context or source_type. Values are ORed within the same filter and combined with other filters. Source values are camera, robot, audio, depth and pointcloud. Responses include source, twin, context and readiness facets for the fully filtered catalog.
For calendar day counts without loading media, request availability with the same filters. Use an IANA timezone when the calendar is not UTC.
Retry materializing playback
GET /api/v1/environments/{uuid}/recordings/{recording_uuid}/data can return 202 Accepted when the recording is known but its playback files are not ready yet. The response includes retry_after_seconds. Wait about that long and retry the same request, instead of treating it as a missing recording.
Lab loop or production loop, same primitive
Next steps
Datasets and export
Convert recordings into LeRobot, RLDS, OpenVLA, or raw Parquet.
SO-101 teleop dataset
End-to-end: record a teleop session and turn it into a training dataset.
Edge record and replay
How the SDK data layer records and replays on the edge device.