foxglove.client (foxglove-client package)

foxglove.client is the Python client for the Foxglove API. It is published separately from the SDK, as the foxglove-client package, and its source is in the foxglove-python repository. The torch and ray extras of foxglove-sdk install it.

This page describes foxglove-client 0.23. It covers the methods of Client that work with datasets, episodes, data coverage, and custom properties.

Pass timezone-aware datetime values for time arguments. The client converts them with astimezone(), so a naive datetime is read as local time. Times in results, such as created_at and start_time, are datetime objects. Result dictionaries use snake_case keys. Values that the client passes through unchanged, such as creation_context and a recording’s location, keep the API’s field names.

The REST API that these methods call is documented at https://docs.foxglove.dev/api.

The examples on this page use the client that the first example creates.

class foxglove.client.Client

Client for the Foxglove API.

__init__(token, host='api.foxglove.dev')

Create a client.

Parameters:
  • token (str) – Required. API key sent with every request.

  • host (str) – Optional, default "api.foxglove.dev". Host name of the API.

import os

from foxglove.client import Client

client = Client(token=os.environ["FOXGLOVE_API_TOKEN"])

Datasets

Client.create_dataset(*, project_id, name, description=None, episode_ids=None)

Create a dataset, optionally seeding the first version with episodes.

Parameters:
  • project_id (str) – Required. Project that owns the dataset.

  • name (str) – Required. 1–100 characters. Unique in the Project, case-insensitive.

  • description (str) – Optional, default None. 1–500 characters.

  • episode_ids (list[str]) – Optional, default None. At most 2,000 episode IDs.

Returns:

The dataset, with id, project_id, name, description, creator_org_member_id, creator_api_key_id, created_at, updated_at, episode_count, and the counts added, updated, removed, and already_present for episode_ids.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 409 when the name is taken.

dataset = client.create_dataset(
    project_id="prj_123",
    name="Training candidates",
    episode_ids=["ep_1"],
)
Client.get_datasets(*, project_id=None, name=None, sort_by=None, sort_order=None, limit=None, cursor=None)

List datasets.

Parameters:
  • project_id (str) – Optional, default None. Restrict to one Project.

  • name (str) – Optional, default None. Case-insensitive substring of the dataset name.

  • sort_by (str) – Optional, default None, which sorts by created_at. One of name, created_at, updated_at, or episode_count.

  • sort_order (str) – Optional, default None. asc or desc.

  • limit (int) – Optional, default None, which returns up to 2,000 datasets. Page size, 0–2000.

  • cursor (str) – Optional, default None. Cursor from a previous page.

Returns:

A page of datasets, each as get_dataset() returns it.

Return type:

Page

Raises:

requests.exceptions.HTTPError – If the API returns an error.

page = client.get_datasets(project_id="prj_123")
for d in page.auto_paging_iter():
    print(d["id"], d["name"], d["episode_count"])
Client.get_dataset(*, dataset_id)

Return one dataset.

Parameters:

dataset_id (str) – Required. Dataset ID.

Returns:

The dataset, with id, project_id, name, description, creator_org_member_id, creator_api_key_id, created_at, updated_at, and episode_count.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 404 when the dataset does not exist.

dataset = client.get_dataset(dataset_id="dset_123")
print(dataset["name"], dataset["episode_count"])
print(dataset["updated_at"].isoformat())
Client.update_dataset(*, dataset_id, name=None, description=...)

Update a dataset’s name, description, or both.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • name (str) – Optional, default None, which leaves the name unchanged. 1–100 characters.

  • description (str or None) – Optional. 1–500 characters. Omit it to leave the description unchanged, or pass None to clear it.

Returns:

The updated dataset, as get_dataset() returns it.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 409 when the name is taken.

dataset = client.update_dataset(
    dataset_id="dset_123", description=None
)
Client.delete_dataset(*, dataset_id)

Delete a dataset. Its episodes remain.

Parameters:

dataset_id (str) – Required. Dataset ID.

Returns:

None.

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 404 when the dataset does not exist.

scratch = client.create_dataset(
    project_id="prj_123", name="Scratch"
)
client.delete_dataset(dataset_id=scratch["id"])
Client.get_dataset_episodes(*, dataset_id, sort_by=None, sort_order=None, limit=None, cursor=None, start=None, end=None, has_missing_recordings=None, recording_id=None, properties_query=None, include_recordings=False, include_properties=False, include_creation_context=False)

List the episodes in a dataset’s latest committed version, or in its draft if no version is committed.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • sort_by (str) – Optional, default None, which sorts by added_at. One of added_at, created_at, start_time, or end_time.

  • sort_order (str) – Optional, default None. asc or desc.

  • limit (int) – Optional, default None, which returns up to 2,000 episodes. Page size, 0–2000.

  • cursor (str) – Optional, default None. Cursor from a previous page.

  • start (datetime.datetime) – Optional, default None. Start of a time range. Episodes whose time window overlaps the range are returned. Pass it together with end.

  • end (datetime.datetime) – Optional, default None. End of the time range.

  • has_missing_recordings (bool) – Optional, default None. True returns episodes with a missing recording. False returns episodes whose recordings are all available.

  • recording_id (str) – Optional, default None. Return episodes that contain this recording.

  • properties_query (str) – Optional, default None. Space-separated key:value terms. Episodes that match every term are returned.

  • include_recordings (bool) – Optional, default False. Add recordings to each episode.

  • include_properties (bool) – Optional, default False. Add properties to each episode.

  • include_creation_context (bool) – Optional, default False. Add creation_context to each episode.

Returns:

A page of dicts with added_at, added_in_version, has_missing_recordings, and episode, which has the keys that get_episodes() lists.

Return type:

Page

Raises:
  • ValueError – If only one of start and end is given.

  • requests.exceptions.HTTPError – If the API returns an error, for example 404 when the dataset does not exist.

page = client.get_dataset_episodes(dataset_id="dset_123")
for m in page.auto_paging_iter():
    print(m["episode"]["id"], m["added_in_version"])
Client.update_dataset_episodes(*, dataset_id, add=None, remove=None, update=None)

Stage episode additions, removals, and episode version changes in a dataset’s draft.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • add (list) – Optional, default None. At most 2,000 episodes to add. Each item is an episode ID, which selects the latest episode version, or a dict {"id": ..., "version": ...} in which version is optional.

  • remove (list[str]) – Optional, default None. At most 2,000 episode IDs to remove.

  • update (list) – Optional, default None. At most 2,000 episodes in the draft whose episode version changes, in the same forms as add.

Returns:

The counts added, updated, removed, and already_present.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example when an episode is in update and also in add or remove.

client.update_dataset_episodes(
    dataset_id="dset_123", add=["ep_new"], remove=["ep_old"]
)
Client.get_dataset_versions(*, dataset_id, sort_order=None, limit=None, cursor=None)

List a dataset’s versions: its committed versions and its draft.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • sort_order (str) – Optional, default None. asc or desc.

  • limit (int) – Optional, default None, which returns up to 2,000 versions. Page size, 0–2000.

  • cursor (str) – Optional, default None. Cursor from a previous page.

Returns:

A page of versions, each with version_number, description, created_at, committed_at, committed_by_org_member_id, committed_by_api_key_id, episode_count, added_episode_count, removed_episode_count, and changed_episode_count. The draft’s committed_at is None.

Return type:

Page

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 404 when the dataset does not exist.

page = client.get_dataset_versions(dataset_id="dset_123")
for v in page.auto_paging_iter():
    print(v["version_number"], v["committed_at"])
Client.get_dataset_version(*, dataset_id, version_number)

Return one dataset version.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • version_number (int) – Required. Dataset version number.

Returns:

The version, with version_number, description, created_at, committed_at, committed_by_org_member_id, committed_by_api_key_id, episode_count, added_episode_count, removed_episode_count, changed_episode_count, and has_missing_recordings.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 404 when the version does not exist.

v = client.get_dataset_version(
    dataset_id="dset_123", version_number=2
)
Client.update_dataset_version(*, dataset_id, version_number, description)

Set the description of a committed version or of the draft.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • version_number (int) – Required. Dataset version number.

  • description (str or None) – Required. New description, 1–2048 characters, or None to clear it.

Returns:

The version, as get_dataset_version() returns it.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 404 when the version does not exist.

client.update_dataset_version(
    dataset_id="dset_123",
    version_number=2,
    description=None,
)
Client.get_dataset_version_episodes(*, dataset_id, version_number, sort_by=None, sort_order=None, limit=None, cursor=None, start=None, end=None, has_missing_recordings=None, recording_id=None, properties_query=None, include_recordings=False, include_properties=False, include_creation_context=False)

List the episodes in one dataset version, at the episode versions it pins.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • version_number (int) – Required. Dataset version number.

  • sort_by (str) – Optional, default None, which sorts by added_at. One of added_at, created_at, start_time, or end_time.

  • sort_order (str) – Optional, default None. asc or desc.

  • limit (int) – Optional, default None, which returns up to 2,000 episodes. Page size, 0–2000.

  • cursor (str) – Optional, default None. Cursor from a previous page.

  • start (datetime.datetime) – Optional, default None. Start of a time range. Episodes whose time window overlaps the range are returned. Pass it together with end.

  • end (datetime.datetime) – Optional, default None. End of the time range.

  • has_missing_recordings (bool) – Optional, default None. True returns episodes with a missing recording. False returns episodes whose recordings are all available.

  • recording_id (str) – Optional, default None. Return episodes that contain this recording.

  • properties_query (str) – Optional, default None. Space-separated key:value terms. Episodes that match every term are returned.

  • include_recordings (bool) – Optional, default False. Add recordings to each episode.

  • include_properties (bool) – Optional, default False. Add properties to each episode.

  • include_creation_context (bool) – Optional, default False. Add creation_context to each episode.

Returns:

A page of dicts with added_at, added_in_version, has_missing_recordings, and episode, which has the keys that get_episodes() lists.

Return type:

Page

Raises:
  • ValueError – If only one of start and end is given.

  • requests.exceptions.HTTPError – If the API returns an error, for example 404 when the version does not exist.

page = client.get_dataset_version_episodes(
    dataset_id="dset_123", version_number=2
)
for m in page.auto_paging_iter():
    print(m["episode"]["id"], m["episode"]["version"])
Client.compare_dataset_versions(*, dataset_id, version_number, base_version, limit=None, cursor=None, include_recordings=False, include_properties=False, include_creation_context=False)

Return the episodes added, removed, or changed from base_version to version_number.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • version_number (int) – Required. Target version.

  • base_version (int) – Required. Base version.

  • limit (int) – Optional, default None, which returns up to 2,000 changes. Page size, 0–2000.

  • cursor (str) – Optional, default None. next_cursor from a previous call.

  • include_recordings (bool) – Optional, default False. Add recordings to each episode.

  • include_properties (bool) – Optional, default False. Add properties to each episode.

  • include_creation_context (bool) – Optional, default False. Add creation_context to each episode.

Returns:

A dict with changes, added_count, removed_count, changed_count, and next_cursor. Each change has added_at, added_in_version, episode, and change, which is added, removed, or changed. A changed episode also has previous_version and previous_episode. The counts are totals across all pages.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 404 when a version does not exist.

diff = client.compare_dataset_versions(
    dataset_id="dset_123", version_number=2, base_version=1
)
Client.commit_dataset(*, dataset_id, description=...)

Commit the draft as a new version and open the next draft.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • description (str or None) – Optional. Description of the committed version, 1–2048 characters. Omit it to keep the draft’s description, or pass None to clear it.

Returns:

A dict with committed and editable_version_number. committed is the committed version, with the keys that get_dataset_versions() lists. editable_version_number is the number of the new draft.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 409 when the draft has no changes.

client.commit_dataset(
    dataset_id="dset_123", description="Labels batch 12"
)
Client.discard_dataset(*, dataset_id)

Discard the staged changes in a dataset’s draft.

Parameters:

dataset_id (str) – Required. Dataset ID.

Returns:

The counts discarded_adds, discarded_removes, and discarded_updates.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 404 when the dataset does not exist.

counts = client.discard_dataset(dataset_id="dset_123")
for name, count in counts.items():
    print(name, count)
Client.restore_dataset_version(*, dataset_id, version_number, force=False)

Stage the changes that make the draft match a committed version.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • version_number (int) – Required. Committed version to restore.

  • force (bool) – Optional, default False. Replace the pending changes in the draft.

Returns:

The counts added, updated, removed, discarded_adds, discarded_removes, and discarded_updates.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 409 when the draft has pending changes and force is False.

client.restore_dataset_version(
    dataset_id="dset_123", version_number=1
)
Client.clone_dataset_version(*, dataset_id, version_number, name, description=None, include_history=None)

Create a new dataset from a committed version.

Parameters:
  • dataset_id (str) – Required. Source dataset ID.

  • version_number (int) – Required. Committed version to clone.

  • name (str) – Required. Name of the new dataset, 1–100 characters. Unique in the Project, case-insensitive.

  • description (str) – Optional, default None. 1–500 characters.

  • include_history (bool) – Optional, default None, which the API treats as False. True copies every version up to and including the cloned one.

Returns:

The new dataset, as get_dataset() returns it.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 409 when the name is taken.

client.clone_dataset_version(
    dataset_id="dset_123",
    version_number=2,
    name="eval-holdout",
)
Client.download_dataset(*, dataset_id, version_number, output_directory, topics=None, include_properties=False)

Export a committed version to a directory, as one MCAP file per episode and a manifest.json.

Parameters:
  • dataset_id (str) – Required. Dataset ID.

  • version_number (int) – Required. Committed version number.

  • output_directory (str or os.PathLike) – Required. An empty directory, or a path that does not exist yet.

  • topics (list[str]) – Optional, default None, which exports every topic. Topics to export.

  • include_properties (bool) – Optional, default False. Add each episode’s custom properties to the manifest.

Returns:

The output directory.

Return type:

pathlib.Path

Raises:
  • requests.exceptions.HTTPError – If the API returns an error.

  • RuntimeError – If the version is not committed, an episode in it has a missing recording, output_directory is a file or a directory with contents, or every episode fails to download.

  • OSError – If a file cannot be written or a transfer is interrupted.

Warns:

DatasetDownloadWarning – If some episodes fail to download. The manifest records each one.

client.download_dataset(
    dataset_id="dset_123",
    version_number=2,
    output_directory="out",
)

Episodes

Client.create_episodes(*, project_id, episodes)

Get or create up to 2,000 episodes. An item returns an existing episode when the time range, recordings, and custom properties of its latest version match.

Parameters:
  • project_id (str) – Required. Project that owns the episodes.

  • episodes (list[dict]) – Required. 1–2000 items. Each item has exactly one of recordings, a list of recording IDs, or event_id. An item with recordings can set start_time and end_time, and takes its time range from the recordings when they are omitted. An item with event_id takes the event’s time range and the completed recordings of its device that overlap it. Any item can set properties, a dict of episode custom property values. All recordings lists together hold at most 100,000 recordings, and all event_id items together resolve to at most 10,000.

Returns:

One dict per item, in request order, with id and created. created is False for an existing episode.

Return type:

list[dict]

Raises:
  • ValueError – If an item has both or neither of recordings and event_id, or has event_id together with start_time or end_time.

  • requests.exceptions.HTTPError – If the API returns an error.

from datetime import datetime, timezone

episodes = client.create_episodes(
    project_id="prj_123",
    episodes=[
        {
            "recordings": ["rec_1"],
            "start_time": datetime(
                2026, 11, 2, 18, 0, tzinfo=timezone.utc
            ),
            "end_time": datetime(
                2026, 11, 2, 18, 5, tzinfo=timezone.utc
            ),
            "properties": {"task": "fold_towel"},
        }
    ],
)
Client.get_episodes(*, project_id=None, start=None, end=None, has_missing_recordings=None, recording_id=None, exact_recording_ids=None, properties_query=None, sort_by=None, sort_order=None, limit=None, cursor=None, include_recordings=False, include_properties=False, include_creation_context=False)

List episodes, each at its latest version.

Parameters:
  • project_id (str) – Optional, default None. Restrict to one Project.

  • start (datetime.datetime) – Optional, default None. Start of a time range. Episodes whose time window overlaps the range are returned. Pass it together with end.

  • end (datetime.datetime) – Optional, default None. End of the time range.

  • has_missing_recordings (bool) – Optional, default None. True returns episodes with a missing recording. False returns episodes whose recordings are all available.

  • recording_id (str) – Optional, default None. Return episodes that contain this recording.

  • exact_recording_ids (list[str]) – Optional, default None. Return episodes whose recordings are exactly these 1–50 recording IDs.

  • properties_query (str) – Optional, default None. Space-separated key:value terms. Episodes that match every term are returned.

  • sort_by (str) – Optional, default None, which sorts by created_at. One of created_at, start_time, or end_time.

  • sort_order (str) – Optional, default None. asc or desc.

  • limit (int) – Optional, default None, which returns up to 2,000 episodes. Page size, 0–2000.

  • cursor (str) – Optional, default None. Cursor from a previous page.

  • include_recordings (bool) – Optional, default False. Add recordings and has_missing_recordings to each episode.

  • include_properties (bool) – Optional, default False. Add properties to each episode.

  • include_creation_context (bool) – Optional, default False. Add creation_context to each episode.

Returns:

A page of episodes, each with id, project_id, start_time, end_time, version, latest_version, creator_org_member_id, creator_api_key_id, and created_at. Each item of recordings has id, path, location, start, end, device_id, and available.

Return type:

Page

Raises:
  • ValueError – If only one of start and end is given, or exact_recording_ids is empty.

  • requests.exceptions.HTTPError – If the API returns an error.

page = client.get_episodes(project_id="prj_123")
Client.get_episode(*, episode_id, include_recordings=False, include_properties=False, version=None)

Return one episode.

Parameters:
  • episode_id (str) – Required. Episode ID.

  • include_recordings (bool) – Optional, default False. Add recordings and has_missing_recordings.

  • include_properties (bool) – Optional, default False. Add properties.

  • version (int) – Optional, default None, which selects the latest version. Episode version to return.

Returns:

The episode, with id, project_id, start_time, end_time, version, latest_version, creator_org_member_id, creator_api_key_id, created_at, and creation_context. Each item of recordings has id, path, location, start, end, device_id, and available.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 404 when the episode does not exist.

episode = client.get_episode(episode_id="ep_123")
Client.update_episode(*, episode_id, applies_to_version=None, start_time=None, end_time=None, recordings=None, properties=None)

Update one episode. An update that changes the episode creates a new episode version.

Parameters:
  • episode_id (str) – Required. Episode ID.

  • applies_to_version (int) – Optional, default None. Episode version that the update applies to. The API rejects the update when it is not the latest version.

  • start_time (datetime.datetime) – Optional, default None. New inclusive start of the episode window.

  • end_time (datetime.datetime) – Optional, default None. New inclusive end of the episode window.

  • recordings (dict) – Optional, default None. Recording IDs to add and remove, as {"add": [...], "remove": [...]}.

  • properties (dict) – Optional, default None. Custom property values to merge into the episode’s properties. A value of None unsets its key.

Returns:

The episode at the resulting version, with the keys that get_episodes() lists.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example when applies_to_version is not the latest version.

client.update_episode(
    episode_id="ep_123", properties={"outcome": "success"}
)
Client.update_episodes(*, episodes)

Update up to 2,000 episodes in one transaction. If one update fails, none is applied.

Parameters:

episodes (list[dict]) – Required. At most 2,000 items. Each item has id and can set applies_to_version, start_time, end_time, recordings, and properties, which have the same meaning as the parameters of update_episode().

Returns:

One dict per item, in request order, with id and version, the episode’s resulting version.

Return type:

list[dict]

Raises:
  • KeyError – If an item has no id.

  • requests.exceptions.HTTPError – If the API returns an error.

client.update_episodes(
    episodes=[
        {
            "id": "ep_123",
            "properties": {"outcome": "success"},
        }
    ]
)
Client.delete_episode(*, episode_id)

Delete an episode that no dataset holds.

Parameters:

episode_id (str) – Required. Episode ID.

Returns:

None.

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 409 when a dataset holds the episode.

client.delete_episode(episode_id="ep_123")
Client.get_episode_versions(*, episode_id, limit=None, cursor=None)

List an episode’s versions, newest first.

Parameters:
  • episode_id (str) – Required. Episode ID.

  • limit (int) – Optional, default None, which returns up to 2,000 versions. Page size, 0–2000.

  • cursor (str) – Optional, default None. Cursor from a previous page.

Returns:

A page of dicts with version, created_at, creator_org_member_id, creator_api_key_id, and changed_fields.

Return type:

Page

Raises:

requests.exceptions.HTTPError – If the API returns an error, for example 404 when the episode does not exist.

page = client.get_episode_versions(episode_id="ep_123")
Client.iter_messages(*, device_id=None, device_name=None, session_id=None, session_key=None, start=None, end=None, topics=None, decoder_factories=None, project_id=None, episode_id=None, episode_version=None, recording_id=None, recording_key=None, replay_policy=None, replay_lookback_seconds=None)

Stream decoded messages. Messages are returned in log-time order across the selected topics.

start and end are required unless episode_id is given, or recording_id or recording_key is given without a device.

Parameters:
  • device_id (str) – Optional, default None. Device that originated the data. Requires start and end.

  • device_name (str) – Optional, default None. Name of the device that originated the data. Requires start and end.

  • session_id (str) – Optional, default None. Session to stream. Requires start and end.

  • session_key (str) – Optional, default None. Key of the session to stream. Requires start and end.

  • start (datetime.datetime) – Optional, default None. Inclusive start of the stream. Pass it together with end.

  • end (datetime.datetime) – Optional, default None. Inclusive end of the stream.

  • topics (list[str]) – Optional, default None, which streams every topic. Topics to stream.

  • decoder_factories (list[DecoderFactory]) – Optional, default None, which uses the client’s default decoders: JSON, plus Protobuf, ROS 1, and ROS 2 when the matching mcap support package is installed. MCAP decoder factories to use instead.

  • project_id (str) – Optional, default None. Project of the device or session. Required with session_key, and with device_name when the name exists in more than one Project.

  • episode_id (str) – Optional, default None. Episode to stream. Its time range is used when start and end are omitted.

  • episode_version (int) – Optional, default None, which selects the latest version. Episode version to stream. Requires episode_id.

  • recording_id (str) – Optional, default None. Recording to stream.

  • recording_key (str) – Optional, default None. Key of the recording to stream.

  • replay_policy (str) – Optional, default None. lastPerChannel adds the most recent message on each channel from before start.

  • replay_lookback_seconds (float) – Optional, default None. How far before start to look for those messages. Used with replay_policy="lastPerChannel".

Returns:

A generator of (schema, channel, message, decoded_message) tuples.

Raises:
  • RuntimeError – If no device, session, recording, or episode is given, episode_id is combined with another of them, a recording is combined with a session, episode_version is given without episode_id, or start and end are missing when required.

  • requests.exceptions.HTTPError – If the API returns an error.

for schema, channel, message, decoded in client.iter_messages(
    recording_id="rec_123",
    topics=["/camera/front"],
):
    print(channel.topic, message.log_time)
Client.download_data(*, device_id=None, device_name=None, session_id=None, session_key=None, start=None, end=None, topics=None, output_format=OutputFormat.mcap, compression_format=None, callback=None, project_id=None, episode_id=None, episode_version=None, include_attachments=None, recording_id=None, recording_key=None, replay_policy=None, replay_lookback_seconds=None)

Download the data of a device, session, recording, or episode as bytes.

start and end are required unless episode_id is given, or recording_id or recording_key is given without a device.

Parameters:
  • device_id (str) – Optional, default None. Device that originated the data. Requires start and end.

  • device_name (str) – Optional, default None. Name of the device that originated the data. Requires start and end.

  • session_id (str) – Optional, default None. Session to download. Requires start and end.

  • session_key (str) – Optional, default None. Key of the session to download. Requires start and end.

  • start (datetime.datetime) – Optional, default None. Inclusive start of the time range. Pass it together with end.

  • end (datetime.datetime) – Optional, default None. Inclusive end of the time range.

  • topics (list[str]) – Optional, default None, which downloads every topic. Topics to download.

  • output_format (OutputFormat) – Optional, default OutputFormat.mcap. Format of the returned data.

  • compression_format (CompressionFormat) – Optional, default None, for which the API uses LZ4. Compression of the chunks in MCAP output.

  • callback – Optional, default None. A function that the client calls as callback(progress=n) during the download, where n is the number of bytes received so far.

  • project_id (str) – Optional, default None. Project of the device or session. Required with session_key, and with device_name when the name exists in more than one Project.

  • episode_id (str) – Optional, default None. Episode to download. Its time range is used when start and end are omitted.

  • episode_version (int) – Optional, default None, which selects the latest version. Episode version to download. Requires episode_id.

  • include_attachments (bool) – Optional, default None. Include MCAP attachments. Applies to MCAP output for a recording, session, or episode.

  • recording_id (str) – Optional, default None. Recording to download.

  • recording_key (str) – Optional, default None. Key of the recording to download.

  • replay_policy (str) – Optional, default None. lastPerChannel adds the most recent message on each channel from before start.

  • replay_lookback_seconds (float) – Optional, default None. How far before start to look for those messages. Used with replay_policy="lastPerChannel".

Returns:

The data in output_format.

Return type:

bytes

Raises:
  • RuntimeError – If no device, session, recording, or episode is given, episode_id is combined with another of them, a recording is combined with a session, episode_version is given without episode_id, or start and end are missing when required.

  • requests.exceptions.HTTPError – If the API returns an error.

data = client.download_data(
    episode_id="ep_123", topics=["/camera/front"]
)
Client.get_topics(*, device_id=None, device_name=None, start=None, end=None, include_schemas=False, project_id=None, session_id=None, session_key=None, episode_id=None, limit=None, offset=None, recording_id=None, recording_key=None, episode_version=None, sort_by=None, sort_order=None)

List the topics of a device, session, recording, or episode.

start and end are required with device_id or device_name. Session, recording, and episode queries can omit them.

Parameters:
  • device_id (str) – Optional, default None. Device to list topics for.

  • device_name (str) – Optional, default None. Name of the device to list topics for.

  • start (datetime.datetime) – Optional, default None. Start of the time range. Pass it together with end.

  • end (datetime.datetime) – Optional, default None. End of the time range.

  • include_schemas (bool) – Optional, default False. Add schema to each topic.

  • project_id (str) – Optional, default None. Restrict to one Project.

  • session_id (str) – Optional, default None. Session to list topics for.

  • session_key (str) – Optional, default None. Key of the session to list topics for.

  • episode_id (str) – Optional, default None. Episode to list topics for. Its time range is used when start and end are omitted.

  • limit (int) – Optional, default None, which returns up to 2,000 topics. Page size, 0–2000.

  • offset (int) – Optional, default None. Number of topics to skip.

  • recording_id (str) – Optional, default None. Recording to list topics for.

  • recording_key (str) – Optional, default None. Key of the recording to list topics for.

  • episode_version (int) – Optional, default None, which selects the latest version. Episode version to list topics for. Requires episode_id.

  • sort_by (str) – Optional, default None. topic or version.

  • sort_order (str) – Optional, default None. asc or desc.

Returns:

One dict per topic, with topic, version, encoding, schema_encoding, and schema_name. With include_schemas, each also has schema, as bytes or None when no schema is available.

Return type:

list[dict]

Raises:
  • RuntimeError – If episode_version is given without episode_id, episode_id is combined with a device, session, or recording, or start and end are missing when required.

  • requests.exceptions.HTTPError – If the API returns an error.

topics = client.get_topics(episode_id="ep_123")
print([t["topic"] for t in topics])

Data coverage

Client.get_coverage(*, start=None, end=None, device_id=None, device_name=None, tolerance=None, project_id=None, session_id=None, session_key=None, recording_id=None, recording_key=None, include_edge_recordings=None)

List the time ranges for which Foxglove has data.

Parameters:
  • start (datetime.datetime) – Optional, default None. Start of the time range. Required with end unless a recording or session is given.

  • end (datetime.datetime) – Optional, default None. End of the time range.

  • device_id (str) – Optional, default None. Restrict to one device.

  • device_name (str) – Optional, default None. Restrict to the device with this name.

  • tolerance (int) – Optional, default None. Minimum gap, in seconds, for two ranges to count as separate.

  • project_id (str) – Optional, default None. Restrict to one Project.

  • session_id (str) – Optional, default None. Restrict to one session.

  • session_key (str) – Optional, default None. Restrict to the session with this key.

  • recording_id (str) – Optional, default None. Restrict to one recording.

  • recording_key (str) – Optional, default None. Restrict to the recording with this key.

  • include_edge_recordings (bool) – Optional, default None, which the API treats as False. Include recordings from an Edge Site or a device running Foxlet. Each range then has an import_status.

Returns:

One dict per range, with device_id, device, start, end, and import_status. device is the device summary as the API returns it.

Return type:

list[dict]

Raises:

requests.exceptions.HTTPError – If the API returns an error.

from datetime import datetime, timezone

ranges = client.get_coverage(
    device_id="dev_123",
    start=datetime(2026, 11, 2, tzinfo=timezone.utc),
    end=datetime(2026, 11, 3, tzinfo=timezone.utc),
)

Custom properties

The properties of an episode use keys that are defined as custom properties with resource_type="episode".

Client.create_custom_property(*, key, label, resource_type, value_type, enum_values=None)

Create a custom property.

Parameters:
  • key (str) – Required. Immutable identifier used in queries. 1–32 characters from A-Z, a-z, 0-9, _, and -.

  • label (str) – Required. Display label, 1–32 characters.

  • resource_type (str) – Required. device, event, session, or episode.

  • value_type (str) – Required. string, multiline-string, number, enum, boolean, or multi-enum.

  • enum_values (list[str]) – Optional, default None. Allowed values. Required when value_type is enum or multi-enum.

Returns:

The custom property, with id, key, label, resource_type, value_type, enum_values, and has_associated_data.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error.

client.create_custom_property(
    key="outcome",
    label="Outcome",
    resource_type="episode",
    value_type="enum",
    enum_values=["success", "failure"],
)
Client.get_custom_properties(*, resource_type=None)

List custom properties.

Parameters:

resource_type (str) – Optional, default None, which returns every type. device, event, session, or episode.

Returns:

The custom properties, each as get_custom_property() returns it.

Return type:

list[dict]

Raises:

requests.exceptions.HTTPError – If the API returns an error.

props = client.get_custom_properties(resource_type="episode")
Client.get_custom_property(*, custom_property_id)

Return one custom property.

Parameters:

custom_property_id (str) – Required. Custom property ID.

Returns:

The custom property, with id, key, label, resource_type, value_type, enum_values, and has_associated_data.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error.

prop = client.get_custom_property(custom_property_id="cp_123")
Client.update_custom_property(*, custom_property_id, label=None, enum_values=None)

Update a custom property’s label, allowed values, or both.

Parameters:
  • custom_property_id (str) – Required. Custom property ID.

  • label (str) – Optional, default None, which leaves the label unchanged. New display label, 1–32 characters.

  • enum_values (list[str]) – Optional, default None, which leaves the values unchanged. New list of allowed values. It contains every existing value and can add or reorder values.

Returns:

The custom property, as get_custom_property() returns it.

Return type:

dict

Raises:

requests.exceptions.HTTPError – If the API returns an error.

client.update_custom_property(
    custom_property_id="cp_123", label="Outcome"
)
Client.delete_custom_property(*, custom_property_id)

Delete a custom property.

Parameters:

custom_property_id (str) – Required. Custom property ID.

Returns:

None.

Raises:

requests.exceptions.HTTPError – If the API returns an error.

client.delete_custom_property(custom_property_id="cp_123")

Supporting types

class foxglove.client.Page

One page of results from a list method.

items

The results on this page, as a list.

next_cursor

Cursor of the next page, or None on the last page.

previous_cursor

Cursor of the previous page, or None when the API returns none.

auto_paging_iter()

Yield the results on this page, then fetch each following page and yield its results.

Returns:

An iterator over the results.

Raises:

requests.exceptions.HTTPError – If the API returns an error for a following page.

for dataset in client.get_datasets().auto_paging_iter():
    print(dataset["name"])
class foxglove.client.DatasetDownloadWarning

Warning that Client.download_dataset() emits when some episodes fail to download. A subclass of UserWarning.

class foxglove.client.OutputFormat

Output formats for Client.download_data(). An enum.Enum.

bag = "bag1"

A .bag file.

mcap = "mcap"

An .mcap file.

mcap0 = "mcap0"

Deprecated. Use mcap.

class foxglove.client.CompressionFormat

Chunk compression formats for Client.download_data(). An enum.Enum.

none = ""

No compression.

zstd = "zstd"

Zstandard compression.

lz4 = "lz4"

LZ4 compression.