Channels

Channels are color-coded, named contexts that enable user-driven data linking between windows. Users assign windows to channels via a Channel Selector UI, and all apps on the same channel automatically share data.

FDC3 Mappingio.Connect Channels map directly to FDC3 User Channels. This provides standard-compliant interoperability with third-party FDC3 applications.

How Channels Work

Unlike Shared Contexts (which are programmatically controlled), Channels are user-driven. The user decides which apps should be linked by assigning them to the same color channel (Red, Green, Blue, etc.) using the Channel Selector widget in each window's title bar.

  • Each channel has a name and a color
  • Apps on the same channel receive each other's published data
  • Switching channels changes the data flow without code changes
  • Channels are global — they work across the entire platform

Channel Modes

io.Connect supports three channel modes, configured in the app definition:

  • Single — the app can join one channel at a time (default)
  • Multi — the app can join multiple channels simultaneously
  • Directional — the app can publish to one channel and subscribe to another

Enabling the Channel Selector

Add a Channel Selector to an app's window by setting it in the app definition JSON:

App Definition
{
  "name": "portfolio-app",
  "type": "window",
  "details": {
    "url": "http://localhost:3001",
    "channelSelector": {
      "enabled": true,
      "type": "single"
    }
  }
}

Joining a Channel

io.channels.join(channelName: string): Promise<void>
Join a channel programmatically
// Join the Red channel
await io.channels.join("Red");

// Leave the current channel
await io.channels.leave();

// Get the current channel
const currentChannel = io.channels.my();
console.log(currentChannel); // "Red"

Publishing Data

Publish data to your current channel. All other apps on the same channel will receive it.

Publish to current channel
await io.channels.publish({
  type: "fdc3.instrument",
  id: { ticker: "AAPL" },
  name: "Apple Inc.",
});

Subscribing to Data

Subscribe to receive data published by other apps on the same channel. The handler receives the data, the full channel context, and the publisher's peer ID.

Subscribe to channel data
io.channels.subscribe((data, context, updaterId) => {
  // Ignore updates from myself
  const isMe = io.interop.instance.peerId === updaterId;
  if (isMe) return;

  console.log("Received:", data);
  // { type: "fdc3.instrument", id: { ticker: "AAPL" }, name: "Apple Inc." }
});
No Promise returnUnlike io.contexts.subscribe(), the Channels subscribe() method does not return a Promise. The subscription is synchronous.

React Pattern

React channel subscription
import { useContext, useEffect, useState } from "react";
import { IOConnectContext } from "@interopio/react-hooks";

interface InstrumentData {
  type: string;
  id: { ticker: string };
  name: string;
}

function InstrumentPanel() {
  const io = useContext(IOConnectContext);
  const [instrument, setInstrument] = useState<InstrumentData | null>(null);

  useEffect(() => {
    if (!io) return;

    io.channels.subscribe((data: InstrumentData, _ctx, updaterId: string) => {
      const isMe = io.interop.instance.peerId === updaterId;
      if (!isMe) {
        setInstrument(data);
      }
    });
  }, [io]);

  return (
    <div>
      <h2>Current Instrument</h2>
      {instrument ? (
        <p>{instrument.name} ({instrument.id.ticker})</p>
      ) : (
        <p>Join a channel and select an instrument</p>
      )}
    </div>
  );
}

Listing Available Channels

List channels
const channels = await io.channels.list();
// Returns array of channel objects:
// [{ name: "Red", meta: { color: "red" } }, ...]

Channels vs. Shared Contexts

FeatureChannelsShared Contexts
ControlUser-driven (Channel Selector)Developer-driven (programmatic)
ScopeGlobal (color-coded groups)Global (named objects)
FDC3 MappingFDC3 User ChannelsFDC3 App Channels
Use CaseUser wants to link specific windowsAutomatic sync between known apps