# System

Source: https://docs.interop.io/desktop/developers/configuration/system/index.html

## System Configuration

The system configuration of **io.Connect Desktop** is controlled via the `system.json` file located in the `<installation_location>/config` folder. This file allows you to alter system-wide settings for window behavior, app stores, io.Connect Gateway settings, and more. In most cases, the default configuration settings should suffice.

> ℹ️ *For more details about the available system configuration properties, see the [system configuration](https://docs.interop.io/desktop/assets/configuration/system.json) and the [io.Connect Gateway configuration](https://docs.interop.io/desktop/assets/configuration/gw.json) schemas.*

> ⚠️ *Note that some of the globally defined properties in the `system.json` file may be overridden by the respective property settings in the [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md) files.*

#### 9.0 Version Stream

If you are still using the **io.Connect Desktop** 9.0 version stream, you can find the `system.json` configuration file in the `<installation_location>/interop.io/io.Connect Desktop/Desktop/config` folder.

## Platform Modes

Available since io.Connect Desktop 10.0

The **io.Connect Desktop** platform can operate in two modes - default and advanced. Both platform modes have certain advantages and limitations which must be considered before choosing which one to use.

The platform modes provide different experiences depending on your specific business needs and requirements:

**Default platform mode**

- Windows - Supports only web groups, lacks support for classic groups and visual integration of native apps.
- macOS - Supports only web groups, lacks support for classic groups and visual integration of native apps. OS limitations may prevent the usage of certain features.

> ℹ️ *For details on the specifics of running **io.Connect Desktop** on macOS, see the [macOS Support](https://docs.interop.io/desktop/developers/macos-support/index.md) section.*

**Advanced platform mode**

- Windows advanced - Supports classic groups and visual integration of native apps.

### Default

The default platform mode is the only option if you want to run **io.Connect Desktop** on [macOS](https://docs.interop.io/desktop/developers/macos-support/index.md). It's also the recommended option for Windows if your business use case doesn't require you to have visual integration for native apps or support for classic groups.

The default platform mode has the following advantages and limitations:

- OS-independent - provides support for both Windows and macOS;
- only [web groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-web_groups) are supported;
- web groups can use the [default OS system buttons](https://docs.interop.io/desktop/developers/configuration/application/index.md#app_definition-web_group_app) instead of the system buttons provided by the [`@interopio/groups-ui-react`](https://www.npmjs.com/package/@interopio/groups-ui-react) library;
- visual integration of native apps isn't supported (e.g., Java, .NET app windows can't be snapped to other io.Connect windows, can't participate in Workspaces and Layouts, and can't use the default Channel Selector app). However, interoperability with native apps is supported (e.g., Java, .NET app windows can use Channels, Interop methods, shared contexts, and more to share data);
- empty spaces in non-rectangular window groups aren't transparent, but are filled with background color instead;
- due to structural changes related to the z-order in the Workspaces App and the Web Group App, if you have custom popup window implementations in your Workspaces or web groups that don't work as expected in the default platform mode, you will have to replace them with the [external popup windows](https://docs.interop.io/desktop/capabilities/windows/workspaces/overview/index.md#extending_workspaces-custom_popups-external_window_popups) provided by the [`@interopio/workspaces-ui-react`](https://www.npmjs.com/package/@interopio/workspaces-ui-react) library and the [external popup windows](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#extending_web_groups-hooks__utilities-useexternalwindowpopup) provided by the [`@interopio/groups-ui-react`](https://www.npmjs.com/package/@interopio/groups-ui-react) library respectively. Both libraries export the `useExternalWindowPopup()` hook which you can use to migrate your existing popup windows;
- the `"SendFeedback"` command that can be sent from **io.Manager** to the platform isn't currently supported;

You should also consider the following list of features that haven't been implemented yet in the default platform mode:

> ⚠️ *Note that any of the features listed here can be implemented upon client request.*

- [HTML windows](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_modes-html_windows) currently don't have a move area and HTML buttons;
- [flydown windows](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#flydown_windows);
- [jump lists](https://docs.interop.io/desktop/capabilities/more/apis/index.md#jump_list);
- [window stickiness](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-stickiness) operations;
- [web page search](https://docs.interop.io/desktop/capabilities/more/features/index.md#web_page_search) with `CTRL + F` in PDF files;
- resizing of external borders of window groups with `ALT` and double clicking on the window border to align to the nearest border;

> ℹ️ *For details on the limitations specific to web groups (the only supported mechanism for managing window groups in the default mode), see the [Capabilities > Windows > Window Management](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#extending_web_groups-limitations) section.*

### Advanced

The advanced platform mode has the following advantages and limitations:

- can be used only on Windows (no support for macOS);
- web groups can't use the [default OS system buttons](https://docs.interop.io/desktop/developers/configuration/application/index.md#app_definition-web_group_app) instead of the system buttons provided by the [`@interopio/groups-ui-react`](https://www.npmjs.com/package/@interopio/groups-ui-react) library;
- supports [classic groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-classic_groups) and [web groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-web_groups) (it's highly recommended to migrate to web groups as classic groups are deprecated and will be entirely removed in a future release);
- supports visual integration of native apps (e.g., Java, .NET app windows can be snapped to other io.Connect windows and can participate in Workspaces);

To switch from the default platform mode to the advanced platform mode, use the `"advancedMode"` top-level key in the `system.json` file:

```json
{
    "advancedMode": true
}
```

## Auto Updates

Available since io.Connect Desktop 10.0

The **io.Connect Desktop** platform can be configured to auto update itself. This means that when your platform implementation has been distributed to your enterprise users, the platform can check for new updates from your update service or from a static storage location. You can choose to notify the user or directly install the update on restart of the platform. If the user is notified, they have the option to postpone the updates or apply them immediately by restarting the platform.

> ⚠️ *Note that for the auto update configuration to work, you must setup your own update service or a static storage location that will hold the updates for the platform. The update service can be an existing service (Nucleus, Hazel, and more) or your own custom update server implementation.*

> ⚠️ *Note that auto updates are supported only by the following platform builds produced via the io.Connect [seed project](https://docs.interop.io/desktop/developers/seed-project/index.md): EXE installers for Windows and DMG files for macOS. The ZIP archive platform builds for Windows and for macOS don't support auto updates.*

To configure the platform to auto update, use the `"autoUpdater"` top-level key:

```json
{
    "autoUpdater": {
        "enabled": true,
        "updateSource": {
            "type": "Service",
            "baseUrl": "https://my-update-service"
        },
        "notifyUser": true
    }
}
```

The `"autoUpdater"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true`, will enable automatically updating **io.Connect Desktop**. Defaults to `false`. |
| `"notifyUser"` | `boolean` | If `true` (default), the user will be prompted to apply the platform update immediately after the update has been downloaded. |
| `"updateIntervalMinutes"` | `number` | Interval in minutes at which to check for updates. The minimum allowed interval is 5 minutes. Defaults to `10`. |
| `"updateSource"` | `object` | **Required.** Settings for the source from which to retrieve the updates. |

The `"updateSource"` property can be an object defining an update service or an object defining a static storage location as an update source.

The object for defining an update service has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"baseUrl"` | `string` | **Required.** Base URL pointing to the service from which to retrieve the **io.Connect Desktop** updates. The feed URL has the following shape: `<baseUrl>/<platform>/<platform-version>/<channel>`. |
| `"channel"` | `string` | The update channel for the feed URL. |
| `"type"` | `string` | **Required.** Type of the update source. Must be set to `"Service"` for service-based updates. |

The object for defining a static storage location has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"baseUrl"` | `string` | **Required.** Base URL pointing to the static storage provider from which to retrieve the **io.Connect Desktop** updates. |
| `"type"` | `string` | **Required.** Type of the update source. Must be set to `"StaticStorage"` for static storage updates. |

## Multiple Local & Remote Configuration Sources

Available since io.Connect Desktop 10.0.3

The system settings for **io.Connect Desktop** can be retrieved from multiple local and remote configuration sources. Each source can be assigned priority and the final system configuration will be the result of merging all available configuration sources.

It's possible to fetch [custom configuration files from remote sources](#multiple_local__remote_configuration_sources-custom_remote_configuration_files). There are also certain [limitations](#multiple_local__remote_configuration_sources-limitations) that you must take into account regarding some of the system configuration properties.

### Configuration

To define system configuration sources, use the `"sources"` property of the `"systemConfigurations"` top-level key. The `"sources"` property accepts an array of objects each describing a local or a remote configuration source.

Each source can be assigned a priority. The properties defined in configuration sources with higher priority will override the values of the properties with same names defined in lower priority sources. It's recommended to avoid configurations with same priorities, but if such exist, they will be merged based on the order defined in the `"sources"` array. For instance, if there are two sources with the same priority, the one that's defined last in the array will take precedence.

The defined configuration sources will be merged only after all of them have been retrieved and sorted by priority by the platform. If a configuration source is marked as required and the platform fails to retrieve it, it will throw a system error and won't initialize. If a source isn't marked as required and the platform fails to retrieve it, the event will only be logged and the platform will initialize without applying the settings from that source.

All remote configuration files will be saved in the `%LocalAppData%/interop.io/io.Connect Desktop/UserData/<ENV>-<REG>/configOverrides` folder on Windows and in the `~Library/Application Support/interop.io/io.Connect Desktop/UserData/<ENV>-<REG>/configOverrides` folder on macOS where `<ENV>-<REG>` represents the environment and region of **io.Connect Desktop** (e.g., `DEMO-INTEROP.IO`).

By default, **io.Connect Desktop** uses the local `system.json` file as a configuration source. The following example demonstrates the default configuration source settings for the platform:

```json
{
    "systemConfigurations": {
        "sources": [
            {
                // The platform uses the locally available `system.json` file from the specified source location.
                "type": "path",
                "source": "./config",
                "configs": "*",
                // This default source is usually set with the lowest priority.
                // All your other configuration sources should have higher priority.
                "priority": 1,
                "required": true
            }
        ]
    }
}
```

The following example demonstrates how to define additional local and remote system configuration sources:

```json
{
    "systemConfigurations": {
        // All additional system configurations will be merged with the local `system.json` file based on priority.
        "sources": [
            {
                // The default local configuration source.
                "type": "path",
                "source": "./config",
                "configs": "*",
                "priority": 1,
                "required": true
            },
            {
                // Additional local configuration source.
                "type": "path",
                "source": "%IO_CD_ROOT_DIR%/my-configs",
                "priority": 5,
                // If this source isn't available, the platform will throw a system error and won't initialize.
                "required": true
            },
            {
                // Additional remote configuration source.
                "type": "rest",
                "source": "https://my-remote-store/",
                // This source has higher priority than the local source and the property values defined in it
                // will take precedence when merging all available configurations.
                "priority": 10
            }
        ]
    }
}
```

The `"systemConfigurations"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"sources"` | `object[]` | Array of objects each describing a configuration source from which **io.Connect Desktop** will load system configurations. Multiple sources can be specified and will be merged based on priority. |

Each object in the `"sources"` array has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"configs"` | `string` | Comma-separated list of the names of the configuration files to apply (e.g., `"system, my-custom-file"`). By default, the platform will fetch and apply all available files from the specified source. If you specify one or more file names, the platform will still fetch all available files, but will apply only the specified ones. Defaults to `*`. |
| `"impersonation"` | `object` | Settings for impersonating a user, a user group, and a platform version for which to fetch configurations. The impersonation details are sent in all requests to all defined remote sources. The remote source implementation may use them to determine which version of a configuration file to return as a response. |
| `"priority"` | `number` | The priority of the configuration source. Higher numbers indicate higher priority when merging configurations from multiple sources. Sources with the same priority will be merged based on their order in the `"sources"` array (e.g., if there are two sources with the same priority, the one that's defined last in the array will take precedence). Defaults to `1000`. |
| `"required"` | `boolean` | If `true`, failing to get the resource will be treated as a system error and the platform won't initialize, otherwise the platform will just log the error. Defaults to `false`. |
| `"restBackoffFactor"` | `number` | Exponential backoff factor in milliseconds used for determining the waiting interval between retries when fetching data from the remote store. The waiting interval is calculated with the `<restBackoffFactor>*2^<retry>` formula and is limited to a maximum of 5 minutes between retries. Valid only for remote sources. Defaults to `1000`. |
| `"restRetries"` | `number` | Number of retries for fetching data from the remote store. Valid only for remote sources. Defaults to `3`. |
| `"restTimeout"` | `number` | Interval in seconds to wait for a response from the remote store. Valid only for remote sources. Defaults to `30`. |
| `"restUseCache"` | `boolean` | If `true` (default), will use the local cache as fallback when the remote source is unavailable. Valid only for remote sources. Defaults to `true`. |
| `"source"` | `string` | **Required.** URL or an absolute or a relative file path pointing to the configuration source. You can use [environment variables](https://docs.interop.io/desktop/developers/configuration/overview/index.md#environment_variables). If you are using [**io.Manager**](https://docs.interop.io/manager/overview/index.md) as a remote configuration store, you must provide the specific URL for retrieving system configurations (e.g., `https://my-io-manager/api/systemConfig/get`) |
| `"type"` | `"path"` \| `"rest"` | **Required.** The type of the configuration source. Can be a local or a remote source. |

The `"impersonation"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"group"` | `string` | The user group to impersonate. Defaults to `"*"`. |
| `"user"` | `string` | The user to impersonate. |
| `"version"` | `string` | The platform version to impersonate. |

### Custom Remote Configuration Files

**io.Connect Desktop** will automatically fetch any custom configuration files (e.g., other than the standard `system.json` files) from remote sources (custom REST stores or [**io.Manager**](https://docs.interop.io/manager/overview/index.md)). Your custom configuration files will be saved in the `%LocalAppData%/interop.io/io.Connect Desktop/UserData/<ENV>-<REG>/configOverrides` folder on Windows and in the `~Library/Application Support/interop.io/io.Connect Desktop/UserData/<ENV>-<REG>/configOverrides` folder on macOS where `<ENV>-<REG>` represents the environment and region of **io.Connect Desktop** (e.g., `DEMO-INTEROP.IO`).

> ⚠️ *Note that custom configuration files can only be fetched from remote sources. All custom configuration files from local sources will be ignored by the platform.*

The following example demonstrates a basic configuration for fetching system configurations from a remote source:

```json
{
    "systemConfigurations": {
        "sources": [
            {
                // Custom configuration files can only be fetched from remote sources.
                "type": "rest",
                // If using io.Manager as a configuration store, you must provide the specific URL
                // for retrieving system configurations - e.g., `https://my-io-manager/api/systemConfig/get`.
                "source": "https://my-remote-store/"
            }
        ]
    }
}
```

By default, **io.Connect Desktop** will use all available configuration files fetched from the remote source. You can use the `"configs"` property to specify one or more files to be used by the platform - all other files will be ignored.

The following example demonstrates how to instruct the platform to use a single custom configuration file from the defined remote source and ignore all other available configurations from that source:

```json
{
    "systemConfigurations": {
        "sources": [
            {
                // Custom configuration files can only be fetched from remote sources.
                "type": "rest",
                "source": "https://my-remote-store/",
                "configs": "my-custom-config"
            }
        ]
    }
}
```

### Limitations

Consider the following limitation regarding some of the system configuration properties.

#### Mandatory Locally Defined Properties

The following properties must be defined only locally and must not be overridden by any remote configuration source:

- `"advancedMode"`
- `"allowMultipleInstances"`
- `"alreadyRunningAction"`
- `"env"`
- `"folders"`
- `"logging"`
- `"protocolHandler"`
- `"proxy"`
- `"region"`
- `"registerHtmlContainer"`
- `"splash"`
- `"switches"`
- The following properties of the `"windowManagement"` object:
    - the `"enabled"` property of the `"hardwareAcceleration"` object;

#### Properties with Initial Local Values

The process of retrieving and applying remote configurations is asynchronous. Due to this fact, on startup, the io.Connect platform will take the locally defined (or default) values of the following properties. When the remote configurations are fetched, if any of these properties are present in the remote configuration and are set with different values, the new values will be re-applied at runtime:

- `"spellchecker"`
- The following properties of the `"windows"` object:
    - `"responseHeaders"`
    - `"urlFilter"`

#### Splash Screen

Due to the asynchronous nature of retrieving and applying remote configurations, the splash screen can display only the locally available values of the following properties:

- `"build"`
- `"uiVersion"`

These properties may exist in remote configurations and their remotely defined values will be displayed in all platform UI elements (e.g., the tray menu, the About app), except the splash screen on startup.

## Gilding Configuration

> ⚠️ *Note that this section is relevant only for the **io.Connect Desktop** 9.0 version stream.*

The gilding executable file of **io.Connect Desktop** is designed to enable the platform to fetch remote configurations and perform other initial operations before starting the actual executable and applying the system settings defined in the `system.json` file.

To provide settings for the gilding executable, use the `gilding.json` configuration file.

### Remote Configurations

The configuration of **io.Connect Desktop** can be extended with configuration files hosted on [**io.Manager**](https://docs.interop.io/manager/overview/index.md) or on another REST service. The configurations from the remote location will be fetched on startup of **io.Connect Desktop** and will be merged with the locally available ones. You can also supply different remote configurations for each [environment and region](#environments__regions) in which **io.Connect Desktop** runs.

#### Requirements

The following minimal conditions must be met in order for **io.Connect Desktop** to function properly when extending its configuration with files from a remote location:

- There must be a locally available `system.json` file and the `"region"`, `"env"`, `"folders"`, `"registerHtmlContainer"`, `"switches"`, `"flash"`, `"protocolHandler"`, `"allowMultipleInstances"`, and `"build"` properties must be defined in it. All other properties in the `system.json` file can be defined in a remote location file.

- The `stickywindows.json`, `channels.json`, and `themes.json` files must be present locally at least as empty files. The `logger.json` file must be present locally and must not be empty - there must be some configuration settings present in it.

#### Configuration

To enable **io.Connect Desktop** to fetch configurations from a remote location, use the `"remoteConfig"` top-level key in the `gilding.json` configuration file.

The following example demonstrates how to enable **io.Connect Desktop** to fetch configuration files from [**io.Manager**](https://docs.interop.io/manager/overview/index.md):

```json
{
    "remoteConfig": {
        "enabled": true,
        "url": "https://<URL-to-my-io.Manager>/api/systemConfig/get",
        "wipeFolder": true
    }
}
```

The `"remoteConfig"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"continueOnError"` | `boolean` | If `true`, **io.Connect Desktop** will initialize even if fetching the remote configurations fails. |
| `"enabled"` | `boolean` | If `true`, will enable fetching **io.Connect Desktop** configurations from a remote location. |
| `"fileSuffix"` | `string` | Suffix that will be added to the name of the configuration files - e.g., if set to `"-dev"`, the `system.json` file will be downloaded and saved as `system-dev.json`. |
| `"folder"` | `string` | Location on the local machine where the remote configuration files will be downloaded. You can use the default OS environment variables and the [environment variables](https://docs.interop.io/desktop/developers/configuration/overview/index.md#environment_variables) registered by **io.Connect Desktop** to specify a dynamic path. Defaults to the `%LocalAppData%/interop.io/io.Connect Desktop/UserData/<ENV>-<REG>/configOverrides` folder where `<ENV>-<REG>` represents the environment and region of **io.Connect Desktop** (e.g., `DEMO-INTEROP.IO`). |
| `"impersonation"` | `object` | Object with `"user"` and `"version"` properties that accept strings as values. Use to override the default OS user and **io.Connect Desktop** version for which to fetch configurations. |
| `"insecureSSL"` | `boolean` | If `true`, will allow insecure connections. |
| `"url"` | `string` | URL pointing to [**io.Manager**](https://docs.interop.io/manager/overview/index.md) or to another REST service hosting the configuration files. A `POST` request will be issued to the specified endpoint. |
| `"wipeFolder"` | `boolean` | If `true`, will delete any previously fetched configuration files from the specified folder before downloading. |

The REST endpoint must return data in the following format:

```json
{
    "system.json": {
        // Overriding JSON configuration for the `system.json` file of io.Connect Desktop.
        "contents": { ... }
    },
    "stickywindows.json": {
        // Overriding JSON configuration for the `stickywindows.json` file of io.Connect Desktop.
        "contents": { ... }
    }
}
```

Each top-level key in the returned JSON object represents an **io.Connect Desktop** configuration file to be overridden and accepts an object with the following properties as a value:

| Property | Type | Description |
|----------|------|-------------|
| `"contents"` | `object` | Object containing the overriding JSON for the respective **io.Connect Desktop** file. |

#### Different Environments & Regions

To enable fetching remote configurations per [environment and region](#environments__regions) for **io.Connect Desktop**, you must provide different versions of the `gilding.json` file for each environment and region. This way, each version of the `gilding.json` can have different settings for the `"remoteConfig"` object.

To provide a configuration file for the gilding executable as a command line argument, use the `--gildingConfigFile=<file name>` argument, where `<file name>` must be replaced with the name of your configuration file:

```cmd
io-connect-desktop.exe --gildingConfigFile=gilding-DEV.json
```

You can also create different versions of the `gilding.json` file, named by using the `gilding-<environment>-<region>.json` pattern, where `<environment>` and `<region>` must be replaced with the environment and region in which **io.Connect Desktop** will run. For instance, if a file is named `gilding-DEV-EMEA.json`, the configuration in it will be used when **io.Connect Desktop** is started with the following system settings:

```json
// In `system.json`.
{
    "env": "DEV",
    "region": "EMEA"
}
```

The environment and region specifiers in the file name are case insensitive, so naming your file `gilding-DEV-EMEA.json` is the same as naming it `gilding-dev-emea.json`.

### Custom Environment Variables

The `gilding.json` file allows you to define your own custom environment variables that will be registered by the platform on startup. These variables can be used throughout all other configuration files (e.g., in the system configuration or in [app definitions](https://docs.interop.io/desktop/developers/configuration/application/index.md)).

#### Defining Environment Variables

To define a custom environment variable, use the `"set"` property of the `"envVars"` top-level key in the `gilding.json` file. It accepts an object with key/value pairs holding the names and the values of the environment variables to register.

The following example demonstrates registering environment variables that hold different app URLs for the different [environments and regions](#environments__regions) in which the app will run:

```json
{
    "envVars": {
        "set": {
            "MY_APP_PROD": "https://my-app.com",
            "MY_APP_DEV": "https://dev.my-app.com"
        }
    }
}
```

#### Environment Variables from Remote Configuration Stores

Available since io.Connect Desktop 9.9

To apply environment variables from a [remote configuration store](#gilding_configuration-remote_configurations) or to override any environment variables set in your local gilding configuration, you must define them in an `env.json` file in [**io.Manager**](https://docs.interop.io/manager/overview/index.md) or in your custom REST service:

```json
// In `env.json`.
{
    "set": {
        // These will override any existing environment variables with the same names in your local `gilding.json`.
        // To remove an environment variable, provide an empty string as a value.
		"MY_APP_PROD": "https://my-app.com",
        "MY_APP_DEV": "https://dev.my-app.com",
        "REMOVED_VAR": ""
    }
}
```

## io.Connect Gateway

The configuration settings for the io.Connect Gateway are located under the `"gw"` top-level key in the `system.json` file.

> ℹ️ *For more details on the available configuration properties for the io.Connect Gateway, see the [io.Connect Gateway configuration schema](https://docs.interop.io/desktop/assets/configuration/gw.json).*

### Dynamic Port

The io.Connect Gateway starts on port 8385 by default. In environments where multiple user sessions run on the same machine (e.g., running **io.Connect Desktop** as a Citrix Virtual App), using a predefined port won't work, as the first instance of **io.Connect Desktop** will occupy that port and all other instances won't be able to connect. To avoid this, the io.Connect Gateway can be configured from the `"gw"` top-level key in the `system.json` file to choose dynamically a free port on startup.

To configure the io.Connect Gateway to use a random free port, set the `"port"` property of the `"configuration"` object to `0`:

```json
{
    "gw": {
        "configuration": {
            "port": 0
        }
    }
}
```

### Username Case Sensitivity

Available since io.Connect Desktop 10.1

The io.Connect Gateway treats usernames as case-insensitive by default, allowing clients authenticated with different letter casing (e.g., `"Test"` and `"test"`) to connect and interoperate seamlessly. To instruct the io.Connect Gateway to treat usernames as case-sensitive, go to the authentication configuration settings for the io.Connect Gateway and set the `"usernameCaseSensitive"` property `true`:

```json
{
    "gw": {
        "configuration": {
             "authentication": {
                 "basic": {
                     "usernameCaseSensitive": true
                 }
             }
        }
    }
}
```

### Memory Diagnostics

The io.Connect Gateway can be configured to take heap memory snapshots when the heap memory exceeds a predefined limit. You can also set limits for the maximum client connections to the io.Connect Gateway and a maximum size of messages sent by apps to the io.Connect Gateway. If the maximum message size is exceeded, a warning in the logs will be triggered, which can help you identify the responsible apps. Use the `"memory"` and `"limits"` properties of the `"configuration"` object to specify the desired settings.

The following is an example configuration:

```json
{
    "gw": {
        "configuration": {
            "memory": {
                "report_interval": 300000,
                "max_backups": 5,
                "memory_limit": 1073741824,
                "dump_location": "%IO_CD_USER_DATA_DIR%/heapsnapshots",
                "dump_prefix": "gw"
            },
            "limits": {
                "max_connections": 1000,
                "large_msg_threshold": 524288
            }
        }
    }
}
```

The `"memory"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `dump_locaton` | `string` | Location for dumping the heap memory snapshots. Defaults to `"%IO_CD_USER_DATA_DIR%/heapsnapshots"`. |
| `dump_prefix` | `string` | Prefix for the file containing the heap memory snapshots. Files will be named in the format `<dump_prefix>.<backup_number>.heapsnapshot`. Defaults to `"gw"`. |
| `max_backups` | `number` | Maximum number of heap memory snapshots that will be saved. Defaults to `10`. |
| `memory_limit` | `number` | Limit for the heap memory size that will trigger heap memory snapshot. Defaults to `1073741824` (1GB). |
| `report_interval` | `number` | Interval in milliseconds at which the heap memory size will be checked and logged. Defaults to `300000`. |

The `"limits"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `large_msg_threshold` | `number` | Maximum size in bytes of messages sent to the io.Connect Gateway that, if exceeded, will trigger a warning in the logs. Useful for detecting apps sending excessively large messages causing the io.Connect Gateway to crash. Defaults to `20000`. |
| `max_connections` | `number` | Limit for the number of simultaneous app connections to the io.Connect Gateway. Unlimited by default. |

## Platform Version

Available since io.Connect Desktop 10.0

To specify a custom platform version to be displayed in selected UI elements instead of the default platform version, use the `"uiVersion"` top-level key. The specified version will be used in various UI elements, including the splash screen, the tray menu, the About app, and more:

```json
{
    "uiVersion": "My Custom Version"
}
```

> ⚠️ *Note that this version is for display purposes only and doesn't have to be a valid semantic version string.*

> ℹ️ *For details on how to retrieve the platform version programmatically, see the [Capabilities > More > APIs > Platform Version](https://docs.interop.io/desktop/capabilities/more/apis/index.md#platform_version) section.*

## App Stores

To specify app stores with app definitions, use the `"appStores"` top-level key, which accepts an array of objects defining one or more app stores.

### Local

To configure **io.Connect Desktop** to load app definition files from a local path, set the `"type"` property of the app store configuration object to `"path"` and specify a relative or an absolute path to the app definitions. The environment variables set by **io.Connect Desktop** can also be used as values:

```json
{
    "appStores": [
        {
            "type": "path",
            "details": {
                "path": "./config/apps"
            }
        },
        {
            "type": "path",
            "details": {
                "path": "%IO_CD_USER_DATA_DIR%/apps"
            }
        }
    ]
}
```

Each local path app store object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"appDefinitionOverrides"` | `object` | Valid [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md) properties that will override the ones in all app definitions from the app store. Top-level app definition properties can be specified directly in the `"appDefinitionOverrides"` object. The properties that are found under the `"details"` top-level key for each app definition type must be specified in a top-level object with the same name as the app type - `"window"`, `"exe"`, `"node"`, `"workspaces"`, `"webGroup"`, `"clickonce"`, `"citrix"` or `"childWindow"`. *Available since **io.Connect Desktop** 9.1.* |
| `"details"` | `object` | **Required.** Specific details about the app store. |
| `"isRequired"` | `boolean` | If `true` (default), the app store will be required. If the app store can't be retrieved, **io.Connect Desktop** will throw an error and shut down. If `false`, **io.Connect Desktop** will initiate normally, without apps from that store. |
| `"type"` | `string` | **Required.** Type of the app store. Must be set to `"path"` for local path app stores. |

The `"details"` object for a local path app store has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"path"` | `string` | **Required.** Must point to the local app store. The specified path can be absolute or relative and you can use defined environment variables. |
| `"trusted"` | `boolean` | If `true`, the app store will be trusted by the platform and the [security settings](https://docs.interop.io/desktop/getting-started/security/index.md) specified in the app definitions won't be overridden by the security settings specified in the system configuration. Defaults to `false`. *Available since **io.Connect Desktop** 9.10.1 & 10.0.3.* |

### REST

App definitions can also be obtained from remote app stores via a REST service.

To configure a connection to the REST service providing the remote app store, add a new entry to the `"appStores"` top-level key and set its `"type"` property to `"rest"`:

```json
{
    "appStores": [
        {
            "type": "rest",
            "details": {
                "url": "https://my-rest-service/apps",
                "auth": "no-auth",
                "pollInterval": 30000,
                "enablePersistentCache": true,
                "cacheFolder": "%LocalAppData%/interop.io/io.Connect Desktop/UserData/%IO_CD_ENV%-%IO_CD_REGION%/configCache/"
            },
            "appDefinitionOverrides": {
                // Overrides for some top-level app definition properties.
                "ignoreSavedLayout": true,
                "allowMultiple": false,
                // Overrides for the properties under the `"details"` top-level key in apps of type `"window"`.
                "window": {
                    "autoInjectAPI": {
                        "enabled": true,
                        "autoInit": {
                            "channels": true
                        }
                    }
                }
            }
        }
    ]
}
```

Each remote app store object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"appDefinitionOverrides"` | `object` | Valid [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md) properties that will override the ones in all app definitions from the app store. Top-level app definition properties can be specified directly in the `"appDefinitionOverrides"` object. The properties that are found under the `"details"` top-level key for each app definition type must be specified in a top-level object with the same name as the app type - `"window"`, `"exe"`, `"node"`, `"workspaces"`, `"webGroup"`, `"clickonce"`, `"citrix"` or `"childWindow"`. *Available since **io.Connect Desktop** 9.1.* |
| `"details"` | `object` | **Required.** Specific details about the app store. |
| `"isRequired"` | `boolean` | If `true` (default), the app store will be required. If the app store can't be retrieved, **io.Connect Desktop** will throw an error and shut down. If `false`, **io.Connect Desktop** will initiate normally, without apps from that store. |
| `"type"` | `string` | **Required.** Type of the app store. Must be set to `"rest"` for remote app stores. |

The `"details"` object for a remote app store has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"auth"` | `string` | Authentication configuration. Can be one of `"no-auth"` (default), `"negotiate"` or `"kerberos"`. |
| `"cacheFolder"` | `string` | Location to keep the persisted configuration files. |
| `"enablePersistentCache"` | `boolean` | If `true` (default), will cache and persist the configuration files locally (e.g., in case of connection interruptions). |
| `"pollInterval"` | `number` | Interval in milliseconds at which to poll the REST service for updates. Default is `60000`. |
| `"proxy"` | `string` | HTTP proxy to use when fetching data. |
| `"readCacheAfter"` | `number` | Interval in milliseconds after which to try to read the cache. Default is `30000`. |
| `"rejectUnauthorized"` | `boolean` | If `true` (default), SSL validation will be enabled for the REST server. |
| `"requestTimeout"` | `number` | Timeout in milliseconds to wait for a response from the REST server. Default is `20000`. |
| `"startRetries"` | `number` | Number of times **io.Connect Desktop** will try to connect to the REST server. Default is `5`. |
| `"startRetryInterval"` | `number` | Interval in milliseconds at which **io.Connect Desktop** will try to connect to the REST server. Default is `10000`. |
| `"trusted"` | `boolean` | If `true`, the app store will be trusted by the platform and the [security settings](https://docs.interop.io/desktop/getting-started/security/index.md) specified in the app definitions won't be overridden by the security settings specified in the system configuration. Defaults to `false`. *Available since **io.Connect Desktop** 9.10.1 & 10.0.3.* |
| `"url"` | `string` | **Required.** The URL to the REST service providing the app definitions. |

The remote store must return app definitions in the following response shape:

```json
{
    "applications": [
        // List of app definition objects.
        {}, {}
    ]
}
```

> ℹ️ *For details on working with remote app stores compliant with FDC3 App Directory standards, see the [FDC3 Compliance](https://docs.interop.io/desktop/getting-started/fdc3-compliance/index.md#app_directory) section and the [FDC3 App Directory](https://fdc3.finos.org/docs/app-directory/overview) documentation.*

> ℹ️ *For a reference implementation of a remote app definitions store, see the [Node.js REST Config](https://github.com/InteropIO/rest-config-example-node-js) example.*

### io.Manager

You can also use [**io.Manager**](https://docs.interop.io/manager/overview/index.md) for hosting and retrieving app stores.

To configure **io.Connect Desktop** to fetch app definitions from **io.Manager**, set the `"type"` property of the app store configuration object to `"server"`:

```json
{
    "appStores": [
        {
            "type": "server"
        }
    ]
}
```

The server app store object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"appDefinitionOverrides"` | `object` | Valid [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md) properties that will override the ones in all app definitions from the app store. Top-level app definition properties can be specified directly in the `"appDefinitionOverrides"` object. The properties that are found under the `"details"` top-level key for each app definition type must be specified in a top-level object with the same name as the app type - `"window"`, `"exe"`, `"node"`, `"workspaces"`, `"webGroup"`, `"clickonce"`, `"citrix"` or `"childWindow"`. *Available since **io.Connect Desktop** 9.1.* |
| `"isRequired"` | `boolean` | If `true` (default), the app store will be required. If the app store can't be retrieved, **io.Connect Desktop** will throw an error and shut down. If `false`, **io.Connect Desktop** will initiate normally, without apps from that store. |
| `"type"` | `string` | **Required.** Type of the app store. Must be set to `"server"` for app stores retrieved from [**io.Manager**](https://docs.interop.io/manager/overview/index.md). |

If you are using only **io.Manager** for retrieving app definitions, you can set the `"appStores"` key to an empty array. **io.Connect Desktop** will automatically try to connect to **io.Manager** using the provided configuration and will retrieve the app definitions from it.

> ℹ️ *For details on how to configure **io.Connect Desktop** to connect to **io.Manager**, see the [io.Manager](https://docs.interop.io/desktop/capabilities/manager/index.md) section.*

### In-Memory

Available since io.Connect Desktop 10.0

The in-memory app store of **io.Connect Desktop** is disabled by default. To enable and configure the in-memory app store, add a new entry to the `"appStores"` top-level key and set its `"type"` property to `"in-memory"`:

```json
{
    "appStores": [
        {
            "type": "in-memory",
            "details": {
                "allowedApps": ["my-app", "my-other-app"]
            }
        }
    ]
}
```

The in-memory app store object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"appDefinitionOverrides"` | `object` | Valid [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md) properties that will override the ones in all app definitions from the app store. Top-level app definition properties can be specified directly in the `"appDefinitionOverrides"` object. The properties that are found under the `"details"` top-level key for each app definition type must be specified in a top-level object with the same name as the app type - `"window"`, `"exe"`, `"node"`, `"workspaces"`, `"webGroup"`, `"clickonce"`, `"citrix"` or `"childWindow"`. |
| `"details"` | `object` | Specific details about the app store. |
| `"isRequired"` | `boolean` | If `true` (default), the app store will be required. If the app store can't be retrieved, **io.Connect Desktop** will throw an error and shut down. If `false`, **io.Connect Desktop** will initiate normally, without apps from that store. |
| `"type"` | `string` | **Required.** Type of the app store. Must be set to `"in-memory"` for the in-memory app store. |

The `"details"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"allowedApps"` | `string[]` | List of app names, as defined in the io.Connect framework, that will be allowed to use the in-memory app store. Provide `"*"` as a value to allow all apps to use the in-memory store (e.g., `["*"]`). Defaults to `["*"]` |

## System App Stores

Besides the regular app stores that usually contain definitions for end user apps, you can define system app stores for critical apps that must be auto started with the platform. The system stores aren't monitored for changes and can be only of type `"path"` and `"rest"`. To define a system app store, use the `"systemAppStores"` top-level key, which accepts an array of objects defining one or more system app stores.

The following example demonstrates how to configure a local system app store:

```json
{
    "systemAppStores": [
        {
            "type": "path",
            "details": {
                "path": "./config/system-apps"
            }
        }
    ]
}
```

> ℹ️ *For details on how to set the priority of system apps, see the [Configuration > Application > Boot Sequence](https://docs.interop.io/desktop/developers/configuration/application/index.md#boot_sequence) section.*

## Layouts

To provide settings for handling Layouts in **io.Connect Desktop**, use the `"layouts"` top-level key.

The `"layouts"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"components"` | `object` | Settings for instructing the io.Connect platform how to process the Layout components. *Available since **io.Connect Desktop** 9.9.4.* |
| `"restoreDefaultGlobalOnStartup"` | `boolean` | If `true` (default), the default Global Layout (if any) will be restored on startup of **io.Connect Desktop**. |
| `"splash"` | `object` | Settings for the loading animation displayed when restoring a Layout. |
| `"store"` | `object` | Settings for the Layout store. |

The `"splash"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"disabled"` | `boolean` | If `true`, the Layout loader will be disabled. |
| `"height"` | `number` | Height in pixels for the Layout loader. |
| `"title"` | `string` | Title for the Layout loader. |
| `"url"` | `string` | URL pointing to the location of the Layout loader. You can use [environment variables](https://docs.interop.io/desktop/developers/configuration/overview/index.md#environment_variables). Defaults to `"file:///%IO_CD_ASSETS_DIR%/loader/index.html"`. |
| `"width"` | `number` | Width in pixels for the Layout loader. |

The `"store"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"rejectUnauthorized"` | `boolean` | If `true` (default), SSL validation will be enabled for the REST server. Valid only in `"rest"` mode. |
| `"restClientAuth"` | `"no-auth"` \| `"negotiate"` \| `"kerberos"` | Authentication configuration. Defaults to `"negotiate"`. Valid only in `"rest"` mode. |
| `"restFetchInterval"` | `number` | Interval in seconds at which to poll the REST service for updates. Default is `60`. Valid only in `"rest"` mode. |
| `"restURL"` | `string` | URL pointing to the Layout store. Valid only in `"rest"` mode. |
| `"type"` | `"file"` \| `"rest"` \| `"server"` | Type of the Layout store. Set to `"file"` (default) to read Layouts from a local file. Set to `"rest"` to fetch Layouts from a REST service. Set to `"server"` to fetch Layouts from **io.Manager**. |

Available since io.Connect Desktop 9.9.4

The `"components"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"maxSize"` | `number` | Maximum allowed size (width or height) in pixels for a Layout component. If this is set, the framework will check the sizes of all Layout components when restoring a Layout and if either the width or the height of the component exceeds the specified value, the component will be resized to the size of the screen on which it is being restored. This setting can be used as a safeguard against platform crashes in cases where a Layout component may be saved on a high-resolution monitor and the user then attempts to restore it on a low-resolution one due to changes in their monitor setup. Defaults to `8192`. |

### Stores

To specify a Layout store with Layout definitions, use the `"store"` property of the `"layouts"` top-level key.

#### Local

By default, the Layouts are saved to and loaded from a local Layout store located in the `<installation_location>/interop.io/io.Connect Desktop/UserData/<ENV>-<REG>/layouts` folder where `<ENV>-<REG>` represents the environment and region of **io.Connect Desktop** (e.g., `DEMO-INTEROP.IO`). There you can store, customize and delete your Layout files locally.

To instruct **io.Connect Desktop** to manage Layouts as local files, set the `"type"` property of the `"store"` object to `"file"`:

```json
{
    "layouts" : {
        "store": {
            "type": "file"
        }
    }
}
```

#### REST

To configure a connection to the REST service providing the Layout store, set the `"type"` property of the `"store"` object to `"rest"`:

```json
{
    "layouts": {
        "store": {
            "type": "rest",
            "restURL": "https://my-rest-service/layouts",
            "restFetchInterval": 20,
            "restClientAuth": "no-auth"
        }
    }
}
```

The remote store must return Layout definitions in the following response shape:

```json
{
    "layouts": [
        // List of Layout definition objects.
        {}, {}
    ]
}
```

> ℹ️ *For a reference implementation of a remote Layout definitions store, see the [Node.js REST Config](https://github.com/InteropIO/rest-config-example-node-js) example.*

#### io.Manager

To configure **io.Connect Desktop** to fetch Layouts from [**io.Manager**](https://docs.interop.io/manager/overview/index.md), set the `"type"` property of the `"store"` object to `"server"`:

```json
{
    "layouts" : {
        "store": {
            "type": "server"
        }
    }
}
```

> ℹ️ *For details on how to configure **io.Connect Desktop** to connect to **io.Manager**, see the [io.Manager](https://docs.interop.io/desktop/capabilities/manager/index.md) section.*

> ⚠️ *Note that when using **io.Manager** as a Layout store, Layout files aren't only fetched from the server, but are also saved on the server (e.g., when the user edits and saves an existing Layout).*

### Default Global Layout

To disable automatic restore of the [default Global Layout](https://docs.interop.io/desktop/capabilities/windows/layouts/overview/index.md#default_global_layout), set the `"restoreDefaultGlobalOnStartup"` property to `false`:

```json
{
    "layouts": {
        "restoreDefaultGlobalOnStartup": false
    }
}
```

### Loader

The default loader for Global Layouts is an HTML file located in the `<installation_location>/interop.io/io.Connect Desktop/Desktop/assets/loader` folder which you can replace with your own custom one or edit it directly.

To customize the Layout loader, use the `"splash"` property of the `"layouts"` top-level key.

The following example demonstrates how to provide a custom loader and settings for it:

```json
{
    "layouts": {
        "splash": {
            "url": "https://example.com/my-custom-loader/index.html",
            "title": "My Custom Loader",
            "width": 500,
            "height": 300
        }
    }
}
```

## App Preferences Store

App preferences can be stored locally in a file or remotely by using a REST service or [**io.Manager**](https://docs.interop.io/manager/overview/index.md).

To define a location for storing app preferences, use the `"store"` property of the `"applicationPreferences"` top-level key.

The `"store"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"newDataCheckInterval"` | `number` | Interval in seconds at which to check for new data from the REST store. Executed only if subscribers are available. Valid only in `"rest"` mode. Defaults to `1800`. |
| `"restBackoffFactor"` | `number` | Exponential backoff factor in milliseconds used for determining the waiting interval between retries when fetching data from the REST store. The waiting interval is calculated with the `<restBackoffFactor>*2^<retry>` formula and is limited to a maximum of 5 minutes between retries. Valid only in `"rest"` mode. Defaults to `1000`. *Available since **io.Connect Desktop** 9.10.* |
| `"restClientAuth"` | `"no-auth"` \| `"negotiate"` \| `"kerberos"` | Authentication configuration. Valid only in `"rest"` mode. |
| `"restRetries"` | `number` | Number of retries when fetching data from the REST store. Valid only in `"rest"` mode. Defaults to `3`. *Available since **io.Connect Desktop** 9.10.* |
| `"restURL"` | `string` | URL pointing to the app preferences store. Valid only in `"rest"` mode. Required if `"type"` is set to `"rest"`. |
| `"type"` | `"file"` \| `"rest"` \| `"server"` | The type of the app preferences store. Set to `"file"` (default) to store and read app preferences from a local file. Set to `"rest"` to store and fetch app preferences from a REST service. Set to `"server"` to store and fetch app preferences from **io.Manager**. |

### Local

By default, app preferences are stored locally in the `<installation_location>/interop.io/io.Connect Desktop/UserData/<ENV>-<REG>/prefs` folder where `<ENV>-<REG>` represents the environment and region of **io.Connect Desktop** (e.g., `DEMO-INTEROP.IO`).

To instruct **io.Connect Desktop** to store app preferences in a local file, set the `"type"` property of the `"store"` object to `"file"`:

```json
{
    "applicationPreferences" : {
        "store": {
            "type": "file"
        }
    }
}
```

### REST

App preferences can also be obtained from remote app preferences stores via a REST service.

> ℹ️ *For a reference implementation of a remote app preferences store, see the [Node.js REST Config](https://github.com/InteropIO/rest-config-example-node-js) example.*

To configure a connection to the REST service providing the app preferences store, set the `"type"` property of the `"store"` object to `"rest"` and provide the URL of the REST service:

```json
{
    "applicationPreferences": {
        "store": {
            "type": "rest",
            "restURL": "https://my-rest-service.com/app-preferences",
            "restClientAuth": "no-auth",
            "newDataCheckInterval": 2000
        }
    }
}
```

The remote store must return an [`AppPreferences`](https://docs.interop.io/desktop/reference/javascript/app%20preferences/apppreferences/index.md) object as a response.

### io.Manager

You can also use [**io.Manager**](https://docs.interop.io/manager/overview/index.md) for hosting and retrieving app preferences.

To configure **io.Connect Desktop** to fetch app preferences from **io.Manager**, set the `"type"` property of the `"store"` object to `"server"`:

```json
{
    "applicationPreferences" : {
        "store": {
            "type": "server"
        }
    }
}
```

> ℹ️ *For details on how to configure **io.Connect Desktop** to connect to **io.Manager**, see the [io.Manager](https://docs.interop.io/desktop/capabilities/manager/index.md) section.*

## Multiple Instances

To control running multiple instances of **io.Connect Desktop**, use the `"allowMultipleInstances"` top-level key.

The following example demonstrates how to prevent users from running multiple instances of **io.Connect Desktop**:

```json
{
    "allowMultipleInstances": "never"
}
```

The `"allowMultipleInstances"` property accepts the following values:

| Value | Description |
|-------|-------------|
| `"inDifferentEnvRegion"` | Default. Allows running multiple instances only in different [environments and regions](#environments__regions). |
| `"never"` | Disables running multiple instances. |

## Environments & Regions

**io.Connect Desktop** allows running it in different environments and regions. Environments usually include development, testing, quality assurance, production environments, and others, in which **io.Connect Desktop** is tested or integrated. Regions can be any semantic groups - geographic regions, user groups, product categories, and more, defined by the client adopting **io.Connect Desktop**.

To enable **io.Connect Desktop** to run in different environments and regions, you must:

- create a separate [system configuration file](#environments__regions-system_configuration_files) for each environment and region combination. You can use the `system.json` file of **io.Connect Desktop** as a base system configuration template, common for all environments and regions;

- create different [shortcuts](#environments__regions-shortcuts) pointing to the **io.Connect Desktop** executable file for each environment and region, and set command line arguments specifying the respective environment and region configuration file that will be merged with the base system configuration file;

### System Configuration Files

To set different environments and regions in which to run **io.Connect Desktop**, use the `system.json` configuration file of **io.Connect Desktop** as a common configuration. Create separate system configuration files for all environments and regions and in each one define only the settings specific for the environment and region. When you start **io.Connect Desktop** in a certain environment and region, the respective configuration file will be merged with the base `system.json` file, overriding the settings in it.

> ⚠️ *Note that it's important to either specify a different port for the io.Connect Gateway for each environment and region, or to use a [Dynamic Gateway Port](#ioconnect_gateway-dynamic_port) by setting the io.Connect Gateway port to `0` in the base system configuration file. Otherwise, you won't be able to run [multiple instances](#multiple_instances) of **io.Connect Desktop** simultaneously in different environments and regions, as the first started instance will occupy the specified port and the other instances won't be able to connect.*

The following example demonstrates creating a system configuration file for a `"PROD"` environment and an `"EMEA"` region, named `system-PROD-EMEA.json`. The port for the io.Connect Gateway isn't specified, as it's set to `0` in the common system configuration file. The only setting that will be overridden is for the [app stores](#app_stores) under the `"appStores"` top-level key:

```json
// system-PROD-EMEA.json
{
    "env": "PROD",
    "region": "EMEA",
    "appStores": [
        {
            "type": "rest",
            "details": {
                "url": "https://my-domain.com/my-app-store",
                "auth": "no-auth",
                "pollInterval": 30000,
                "enablePersistentCache": true,
                "cacheFolder": "%LocalAppData%/interop.io/io.Connect Desktop/UserData/%IO_CD_ENV%-%IO_CD_REGION%/configCache/"
            }
        }
    ]
}
```

Keep in mind that by default **io.Connect Desktop** is configured to create sub-folders for each environment and region in the `UserData` and `Cache` folders by using the `%IO_CD_ENV%` and `%IO_CD_REGION%` environment variables:

```json
{
    "folders": {
        "userData": "%LocalAppData%/interop.io/io.Connect Desktop/UserData/%IO_CD_ENV%-%IO_CD_REGION%/",
        "cache": "%LocalAppData%/interop.io/io.Connect Desktop/Cache/%IO_CD_ENV%-%IO_CD_REGION%/"
    }
}
```

This means that the information stored in these folders by default will be separated per environment and region. To avoid overwriting data in case you decide to change the locations of the `/UserData` and `/Cache` folders in your base configuration, either use the `%IO_CD_ENV%` and `%IO_CD_REGION%` environment variables to create sub-folders for each environment and region, or make sure that each environment and region configuration file specifies different locations for these folders.

### Shortcuts

It's possible to create any number of shortcuts to **io.Connect Desktop**, which will allow you to launch it with custom configuration according to your requirements. The entry point executable is found in `<installation_location>/interop.io/io.Connect Desktop/Desktop/io-connect-desktop.exe`. Running it without arguments will use the default configuration in the `system.json` file of **io.Connect Desktop**. To override the base configuration with the specific configuration for an environment and region, use the following template to provide command line arguments for each shortcut:

```cmd
io-connect-desktop.exe [optional Electron arguments] -- config=<base-config-file> configOverrides config0=<custom-config-override> config1=...
```

Substitute `<base-config-file>` with the location of your base configuration file (usually `config/system.json`), and `<custom-config-override>` with the location of your configuration override file. It's possible to supply more than one configuration override files.

The following example demonstrates how to use the `system.json` file as a base configuration for **io.Connect Desktop** and override it with a file named `system-PROD-EMEA.json` and also placed in the `<installation_location>/interop.io/io.Connect Desktop/Desktop/config` folder:

```cmd
io-connect-desktop.exe -- config=config/system.json configOverrides config0=config/system-PROD-EMEA.json
```

> ⚠️ *Note that to specify command line arguments when using a shortcut to the **io.Connect Desktop** executable file, you must right click on the shortcut, select the "Properties" menu option, go to the "Target" field and add the arguments after the name of the executable file. Note the space before and after the double dash.*

## Splash Screen

To [customize the splash screen](https://docs.interop.io/desktop/getting-started/how-to/rebrand-io-connect/user-interface/index.md#splash_screen) of **io.Connect Desktop**, use the `"splash"` top-level key.

The following example demonstrates how to provide a custom splash screen and settings for it:

```json
{
    "splash": {
        "disabled": false,
        "url": "file:///my-assets/custom/splash.html",
        "width": 350,
        "height": 233,
        "blockStartup": true
    }
}
```

The `"splash"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"alwaysOnTop"` | `boolean` | If `true`, the splash screen will always be on top of other windows. *Available since **io.Connect Desktop** 9.5.* |
| `"blockStartup"` | `boolean` | If `true` (default), will block startup until the splash screen has loaded. |
| `"disabled"` | `boolean` | If `true`, the splash screen will be disabled. |
| `"height"` | `number` | Height in pixels for the splash screen. Defaults to `233`. |
| `"showInTaskbar"` | `boolean` | If `true` (default), the splash screen icon will be shown in the Windows taskbar. *Available since **io.Connect Desktop** 9.7.* |
| `"showOnShutdown"` | `boolean` | If `true` (default), will show the splash screen when **io.Connect Desktop** is shutting down. |
| `"timeout"` | `number` | Interval in milliseconds to wait for the splash screen to load. Defaults to `5000`. |
| `"transparent"` | `boolean` | If `true` (default), the splash screen background will become transparent. |
| `"url"` | `string` | URL pointing to the location of the splash screen. You can use [environment variables](https://docs.interop.io/desktop/developers/configuration/overview/index.md#environment_variables). Defaults to `"file:///%IO_CD_ASSETS_DIR%/splash/splash.html"`. |
| `"width"` | `number` | Width in pixels for the splash screen. Defaults to `350`. |

## Tray Menu

To configure the tray menu of **io.Connect Desktop**, use the `"tray"` top-level key.

The `"tray"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"about"` | `boolean` | If `true` (default), will show the "About" item for opening the About app. |
| `"applications"` | `boolean` | If `true` (default), will show the "Application" item for starting the Applications app. |
| `"diagnostic"` | `boolean` | If `true` (default), will show the "Diagnostic" item containing various diagnostics actions and settings. |
| `"enabled"` | `boolean` | If `true` (default), will enable the tray menu. |
| `"exit"` | `boolean` | If `true` (default), will show the "Exit" item for shutting down **io.Connect Desktop**. |
| `"feedback"` | `boolean` | If `true` (default), will show the "Feedback" item for opening the Feedback Form. |
| `"hotkeys"` | `boolean` | If `true` (default), will show the "Hotkeys" item for opening the Hotkeys table. |
| `"info"` | `boolean` | If `true` (default), will show the section providing information about the product. |
| `"notifications"` | `boolean` | If `true`, will show the "Notifications" item for opening the Notification Panel when there are active notifications. Defaults to `false`. |
| `"open"` | `boolean` | If `true` (default), will show the "Open" item for starting the Open app. |
| `"restart"` | `boolean` | If `true` (default), will show the "Restart" item for restarting **io.Connect Desktop**. |
| `"themes"` | `boolean` | If `true` (default), will show the "Themes" item for switching the themes. |

## Channels

Available since io.Connect Desktop 10.0

To define any number of default system Channels in **io.Connect Desktop** to be used by your apps, use the `"channels"` top-level key.

The following example demonstrates adding a custom black Channel to the already existing default list of Channels:

```json
{
    "channels": {
        "definitions": [
            // Other default Channel definitions.
            {...}, {...},
            // Custom Channel definition.
            {
                "name": "Black",
                "meta": {
                    "color": "black"
                }
            }
        ]
    }
}
```

![Custom Channel](https://docs.interop.io/desktop/images/channels/custom-channel.mp4)

The `"channels"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true` (default), the io.Connect Channels defined here will be available as system Channels to all interop-enabled apps. |
| `"definitions"` | `object[]` | Array of Channel definition objects describing the default system Channels. You can define as many Channels as you need. |

Each object in the `"definitions"` array has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"meta"` | `object` | **Required.** Metadata associated with the Channel. This object may contain any data related to the respective Channel. |
| `"name"` | `object` | **Required.** Unique name for the io.Connect Channel. |

The `"meta"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"color"` | `string` | **Required.** The Channel color displayed on the Channel Selector UI and on each app using that Channel. Can be either an HTML color name or a hexadecimal color code. |

> ℹ️ *For details on using Channels in FDC3 apps, see the [FDC3 Compliance > Channels](https://docs.interop.io/desktop/getting-started/fdc3-compliance/index.md#channels) section.*

## Notifications

To specify global notification settings, use the `"notifications"` top-level key.

The following is an example configuration for notifications:

```json
{
    "notifications": {
        "enabled": true,
        "enableToasts": true,
        "sourceFilter": {
            "allowed": ["*"]
        },
        "toastExpiry": 15000
    }
}
```

The `"notifications"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"closeNotificationOnClick"` | `boolean` | If `true`, when the user clicks on the body of a notification in the Notification Panel, the notification will be removed from the list. Set to `false` if you want users to be able to click on the notification body (e.g., to copy text) without the notification disappearing from the Notification Panel. *Available since **io.Connect Desktop** 9.6.* |
| `"enabled"` | `boolean` | If `true` (default), will enable all notifications - notification toasts and notifications in the Notification Panel. |
| `"enableToasts"` | `boolean` | If `true` (default), will enable notification toasts. |
| `"placement"` | `object` | Placement settings for the Notification Panel and the notification toasts. *Available since **io.Connect Desktop** 9.2.* |
| `"showNotificationBadge"` | `boolean` | If `true`, will enable showing a notification badge on the tray menu icon, in the "Notifications" section of the io.Connect launcher, and on the shell app icon in the Windows taskbar (or the Dock on macOS). *Available since **io.Connect Desktop** 9.4.* |
| `"snooze"` | `object` | Settings for snoozing notifications. *Available since **io.Connect Desktop** 9.3.* |
| `"sourceFilter"` | `object` | Filter with names of apps that are allowed or not allowed to raise notifications. |
| `"toastExpiry"` | `number` | Interval in milliseconds after which the notification toasts will be hidden. Defaults to `15000`. |
| `"toasts"` | `object` | Settings for the notification toasts. |

The `"snooze"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"duration"` | `number` | Interval in milliseconds for which the notifications will be snoozed. Defaults to `60000`. |
| `"enabled"` | `boolean` | If `true`, will enable snoozing notifications. Defaults to `false`. |

The `"placement"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"panel"` | `"left"` \| `"right"` | Sets the position of the Notification Panel on the screen - left or right. Defaults to `"right"`. |
| `"toasts"` | `"top-left"` \| `"top-right"` \| `"bottom-left"` \| `"bottom-right"` | Sets the position of the notification toasts on the screen - top right, top left, bottom right or bottom left. Defaults to `"bottom-right"`. |

The `"sourceFilter"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"allowed"` | `string[]` | Names of apps allowed to raise notifications. Defaults to `"*"`. |
| `"blocked"` | `string[]` | Names of apps not allowed to raise notifications. |

The `"toasts"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"mode"` | `"single"` \| `"stacked"` | Mode for the notification toasts. Notification toasts can appear individually, or can be stacked together based on a criterion (severity or app that has raised the notification). Defaults to `"single"`. |
| `"stackBy"` | `"severity"` \| `"application"` | Criterion for stacking the notification toasts. Defaults to `"severity"`. |

## Alerts

Available since io.Connect Desktop 9.9

To configure the io.Connect [alerts](https://docs.interop.io/desktop/capabilities/windows/modals/overview/index.md), use the `"alerts"` top-level key.

```json
{
    "alerts": {
        "enabled": true,
        "width": 450,
        "height": 100,
        "ttl": 7000,
        "roundedCorners": true
    }
}
```

The `"alerts"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true` (default), will enable the io.Connect alerts. |
| `"height"` | `number` | Height in pixels for the io.Connect alerts. Defaults to `82`. |
| `"roundedCorners"` | `boolean` | If `true`, the io.Connect Window containing the alerts will have rounded corners. Defaults to `false`. |
| `"transparent"` | `boolean` | If `true` (default), the io.Connect Window containing the alerts will be transparent. |
| `"ttl"` | `number` | Interval in milliseconds that defines how long the alert is displayed to the user before it automatically disappears. Defaults to `5000`. |
| `"url"` | `string` | URL pointing to the location of the io.Connect alerts app. You can use this to provide a URL pointing to your custom alerts app. |
| `"width"` | `number` | Width in pixels for the io.Connect alerts. Defaults to `400`. |

## Dialogs

To configure the io.Connect [dialogs](https://docs.interop.io/desktop/capabilities/windows/modals/overview/index.md), use the `"dialogs"` top-level key.

The following example demonstrates how to provide a URL for a custom dialog app, set default dialog size, and disable the default dialogs for preventing shut down and window close:

```json
{
    "dialogs": {
        "url": "https://my-custom-dialog.com",
        "width": 380,
        "height": 150,
        "enableDefaultDialogs": {
            "preventShutdown": false,
            "preventWindowClose": false
        }
    }
}
```

The `"dialogs"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enableDefaultDialogs"` | `object` | Enable or disable the default io.Connect dialog messages. |
| `"height"` | `number` | Height in pixels for the io.Connect dialogs. Defaults to `205`. |
| `"transparent"` | `boolean` | If `true`, the io.Connect Window containing the dialog will be transparent. |
| `"url"` | `string` | URL pointing to the location of the io.Connect dialog app. |
| `"width"` | `number` | Width in pixels for the io.Connect dialogs. Defaults to `400`. |

The `"enableDefaultDialogs"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"preventShutdown"` | `boolean` | If `true` (default), will enable the dialog message that appears when **io.Connect Desktop** is about to shutdown. |
| `"preventWindowClose"` | `boolean` | If `true` (default), will enable the dialog message that appears when the user tries to close an io.Connect Window that is programmatically prevented from closing. This dialog will appear also when such window participates in a Layout that is being closed. |
| `"unsavedLayoutChanges"` | `boolean` | If `true`, will enable the dialog message that appears when the user modifies the current [Global Layout](https://docs.interop.io/desktop/capabilities/windows/layouts/overview/index.md) and tries to restore another Global Layout. Defaults to `false`. *Available since **io.Connect Desktop** 9.2.* |

> ℹ️ *For details on using the io.Connect dialogs programmatically, see the [Capabilities > Windows > Modals](https://docs.interop.io/desktop/capabilities/windows/modals/javascript/index.md#dialogs) and the [Capabilities > Windows > Window Management](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-dialogs) sections.*

## Default Search Provider

**io.Connect Desktop** has a built-in search provider that returns search results for apps, Workspaces, Layouts, and [actions](https://docs.interop.io/desktop/capabilities/search/overview/index.md#global_search_app-actions). To disable it, or to modify the search types for which it will provide results, use the `"searchProvider"` top-level key:

The following example demonstrates how to configure the default search provider to return search results only for Workspaces and Layouts:

```json
{
    "searchProvider": {
        "enabled": true,
        "types": ["workspace", "layout"]
    }
}
```

The `"searchProvider"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true` (default), will enable the default search provider of **io.Connect Desktop**. |
| `"types"` | `string[]` | Predefined search types for which the provider will return results. The possible values you can use in the array are `"application"`, `"layout"`, `"workspace"`, and `"action"`. Defaults to `["application", "layout", "workspace", "action"]`. |

## Interception

Available since io.Connect Desktop 9.6

To enable your apps to register [interception](https://docs.interop.io/desktop/capabilities/interception/overview/index.md) handlers, use the `"interception"` top-level key.

The following example demonstrates how to enable interception for all apps:

```json
{
    "interception": {
        "enabled": true
    }
}
```

The `"interception"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"applications"` | `string[]` | List of names of the apps that will be allowed to register interception handlers. |
| `"enabled"` | `boolean` | If `true`, will enable intercepting platform operations. Defaults to `false`. |

To allow only specific apps to register interception handlers, use the `"applications"` property and provide the names of the apps as specified in their respective [app definitions](https://docs.interop.io/desktop/developers/configuration/application/index.md):

```json
{
    "interception": {
        "enabled": true,
        "applications": ["my-app", "my-other-app"]
    }
}
```

## Spellchecker

Available since io.Connect Desktop 9.6

**io.Connect Desktop** utilizes the built-in [Electron spellchecker](https://www.electronjs.org/docs/latest/tutorial/spellchecker) which is enabled by default. To provide settings for the spellchecker, use the `"spellchecker"` top-level key:

```json
{
    "spellchecker": {
        "enabled": true,
        "languages": ["en-US", "fr"],
        "dictionaryDownloadURL": "https://example.com/dictionaries"
    }
}
```

The `"spellchecker"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"dictionaryDownloadURL"` | `string` | URL pointing to a location from where to download the dictionaries for the built-in Electron spellchecker. By default, the dictionaries are downloaded from a Chromium CDN. |
| `"enabled"` | `boolean` | If `true` (default), will enable the built-in Electron spellchecker. |
| `"languages"` | `string[]` | List of language codes for the built-in Electron spellchecker (e.g., `["en-US", "fr"]`). |

## App Settings

### Title Format

To set a format for the titles of app instances, use the `"titleFormat"` property of the `"applications"` top-level key. The supported macros are `{title}` and `{instanceIndex}`. The `{title}` macro will be substituted with the title set in the app definition and the `{instanceIndex}` macro will be substituted with the consecutive number of the started app instance which is incremented for each new app instance starting from `1`. If all instances are closed, the counter is reset. If some instances are closed while others are still running, the counter will continue to increment accordingly:

```json
{
    "applications": {
        "titleFormat": "{title} ({instanceIndex})"
    }
}
```

![Title format](https://docs.interop.io/desktop/images/system-configuration/title-format.png)

> ⚠️ *Note that if the window title is set programmatically via the io.Connect APIs, the specified title format will be overridden. For web apps and Workspaces Apps, the `"syncTitleWithDocumentTitle"` property will override the specified title format.*

### Hibernation

To specify whether app instances are to be closed when hibernating [Global Layouts](https://docs.interop.io/desktop/capabilities/windows/layouts/javascript/index.md#layout_operations-hibernate__resume), [Workspaces](https://docs.interop.io/desktop/capabilities/windows/workspaces/overview/index.md#extending_workspaces-configuration-hibernation) or [window groups](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_groups-group_operations-hibernation), use the `"closeOnHibernate"` property of the `"applications"` top-level key:

```json
{
    "applications": {
        "closeOnHibernate": false
    }
}
```

By default, this property is set to `true`. Set to `false` to prevent the apps participating in the hibernation process to close. This will result in faster display of hibernated apps when resuming Global Layouts, Workspaces or window groups, but won't save as much system resources.

Setting this to `false` may also be useful if you want to [hibernate and resume io.Connect Window groups](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_groups-group_operations-hibernation) programmatically, in order to preserve the original group objects and IDs.

You can also configure the hibernation behavior per app, which provides you with flexibility in designing your hibernation strategy. You may choose to close the instances of lightweight apps, as they won't take much time to load, and preserve only the instances of heavy apps during hibernation. This will save the time needed for loading the heavy apps when the user resumes the Layout later, but comes at the expense of higher memory consumption on the user machine.

> ℹ️ *For details on how to configure hibernation per app, see the [Configuration > Application > Hibernation](https://docs.interop.io/desktop/developers/configuration/application/index.md#hibernation) section.*

## Window Management

Available since io.Connect Desktop 9.3

Global settings for the internal window management mechanisms are found under the `"windowManagement"` top-level key in the `system.json` file of **io.Connect Desktop**, and with the exception of window group settings, can be overridden per app from the [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md) settings.

### Window Groups

To configure the behavior of window groups, use the `"group"` property of the `"windowManagement"` top-level key.

The `"group"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"externalResizeMode"` | `"Fill"` \| `"Proportional"` | Defines the behavior of windows with size restrictions that will be violated during [resize operations](#window_management-window_groups-mode_for_resizing_windows_with_size_restrictions) with Windows mouse and keyboard gestures. If set to `"Fill"` (default), the group will be resized in a way that all windows unrestricted in size will fill as much space as possible left free by any size-restricted window. Currently, only rectangular groups without holes are supported in `"Fill"` mode. If set to `"Proportional"`, the proportions of all windows in the group will be preserved relatively to the size of the restricted window. *Available since **io.Connect Desktop** 10.0.* |
| `"header"` | `object` | Settings for the window [group header](#window_management-window_groups-group_header). Defaults to `{}`. *Available since **io.Connect Desktop** 10.0.* |
| `"tabs"` | `object` | Settings for the tabs in io.Connect Window groups. Defaults to `{}`. |
| `"type"` | `"Web"` \| `"Classic"` | Specifies the implementation type of the io.Connect Window group. If set to `"Web"` (default), decorations are implemented via HTML elements and the theme properties are set via CSS. This is the only available window group type in the default platform mode. If set to `"Classic"`, decorations like headers, tabs, captions, etc., are implemented via WPF components and the theme properties (colors, sizes, etc.) are set via the `themes.json` file. Classic groups are available only in the [advanced platform mode](#platform_modes). *Available since **io.Connect Desktop** 10.0.* |
| `"unlockOnLongMousePress"` | `object` | Settings for [unlocking windows](#window_management-window_groups-ungrouping_windows) from windows groups when the user holds down the left mouse button inside the default window move area (between the tabs and the system buttons for tab windows, the caption bar for flat windows, and the HTML move area for HTML windows). Defaults to `{}`. |

The `"tabs"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"defaultTaskbarTitle"` | `string` | Text that will be used in the Windows taskbar for single tab groups (tab groups that aren't snapped to other windows or groups) unless `"showSelectedTabTitleInTaskbar"` is set to `true`. Defaults to `"Group"`. *Available since **io.Connect Desktop** 10.0.* |
| `"flatWhenSingle"` | `boolean` | If `true`, the tab window will look as a flat window (without a tab header) when it's single. The tab header will appear automatically when you add one or more tab windows to the current window. Defaults to `false`. *Available since **io.Connect Desktop** 10.0.* |
| `"loadingStrategy"` | `"direct"` \| `"lazy"` \| `"delayed"` | Strategy for loading web apps when restoring tabbed groups. Use `"direct"` (default) to load all apps in tabbed groups simultaneously. Use `"lazy"` to load all visible apps first, and load hidden apps on demand (only when the user clicks on a tab to activate). Currently, the `"delayed"` strategy isn't supported. |
| `"overflow"` | `boolean` | If `true`, when the total width of the tabs in a group exceeds the width of the tab header area, the tabs will overflow. The user will be able to navigate to the desired tab by using the scroll bar or the dropdown menu that will appear automatically when the tabs exceed the available width of the tab header area. If `false` (default), when a new tab is added to the group, the tabs will keep shrinking in width up to the minimum possible size in order to fit in the available width of the tab header area. It's important to keep in mind that in this case if the total width of the tabs exceeds the available width of the tab header area, the rightmost tabs will start to disappear and will become inaccessible to the user unless one or more previous tabs are closed first. |
| `"selectPreviousOnClose"` | `boolean` | If `true`, will select the previously selected tab when the current one is closed. If `false` (default), will select the previous adjacent tab when the current one is closed. |
| `"showSelectedTabTitleInTaskbar"` | `boolean` | If `true`, the title of the selected tab will be shown in the Windows taskbar. Valid only for single tab groups (tab groups that aren't snapped to other windows or groups) and will override the `"defaultTaskbarTitle"` property. Defaults to `false`. |

#### Group Type

Available since io.Connect Desktop 10.0

> ⚠️ *Note that this feature is available only in the [advanced platform mode](#platform_modes).*

In the [default platform mode](#platform_modes), **io.Connect Desktop** uses [web groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-web_groups) as the default implementation for managing io.Connect Window groups and in this mode [classic groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-classic_groups) aren't available.

In the advanced platform mode, classic groups are the default implementation and it's possible to switch to web groups by using the `"type"` property of the `"group"` object:

```json
{
    "windowManagement": {
        "group": {
            "type": "Web"
        }
    }
}
```

#### Group Header

Available since io.Connect Desktop 10.0

To specify settings for the window group header, use the `"header"` property of the `"group"` object:

```json
{
    "windowManagement": {
        "group": {
            "header": {
                "hide": true
            }
        }
    }
}
```

The `"header"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"defaultTitle"` | `string` | Default header title for io.Connect Window groups, also displayed in the Windows taskbar. Defaults to `"Group"`. |
| `"editTitle"` | `boolean` | If `true` (default), the user will be able to edit the title of the window group header. |
| `"hide"` | `boolean` | If `true`, the window group header will be hidden. Valid for all types of apps (native and web). Defaults to `false`. |

#### Mode for Resizing Windows with Size Restrictions

Available since io.Connect Desktop 10.0

To specify settings for the platform behavior when resizing window groups which contain windows with size restrictions, use the `"externalResizeMode"` property of the `"group"` object:

```json
{
    "windowManagement": {
        "group": {
            "externalResizeMode": "Proportional"
        }
    }
}
```

#### Tab Overflow

Available since io.Connect Desktop 9.4

> ⚠️ *Note that this feature is available only for [web groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-web_groups).*

Tab overflow allows the extra tabs on the right side of the tab header to be collected in a dropdown menu in their original order instead of becoming smaller and smaller each time a new tab is added to the group. The user can open the menu and select the desired tab (or close a tab directly from the menu). The tabs will be scrolled horizontally and the selected tab will be focused.

![Tab Overflow](https://docs.interop.io/desktop/images/window-management/tab-overflow.mp4)

To enable tab overflow, use the `"overflow"` property of the `"tabs"` object:

```json
{
    "windowManagement": {
        "group": {
            "tabs": {
                "overflow": true
            }
        }
    }
}
```

#### Tab Selection

Available since io.Connect Desktop 9.4

> ⚠️ *Note that this feature is available only for [web groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-web_groups).*

By default, when the user closes a tab in a window group with multiple tabs, the tab immediately to its left (or immediately to its right, if the closed tab was the first one in the tab group) is automatically focused. You can override this behavior and instruct **io.Connect Desktop** to focus the tab that was previously selected by the user instead.

To enable focusing the previously selected tab, use the `"selectPreviousOnClose"` property of the `"tabs"` object:

```json
{
    "windowManagement": {
        "group": {
            "tabs": {
                "selectPreviousOnClose": true
            }
        }
    }
}
```

#### Selected Tab Title

Available since io.Connect Desktop 9.8

By default, **io.Connect Desktop** displays the title of the window group when the user hovers over the group icon in the Windows taskbar. You can instruct the platform to show the title of the currently selected tab instead when the user hovers over the icon of a single tab group in the Windows taskbar:

![Selected Tab Title in Windows Taskbar](https://docs.interop.io/desktop/images/window-management/show-selected-tab-title.png)

To show the title of the currently selected tab in the Windows taskbar, use the `"showSelectedTabTitleInTaskbar"` property of the `"tabs"` object:

```json
{
    "windowManagement": {
        "group": {
            "tabs": {
                "showSelectedTabTitleInTaskbar": true
            }
        }
    }
}
```

> ⚠️ *Note that this property is valid only for single tab groups (tab groups that aren't snapped to other windows or groups) and will override the `"defaultTaskbarTitle"` property.*

#### Loading Strategy

Available since io.Connect Desktop 9.4

> ⚠️ *Note that this feature is available only for [web groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-web_groups).*

It's possible to specify a loading strategy for restoring tabbed window groups. The available options are to load all apps in the tabs simultaneously, or to load only the visible apps first and then load hidden apps on demand (only when the user clicks on a tab to activate it).

To specify a loading strategy for window groups, use the `"loadingStrategy"` property of the `"tabs"` object:

```json
{
    "windowManagement": {
        "group": {
            "tabs": {
                "loadingStrategy": "lazy"
            }
        }
    }
}
```

Possible values for the `"loadingStrategy"` property are `"direct"` (default) or `"lazy"`.

#### Ungrouping Windows

Available since io.Connect Desktop 9.4

To enable or disable ungrouping windows when the user holds down the left mouse button on the window header, use the `"unlockOnLongMousePress"` property of the `"group"` object:

```json
{
    "windowManagement": {
        "group": {
            "unlockOnLongMousePress": {
                "enabled": true,
                "timeout": 1200,
                "tolerance": 10
            }
        }
    }
}
```

The `"unlockOnLongMousePress"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true` (default), will enable unlocking windows from window groups on a long mouse press. |
| `"timeout"` | `number` | Interval in milliseconds to wait before unlocking a window from a window group on a long mouse press. Defaults to `1000`. |
| `"tolerance"` | `number` | Distance in pixels allowed for the mouse to move from its initial position before the unlocking operation becomes unavailable. Defaults to `5`. |

#### Flat When Single

Available since io.Connect Desktop 10.0

To make a tab window appear as a flat window (without a tab header) when it's single, use the `"flatWhenSingle"` property of the `"tabs"` object:

```json
{
    "windowManagement": {
        "group": {
            "tabs": {
                "flatWhenSingle": true
            }
        }
    }
}
```

#### Default Windows Taskbar Title

Available since io.Connect Desktop 10.0

To specify a title to be displayed in the Windows taskbar for single tab groups (tab groups that aren't snapped to other windows or groups), use the `"defaultTaskbarTitle"` property of the `"tabs"` object:

```json
{
    "windowManagement": {
        "group": {
            "tabs": {
                "defaultTaskbarTitle": "My Tab Group"
            }
        }
    }
}
```

> ⚠️ *Note that this property is valid only for single tab groups (tab groups that aren't snapped to other windows or groups) and will be overridden if the `"showSelectedTabTitleInTaskbar"` property is set to `true`.*

### Workspaces

Available since io.Connect Desktop 9.9

To configure the behavior of Workspaces, use the `"workspaces"` property of the `"windowManagement"` top-level key.

The `"workspaces"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"operationTimeout"` | `number` | Interval in milliseconds to wait for API operations to complete. Defaults to `30000`. |

#### Awaiting Workspaces API Operations

The following example demonstrates configuring the interval for awaiting Workspaces API operations to complete:

```json
{
    "windowManagement": {
        "workspaces": {
            "operationTimeout": 45000
        }
    }
}
```

### Snapping

Available since io.Connect Desktop 10.0

To provide settings for snapping windows to other windows and window groups, use the `"snapping"` property:

```json
{
    "windowManagement": {
        "snapping": {
            "enabled": true,
            "approachingDistance": 30
        }
    }
}
```

The `"snapping"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"approachingDistance"` | `number` | Distance in pixels at which the approaching edges of windows will be highlighted. The approaching distance value must be in the range of 10 to 100 pixels. Defaults to `50`. |
| `"autoAlign"` | `boolean` | If `true` (default), when a window is added to a window group, it will be aligned automatically to the neighboring windows. |
| `"edgeDistance"` | `number` | Distance in pixels between the edges of snapped windows. The edge distance value must be in the range of 2 to 10 pixels. Defaults to `4`. |
| `"enabled"` | `boolean` | If `true` (default), will enable io.Connect Windows to snap together forming window groups. |

### Collapse & Expand

Available since io.Connect Desktop 9.4

> ⚠️ *Note that this feature is available only for [classic groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-classic_groups).*

To specify the behavior for collapsing and expanding grouped windows, use the `"mode"` property of the `"collapseExpand"` object. By default, when you collapse a window in a group, the height and shape of the group may change (depending on where the collapsed window is situated), because the neighboring windows at the bottom of the collapsed window (if any) won't try to compensate the lost group height by expanding. To override this behavior and instruct the io.Connect Windows to try to compensate the height of a collapsed window in a group by expanding, set the `"mode"` property of the `"collapseExpand"` object to `"Proportional"`:

```json
{
    "windowManagement": {
        "collapseExpand": {
            "mode": "Proportional"
        }
    }
}
```

The `"collapseExpand"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"alignBottomBordersWhenExpanding"` | `boolean` | If `true` (default) and the expanding window is in a perfect window group column, the framework will attempt to align the bottom borders of the last windows in that column to the bottom border of the closest window neighbor. |
| `"mode"` | `"Proportional"` \| `"Single"` | Specifies the behavior for collapsing and expanding windows. If set to `"Single"` (default), the group will change in height when a window with neighbors at the top or at the bottom is collapsed or expanded. If set to `"Proportional"`, the bottom window neighbor (if any) will attempt to compensate the height difference and preserve the overall group height. |

> ⚠️ *Note that depending on the position of the collapsed window within the group structure, it may not always be possible for the neighboring windows to fill the empty space left by collapsing it.*

> ⚠️ *Note that when the group is maximized, the neighboring windows will always try to fill in the empty space left by a collapsed window, irrespective of the mode used.*

Collapsing a window in a group when using `"Single"` mode:

![Collapse Group Single](https://docs.interop.io/desktop/images/window-management/collapse-single.mp4)

Collapsing a window in a group when using `"Proportional"` mode:

![Collapse Group Single](https://docs.interop.io/desktop/images/window-management/collapse-proportional.mp4)

### Snapping to Screen Edges

Available since io.Connect Desktop 9.3

> ⚠️ *Note that this property is valid only for apps of type `"window"`.*

To configure whether windows should snap to the edges of the screen when the user moves them within a specified distance from a screen edge, use the `"snapToScreenEdges"` property:

```json
{
    "windowManagement": {
        "snapToScreenEdges": {
            "enabled": true,
            "distance": 30
        }
    }
}
```

![Snap to Screen Edges](https://docs.interop.io/desktop/images/system-configuration/snap-to-screen-edges.mp4)

The `"snapToScreenEdges"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"distance"` | `number` | Distance in pixels from the screen edge at which the window will snap to it. The minimum is `5`, the maximum is `30`. Defaults to `20`. |
| `"enabled"` | `boolean` | If `true`, will enable snapping windows to the screen edges when the user moves them within the specified distance from the screen edge. Defaults to `false`. |

> ℹ️ *For details on how to configure snapping to screen edges per app, see the [Configuration > Application > Snapping to Screen Edges](https://docs.interop.io/desktop/developers/configuration/application/index.md#snapping_to_screen_edges) section.*

### Alternate Behavior

Available since io.Connect Desktop 9.9

By default, when you move an io.Connect Window close enough to another io.Connect Window and drop it, it will automatically stick to it. If you move a window over a tabbed window group and drop it, it will be added to that group. The same is valid for dropping windows and window groups in Workspaces. To prevent these automatic operations, you can hold the `ALT` key while moving an io.Connect Window or a window group.

To reverse these default window management behaviors, use the `"alternateBehavior"` property of the `"windowManagement"` top-level key.

The following example demonstrates how to instruct the io.Connect platform to stick windows together and add dropped windows to tab groups and Workspaces only when the `ALT` key is pressed:

```json
{
    "alternateBehavior": {
        "snapping": {
            "reverse": true
        },
        "dropInTabGroup": {
            "reverse": true
        },
        "dropInWorkspace": {
            "reverse": true
        }
    }
}
```

The `"alternateBehavior"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"dropInTabGroup"` | `object` | Controls dropping windows in tab groups when the `ALT` key is pressed or released. Accepts an object with a `"reverse"` property as a value. Set `"reverse"` to `true` to reverse the default behavior. |
| `"dropInWorkspace"` | `object` | Controls dropping windows in Workspaces when the `ALT` key is pressed or released. Accepts an object with a `"reverse"` property as a value. Set `"reverse"` to `true` to reverse the default behavior. |
| `"snapping"` | `object` | Controls window snapping when the `ALT` key is pressed or released. Accepts an object with a `"reverse"` property as a value. Set `"reverse"` to `true` to reverse the default behavior. |

### Hardware Acceleration

Available since io.Connect Desktop 9.3

> ⚠️ *Note that this property is valid only for apps of type `"window"`.*

To enable hardware acceleration for web apps, use the `"hardwareAcceleration"` property:

```json
{
    "windowManagement": {
        "hardwareAcceleration": {
            "enabled": true
        }
    }
}
```

The `"hardwareAcceleration"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true`, will enable hardware acceleration for web pages. Forced to `true` in the [default platform mode](#platform_modes). Defaults to `false` in the advanced platform mode. |

#### 9.0 Version Stream

In the **io.Connect Desktop** 9.0 version stream, the `"hardwareAcceleration"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true`, will enable hardware acceleration for web pages. Defaults to `false`. |
| `"transparency"` | `object` | Settings specifying how the platform will achieve transparency and will handle mouse events in the Workspaces App and the Web Group App when hardware acceleration is enabled. By design, the Workspaces App and the Web Group App web pages are positioned on top of the app windows participating in the respective Workspace or web group. This requires the platform to ensure that the app windows below the web pages remain visible and can receive mouse events. Adjusting the transparency settings may be necessary when you have custom popups that are shown over app windows in your Workspaces App or Web Group App. *Available since **io.Connect Desktop** 9.15.* |

The `"transparency"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"mode"` | `"UseRegions"` \| `"UseAppRegion"` | Specifies how to achieve transparency in the Workspaces App and the Web Group App when hardware acceleration is enabled. If set to `"UseRegions"` (default), the platform will attempt to automatically determine and cut out the app window areas from the respective web pages, which may lead to undesirable behavior like cutting out areas of custom popups displayed over the app windows participating in the Workspace or the web group. If set to `"UseAppRegion"` (recommended), the platform will use the transparent and opaque areas defined via the `-webkit-app-region` CSS property in the Workspaces App and the Web Group App in order to determine which areas of the respective web pages to cut out to reveal the app windows positioned below. The `"UseAppRegion"` value requires [`@interopio/workspaces-ui-react`](https://www.npmjs.com/package/@interopio/workspaces-ui-react) version 4.5.1 or later and [`@interopio/groups-ui-react`](https://www.npmjs.com/package/@interopio/groups-ui-react) 4.5.1 or later for the Workspaces App and the Web Group App respectively. |

### Flydown Windows

Available since io.Connect Desktop 10.0

> ⚠️ *Note that this feature is available only in the [advanced platform mode](#platform_modes).*

To specify settings for the io.Connect [flydown windows](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#flydown_windows), use the `"flydownWindows"` property:

```json
{
    "windowManagement": {
        "flydownWindows": {
            "showDelay": 250,
            "hideDelay": 500
        }
    }
}
```

The `"flydownWindows"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"hideCheckInterval"` | `number` | Interval in milliseconds at which to check whether the flydown window should be hidden. This value should be less than the value of `"hideDelay"`, otherwise the flydown window will be hidden at the end of this interval and not at the end of the interval specified in `"hideDelay"`. Defaults to `100`. |
| `"hideDelay"` | `number` | Delay in milliseconds before hiding the flydown window (e.g., when the user moves the cursor out of the flydown zone). Defaults to `400`. |
| `"showDelay"` | `number` | Delay in milliseconds before showing flydown windows after the user hovers over a flydown zone. Defaults to `200`. |
| `"zoneChangeCallbackTimeout"` | `number` | Interval in milliseconds to await the callback for handling the flydown window to return a result when the flydown zone has changed. Defaults to `150`. |

### Edit Window Title

Available since io.Connect Desktop 10.0

> ⚠️ *Note that this property is valid only for flat and tab windows.*

By default, users can edit the titles of flat and tab windows. To prevent this, use the `"editWindowTitle"` property:

```json
{
    "windowManagement": {
        "editWindowTitle": false
    }
}
```

### Transparency Control

Available since io.Connect Desktop 10.0

> ⚠️ *Note that this feature is available only in the [advanced platform mode](#platform_modes).*

To instruct the platform how to achieve transparency in Workspaces and web groups, use the `"transparencyControl"` property:

```json
{
    "windowManagement": {
        "transparencyControl": {
            "mode": "Auto"
        }
    }
}
```

The `"transparencyControl"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"mode"` | `boolean` | Specifies how to handle the transparency of the HTML elements that are part of io.Connect web groups and Workspaces and are placed over the app windows. These HTML elements must be transparent in order for the app windows to be visible and for the mouse clicks to reach the app windows. By default, the io.Connect platform uses `"Transparent"` mode which provides more flexibility for customizing Workspaces and web groups (freely showing popups with drop shadows and irregular shapes). The other values (`"Auto"`, `"KeyColor"` and `"Regions"`) are supported for legacy reasons. Using `"Auto"` will select `"Transparent"`. |
| `"keyColor"` | `boolean` | Specifies the key color when `"mode"` is set to `"KeyColor"` (supported for legacy reasons). The key color is the color that will be treated as transparent in the HTML elements that are part of io.Connect web groups and Workspaces. Defaults to `"#FD12EF"`. |

## Window Settings

Global io.Connect Window settings are found under the `"windows"` top-level key in the `system.json` file of **io.Connect Desktop** and can be overridden per app from the [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md) settings.

> ⚠️ *Note that each setting under the `"windows"` top-level may be valid only for certain [app definition types](https://docs.interop.io/desktop/developers/configuration/application/index.md#app_definition).*

### Channel Selector

Available since io.Connect Desktop 9.3

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"exe"`, `"clickonce"`, `"childWindow"`, and `"citrix"`.*

To configure the [Channel Selector](https://docs.interop.io/desktop/capabilities/data-sharing/channels/overview/index.md#channel_selector), use the `"channelSelector"` property:

```json
{
    "windows": {
        "channelSelector": {
            "enabled": true,
            "type": "directionalSingle"
        }
    }
}
```

The `"channelSelector"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true`, will allow showing the Channel Selector. Defaults to `false`. |
| `"channelId"` | `string` | Name of the Channel to which the window will be joined by default when it's started. |
| `"readOnly"` | `boolean` | If `true`, the Channel Selector will be visible, but the user won't be able to switch between Channels from it. Defaults to `false`. |
| `"type"` | `"single"` \| `"directionalSingle"` \| `"multi"` \| `"directionalMulti"` | Type of the Channel Selector to show on the io.Connect Windows. Using multiple Channels is available only for [web groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-web_groups). <br> - `"single"` (default) - allows the window to join a single Channel to which it can subscribe and publish data unrestrictedly; <br> - `"directionalSingle"` - allows the window to join a single Channel, but also enables the user to restrict the window from publishing or from subscribing to the current Channel; <br> - `"multi"` -  allows the window to join multiple Channels simultaneously to which it can subscribe and publish data unrestrictedly. *Available since **io.Connect Desktop** 9.7.* <br> - `"directionalMulti"` - allows the window to join multiple Channels, but also enables the user to restrict the window from publishing or from subscribing to the selected Channels. *Available since **io.Connect Desktop** 9.8.* |

> ℹ️ *For details on how to configure the Channel Selector per app, see the [Configuration > Application > Channels](https://docs.interop.io/desktop/developers/configuration/application/index.md#channels) section.*

### Preload Scripts

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"workspaces"`, and `"webGroup"`.*

To specify preload scripts globally for all your web apps, use the `"preloadScripts"` property:

```json
{
    "windows": {
        "preloadScripts": {
            "scripts": [
                "https://my-domain.com/my-script.js",
                "https://my-domain.com/my-other-script.js"
            ]
        }
    }
}
```

The `"preloadScripts"` property accepts as a value either an array of URLs pointing to the preload scripts to inject, or an object with the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"scripts"` | `string[]` | List of URLs pointing to preload scripts to be injected. |
| `"useBase64PreloadScripts"` | `boolean` | This property allows you to control how **io.Connect Desktop** will import the preload scripts. If set to `true`, the preload scripts will be injected directly into the web page as Base64 strings via a `<script>` tag. In certain scenarios, depending on the browser security policies, this may prevent the preload scripts from loading and executing. If set to `false` (default), the platform will use the built-in mechanisms of the Electron framework to inject the preload scripts, which guarantees that the preload scripts will always load. It's highly recommended to leave the `"useBase64PreloadScripts"` property set to `false`. |

Available since io.Connect Desktop 9.1

The `"scripts"` property of the configuration object for the `"preloadScripts"` key also accepts an array of objects which you can use to specify detailed settings for the preload scripts:

```json
{
    "windows": {
        "preloadScripts": {
            "scripts": [
                {
                    "url": "https://my-domain.com/my-script.js",
                    "fallback": "https://my-domain.com/my-fallback-script.js",
                    "timeout": 5000
                },
                {
                    "url": "https://my-domain.com/my-other-script.js",
                    "fallback": "https://my-domain.com/my-other-fallback-script.js",
                    "timeout": 5000
                }
            ]
        }
    }
}
```

Each object in the `"scripts"` array has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"critical"` | `boolean` | If `true`, failure to load the preload script will be treated as a critical error and the platform will shut down. This property is valid only for globally defined preload scripts and isn't taken into account if used in an app definition. *Available since **io.Connect Desktop** 9.7.* |
| `"fallback"` | `string` | URL pointing to a local or a remote preload script that will be used as a fallback in case the one specified in the `"url"` property doesn't load. **io.Connect Desktop** will reuse the cached fallback script and won't attempt to load again the one specified in the `"url"` property, unless the platform is shutdown or restarted. |
| `"timeout"` | `number` | Interval in milliseconds to wait for the preload script to load. |
| `"url"` | `string` | **Required.** URL pointing to a local or a remote preload script. |

> ℹ️ *For details on how to configure preload scripts per app, see the [Configuration > Application > Preload Scripts](https://docs.interop.io/desktop/developers/configuration/application/index.md#preload_scripts) section.*

### Injecting Styles

Available since io.Connect Desktop 9.3

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"workspaces"`, and `"webGroup"`.*

**io.Connect Desktop** allows injecting CSS files in your web apps, the Workspaces App and the Web Group App. Styles will be injected after the DOM content has been loaded. You can choose whether to merge the injected styles with the already existing ones, or to replace them entirely.

To define globally CSS files to inject in your apps, use the `"injectedStyles"` property:

```json
{
    "windows": {
        "injectedStyles": {
            "replace": false,
            "styles": [
                {
                    "url": "https://my-org.com/my-styles.css",
                    "fallback": "https://my-org.com/my-fallback-styles.css",
                    "timeout": 20000
                },
                {
                    "url": "https://my-org.com/my-other-styles.css",
                }
            ]
        }
    }
}
```

The `"injectedStyles"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"replace"` | `boolean` | If `true`, will replace the existing styles of the web app with the injected ones. This won't affect styles added dynamically after the initial page load. If `false`, the existing styles will be merged with the injected ones. |
| `"styles"` | `object` | List of objects describing CSS files that will be injected in the specified order. |

Each object in the `"styles"` array has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"critical"` | `boolean` | If `true`, failure to load the CSS file will be treated as a critical error and the platform will shut down. This property is valid only for globally defined CSS files and isn't taken into account if used in an app definition. *Available since **io.Connect Desktop** 9.7.* |
| `"fallback"` | `string` | URL pointing to a local or a remote CSS file that will be used as a fallback in case the one specified in the `"url"` property doesn't load. **io.Connect Desktop** will reuse the cached fallback CSS file and won't attempt to load again the one specified in the `"url"` property, unless the platform is shutdown or restarted. |
| `"timeout"` | `number` | Interval in milliseconds to wait for the CSS file to load. |
| `"url"` | `string` | **Required.** URL pointing to a local or a remote CSS file. |

> ℹ️ *For details on how to configure injecting styles per app, see the [Configuration > Application > Injecting Styles](https://docs.interop.io/desktop/developers/configuration/application/index.md#injecting_styles) section.*

### Persisting Data in Layouts

Data for both web and native apps can be persisted when the app is saved in a Layout. For web apps, this includes the current URL and title, and for native apps - the command and the parameters with which the app was started.

Available since io.Connect Desktop 9.2

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"exe"`, `"clickonce"`, and `"citrix"`.*

To persist data for web and native apps in Layouts, use the `"saveInLayout"` property.

The `"saveInLayout"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"command"` | `boolean` | *Valid only for native apps.* If `true`, when the app is saved in a Layout, the command with which it was started will be persisted. If the value of the `"command"` property in the app definition is changed, when the Layout is restored, the app will be started with the previously persisted command, and not the one in the current app definition. |
| `"env"` | `boolean` | *Valid only for native apps.* If `true`, when the app is saved in a Layout, the environment variables with which it was started will be persisted. If the value of the `"env"` property in the app definition is changed, when the Layout is restored, the app will be started with the previously persisted environment variables, and not the ones in the current app definition. *Available since **io.Connect Desktop** 9.3.* |
| `"parameters"` | `boolean` | *Valid only for native apps.* If `true`, when the app is saved in a Layout, the parameters with which it was started will be persisted. If the value of the `"parameters"` property in the app definition is changed, when the Layout is restored, the app will be started with the previously persisted parameters, and not the ones in the current app definition. |
| `"title"` | `boolean` \| `string[]` | *Valid only for web apps.* If `true`, the current window title will be saved for all Layout types. Alternatively, you can provide a list of Layout types for which the window title is to be saved. The possible string values are `"Global"`, `"Workspace"`, and `"ApplicationDefault"`. |
| `"url"` | `boolean` \| `string[]` | *Valid only for web apps.* If `true`, the current window URL will be saved for all Layout types. Alternatively, you can provide a list of Layout types for which the window URL is to be saved. The possible string values are `"Global"`, `"Workspace"`, and `"ApplicationDefault"`. |

#### Web Apps

Available since io.Connect Desktop 9.2

> ⚠️ *Note that this property is valid only for apps of type `"window"`.*

To persist data for web apps in Layouts, use the `"saveInLayout"` property.

The following example demonstrates how to persist the current URLs of web apps only when they participate in Global Layouts and Workspaces, and how to persist the current window titles of web apps in all types of Layouts:

```json
{
    "windows": {
        "saveInLayout": {
            "url": ["Global", "Workspace"],
            "title": true
        }
    }
}
```

> ℹ️ *For details on how to control saving web app data in Layouts per app, see the [Configuration > Application > Persisting Data in Layouts > Web Apps](https://docs.interop.io/desktop/developers/configuration/application/index.md#persisting_data_in_layouts-web_apps) section.*

#### Native Apps

Available since io.Connect Desktop 9.2

> ⚠️ *Note that this property is valid only for apps of type `"exe"`, `"clickonce"`, and `"citrix"`.*

To persist data for native apps in Layouts, use the `"saveInLayout"` property.

The following example demonstrates how to persist the command and the parameters with which native apps are started when they are saved in a Layout:

```json
{
    "windows": {
        "saveInLayout": {
            "command": true,
            "parameters": true
        }
    }
}
```

> ℹ️ *For details on how to control saving native app data in Layouts per app, see the [Configuration > Application > Persisting Data in Layouts > Native Apps](https://docs.interop.io/desktop/developers/configuration/application/index.md#persisting_data_in_layouts-native_apps) section.*

### Synchronizing App Titles

> ⚠️ *Note that this property is valid only for apps of type `"window"` and `"workspaces"`.*

Titles of web app instances and Workspaces App instances can be synchronized with the document title whenever the document title changes. To specify global settings for the desired behavior, use the `"syncTitleWithDocumentTitle"` property:

```json
{
    "windows": {
        "syncTitleWithDocumentTitle": true
    }
}
```

Available since io.Connect Desktop 9.4

The `"syncTitleWithDocumentTitle"` property also accepts a `"preserveCustomTitle"` string as a value. If set to `"preserveCustomTitle"`, the window title will be synchronized with the document title until the moment the user or the API sets a custom title for the window. After that, the custom title will be preserved and the window title won't be synchronized with the document title.

```json
{
    "details": {
        "syncTitleWithDocumentTitle": "preserveCustomTitle"
    }
}
```

> ℹ️ *For details on how to control the synchronizing behavior for app titles per app, see the [Configuration > Application > Synchronizing App Titles](https://docs.interop.io/desktop/developers/configuration/application/index.md#synchronizing_app_titles) section.*

### Handling the Browser window.open()

> ⚠️ *Note that this property is valid only for apps of type `"window"`.*

To control the behavior of the browser [`window.open()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) method when opening child windows, use the `"nativeWindowOpen"` property.

The following example demonstrates how to configure **io.Connect Desktop** to open windows created with `window.open()` in the default browser:

```json
{
    "windows": {
        "nativeWindowOpen": "browser"
    }
}
```

The `"nativeWindowOpen"` property accepts either a string or an object as a value.

The possible string values for the `"nativeWindowOpen"` property are:

| Value | Description |
|-------|-------------|
| `"browser"` | Windows created with `window.open()` will be opened in the default browser. |
| `"off"` | Opening windows with `window.open()` is disabled. |
| `"window"` | Default. Windows created with `window.open()` will be opened as io.Connect Windows. |

The `"nativeWindowOpen"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"grouping"` | `object` | Settings for grouping the newly opened child window with the parent window. The child window can be snapped to any side of the parent window, or can be added to its tab group, provided that both windows are io.Connect tab windows. *Available since **io.Connect Desktop** 9.3.* |
| `"mode"` | `string` | Must be set to `"window"`. |
| `"outlivesOpener"` | `boolean` | If `true`, will prevent child windows from being closed when their parent is closed. |

#### Grouping Windows

Available since io.Connect Desktop 9.3

To group child windows with the parent window when using the browser native `window.open()` method to open windows as io.Connect Windows, use the `"grouping"` property of the `"nativeWindowOpen"` object.

The following example demonstrates how to configure **io.Connect Desktop** to snap newly opened child windows to the left of the parent window:

```json
{
    "windows": {
        "nativeWindowOpen": {
            "mode": "window",
            "grouping": {
                "snap": true,
                "snappingOptions": {
                    "direction": "left"
                }
            }
        }
    }
}
```

The `"grouping"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"addToTabGroup"` | `boolean` | If `true`, will add the new child window to the tab group of the parent. Valid only when both the parent and the child are io.Connect tab windows. |
| `"snap"` | `boolean` | If `true`, the child window will be snapped to the parent window. To specify a relative direction for the snapped window, use the `"direction"` property of the `"snappingOptions"` object. If no direction is specified, the child window will be snapped to the right side of the parent window. |
| `"snappingOptions"` | `object` | Options for snapping the child window to the parent window. |

The `"snappingOptions"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"direction"` | `"right"` \| `"left"` \| `"bottom"` \| `"top"` | Direction (bottom, top, left or right) for positioning the child window relatively to the parent window. Considered only if `"snap"` is set to `true`. |

#### Window Options

Available since io.Connect Desktop 9.2

> ⚠️ *Note that this property is valid only for apps of type `"window"`.*

To provide options for windows opened as io.Connect Windows via the browser `window.open()` method (i.e., when `"nativeWindowOpen"` is set to `"window"`), use the `"nativeWindowOpenOptions"` property:

```json
{
    "windows": {
        "nativeWindowOpenOptions": {
            "maxHeight": 500,
            "hasSizeAreas": true
        }
    }
}
```

> ℹ️ *For a list of the supported options, see the [Capabilities > Windows > Window Management](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#opening_windows-handling_the_browser_windowopen) section.*

> ℹ️ *For details on how to control the behavior for handling the browser `window.open()` per app, see the [Configuration > Application > Handling the Browser window.open()](https://docs.interop.io/desktop/developers/configuration/application/index.md#handling_the_browser_windowopen) section.*

### Cascading Windows

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"exe"`, `"clickonce"`, `"childWindow"`, and `"citrix"`.*

io.Connect Windows that are instances of the same app can be opened in a cascade. Each new window is offset from the previously opened window by a specified distance.

Cascading windows is enabled by default. To specify offset for the cascaded windows, use the `"cascade"` property:

```json
{
    "windows": {
        "cascade": {
            "offset": 30
        }
    }
}
```

The `"cascade"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true` (default), will enable cascading windows. |
| `"offset"` | `number` | Offset in pixels for the cascaded window. |

> ℹ️ *For details on how to control window cascading per app, see the [Configuration > Application > Cascading Windows](https://docs.interop.io/desktop/developers/configuration/application/index.md#cascading_windows) section.*

### Sticky Button

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"exe"`, `"clickonce"`, `"childWindow"`, and `"citrix"`.*

To show the ["Sticky" button](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#sticky_button) on all io.Connect Windows, set the `"showStickyButton"` property to `true`:

```json
{
    "windows": {
        "showStickyButton": true
    }
}
```

![Sticky Button](https://docs.interop.io/desktop/images/window-management/stickiness.mp4)

> ℹ️ *For details on how to enable or disable the "Sticky" button per app, see the [Configuration > Application > Sticky Button](https://docs.interop.io/desktop/developers/configuration/application/index.md#sticky_button) section.*

> ℹ️ *For details on how to use stickiness programmatically, see the [Capabilities > Windows > Window Management](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-stickiness) section.*

### Feedback Button

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"exe"`, `"clickonce"`, `"childWindow"`, and `"citrix"`.*

To enable the ["Feedback" button](https://docs.interop.io/desktop/capabilities/more/features/index.md#feedback_form-feedback_button) globally for all io.Connect Windows, set the `"showFeedbackButton"` property to `true`:

```json
{
    "windows": {
        "showFeedbackButton": true
    }
}
```

![Feedback Button](https://docs.interop.io/desktop/images/window-management/feedback-button.mp4)

> ℹ️ *For details on how to enable or disable the "Feedback" button per app, see the [Configuration > Application > Feedback Button](https://docs.interop.io/desktop/developers/configuration/application/index.md#feedback_button) section.*

### Clone Button

Available since io.Connect Desktop 9.2

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"exe"`, `"clickonce"`, `"childWindow"`, and `"citrix"`.*

> ⚠️ *Note that this feature is available only for [web groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-web_groups).*

To enable the ["Clone" button](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#clone_button) globally for all io.Connect Windows, set the `"showCloneButton"` property to `true`:

```json
{
    "windows": {
        "showCloneButton": true
    }
}
```

![Clone Button](https://docs.interop.io/desktop/images/window-management/clone-button.mp4)

> ℹ️ *For details on how to enable or disable the "Clone" button per app, see the [Configuration > Application > Clone Button](https://docs.interop.io/desktop/developers/configuration/application/index.md#clone_button) section.*

> ℹ️ *For details on how to clone windows programmatically, see the [Capabilities > Windows > Window Management](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-clone) section.*

### Context Menu

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"workspaces"`, and `"webGroup"`.*

**io.Connect Desktop** provides a native right-click context menu available in all io.Connect web apps for which it has been enabled. It provides standard editing actions (select, cut, copy, paste, undo, redo), zoom and spelling options.

Available since io.Connect Desktop 9.4

The native context menu supports three different modes: "Edit" mode, "Edit with Suggestions" mode, and "Selection" mode. Each mode is automatically applied based on whether the text can be edited or only selected. The following demonstrates each of the context modes:

![Context Menu](https://docs.interop.io/desktop/images/platform-features/context-menu.mp4)

To configure the context menu globally, use the `"contextMenu"` property:

```json
{
    "windows": {
        "contextMenu": {
            "enabled": true
        }
    }
}
```

> ℹ️ *For details on how to configure the context menu per app, see the [Configuration > Application > Context Menu](https://docs.interop.io/desktop/developers/configuration/application/index.md#context_menu) section.*

### Jump List

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"exe"`, `"clickonce"`, `"childWindow"`, and `"workspaces"`.*

To configure the jump list globally for all io.Connect Windows, use the `"jumpList"` property:

```json
{
    "windows": {
        "jumpList": {
            "enabled": true,
            "categories": [
                {
                    "title": "Tasks",
                    "actions": [
                        {
                            "icon": "%IO_CD_ROOT_DIR%/assets/images/center.ico",
                            "type": "centerScreen",
                            "singleInstanceTitle": "Center on Primary Screen",
                            "multiInstanceTitle": "Center all on Primary Screen"
                        }
                    ]
                }
            ]
        }
    }
}
```

The `"jumpList"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"categories"` | `object[]` | Categorized lists with actions to execute when the user clicks on them. |
| `"enabled"` | `boolean` | If `true` (default), will enable the jump list. |

Each object in the `"categories"` array has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"actions"` | `object[]` | List of actions contained in the category. |
| `"title"` | `string` | Title of the category to be displayed in the context menu. |

Each object in the `"actions"` array has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"icon"` | `string` | Icon for the action to be displayed in the context menu. Must point to a local file. |
| `"multiInstanceTitle"` | `string` | Title of the action to be displayed in the context menu when there are multiple instances with grouped Windows taskbar icons. |
| `"singleInstanceTitle"` | `string` | Title of the action to be displayed in the context menu when there is a single instance with a single Windows taskbar icon. |
| `"type"` | `string` | Type of the [predefined action](https://docs.interop.io/desktop/capabilities/more/apis/index.md#jump_list-predefined_actions) to execute. |

> ℹ️ *For details on how to configure jump lists per app, see the [Configuration > Application > Jump List](https://docs.interop.io/desktop/developers/configuration/application/index.md#jump_list) section.*

> ℹ️ *For details on using jump lists programmatically, see the [Capabilities > More > APIs > Jump List](https://docs.interop.io/desktop/capabilities/more/apis/index.md#jump_list) section.*

### Downloads

> ⚠️ *Note that this property is valid only for apps of type `"window"`.*

To configure the global behavior of the io.Connect Windows when downloading files, use the `"downloadSettings"` property:

```json
{
    "windows": {
        "downloadSettings": {
            "autoSave": true,
            "autoOpenPath": false,
            "autoOpenDownload": false,
            "enable": true,
            "enableDownloadButton": true,
            "path": "%DownloadsFolder%"
        }
    }
}
```

The `"downloadSettings"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"autoOpenDownload"` | `boolean` | If `true`, will open the download file after the download is completed. Defaults to `false`. |
| `"autoOpenPath"` | `boolean` | If `true`, will open the folder that contains the downloaded file after the download is completed. Defaults to `false`. |
| `"autoSave"` | `boolean` | If `true` (default), will auto save the file (without asking the user where to save it). If `false`, a system save dialog will appear. |
| `"closeBlankDownloadWindows"` | `boolean` | If `true`, empty windows opened when the user clicks on a download link with a `"target=_blank"` attribute will be closed automatically. Defaults to `false`. *Available since **io.Connect Desktop** 10.3.* |
| `"enable"` | `boolean` | If `true` (default), will enable the window to download files. |
| `"enableDownloadBar"` | `boolean` | If `true` (default), a download bar tracking the download progress will appear at the bottom of the window. If `false`, the download process will be invisible. Available only in the advanced platform mode. |
| `"enableDownloadButton"` | `boolean` | If `true`, a "Download" button will be available at the top of the window. The "Download" button opens a download popup in the current window which displays all downloads initiated by the user and provides controls for managing them and accessing the [Download Manager](#download_manager). The "Download" button is available only for web groups. If an io.Connect Window is inserted into a Workspace during an ongoing download, the "Download" button will disappear. Defaults to `true` in the default platform mode and to `false` in the advanced platform mode. *Available since **io.Connect Desktop** 10.2.* |
| `"path"` | `string` | Location where the downloaded file will be saved. You can specify any sensible location within the OS, except system directories (i.e., it isn't possible to use locations such as the "Program Files" or "Windows" directories on Windows). Defaults to `"%DownloadsFolder%"`. |

> ℹ️ *For details on how to specify download settings per app, see the [Configuration > Application > Downloads](https://docs.interop.io/desktop/developers/configuration/application/index.md#downloads) section.*

> ℹ️ *For details on how to configure the Download Manager, see the [Download Manager](#download_manager) section.*

> ℹ️ *For details on using downloads programmatically, see the [Capabilities > Windows > Window Management](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-download) section.*

### Zooming

> ⚠️ *Note that this property is valid only for apps of type `"window"`, `"workspaces"`, and `"webGroup"`.*

To set the zoom behavior globally for all io.Connect Windows, use the `"zoom"` property:

```json
{
    "windows": {
        "zoom": {
            "enabled": true,
            "mouseWheelZoom": false,
            "factors": [25, 33, 50, 67, 75, 80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500],
            "defaultFactor": 100
        }
    }
}
```

The `"zoom"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"defaultFactor"` | `number` | Default zoom factor within the range of `25` to `500`. Avoid negative values. Defaults to `100`. |
| `"enabled"` | `boolean` | If `true` (default), will enable zooming. |
| `"factors"` | `number[]` | List of zoom factors to be used when the user zooms in or out of the window. The factors must be in ascending order and may have integer or floating point values. Zooming will only work with factor values within the range of `25` to `500`. Avoid passing negative values when setting the zoom factor (via configuration or programmatically), as this will cause unexpected behavior. Defaults to `[25, 33, 50, 67, 75, 80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500]`.|
| `"mode"` | `"domain"` \| `"window"` | Determines the default zoom behavior for web apps. If set to `"domain"` (default), changes in the zoom factor will be applied to the current window, as well as to all other windows within the same domain (default web browser behavior). If set to `"window"`, changes in the zoom factor will be applied only to the current window and won't affect other windows within the domain. *Available since **io.Connect Desktop** 9.10.* |
| `"mouseWheelZoom"` | `boolean` | If `true`, will enable zooming with `CTRL` + `mouse scroll`. Defaults to `false`. |
| `"shortcuts"` | `object` | Keyboard shortcuts for zooming. *Available since **io.Connect Desktop** 10.3.* |

The `"shortcuts"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"resetZoom"` | `string[]` | Keyboard shortcuts for resetting the zoom factor to the default value. Defaults to `["ctrl+0", "ctrl+num0"]`. |
| `"zoomIn"` | `string[]` | Keyboard shortcuts for zooming in. Defaults to `["ctrl+=", "ctrl+shift+=", "ctrl+numadd"]`. |
| `"zoomOut"` | `string[]` | Keyboard shortcuts for zooming out. Defaults to `["ctrl+-", "ctrl+numsub"]`. |

Available since io.Connect Desktop 9.10.1 & 10.0.3

The current zoom factors of all web app instances are persisted and restored automatically as follows when the default zoom behavior is set globally to `"window"` via the `"mode"` property of the `"zoom"` object:

- window refresh - When a window is refreshed, the io.Connect platform captures the current zoom factor before the page reloads and re-applies it automatically after the page has finished loading.

- zoom factor change - When the user changes the zoom factor of a standalone (not part of a Global Layout or a Workspace) web app instance, the platform persists the new zoom factor internally in the platform preferences per app. This zoom factor is automatically restored when a new instance of the same app is started or when the **io.Connect Desktop** is restarted.

- Global Layouts and Workspace Layouts - The current zoom factor of each window participating in the Layout is saved per window. When the Layout is restored, the zoom factor saved in the Layout for each participating window takes precedence over the zoom factor from the platform preferences. To persist the current zoom factors of windows in a Layout, the user must save the Layout first.

Each new instance of the same web app will have the last persisted zoom factor for that app. For example, if there are two running instances of the same app and the user sets the zoom factor of the first one to 125, then sets the zoom factor of the second one to 150, the third started instance of that app will have a zoom factor of 150.

> ℹ️ *For details on how to specify zoom settings per app, see the [Configuration > Application > Zooming](https://docs.interop.io/desktop/developers/configuration/application/index.md#zooming) section.*

> ℹ️ *For details on zooming windows programmatically, see the [Capabilities > Windows > Window Management](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-zoom) section.*

### Printing

> ⚠️ *Note that this property is valid only for apps of type `"window"`.*

Use the `CTRL + P` key combination to print a web page opened in an io.Connect Window. To enable or disable printing, or to configure the default print settings globally, use the `"print"` property.

The following is an example configuration for printing:

```json
{
    "windows": {
        "print": {
            "enabled": true,
            "silent": true,
            "color": false,
            "copies": 1,
            "footer": "https://my-domain.com/",
            "pageSize": "A4",
            "duplexMode": "longEdge"
        }
    }
}
```

| Property | Type | Description |
|----------|------|-------------|
| `"color"` | `boolean` | If `true` (default), will print the page in color. Otherwise, in grayscale. |
| `"copies"` | `number` | The number of copies to print. |
| `"duplexMode"` | `string` | Setting for duplex printing. |
| `"enabled"` | `boolean` | If `true` (default), will enable printing. |
| `"footer"` | `string` | String that will be printed as a footer on each page. |
| `"pageSize"` | `string` | The size of the printed page. |
| `"silent"` | `boolean` | If `true`, won't ask the user for print settings. Defaults to `false`. |

> ℹ️ *For more details on all available properties for printing, see the `"print"` key in the [`system.json`](https://docs.interop.io/desktop/assets/configuration/system.json) schema.*

To enable or disable printing a web page as a PDF file, or to configure the default settings for printing to PDF globally, use the `"printToPdfSettings"` property.

The following is an example configuration for printing to a PDF file:

```json
{
    "windows": {
        "printToPdfSettings": {
            "enabled": true,
            "autoSave": true,
            "autoOpenPath": true,
            "fullPath": "C:/Users/%USERNAME%/Documents/PDF",
            "usePrintShortcutKey": true,
            "pageSize": "A4",
            "printBackground": true,
            "printSelectionOnly": true
        }
    }
}
```

| Property | Type | Description |
|----------|------|-------------|
| `"autoOpenPath"` | `boolean` | If `true`, will open automatically the directory where the file was saved. Defaults to `false`. |
| `"autoSave"` | `boolean` | If `true`, will auto save the PDF file. If `false`, a system dialog will appear asking the user where to save the file. Defaults to `false`. |
| `"enabled"` | `boolean` | If `true` (default), will enable printing to a PDF file. |
| `"fullPath"` | `string` | The default directory where PDF files will be saved. Defaults to `"%DownloadsFolder%"`. |
| `"pageSize"` | `string` | The size of the printed page. |
| `"printBackground"` | `boolean` | If `true`, will print the page background. |
| `"printSelectionOnly"` | `boolean` | If `true`, will print only the currently selected section of the page. |
| `"usePrintShortcutKey"` | `boolean` | If `true`, will use `CTRL + P` by default to print to a PDF file. |

> ℹ️ *For more details on all available properties for printing to a PDF file, see the `"printToPdfSettings"` key in the [`system.json`](https://docs.interop.io/desktop/assets/configuration/system.json) schema.*

> ℹ️ *For details on how to specify print settings per app, see the [Configuration > Application > Printing](https://docs.interop.io/desktop/developers/configuration/application/index.md#printing) section.*

> ℹ️ *For details on how to print web pages programmatically, see the [Capabilities > Windows > Window Management](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-print) section.*

### Filtering Web Requests

To instruct **io.Connect Desktop** to filter web requests, use the `"urlFilter"` property. Provide a regular expression as a value that will be matched against the URLs for all web requests. Matched URLs will be allowed, all other requests will be blocked and a dialog will be shown to the user informing them that the URL is blocked by the organization.

The following example demonstrates how to allow only web requests for URLs that start with `https://`:

```json
{
    "windows": {
        "urlFilter": "^https://"
    }
}
```

Available since io.Connect Desktop 10.3

The `"urlFilter"` property also accepts an array of strings as a value. Use this to define multiple allowed domain patterns without combining them into a single complex regular expression:

```json
{
    "windows": {
        "urlFilter": [
            "^https://.*\\.example\\.com",
            "^https://.*\\.another-example\\.com"
        ]
    }
}
```

### Modifying Response Headers

Available since io.Connect Desktop 9.8

> ⚠️ *Note that this property is valid only for apps of type `"window"`.*

To configure the behavior for handling the response headers globally for all web apps, use the `"responseHeaders"` property. It accepts as a value an object holding combinations of string keys and object values describing the response headers to modify or to remove. Each key in the `"responseHeaders"` object must correspond to an [HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers) name. Each object value has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"directives"` | `object[]` | List of response header directives to be modified. It's possible to remove a directive, to replace its value, or to append a value to its current value. |
| `"remove"` | `boolean` | If `true`, the entire response header will be removed. |

Each object in the `"directives"` array has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"action"` | `"append"` \| `"remove"` \| `"replace"` | Action to be performed on the directive. Set to `"remove"` to remove the directive. Set to `"replace"` to replace the current value. Set to `"append"` to append a value to the current directive value. When replacing or appending a value, it's required to specify a new value. |
| `"name"` | `string` | Name of the directive to modify. |
| `"value"` | `string` | New value for the directive. Required when replacing or appending a directive value. |

The following example demonstrates how to configure **io.Connect Desktop** to modify the `Content-Security-Policy` response header for all web apps by appending a value to its `frame-ancestors` directive:

```json
{
    "windows": {
        "responseHeaders": {
            "Content-Security-Policy": {
                "directives": [
                    {
                        "name": "frame-ancestors",
                        "action": "append",
                        "value": "https://another-trusted-site.com/"
                    }
                ]
            }
        }
    }
}
```

> ℹ️ *For details on how to configure the behavior for handling response headers per app, see the [Configuration > Application > Modifying Response Headers](https://docs.interop.io/desktop/developers/configuration/application/index.md#modifying_response_headers) section.*

### User Agent

> ⚠️ *Note that this property is valid only for apps of type `"window"`.*

To specify a custom `User-Agent` request header to be sent when connecting to a server, use the `"userAgent"` property:

```json
{
    "windows": {
        "userAgent": "custom-user-agent-string"
    }
}
```

Available since io.Connect Desktop 10.1

The `"userAgent"` property accepts also an object with the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"append"` | `string` | String to append to the end of the clean Chromium `User-Agent` string. Valid only if `"type"` is set to `"chromium"`. Use this to add custom tokens to the clean Chromium `User-Agent` string. |
| `"type"` | `"chromium" \| "custom"` | Type of the `User-Agent` string. If set to `"chromium"`, will use the default Chromium `User-Agent` string without the Electron token. If set to `"custom"`, you must provide a custom string via the `"value"` property. |
| `"value"` | `string` | Custom string to use for the `User-Agent` request header. Valid only if `"type"` is set to `"custom"`. This value will replace the entire default `User-Agent` string. |

The following example demonstrates how to configure a custom `User-Agent` request header by using the clean Chromium `User-Agent` string and appending a custom suffix to it:

```json
{
    "windows": {
        "userAgent": {
            "type": "chromium",
            "append": "MyCustomUserAgent"
        }
    }
}
```

> ℹ️ *For details on how to control the custom `User-Agent` request header per app, see the [Configuration > Application > User Agent](https://docs.interop.io/desktop/developers/configuration/application/index.md#user_agent) section.*

## Themes

To specify settings for the io.Connect themes and for your own custom themes, use the `"themes"` top-level key:

```json
{
    "themes": {
        "availableThemes": [
            // Default values for the built-in io.Connect themes.
            {
                "name": "dark",
                "displayName": "Dark",
                "description": "Dark theme for the io.Connect platform."
            },
            {
                "name": "light",
                "displayName": "Light",
                "description": "Light theme for the io.Connect platform."
            },
            // Adding a custom theme.
            {
                "name": "my-custom-theme",
                "displayName": "My Custom Theme",
                "description": "Custom theme for my platform.",
                "background": "#E30B5D",
                "loadingAnimation": "./assets/my-custom-loader/loader.xaml"
            }
        ]
    }
}
```

The `"themes"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"availableThemes"` | `object[]` | List of objects describing the available platform themes. *Available since **io.Connect Desktop** 10.0.* |
| `"convertThemesConfigToCSS"` | `boolean` | If `true`, the theme settings for the io.Connect [classic groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-classic_groups) defined in the `themes.json` file will be converted to CSS variables and injected in the Web Group App. Set to `true` if you are using classic groups instead of [web groups](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_groups-web_groups) and you want to automatically migrate your custom [theme styles](https://docs.interop.io/desktop/developers/configuration/themes/index.md) to the Web Group App. This is necessary, because, as of **io.Connect Desktop** 10.0, [classic groups are deprecated](https://docs.interop.io/desktop/getting-started/changelog/10-0/index.md#deprecated_platform_apps-classic_groups) and web groups are the default mechanism for handling io.Connect windows in the [default platform mode](#platform_modes). Defaults to `false`. *Available since **io.Connect Desktop** 10.0.* |
| `"getThemesMethodName"` | `string` | The name of the registered [Interop method](https://docs.interop.io/desktop/capabilities/data-sharing/interop/overview/index.md) for retrieving the themes. Defaults to `"T42.Themes.Get"`. |
| `"setThemesMethodName"` | `string` | The name of the registered Interop method for changing the themes. Defaults to `"T42.Themes.Change"`. |
| `"sharedContextName"` | `string` | Name of the shared context object for the themes. Defaults to `"T42.Themes"`. |
| `"syncWithDefaultOSAppMode"` | `boolean` | If `true`, will synchronize the io.Connect theme with the default OS app mode. Defaults to `false`. |
| `"toggleThemesMethodName"` | `string` | The name of the registered Interop method for toggling the themes. Defaults to `"T42.Themes.Toggle"`. |

Each object in the `"availableThemes"` array has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"background"` | `string` | Background color for the theme in hex format (e.g., `"#FFFFFF"`). |
| `"description"` | `string` | Optional description for the theme. |
| `"displayName"` | `string` | Display name for the theme. |
| `"groupIcon"` | `string` | The name of an icon file that will be used in the Windows taskbar for io.Connect Window groups. The file must be in ICO format and must be located in the `<installation_location>/assets/images` folder. |
| `"groupIconURL"` | `string` | If you have the same icon for some or all apps and want to group them with window groups in the Windows taskbar, you should provide the URL of this icon as specified in the app definitions. This icon won't be downloaded - the icon URL specified here will be used only for creating an icon ID that the OS needs for grouping icons in the Windows taskbar. |
| `"loadingAnimation"` | `string` | Path to a loading animation in XAML format to be used by the platform for io.Connect Windows when using classic groups. This must be a local file. The path can be absolute or relative and you can use environment variables. |
| `"name"` | `string` | **Required.** Unique name for the theme. Will be used as a CSS class selector applied to the `<html>` element of the web app. |
| `"tabGroupIcon"` | `string` | The name of an icon file that will be used in the Windows taskbar for io.Connect Window tab groups. The file must be in ICO format and must be located in the `<installation_location>/assets/images` folder. |

## Citrix Apps

> ⚠️ *Note that this feature is still experimental in **io.Connect Desktop**.*

The default system settings for the Citrix Virtual Apps support should work fine in most cases and usually it isn't necessary to make any modifications. If the default settings don't work for your specific environment, use the `"citrix"` top-level key to provide custom values.

The following configuration contains the default Citrix settings:

```json
{
    "citrix": {
        "launcherPath": "%ProgramFiles(x86)%/Citrix/ICA Client/SelfServicePlugin",
        "launcherModule": "SelfService.exe",
        "launcherArguments": "-qlaunch \"$appName$\"",
        "launcherSpawnInterval": 1500
    }
}
```

The `"citrix"` key has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"launcherArguments"` | `string` | The command line arguments used to launch published Citrix Virtual Apps. Defaults to `"-qlaunch \"$appName$\""`. |
| `"launcherModule"` | `string` | The file name of the Citrix module used to launch published Citrix Virtual Apps. Defaults to `"SelfService.exe"`. |
| `"launcherPath"` | `string` | Location of the Citrix module used to launch published Citrix Virtual Apps. Defaults to `"%ProgramFiles(x86)%/Citrix/ICA Client/SelfServicePlugin"`. |
| `"launcherSpawnInterval"` | `number` | Interval in milliseconds at which multiple launcher modules will be spawned. Defaults to `1500`. |

## Email Client

Available since io.Connect Desktop 9.1

To provide settings for the email client to be used by **io.Connect Desktop** when sending emails via the io.Connect API or when submitting feedback, use the `"emailClient"` top-level key:

```json
{
    "emailClient" {
        "type": "SMTP",
        "config": {
            "host": "smtp-mail.outlook.com",
            "port": 587,
            "user": "my-email@my-org.com",
            "password": "password",
            "enableSSL": true
        }
    }
}
```

The `"emailClient"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"config"` | `object` | Configuration for the email client. |
| `"type"` | `"Outlook"` \| `"SMTP"` \| `"MAPI"` | Defines the type of the email client. Defaults to `"Outlook"`. |

The `"config"` property is necessary only when `"type"` is set to `"SMTP"` and has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enableSSL"` | `boolean` | If `true`, the SMTP email client will use SSL to encrypt the connection. |
| `"from"` | `string` | The email address of the sender. |
| `"host"` | `string` | The name or IP address of the host used for SMTP transactions. |
| `"password"` | `string` | The password used for authentication. |
| `"port"` | `number` | The port used for SMTP transactions. |
| `"user"` | `string` | The username used for authentication. |

## Feedback Form

To configure the [Feedback Form](https://docs.interop.io/desktop/capabilities/more/features/index.md#feedback_form) of **io.Connect Desktop**, use the `"issueReporting"` top-level key:

```json
{
    "issueReporting": {
        "attachmentsViewMode": "category",
        "mail": {
            "enabled": true,
            "zipAttachments": true,
            "bugSubjectPrefix": "Error:",
            "reportSubjectPrefix": "Feedback:",
            "recipients": ["support@example.com", "dev-support@example.com"],
            "allowEditRecipients": true,
            "maxAttachmentMB": "10"
        },
        "folderAttachments": [
            {
                "name": "Screenshots",
                "folderPath": "%IO_CD_USER_DATA_DIR%/logs",
                "zipFolderPath": "io.Connect Desktop/Screenshots",
                "filter": "*.png",
                "category": "Screenshots",
                "selected": false,
                "recursive": true
            },
            {
                "name": "io.Connect Desktop-AppLogs",
                "folderPath": "%IO_CD_USER_DATA_DIR%/logs",
                "zipFolderPath": "io.Connect Desktop/Logs",
                "filter": "*.log*",
                "category": "App Logs",
                "selected": true,
                "recursive": true
            },
            {
                "name": "io.Connect Desktop-Crashes",
                "folderPath": "%IO_CD_USER_DATA_DIR%/crashes/reports",
                "zipFolderPath": "io.Connect Desktop/Crashes",
                "filter": "*.dmp",
                "category": "Crashes",
                "recursive": false
            }
        ],
        "form": {
            "width": 350,
            "height": 500
        }
    }
}
```

The `"issueReporting"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"attachmentsViewMode"` | `"file"` \| `"category"` | Defines how the attachments will be displayed in the Feedback Form. Possible values are `"file"` or `"category"`. If set to `"file"`, all attachable files will be displayed as separate items, otherwise several main categories will be displayed and if the category is selected by the user, all files in it will be attached. |
| `"attachScreenshots"` | `boolean` | If `true`, will attach screenshots of all monitors to the issue report. |
| `"enabled"` | `boolean` | If `true` (default), the Feedback Form will be enabled in **io.Connect Desktop**. Set to `false` to disable it. When disabled, the Feedback Form won't be displayed automatically in case of platform crashes and the users won't be able to access it from the platform tray menu or from the "Feedback" button of your interop-enabled apps. *Available since **io.Connect Desktop** 9.10.* |
| `"folderAttachments"` | `object[]` | Attachments configuration. For more details, see the [Attachments](#feedback_form-attachments) section. |
| `"form"` | `object` | Object that can be used to specify various properties for the io.Connect Window containing the Feedback Form, or to provide a URL pointing to a custom Feedback app. |
| `"mail"` | `object` | Email configuration. For more details, see the [Email](#feedback_form-email) section. |

### Email

The configuration for automatically sending an email when submitting a Feedback Form is found under the required `"mail"` property of the `"issueReporting"` top-level key. It accepts an object with the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"action"` | `"send"` \| `"display"` | Defines the action to be performed when submitting the Feedback Form. If set to `"send"` (default), the email will be sent immediately (if possible, depending on security settings). If set to `"display"`, an email draft will be shown to be reviewed and sent manually by the user. Valid only for Outlook and MAPI [email clients](#email_client). *Available since **io.Connect Desktop** 10.0.* |
| `"allowEditRecipients"` | `boolean` | If `true`, the user will be allowed to manually add more recipients. |
| `"bugSubjectPrefix"` | `string` | Prefix for the email subject when the issue is a bug. |
| `"enabled"` | `boolean` | If `true`, will enable the option to send an email when submitting the issue. |
| `"maxAttachmentMB"` | `string` | The maximum size of the attachments in MB. |
| `"recipients"` | `string[]` | List of email addresses to which the issue report will be sent. |
| `"reportSubjectPrefix"` | `string` | Prefix for the email subject when sending feedback. |
| `"zipAttachments"` | `boolean` | If `true`, the attachments will be archived. |

### Attachments

The configuration for attaching files when submitting a Feedback Form is found under the required `"folderAttachments"` property of the `"issueReporting"` top-level key. It accepts an array of objects, each with the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"category"` | `string` | **Required.** Category for the attached item. |
| `"filter"` | `string` | **Required.** Regex filter that will be applied to each file in the folder - e.g., `"*.log"`. |
| `"folderPath"` | `string` | **Required.** Path to the folder that will be attached. |
| `"name"` | `string` | **Required.** Name for the attachment. |
| `"recursive"` | `boolean` | If `true`, will collect and attach all files from all folders located inside the specified folder. Set to `false` to collect the files only in the specified folder. |
| `"selected"` | `boolean` | If `true`, the category (or all files under this category) in the Feedback Form will be selected by default. |
| `"zipFolderPath"` | `string` | **Required.** Path in the archived folder. |

#### Form

To configure the io.Connect Window containing the Feedback Form, use the `"form"` property of the `"issueReporting"` top-level key. It accepts an object with the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"height"` | `number` | Height in pixels for the Feedback Form. |
| `"showEnvironmentInfo"` | `boolean` | If `true`, the Feedback Form will show a field with details about the io.Connect environment. |
| `"transparent"` | `boolean` | If `true`, the io.Connect Window containing the Feedback Form will have a transparent background. *Available since **io.Connect Desktop** 9.1.* |
| `"url"` | `string` | URL pointing to the location of the Feedback app. |
| `"width"` | `number` | Width in pixels for the Feedback Form. |

> ⚠️ *Note that the `"transparent"` property will set a transparent background only for the io.Connect Window that contains the Feedback app. To achieve actual transparency, you must also set a transparent background for your app from its styles.*

![Feedback Form](https://docs.interop.io/desktop/images/platform-features/feedback-form.png)

> ℹ️ *For details on how to enable or disable the ["Feedback" button](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#feedback_button) globally or per app, see the [Window Settings > Feedback Button](#window_settings-feedback_button) and the [Configuration > Application > Feedback Button](https://docs.interop.io/desktop/developers/configuration/application/index.md#feedback_button) sections respectively.*

> ℹ️ *For details on how to create your custom Feedback app, see the [Capabilities > More > Features > Feedback Form > Extending the Feedback Form](https://docs.interop.io/desktop/capabilities/more/features/index.md#feedback_form-extending_the_feedback_form) section.*

## Download Manager

**io.Connect Desktop** allows for files to be downloaded in io.Connect Windows. Users can pause and cancel downloads, and open the location of completed downloads by clicking on them.

Available since io.Connect Desktop 9.2

The io.Connect Download Manager is a central place for managing all downloads. It maintains and displays a list of ongoing, paused, completed, and canceled downloads (download items). Users can pause, resume or cancel downloads from it, open the location of a downloaded file, clear the list of downloads or remove individual download items from it, search for downloads, set the default location for downloading files. The Download Manager can be started via a configurable keyboard shortcut (`CTRL + J` by default), and can also be configured to open automatically when a download is initiated. Programmatic changes to download items are reflected in the Download Manager.

![Download Manager](https://docs.interop.io/images/window-management/download-manager.png)

Available since io.Connect Desktop 10.2

The Download Manager can be accessed via the "Download" button in the header of io.Connect Windows that appears when a file is being downloaded. The button opens a download popup which allows users to see the download progress, pause, resume, cancel downloads, and open the location of completed downloads.

> ⚠️ *Note that the "Download" button is available only for web groups. If an io.Connect Window is inserted into a Workspace during an ongoing download, the "Download" button will disappear.*

![Download Popup](https://docs.interop.io/images/window-management/download-popup.png)

> ℹ️ *For details on how to configure the "Download" button, see the [Window Settings > Downloads](#window_settings-downloads) section.*

To configure the [Download Manager](https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.md#window_operations-download) of **io.Connect Desktop**, use the `"downloadManager"` top-level key.

```json
{
    "downloadManager": {
        "autoStartOnDownload": true,
        "shortcut": "ctrl+alt+d"
    }
}
```

The `"downloadManager"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"appName"` | `string` | Name of an io.Connect app, as specified in its definition, to be used as a Download Manager. Defaults to `"io-connect-download-manager"`. |
| `"autoStartOnDownload"` | `boolean` | If `true`, the Download Manager app will be started automatically when a download is initiated. Defaults to `false`. |
| `"shortcut"` | `string` | Shortcut for starting the Download Manager app. Defaults to `"ctrl+j"`. |

## About App

To customize the [About app](https://docs.interop.io/desktop/capabilities/more/features/index.md#about_app) of **io.Connect Desktop**, use the `"about"` top-level key.

The `"about"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"height"` | `number` | Height in pixels for the About app. |
| `"hideTrademark"` | `boolean` | Hide the trademark information section in the About app. |
| `"url"` | `string` | URL pointing to the location of the About app. |
| `"width"` | `number` | Width in pixels for the About app. |

To remove the trademark information at the bottom of the page, use the `"hideTrademark"` property:

```json
{
    "about": {
        "hideTrademark": true
    }
}
```

You can also change the entire content displayed in the About app and its size by providing a URL to be loaded instead of the default app and specifying the desired width and height.

The following example demonstrates how to modify the size and the content of the About app:

```json
{
    "about": {
        "url": "https://interop.io/",
        "width": 500,
        "height": 500
    }
}
```

![Custom About](https://docs.interop.io/desktop/images/platform-features/about-custom.mp4)

## Telemetry Data

Telemetry data is disabled by default. To enable it, set the `"telemetry"` top-level key to `true`:

```json
{
    "telemetry": {
        "enabled": true
    }
}
```

The `"telemetry"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true`, will enable telemetry data published by **io.Connect Desktop**. If `false`, telemetry data won't be gathered or published. |
| `"features"` | `object` | Telemetry data sets that you can enable or disable from being published by **io.Connect Desktop**. *Available since **io.Connect Desktop** 9.5.* |

The `"features"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"apps"` | `boolean` | If `true`, will enable publishing telemetry data related to web app performance. |
| `"stores"` | `boolean` | If `true`, will enable publishing telemetry data related to app stores. |
| `"system"` | `boolean` | If `true`, will enable publishing telemetry data related to system performance. |

> ℹ️ *For details on how to retrieve telemetry data programmatically, see the [Capabilities > More > Features > Telemetry Data](https://docs.interop.io/desktop/capabilities/more/features/index.md#telemetry_data) section.*

## Folders

To configure the location of the system folders of **io.Connect Desktop**, use the `"folders"` top-level key.

The `"folders"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"cache"` | `string` \| `object` | Settings for the Electron cache. Defaults to `"%IO_CD_USER_DATA_DIR%"`. |
| `"platformCache"` | `string` | Settings for the **io.Connect Desktop** cache (preload files, injected CSS files, and app icons). *Available since **io.Connect Desktop** 9.6.* |
| `"remoteConfig"` | `string` | Location for storing configuration files for **io.Connect Desktop** downloaded from remote locations. Defaults to `"%IO_CD_USER_DATA_DIR%/remoteConfig"`. |
| `"userData"` | `string` | Location for storing user-specific data like app definitions, Layouts, logs, cache and other system information. Accepts an absolute path, or a path relative to the location of the **io.Connect Desktop** executable file. You can use environment variables. Defaults to `"%IO_CD_USER_DATA_DIR%"`. |

The following example demonstrates how to change the location of the folder containing remote configurations for **io.Connect Desktop**:

```json
{
    "folders": {
        "remoteConfig": "%LocalAppData%/my-configs/%IO_CD_ENV%-%IO_CD_REGION%/remote"
    }
}
```

Available since io.Connect Desktop 9.2

The `"cache"` property accepts also an object with the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"clearOld"` | `boolean` | If `true`, the Electron cache from previous platform versions within the same location will be deleted on startup. Defaults to `false`. *Available since **io.Connect Desktop** 9.4.* |
| `"copy"` | `boolean` \| `object` | - If `true`, the Electron cache from the closest previously installed **io.Connect Desktop** version will be copied and added to the cache files for the upgraded version of **io.Connect Desktop**. Defaults to `false`. <br> - Settings for copying the Electron cache. *Available since **io.Connect Desktop** 9.5.*  |
| `"location"` | `string` | Location for the Electron cache. Accepts an absolute path, or a path relative to the location of the **io.Connect Desktop** executable file. You can use environment variables. Defaults to `"%IO_CD_USER_DATA_DIR%"`. |

The following example demonstrates how to define a custom location for the Electron cache and instruct **io.Connect Desktop** to copy the cache from the closest previously installed version:

```json
{
    "folders": {
        "cache": {
            "copy": true,
            "location": "../MyCache/%IO_CD_ENV%-%IO_CD_REGION%/"
        }
    }
}
```

Available since io.Connect Desktop 9.5

The `"copy"` property of the `"cache"` object accepts also an object with the following properties as a value:

| Property | Type | Description |
|----------|------|-------------|
| `"path"` | `string` | Absolute path pointing the location from where to copy the Electron cache and add it to the cache files for the upgraded version of **io.Connect Desktop**. |

Available since io.Connect Desktop 9.6

The `"platformCache"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"location"` | `string` | Absolute path determining the location for storing the cached files. The platform will use this location to cache all preload scripts and injected CSS files defined in the system configuration and in the app definition files, as well as all app icons. You can use [environment variables](https://docs.interop.io/desktop/developers/configuration/overview/index.md#environment_variables). Defaults to `"%IO_CD_USER_DATA_DIR%/cache"`. |

## Logging

The logging configuration for **io.Connect Desktop** is found under the `"logging"` top-level key in the `system.json` file.

You can use it to define [custom log appenders](#logging-custom_log_appenders) and categories to be used by **io.Connect Desktop** for logging, as well as to specify settings for the [system logging](#logging-system_log_settings) of **io.Connect Desktop**.

The `"logging"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"configuration"` | `object` | Settings for the logging mechanism of **io.Connect Desktop**. This property accepts any valid `log4js-node` configuration object containing definitions of log appenders and categories. The available configuration options are described in detail in the `log4js-node` [API documentation](https://log4js-node.github.io/log4js-node/api.html). *Available since **io.Connect Desktop** 10.0.* |
| `"files"` | `boolean` | Settings for handling [log files](#logging-system_logs-log_files). |
| `"logSanitization"` | `boolean` | If `true` (default), the platform logs will be sanitized. If set to `false`, sensitive information (credentials, personal details, network information, API keys and tokens, window details) won't be removed from the platform logs. |
| `"streaming"` | `object` | Settings for [streaming the system logs](#logging-system_logs-streaming) of **io.Connect Desktop**. |

By default, **io.Connect Desktop** uses two of the core `log4js-node` [appenders](https://log4js-node.github.io/log4js-node/appenders.html) - `file` and `multiFile`. The `file` appender is used for logging events related to the **io.Connect Desktop** app itself, while the `multiFile` appender is used for logging events related to io.Connect client apps.

> ℹ️ *For details on how to use the [Logger API](https://docs.interop.io/desktop/capabilities/logging/javascript/index.md) that enables your io.Connect apps to output logs to files or to the console, see the [Capabilities > Logging](https://docs.interop.io/desktop/capabilities/logging/overview/index.md) section.*

> ℹ️ *For details on how to configure logging per app, see the [Configuration > Application > Logging](https://docs.interop.io/desktop/developers/configuration/application/index.md#logging) section.*

> ℹ️ *For more details on examining the io.Connect logs, see the [Examining Logs in Practice](https://community.interop.io/t/examining-logs-in-practice/110) article on the [Developer Community](https://community.interop.io/) site.*

#### 9.0 Version Stream

If you are still using the **io.Connect Desktop** 9.0 version stream, you can find the configuration for log appenders and categories in the `logger.json` file of **io.Connect Desktop** located in the `<installation_location>/interop.io/io.Connect Desktop/Desktop/config` folder. JSON schema for the `logger.json` file isn't available, as the **io.Connect Desktop** logging mechanism is based on [`log4js-node`](https://github.com/log4js-node/log4js-node).

### Custom Log Appenders

You can add any other `log4js-node` [appenders](https://log4js-node.github.io/log4js-node/appenders.html) (core, optional and custom) and [categories](https://log4js-node.github.io/log4js-node/categories.html) to the **io.Connect Desktop** logging configuration.

The following example demonstrates how to add the [`logstashHTTP`](https://github.com/log4js-node/logstashHTTP) optional appender to **io.Connect Desktop**:

1. Create a directory for the appender and run the following command to install it:

```cmd
npm install @log4js-node/logstash-http
```

2. Create an `index.js` file in which import and export the appender:

```javascript
module.exports = require("@log4js-node/logstash-http");
```

3. Add the [`logstashHTTP`](https://github.com/log4js-node/logstashHTTP) appender under the `"appenders"` property of the `"configuration"` object under the `"logging"` top-level key in the `system.json` file:

```json
{
    "logging": {
        "configuration": {
            "appenders": {
                "logstash": {
                    "type": "%IO_CD_ROOT_DIR%/assets/logstash-http",
                    "url": "http://localhost:9200/_bulk",
                    "application": "My App",
                    "logType": "application",
                    "logChannel": "node"
                }
            }
        }
    }
}
```

The `"type"` property must point to the location of the [`logstash-http`](https://www.npmjs.com/package/@log4js-node/logstash-http) package. You can also use environment variables.

4. Under the `"categories"` property of the `"configuration"` object under the `"logging"` top-level key in the `system.json` file, define the log event [categories](https://log4js-node.github.io/log4js-node/categories.html) for which the log appender will be used:

```json
{
    "logging": {
        "configuration": {
            "categories": {
                "my-custom-category": {
                    "appenders": ["logstash"],
                    "level": "info"
                }
            }
        }
    }
}
```

### Log Appenders per App

Available since io.Connect Desktop 9.5

By default, **io.Connect Desktop** uses a `multiFile` appender named `"applications"` for logging events related to io.Connect client apps. To define separate log appenders per app, execute the following steps:

1. Define a log appender to be used for your app:

```json
{
    "logging": {
        "configuration": {
            "appenders": {
                "my-app-appender": {
                    "type": "file",
                    "filename": "%IO_CD_USER_DATA_DIR%/logs/my-app.log",
                    "maxLogSize": 10485760,
                    "backups": 5,
                    "minLevel": "info",
                    "keepFileExt": true,
                    "compress": true
                }
            }
        }
    }
}
```

2. Create a category with the name of your app as defined in its [app definition](https://docs.interop.io/desktop/developers/configuration/application/index.md) and assign the log appender to it. This will instruct **io.Connect Desktop** to use the specified log appender for your app:

```json
{
    "logging": {
        "configuration": {
            "categories": {
                "my-app": {
                    "appenders": [
                        "my-app-appender"
                    ],
                    "level": "trace"
                }
            }
        }
    }
}
```

### System Log Settings

To configure the system logging for **io.Connect Desktop**, use the `"logging"` top-level key in the `system.json` file.

#### Streaming

You can configure **io.Connect Desktop** to stream the system logs so that they can be consumed by your apps. To specify the log streaming configuration, use the `"streaming"` property of the `"logging"` top-level key:

```json
{
    "logging": {
        "streaming": {
            "enabled": true,
            "minLevel": "warn",
            "interval": 60
        }
    }
}
```

The `"streaming"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"enabled"` | `boolean` | If `true`, will enable streaming system log entries. Defaults to `false`. |
| `"interval"` | `number` | Interval in seconds at which the log entries will be streamed. Defaults to `120`. |
| `"minLevel"` | `"error"` \| `"warn"` \| `"info"` | The minimum level of the log entries to be streamed. Defaults to `"error"`. |

> ℹ️ *For details on how to consume the system logs, see the [Capabilities > Logging](https://docs.interop.io/desktop/capabilities/logging/overview/index.md#system_logs) section.*

#### Log Files

Available since io.Connect Desktop 9.3

To specify settings for handling the system log files, use the `"files"` property of the `"logging"` top-level key:

```json
{
    "logging": {
        "files": {
            "onStartup": "archive",
            "moveOldTo": "%LocalAppData%/my-org/logs"
        }
    }
}
```

The `"files"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"moveOldTo"` | `string` | Absolute path pointing to the location where the log files from the previous session (if any) will be moved on startup of **io.Connect Desktop**. You can use environment variables. Defaults to `"%GLUE-USER-DATA%/logs/archive"`. |
| `"onStartup"` | `"archive"` \| `"delete"` \| `"keep"` | Specifies how to handle the log files on system startup. Set to `"archive"` to archive the existing log files. Set to `"delete"` to delete the existing log files. Set to `"keep"` (default) to leave the existing log files intact. |

## Crash Reporter

To configure **io.Connect Desktop** how to handle system crash reports, use the `"crashReporter"` top-level key. You can enable or disable crash reporter logging, define metadata to be included in the crash reports, and also provide output settings for the reports:

```json
{
    "crashReporter": {
        "enabled": true,
        "folderPath": "%LocalAppData%/my-org/crashes",
        "companyName": "My Org",
        "productName": "My Product",
        "output": {
            "type": "local"
        }
    }
}
```

The `"crashReporter"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"companyName"` | `string` | **Required.** The company name to be included in the crash report. |
| `"enabled"` | `boolean` | **Required.** If `true`, the crash reporter will be enabled. |
| `"folderPath"` | `string` | **Required.** Location for the crash reporter logging and memory dumps when the output type is set to `"local"`. |
| `"ignoreSystemCrashHandler"` | `boolean` | If `true`, crashes generated in the main process won't be forwarded to the system crash handler. |
| `"output"` | `object` | **Required.** Output settings for the crash reporter. |
| `"productName"` | `string` | **Required.** The product name to be included in the crash report. |

The `"output"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"backTraceConfig"` | `object` | Settings for the Backtrace client. |
| `"dumps"` | `object` | Settings for handling the dump files for crash reports. *Available since **io.Connect Desktop** 9.3.* |
| `"serverUrl"` | `string` | URL pointing to the server (or to [**io.Manager**](https://docs.interop.io/manager/overview/index.md)) that will receive the crash report if the output type is set to `"server"`. Required if `"type"` is set to `"server"`. |
| `"type"` | `"local"` \| `"server"` \| `"backtrace"` | Type of the crash reporter output. Crash reports can be saved locally, sent to a REST service (including [**io.Manager**](https://docs.interop.io/manager/overview/index.md)), or to a Backtrace server. |

Available since io.Connect Desktop 9.3

To instruct **io.Connect Desktop** how to handle the dump files from the crash reporter, use the `"dumps"` property of the `"output"` object under the `"crashReporter"` top-level key:

```json
{
    "crashReporter": {
        "output": {
            "dumps": {
                "deleteOnSent": true,
                "limit": 10
            }
        }
    }
}
```

The `"dumps"` object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `"deleteOnSent"` | `boolean` | If `true`, when a dump file is sent, it will be deleted instead of moved to the `/sent` folder located in the directory containing the dump files. |
| `"limit"` | `number` | Limit for the number of dump files to keep. On system restart, the oldest files will be deleted until the file limit is met. |

## Electron Command Line Switches

To provide command line arguments (switches) which **io.Connect Desktop** will pass to the underlying Electron framework, use the `"switches"` top-level key and specify the arguments as key/value pairs. The [switches supported by Electron](https://www.electronjs.org/docs/latest/api/command-line-switches) include Electron CLI flags, as well as a limited set of Node.js CLI flags and Chromium flags:

```json
{
    "switches": {
        "remote-debugging-port": "4242",
        "no-deprecation": true
    }
}
```

The `"switches"` property enables you to specify command line arguments directly in the system configuration of **io.Connect Desktop**, sparing you the need to create additional BAT or CMD files.

If you need to, you can still pass the command line arguments directly to the **io.Connect Desktop** executable file:

```cmd
io-connect-desktop.exe --enable-logging --log-file=my-log-file.log
```

## Node.js Environment

**io.Connect Desktop** comes with the Node.js version distributed with the Electron framework. To use a different version of the Node.js environment for your Node.js apps, add one or more Node.js versions in the `<installation_location>/assets/node` folder of **io.Connect Desktop**. The names of the Node.js executable files must be in the format `node-[version].exe` (e.g., `node-22.21.1.exe`) in order for **io.Connect Desktop** to be able to find the correct version for each Node.js app.

To instruct the platform where to find the default Node.js environment, use the `"nodePath"` top-level key:

```json
{
    "nodePath": "./assets/node/node-22.21.1.exe"
}
```

> ℹ️ *For details on how to specify a Node.js version per app, see the [Configuration > Application > App Definition > Node.js](https://docs.interop.io/desktop/developers/configuration/application/index.md#app_definition-nodejs-nodejs_environment) section.*
