Appearance
Sites
Select a target site (for example, San Jose, Shanghai, Noida) and filter visible apps and site-specific policy objects based on that selection. Sites replace Location Profiles.
What You'll Learn
- Define sites users can select in the Launcher
- Filter app visibility and configuration using
siteRefs - Understand filter-then-precedence evaluation and first-run behavior
Overview
Sites let you present different application catalogs and configuration per target region or infrastructure. When a user selects a site, only objects that apply to that site become eligible. This differs from geo-based authorization (ABAC); Sites are an explicit user or policy selection, not a detected physical location.
Key properties
- Sites are active when
configuration.sites.profileshas one or more entries; if empty or missing, Sites are inactive. - Sites are defined once under
configuration.sites. - Objects opt in to site-aware behavior by declaring
siteRefs. - Site filtering does not add a new precedence layer. It determines eligibility, then existing precedence rules apply.
- When Sites are active, the policy is secure-by-default: no site-filtered policy entries are eligible until a site is selected (apps, proxy routing rules, and other
siteRefs-aware configuration).
Configuration
Define Sites (replaces Location Profiles)
json
{
"configuration": {
"sites": {
"defaultSiteId": "san-jose",
"selectionMode": "user",
"profiles": [
{ "id": "san-jose", "displayName": "San Jose", "countryCode": "us" },
{ "id": "shanghai", "displayName": "Shanghai", "countryCode": "cn" },
{ "id": "noida", "displayName": "Noida", "countryCode": "in" }
]
}
}
}Fields
defaultSiteId(string, optional): Site id to use when no valid site is selected and auto selection is not used or fails. Must match a value inprofiles[].id.selectionMode("user" | "device" | "policy-assigned" | "auto"): How the active site is selected. Use"auto"to pick a site automatically based on anchor measurements. Auto selection runs only when no user selection exists; once a user selects a site, their choice persists across launches and is not overridden by auto selection.profiles[](array): Available sites.profiles[].id(string): Stable identifier; referenced bysiteRefs.profiles[].displayName(string): UI label.profiles[].countryCode(string, optional): ISO 3166-1 alpha-2 country code (for example,"us","cn","in"). Used to display a flag icon in the sites dropdown in Turbo Launcher.defaultSelectionStrategy(string): Strategy used whenselectionMode: "auto". Current value:lowestLatency.profiles[].anchor(object, optional): Anchor used for auto-selection. Fortype: "proxy", setproxyRefto a proxy id inconfiguration.network.proxies.
Anchoring and Auto Selection
When selectionMode: "auto", the Launcher selects the active site automatically by measuring the configured anchors on each site profile and choosing the best fit according to defaultSelectionStrategy.
Triggering Behavior
- Auto selection runs only when there is no saved user selection yet (for example, on first run or after the setting is cleared).
- If a user later selects a site, that selection persists across launches and auto selection does not run again unless the user setting is cleared.
Fallback behavior
- If auto-selection is not configured, no anchors are configured, or anchor measurements fail, the Launcher uses
defaultSiteId(if configured).
Auto-selection triggers
- Auto-selection runs when the Launcher starts and no site selection exists.
- Once you manually select a site, that selection persists and auto-selection does not override it.
Anchor configuration
- Anchors are declared directly on
profiles[]via ananchorobject. The current anchor type isproxyand references proxies inconfiguration.network.proxies. - Single proxy: Use
proxyRef(string, deprecated) to reference one proxy by id. - Multiple proxies: Use
proxyRefs(string[]) to reference multiple proxies by id. When multiple proxies are specified, latency is measured to all proxies and the lowest latency from that set is used as the site's effective latency score. - With
defaultSelectionStrategy: "lowestLatency", the client performs a TCP connect test to each anchored proxy and selects the site with the lowest measured latency. - Profiles without an anchor (or with an unreachable anchor) are treated as high-latency candidates or ignored for auto-selection.
Example
json
{
"configuration": {
"network": {
"proxies": [
{ "id": "proxy-us-west", "type": "https", "url": "https://proxy-west.us.corp:443" },
{ "id": "proxy-us-east", "type": "https", "url": "https://proxy-east.us.corp:443" },
{ "id": "proxy-us-central", "type": "https", "url": "https://proxy-central.us.corp:443" },
{ "id": "proxy-cn-beijing", "type": "https", "url": "https://proxy-beijing.cn.corp:443" },
{ "id": "proxy-cn-shanghai", "type": "https", "url": "https://proxy-shanghai.cn.corp:443" }
]
},
"sites": {
"selectionMode": "auto",
"defaultSelectionStrategy": "lowestLatency",
"profiles": [
{
"id": "americas",
"displayName": "Americas",
"countryCode": "us",
"anchor": {
"type": "proxy",
"proxyRefs": ["proxy-us-west", "proxy-us-east", "proxy-us-central"]
}
},
{
"id": "china",
"displayName": "China",
"countryCode": "cn",
"anchor": {
"type": "proxy",
"proxyRefs": ["proxy-cn-beijing", "proxy-cn-shanghai"]
}
}
]
}
}
}Implementation Notes for the App
- Lookup
profiles[].anchor.proxyReforprofiles[].anchor.proxyRefs. - Resolve proxy ids against
configuration.network.proxiesto obtain endpointurl(s). - Perform a TCP connect test to each proxy URL and measure latency.
- When multiple proxies are specified (
proxyRefs), use the lowest latency from the set as the site's effective latency score. - Fallback: If a profile has no
anchor(or all proxies are unreachable), treat that site as high latency or ignore it during auto-selection.
App Visibility by Site
Use apps[].visibilityConstraints.siteRefs to scope app visibility to selected sites:
json
{
"apps": [
{
"id": "india-payroll",
"displayName": "India Payroll",
"enabled": true,
"priority": 100,
"visibility": "visible",
"visibilityConstraints": { "siteRefs": ["noida"] },
"matchAll": [ { "type": "targetPath", "pattern": "**\\\\IndiaPayroll.exe", "patternType": "glob" } ],
"action": "allow"
}
]
}Visibility resolution
visibility: "hidden"→ always hidden.visibility: "visible"+siteRefsomitted/empty → visible for all sites.visibility: "visible"+siteRefs: ["<site>"]→ visible only when the selected site matches.- Hidden-by-site apps can still be used by file associations if referenced and authorized.
Site-Filtered Objects
Objects become site-aware by adding an optional siteRefs: string[]. If omitted, the object is eligible for all sites.
Network Proxy Routing Rules
json
{
"configuration": {
"network": {
"proxyRouting": [
{
"id": "us-default",
"enabled": true,
"priority": 500,
"match": { "hosts": [{ "pattern": "*", "patternType": "glob" }] },
"action": { "type": "proxy", "proxyRef": "corp-proxy-us" }
},
{
"id": "cn-proxy-default",
"enabled": true,
"priority": 500,
"siteRefs": ["shanghai"],
"match": { "hosts": [{ "pattern": "*", "patternType": "glob" }] },
"action": { "type": "proxy", "proxyRef": "corp-proxy-cn" }
}
]
}
}
}Semantics
- Rules with
siteRefsare eligible only when the selected site is included. - Priority/id tie-breaks apply among eligible rules only.
Proxy DNS behavior is per-proxy, not per-site
Whether the proxy or the client performs hostname resolution is a property of the proxy itself (declared via resolveViaProxy on configuration.network.proxies[]), not of the site. The launcher uses the eligible proxy set for the selected site to decide whether to emit --disable-proxy-resolve-via-proxy. See Networking for details.
Storage: Mounts and Contexts
Global mounts (same name used for per-site variants):
json
{
"configuration": {
"launch": {
"mounts": [
{ "name": "corp-share", "source": "\\\\us-fs01\\share", "destination": "S:\\share", "options": ["read-write"] },
{ "name": "corp-share", "siteRefs": ["shanghai"], "source": "\\\\cn-fs01\\share", "destination": "S:\\share", "options": ["read-write"] }
]
}
}
}Storage contexts (same id used for per-site variants):
json
{
"configuration": {
"launch": {
"runtime": {
"files": {
"contexts": [
{ "id": "regional-share", "displayName": "US Share", "type": "smb", "source": "\\\\us-fs01\\data" },
{ "id": "regional-share", "siteRefs": ["shanghai"], "displayName": "China Share", "type": "smb", "source": "\\\\cn-fs01\\data" }
]
}
}
}
}
}Semantics
- Collect eligible items (matching
siteRefsor none). - For conflicts by identity (
namefor mounts,idfor contexts), the site-specific item overrides the non-site-specific item for the active site.
Launch Profiles
Show site-specific variants in the app’s context menu:
json
{
"apps": [
{
"id": "sap-gui",
"displayName": "SAP GUI",
"enabled": true,
"priority": 200,
"visibility": "visible",
"visibilityConstraints": { "siteRefs": ["san-jose", "noida", "shanghai"] },
"matchAll": [ { "type": "targetPath", "pattern": "**\\\\sapgui.exe", "patternType": "glob" } ],
"action": "allow",
"profiles": [
{ "id": "sap-san-jose", "displayName": "SAP (San Jose)", "siteRefs": ["san-jose"], "arguments": { "replace": "-client 200 -lang EN" } },
{ "id": "sap-shanghai", "displayName": "SAP (Shanghai)", "siteRefs": ["shanghai"], "arguments": { "replace": "-client 300 -lang ZH" } }
]
}
]
}Optional: Data Motion Rules and Processors
Data Motion rules:
json
{
"configuration": {
"launch": { "runtime": { "dataMotion": {
"rules": [
{
"id": "clip-dlp-us",
"enabled": true,
"priority": 900,
"channel": "clipboard",
"direction": "out",
"action": { "type": "process", "pipeline": [ { "processorRef": "dlp-us", "mode": "inspect" } ] }
},
{
"id": "clip-dlp-cn",
"enabled": true,
"priority": 900,
"siteRefs": ["shanghai"],
"channel": "clipboard",
"direction": "out",
"action": { "type": "process", "pipeline": [ { "processorRef": "dlp-cn", "mode": "inspect" } ] }
}
]
} } }
}
}Processors:
json
{
"configuration": {
"integrations": {
"processors": [
{ "id": "dlp-http", "type": "http", "endpoint": "https://dlp.us.example.com/inspect" },
{ "id": "dlp-http", "siteRefs": ["shanghai"], "type": "http", "endpoint": "https://dlp.cn.example.com/inspect" }
]
}
}
}Semantics
- Site-filtered items with the same identity (
id) override non-filtered ones for the active site.
Evaluation Semantics
Filter-then-precedence model:
- Determine the active site from
configuration.sites. - For each feature area, collect only objects that are eligible for the active site:
- Eligible when
siteRefsis omitted/empty or includes the active site.
- Eligible when
- Resolve conflicts among eligible objects:
- Prefer site-specific items over non-site-specific for the same identity.
- Then apply existing tie-breaks (for example,
prioritydesc, thenidalphabetical) and scope precedence.
- Apply standard scope precedence:
- Launch Profile > User Configuration > Policy (App) > Global
Notes
- When Sites are active (site profiles are defined): the policy is fail-closed. No policy entries are eligible until a site is selected or a default/auto selection produces an active site.
- Using
siteRefsdoes not change authorization; combine with ABAC for geo or posture enforcement.
First-Run Behavior
When Sites are active and no site has been selected:
- If
selectionMode: "auto", the client performs auto selection to choose the initial site. Subsequent manual user selections persist and are not overridden. - If auto selection does not yield a site, the Launcher uses
defaultSiteIdwhen configured. - If no active site can be determined, the policy is secure-by-default: no policy entries are eligible until the user selects a site.
- Recommend prompting users to select a site on first launch when no default is configured.
Validation
- Every
siteRefsentry must match an id inconfiguration.sites.profiles[].id. - Warn or error on duplicate objects with the same identity (
id/name) and overlappingsiteRefs.
Examples
Regional Proxies
json
{
"configuration": {
"sites": {
"selectionMode": "user",
"profiles": [ { "id": "san-jose", "displayName": "San Jose", "countryCode": "us" }, { "id": "shanghai", "displayName": "Shanghai", "countryCode": "cn" } ]
},
"network": {
"proxyRouting": [
{ "id": "default-us", "enabled": true, "priority": 500, "match": { "hosts": [ { "pattern": "*", "patternType": "glob" } ] }, "action": { "type": "proxy", "proxyRef": "corp-proxy-us" } },
{ "id": "default-cn", "enabled": true, "priority": 500, "siteRefs": ["shanghai"], "match": { "hosts": [ { "pattern": "*", "patternType": "glob" } ] }, "action": { "type": "proxy", "proxyRef": "corp-proxy-cn" } }
]
}
}
}Regional Storage
json
{
"configuration": {
"launch": {
"runtime": {
"files": { "contexts": [
{ "id": "regional-share", "displayName": "US Share", "type": "smb", "source": "\\\\us-fs01\\data" },
{ "id": "regional-share", "siteRefs": ["shanghai"], "displayName": "China Share", "type": "smb", "source": "\\\\cn-fs01\\data" }
] }
},
"mounts": [
{ "name": "corp-share", "source": "\\\\us-fs01\\share", "destination": "S:\\share" },
{ "name": "corp-share", "siteRefs": ["shanghai"], "source": "\\\\cn-fs01\\share", "destination": "S:\\share" }
]
}
}
}App Variants by Site (Launch Profiles)
json
{
"apps": [
{
"id": "sap-gui",
"displayName": "SAP GUI",
"enabled": true,
"priority": 200,
"visibility": "visible",
"visibilityConstraints": { "siteRefs": ["san-jose", "shanghai"] },
"matchAll": [ { "type": "targetPath", "pattern": "**\\\\sapgui.exe", "patternType": "glob" } ],
"action": "allow",
"profiles": [
{ "id": "sap-san-jose", "displayName": "SAP (San Jose)", "siteRefs": ["san-jose"], "arguments": { "replace": "-client 200 -lang EN" } },
{ "id": "sap-shanghai", "displayName": "SAP (Shanghai)", "siteRefs": ["shanghai"], "arguments": { "replace": "-client 300 -lang ZH" } }
]
}
]
}Migration from Location Profiles
Migrating from Location Profiles
Location Profiles have been replaced by Sites. To migrate:
- Rename
configuration.locationProfiles→configuration.sites(fields map 1:1). - Rename
visibilityConstraints.locationRefs→visibilityConstraints.siteRefs. - Optionally add
siteRefsto proxy routing rules, mounts/contexts, launch profiles, and (optionally) data motion rules or processors.
Troubleshooting
- App not visible after selecting site: Verify
visibilityConstraints.siteRefsincludes the selected site id. - Site-specific mount/context not applied: Ensure the identity (
name/id) matches the non-filtered entry andsiteRefscontains the selected site id. - Conflicts across sites: Avoid overlapping
siteRefson objects with the same identity.
