Skip to main content

Introduction

Extend Foxglove's capabilities with custom extensions to better support your team's unique workflows. Build bespoke panels, convert custom messages to Foxglove-supported schemas, and alias topic names for easy visualization.

Once you've developed and installed your extension, you can open your app settings to display all available and installed extensions.

Custom panels

While Foxglove offers a suite of built-in panels for robotics data visualization and debugging, many users have domain-specific needs that our out-of-the-box offering does not address.

Custom panel extensions allow you to build an entire panel. Custom panels can subscribe to messages on various topics, advertise and publish, and display the message information in whatever form is most relevant for your workflow.

Custom panels are ideal when your visualization or interaction needs are bespoke and not easily solved via one of the built-in panels.

Message converters

Message converter extensions allow you to convert messages from one schema to another. By transforming messages to adhere to Foxglove-supported schemas, you can inspect them using Foxglove's built-in visualization features. For example, you can use a message converter to convert your custom GPS messages into foxglove.LocationFix messages for visualization in the Map panel.

Topic aliases

Topic alias extensions allow you to alias topics in your data source to new topics. Foxglove panels can subscribe to both the aliased topics and the original data source's topics.

Writing an extension

You can write extensions in JavaScript or Typescript and package them into .foxe files. You can distribute these files privately to your Foxglove organization or publicly via our marketplace - installing extensions via the marketplace is only supported on the desktop app. A single extension can include multiple panels or converters.

Foxglove provides a set of starter templates and commands in the create-foxglove-extension package to simplify authoring an extension.

Requirements:

To set up your extension project, navigate to the directory where you'll want your source code to live and run the following command in a Terminal window:

$ npm init foxglove-extension@latest my-extension-name

This will set up an extension directory structure. The entrypoint of your extension is the index.ts file.

The entrypoint script MUST export a single activate function which accepts a single ExtensionContext argument.

Custom panels

export function activate(extensionContext: ExtensionContext) {
// your extension code will decide which methods to call on the extensionContext
// Here's an example which registers a new panel:
extensionContext.registerPanel({ name: "example-panel", initPanel: initExamplePanel });
}

Message converters

export function activate(extensionContext: ExtensionContext) {
// Register a new message converter:
extensionContext.registerMessageConverter({
fromSchemaName: "sensors.MyGps",
toSchemaName: "foxglove.LocationFix",
converter: (inputMessage) => {
// logic to turn sensors.MyGps messages into foxglove.LocationFix messages
},
});
}

Topic aliases

The registerTopicAliases function accepts an argument with two fields – topics with the data source's original topics and globalVariables with the current layout's variables – and returns a list of aliased topics:

import { ExtensionContext } from "@foxglove/studio";

export function activate(extensionContext: ExtensionContext): void {
// Register a topic alias function that takes the current list of datasource topics and
// global variables and outputs a list of topic aliases.
extensionContext.registerTopicAliases((args) => {
// Use args.topics if you want to access the list of available topics in your data source.

const { globalVariables } = args;
// Output a list of aliased topics, in this case influenced by the current value of
// the global variable `camera`.
const camera = globalVariables["camera"] ?? "FRONT";
return [
{ sourceTopicName: `/CAM_${camera}/image_rect_compressed`, name: `/selected_camera_image` },
{ sourceTopicName: "/imu", name: "/aliased_imu" },
{ sourceTopicName: "/odom", name: "/aliased_odom" },
];
});
}

This registerTopicAliases function is rerun whenever the data source's original topics or the current layout's global variables change.

API reference