Background
This article covers two related issues that came up together in practice: a Workspaces restore bug that affected channel restoration (fixed in io.Connect Browser 4.1), and the broader question of how to persist FDC3 app-channel data across layout save/restore, which is application-managed by design.
The Problem
When using FDC3 app channels in io.Connect Browser e.g. for broadcasting context via fdc3.getOrCreateChannel('myChannel') - the channel subscription and context data work as expected at runtime. However, when you save a layout and later restore it, the FDC3 app-channel data is not automatically restored with it.
How User Channels and App Channels Differ on Layout Restore
FDC3 User Channels are predefined channels within the platform. They can be joined programmatically or through the UI. in io.Connect Browser 4.1 and later, apps should rejoin the last selected user channel automatically when the layout is restored. However, because user channels are shared across the entire io.Connect Browser ecosystem, the data within them is not saved or restored - only the channel membership is retained. This avoids interfering with other applications’ workflows.
FDC3 App Channels are created dynamically and are not predefined like user channels. They are implemented using the io.Connect Browser Shared Contexts API. Unlike user channels, app channels cannot be joined in the traditional sense, and they are not persisted by the platform when saving layouts.
Regardless of which channel type you use, the platform will not populate any context data when restoring a layout.
The Solution: App-Managed Persistence via onSaveRequested and Window Context
Since the platform does not automatically persist app-channel state, the recommended approach is to save whatever you need into the window context and restore it in your own app logic.
You can do this using the onSaveRequested hook from the Layouts API.
Step 1: Save the App-Channel Data on Layout Save
Subscribe in the workspace window to save the app channel name and context when the layout is saved. Note that the callback must be synchronous.
const unsub = await io.layouts.onSaveRequested(() => {
return {
windowContext: {
appChannelName: "myChannel",
appChannelContext: { test: 42 }
}
};
});
Step 2: Retrieve the Saved Data on Layout Restore
When the layout is restored, retrieve the window context:
const myWindow = io.windows.my();
const myContext = await myWindow.getContext();
/*
{
"appChannelName": "myChannel",
"appChannelContext": { "test": 42 }
}
*/
You can also subscribe for context updates via onContextUpdated.
Step 3: Save and restore context
With this approach, you can:
-
Use
onSaveRequestedto store your current app channel and context into the window context during layout save. -
On app initialization (after layout restore), consume the window context and implement your logic — for example, re-create the channel and broadcast the saved context.
Summary
Window Context:
The data associated with a single window instance inside the layout. Each window can have its own context, and it may be any object. Apps consume this using `io.windows.my().getContext()`.
FDC3 Context:
A standardized data format defined by the FDC3 spec, used for passing business identifiers (e.g., instrument, contact, organization) between apps. All FDC3 contexts require a `type` property (e.g., `“fdc3.instrument”`).
Any type of object may be saved as a layout or a window context.
-
To save a window context into a layout, use the onSaveRequested hook.
-
For obtaining a window context, call getContext or subscribe for updates via onContextUpdated
A bug in the Workspaces library caused
io.workspaces.restoreWorkspace()to fail to restore even user-channel associations correctly. This was fixed in io.Connect Browser 4.1, so if you face it update your version.