Skip to main content

Typescript SDK guide

You can embed Foxglove in your application or website to enable multi-modal data visualization and debugging within your application.

Installation

Start by installing the @foxglove/embed package.

npm install --save @foxglove/embed

Basic setup

The @foxglove/embed package provides the FoxgloveViewer class. This class creates and manages an iframe to embed Foxglove in your application.

To create a new FoxgloveViewer, you need to provide the parent element to which the iframe will be appended and the organization slug for signing in. Passing a slug ensures users sign into the correct organization before they can visualize anything. If you don't know your organization slug (or if you're using a fully self-hosted embedded viewer) you can pass undefined, allowing users to select the organization they want to sign into.

import { FoxgloveViewer } from "@foxglove/embed";

const viewer = new FoxgloveViewer({
// The parent element to append the iframe to.
parent: document.getElementById("container")!,
// The Foxglove organization the user should be signed into.
orgSlug: "my-org",
});

Events

You can listen to events from the embedded viewer using the addEventListener method.

viewer.addEventListener("ready", (e) => {
console.log("FoxgloveViewer is ready");
});

viewer.addEventListener("error", (e) => {
console.log("FoxgloveViewer error:", e.detail);
});

The following events are supported:

  • ready - The embedded viewer has been initialized and is ready to receive commands.
  • error - An error occurred while executing a command.

Changing the data source

The embedded viewer can be used to visualize data from a variety of sources (including files, live data sources, and recordings). The data source is set using the setDataSource method.

The following example shows how to open a file picker and set the selected file as data source.

// Open a file picker and set the selected file as data source
window
.showOpenFilePicker({
multiple: false,
types: [
{
description: ".bag, .db3, .ulg, .ulog, .mcap",
accept: {
"application/octet-stream": [".bag", ".db3", ".ulg", ".ulog", ".mcap"],
},
},
],
})
.then(async (handles) => {
const file = await handles[0]!.getFile();
viewer.setDataSource({
type: "file",
file,
});
});

You can also connect to a live data source, such as a Foxglove WebSocket, a ROS Bridge, or a file hosted on a remote server.

// Connect to a Foxglove WebSocket
viewer.setDataSource({
type: "live",
// The protocol defined the type of live data source to connect to.
// Supported protocols are:
// - "foxglove-websocket" => Foxglove WebSocket
// - "rosbridge-websocket" => ROS Bridge
// - "remote-file" => File hosted on a remote server
protocol: "foxglove-websocket",
url: "ws://localhost:8765",
});

You can also visualize a recording stored in your Foxglove organization:

// Connect to a recording
viewer.setDataSource({
type: "recording",
recordingId: "rec_0dHVqSWhIQ8HUUJU",
projectId: "prj_0dX15xqpCP0yPYNq",
});

Another way to visualize a recording is by connecting to a device. You can provide the device ID or device name, along with the start and end times. Both start and end are required strings compatible with ISO8601/RFC3339.

Here are two examples of how to connect to a device:

// Connect to a device by ID
viewer.setDataSource({
type: "device",
deviceId: "dev_0dHVqSWhIQ8HUUJU",
start: "2025-01-01T00:00:00Z",
end: "2025-02-01T00:00:00Z",
});

// Connect to a device by name
viewer.setDataSource({
type: "device",
deviceName: "my-device",
start: "2025-01-01T00:00:00Z",
end: "2025-02-01T00:00:00Z",
});

Layout Management

Layouts are stored in the browser's local storage. The storageKey is used to identify the layout. Any changes made by the user will be restored when the layout is selected again. Setting the force parameter to true overrides the user's local changes.

Restore a layout with persisted changes

The following example shows how to restore a layout from local storage. If no layout with the same storage key is found, a default layout will be created and saved to the local storage under the provided storage key.

viewer.selectLayout({
storageKey: "layout-a",
});

You could also customize the fallback layout using the opaqueLayout parameter.

// Load a layout from a JSON file
window
.showOpenFilePicker({
multiple: false,
types: [
{
description: ".json",
accept: {
"application/json": [".json"],
},
},
],
})
.then(async (handles) => {
const file = await handles[0]!.getFile();
const layoutData = JSON.parse(await file.text());
viewer.selectLayout({
storageKey: "layout-a",
opaqueLayout: layoutData,
});
});

Override local changes to a layout

The following example loads a layout from a JSON file and overrides the existing layout.

// Load a layout from a JSON file
window
.showOpenFilePicker({
multiple: false,
types: [
{
description: ".json",
accept: {
"application/json": [".json"],
},
},
],
})
.then(async (handles) => {
const file = await handles[0]!.getFile();
const layoutData = JSON.parse(await file.text());
viewer.selectLayout({
storageKey: "layout-a",
opaqueLayout: layoutData,
force: true,
});
});

Retrieve the current layout

Use getLayout to retrieve the currently configured layout, including any user modifications:

const layoutData = await viewer.getLayout();
// Save the layoutData

The layout data can later be passed in to the opaqueLayout parameter:

viewer.selectLayout({
storageKey: "layout-a",
opaqueLayout: layoutData,
force: true,
});

API reference

Refer to the @foxglove/embed documentation for the full API reference.