# \[FAQ\] How to Determine When an App Is Visible in Workspaces

**URL:** <https://community.interop.io/t/faq-how-to-determine-when-an-app-is-visible-in-workspaces/584>\
**Category:** io.Connect Desktop\
**Tags:** FAQs\
**Created:** [May 21, 2026, 7:25am UTC](https://community.interop.io/t/faq-how-to-determine-when-an-app-is-visible-in-workspaces/584 "2026-05-21T07:25:53Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![toni.petrov](https://yyz2.discourse-cdn.com/flex028/user_avatar/community.interop.io/toni.petrov/32/17_2.png) [@toni.petrov](https://community.interop.io/u/toni.petrov)\
**Post date:** [May 21, 2026, 7:25am UTC](https://community.interop.io/t/faq-how-to-determine-when-an-app-is-visible-in-workspaces/584/1 "2026-05-21T07:25:53Z")

</div>

## Question

The standard window visibility events used to track regular app windows (for example, to deactivate apps when they are minimized or running as a background tab) do not give a complete picture for apps that run inside Workspaces. How can you determine whether a window inside a Workspace is currently visible, and how can you react to changes in its visibility?

## Answer

The snippet below covers visible windows that are part of Workspaces. It does not replace the standard visibility handling for regular floating windows.

```auto
    const isWindowVisible = async (windowId) => {
        const allWorkspaces = await io.workspaces.getAllWorkspaces();
        const workspaceWithWindow = allWorkspaces.find((wsp) => {
            const allWindows = wsp.getAllWindows();
            return allWindows.find((win) => win.id === windowId);
        });

        if (!workspaceWithWindow) {
            // handle the case where the window is not found in any workspace
            return false;
        }

        const isWorkspaceSelected = workspaceWithWindow.isSelected;
        const frameState = await workspaceWithWindow.frame.state();
        const isFrameNormalOrMaximized = frameState === 'normal' || frameState === 'maximized';
        const workspaceWindow = workspaceWithWindow.getAllWindows().find((win) => win.id === windowId);
        const isWindowSelected = workspaceWindow.isSelected;

        // A window is considered visible if its workspace is selected,
        // the workspace frame is either normal or maximized,
        // and the window itself is selected.
        return isWorkspaceSelected && isFrameNormalOrMaximized && isWindowSelected;
    };

    const onWindowVisibilityChange = async (windowId, callback) => {
        const allWorkspaces = await io.workspaces.getAllWorkspaces();
        const workspaceWithWindow = allWorkspaces.find((wsp) => {
            const allWindows = wsp.getAllWindows();
            return allWindows.find((win) => win.id === windowId);
        });

        if (!workspaceWithWindow) {
            // handle the case where the window is not found in any workspace
            return () => { };
        }

        // Pre-populating the initial state
        let isWorkspaceSelected = workspaceWithWindow.isSelected;
        const frameState = await workspaceWithWindow.frame.state();
        let isFrameNormalOrMaximized = frameState === 'normal' || frameState === 'maximized';
        const workspaceWindow = workspaceWithWindow.getAllWindows().find((win) => win.id === windowId);
        let isWindowSelected = workspaceWindow.isSelected;

        const triggerCallback = () => {
            // A window is considered visible if its workspace is selected,
            // the workspace frame is either normal or maximized,
            // and the window itself is selected.
            const isVisible = isFrameNormalOrMaximized && isWindowSelected && isWorkspaceSelected;
            callback(isVisible);
        };

        const minimizedUnsub = await workspaceWithWindow.frame.onMinimized(() => {
            isFrameNormalOrMaximized = false;
            triggerCallback();
        });

        const restoredUnsub = await workspaceWithWindow.frame.onNormal(() => {
            isFrameNormalOrMaximized = true;
            triggerCallback();
        });

        const maximizedUnsub = await workspaceWithWindow.frame.onMaximized(() => {
            isFrameNormalOrMaximized = true;
            triggerCallback();
        });

        const workspaceSelectedUnsub = await workspaceWithWindow.frame.onWorkspaceSelected((w) => {
            if (w.id === workspaceWithWindow.id) {
                isWorkspaceSelected = true;
            } else {
                isWorkspaceSelected = false;
            }
            triggerCallback();
        });

        const windowSelectedUnsub = await workspaceWithWindow.onWindowSelected((win) => {
            if (win.id === windowId) {
                isWindowSelected = true;
            } else {
                isWindowSelected = false;
            }
            triggerCallback();
        });

        triggerCallback();

        return () => {
            minimizedUnsub();
            restoredUnsub();
            maximizedUnsub();
            workspaceSelectedUnsub();
            windowSelectedUnsub();
        }
    };

```

### A window inside a Workspace is considered visible when:

- The Workspace that contains the window is the selected (active) Workspace in its Frame.

- The Frame that hosts the Workspace is in `normal` or `maximized` state (i.e. not minimized).

- The window itself is the selected window within its tab group in the Workspace.

## References

- [Workspaces — Overview (io.Connect Desktop)](https://docs.interop.io/desktop/capabilities/windows/workspaces/overview/index.html)

- [Workspaces JavaScript API Reference](https://docs.interop.io/desktop/reference/javascript/workspaces/api/index.html)
