SfSkills Domains Docs GitHub

Home / admin / service-console-configuration

service-console-configuration

Use this skill to configure a Lightning Service Console app in Salesforce — Console Navigation (split view), workspace tabs and subtabs, the utility bar with Omni-Channel, Macros and History, Quick Text, keyboard shortcuts, and navigation rules per object.

Open the skill folder on GitHub


Service Console Configuration

Use this skill when an admin needs to configure a Lightning Service Console app for a support team — this includes enabling Console Navigation (split view), configuring workspace tabs and subtabs, setting up the utility bar, creating macros and Quick Text entries, defining navigation rules per object, and customizing keyboard shortcuts. This skill covers the full console setup from app creation to agent-ready configuration.


Before Starting

Gather this context before working on anything in this domain:


Questions to Ask Before Configuring

Ask these before opening App Manager. Each one changes the metadata, and an LLM that skips them produces a console app that deploys cleanly and behaves wrong for agents.

AskWhy it mattersWhat a good answer adds
"For each object agents open, which record should it appear under, and which field says so?"WorkspaceMapping.fieldName names a lookup on the child's own object; absence of a fieldName means primary tab, not "inherit the current workspace" (Gotcha 6, Gotcha 7)One mappings entry per tab, each with the exact lookup API name or a deliberate blank
"Does an app for these agents already exist, and is it Standard or Console navigation?"navType is "Not updateable" — the answer decides between editing and rebuilding (Gotcha 1)A build-vs-migrate decision made before any configuration is invested
"Which other apps use the utility bar we are about to edit?"Utility bars are shared FlexiPages; an edit here changes every app that names it (Gotcha 12)A named FlexiPage this app owns, or an explicit accepted coupling
"Do two teams need the same object to behave differently?"Workspace mappings have no profile field, unlike record-page overrides (Gotcha 5)Either one standardized rule with training, or a second console app, decided now
"Which utility items must run without the agent clicking anything?"Background utility items need a second flexiPageRegions entry of type Background, supported for utility bars onlyThe split between visible footer items and invisible listeners
"Is a developer available for the keyboard shortcuts you want?"Custom shortcuts require an addEventListener() handler in the Console Integration Toolkit first; only the 18 default actions are declarative (Gotcha 11)Shortcuts scoped to what can actually ship this release
"Who owns the Quick Text library, and which channels does each snippet serve?"Channel is a multipicklist backed by a standard value set, not a fixed five-value picklist (Gotcha 4)One record per snippet with all its channels, instead of a triplicated library that drifts

What a proper configuration adds over just creating a console app: every tab's behaviour is a stated decision with the lookup field that implements it, the utility bar belongs to one app, and the checker can prove before deploy that no mapping points at a field that does not exist.


Core Concepts

Console Navigation vs Standard Navigation

Lightning apps use one of two navigation types set at app creation time in App Manager:

The navigation type is a fixed property of the app — you cannot switch an existing app from Standard to Console or vice versa without recreating it. The Metadata API field is navType set to Console on the CustomApplication component, and the guide marks it "Not updateable" (api_meta.txt L39719–39723).

Two related fields are easy to misread:

Console Navigation is the core differentiator of the Service Console. Everything else (utility bar, macros, keyboard shortcuts) works in any Lightning app, but split view and workspace tabs only function in console navigation apps.

Workspace Tabs and Subtabs — the workspaceConfig mechanism

In a console app, records open as workspace tabs — full horizontal tabs across the top of the main content area. Each workspace tab has its own subtab bar where related records opened from within that workspace appear as narrower tabs.

What Setup calls navigation rules is CustomApplication.workspaceConfig in the API — an AppWorkspaceConfig holding mappings (L39796–39799, L40019–40032). Each mapping is a WorkspaceMapping with exactly two fields:

FieldRequiredGuide text (L40038–40047)
tabYes"Name of the tab."
fieldNameNo"The name of the field that specifies the primary tab in which to display tab as a subtab. If not specified, tab opens as a primary tab."

So the behaviour is not an enum of three UI choices. It is the presence or absence of a lookup field name:

MappingWhat the agent sees
<tab>standard-Case</tab>A Case opens as its own workspace (primary) tab
<fieldName>AccountId</fieldName><tab>standard-Contact</tab>A Contact opens as a subtab of the Account named in Contact.AccountId
<fieldName>ParentId</fieldName><tab>standard-Account</tab>A child Account opens as a subtab of its parent Account

The last two are the guide's own console sample (L40701–40724). Three consequences:

There is no element named navRules, consoleComponents, or navigationRules anywhere in the Metadata API. Full XML in references/metadata-examples.md § 1–2.

Utility Bar

The utility bar is a persistent footer toolbar, and it is a separate metadata component: a FlexiPage whose type is UtilityBar — "A Lightning page used as the utility bar in Lightning Experience apps", API 38.0+ (L67084–67086). The app points at it by developer name through CustomApplication.utilityBar (L39788–39794).

Utility itemPurpose
HistoryList of recently visited records within the current session. UNVERIFIED (2026-09-05): the widely-repeated "console apps only" restriction is Salesforce Help content — neither api_meta.txt nor object_reference.txt names a History utility item at all, and help.salesforce.com cannot be fetched to confirm it. Test in a standard-navigation app before relying on either answer.
Omni-ChannelDisplays the agent's Omni-Channel status and incoming work requests; requires Omni-Channel to be enabled and the user to have a presence configuration and routing configuration.
MacrosA macros panel so agents can run macros without leaving the active workspace.
Open CTI SoftphoneRequires a CTI adapter package to be installed; the utility item renders the adapter's phone panel.
Quick TextSurfaces Quick Text snippets for insertion into emails, chats, or feed posts. Snippets are QuickText records scoped by a Channel multipicklist (object_reference L238905–238913).

Three structural facts that decide where configuration lives:

UNVERIFIED (2026-09-05): the "auto-open when the app loads" / Start automatically setting has no counterpart in the FlexiPage field tables in api_meta.txt. It is presumably a further decorator property; confirm its property name against a retrieved utility bar rather than authoring one from memory.

Macros

A macro is not one record. "A macro definition consists of a Macro object and several associated MacroInstruction objects" (object_reference L177953–177958), and neither has a Metadata API type — they move between orgs as data, not in a package.

Each MacroInstruction has an Operation and a Target. The Operation picklist is exactly Select, Set, Insert, Submit, Close, plus IF, ELSEIF, ELSE, ENDIF for conditional macros in API 46.0 and later (L178095–178126). There is no "Update Field", "Send Email", "Post to Chatter", or "Save Record" operation — those are Setup-UI labels for combinations of the five. The guide's own worked example of sending an email is:

0. SELECT Tab.Case
1.   SELECT QuickAction.Case.Email
2.     SET    Field.EmailMessage.Subject
3.     SET    Field.EmailMessage.ToAddress
4.     INSERT Field.EmailMessage.HtmlBody.cursor
5.     SUBMIT

Target follows a published grammar and hierarchy (L177980–178020): Tab.<EntityApiName> at the root, then QuickAction.<EntityApiName>.<QuickActionName>, then Field.<QATargetEntityApiName>.<FieldApiName>, with .cursor and .end suffixes for INSERT into text fields. "A target isn't available if its parent isn't" — which is why step 0 selects the tab. SortOrder is 0-based and "If there's an incorrect sequence of macro instructions, the macro doesn't execute" (L177958–177961).

StartingContext names the object the macro acts on, and it is constrained: "In Lightning Experience, macros are supported on standard and custom objects that allow quick actions and have a customizable page layout" (L177943–177950). Macros can be run manually or as bulk macros — MacroUsage.IsFromBulk marks the latter, where "usage is recorded per record" (L178346–178352). Agents must have the Macros user permission — see Gotcha 3, which carries an UNVERIFIED marker on the permission's exact name.

Keyboard Shortcuts

KeyboardShortcuts (L40211–40232) holds two collections: defaultShortcuts and customShortcuts.

Tab limits and session persistence

Two levers the Setup wizard buries:


Common Patterns

Pattern: Full Service Console App Setup for a Case-Centric Team

When to use: A support team works primarily on Cases, with Contacts and Accounts as reference records opened from within Cases. Agents handle multiple cases concurrently.

How it works:

  1. Setup > App Manager > New Lightning App — choose Console Navigation; add branding.
  2. Navigation Items — add Cases, Contacts, Accounts, Knowledge in that order, and set defaultLandingTab explicitly rather than relying on tab order.
  3. Utility Bar — build one UtilityBar FlexiPage owned by this app with History, Omni-Channel, Macros, and Open CTI Softphone (if CTI is configured).
  4. User Profiles — assign Service Cloud agent profiles via PermissionSet.applicationVisibilities; CustomApplication has no visibility field of its own.
  5. Write one workspaceConfig mapping per tab — Case and Account with no fieldName (primary tabs), Contact keyed on AccountId, Knowledge with no fieldName.
  6. Create Macro records for the top three agent repetitive tasks, expressed as Select / Set / Insert / Submit instruction rows with 0-based SortOrder.
  7. Create Quick Text entries, one record per snippet with every applicable channel in the Channel multipicklist.

Why not the alternative: Using a standard navigation app forces agents to navigate away from the current case every time they open a contact or account, losing context and increasing handle time.

Pattern: Workspace Mappings for Complex Object Hierarchies

When to use: Agents work with Cases linked to Assets or Work Orders, and those child records need to open in context rather than as independent primary tabs.

How it works:

  1. Map the parent object with no fieldName — it opens as a workspace tab.
  2. Map each child on the lookup field that lives on the child and points at the parent: <fieldName>Case__c</fieldName><tab>Work_Order__c</tab>.
  3. If agents also open Assets independently, the object cannot be both — a tab is either mapped with a fieldName or without one. Give the second workflow its own console app rather than looking for a conditional rule that does not exist.
  4. Confirm the parent's tab is in the app. A mapping that points at an object with no tab has nothing to nest under.

Why not the alternative: Leaving tabs unmapped means every record click opens a new primary tab, quickly filling the tab bar and making it difficult to track the active case — and because mappings is documented as required per tab, the omission is a defect rather than a default.


Decision Guidance

SituationRecommended ApproachReason
New app for case-handling agentsCreate a new app with navType ConsoleStandard navigation loses agent context between records
Existing standard app used by service teamCreate a new console app; do not convertnavType is documented "Not updateable" (L39719)
Related record should open in contextMap its tab with the lookup fieldName that points at the parentAbsence of fieldName means primary tab, not inheritance (L40044–40046)
Two teams want different tab behaviour for one objectTwo console appsWorkspaceMapping has no profile field; record-page overrides do (L39973–39976)
Agents need phone panel in the consoleAdd Open CTI Softphone utility; ensure CTI adapter is installedSoftphone utility renders the CTI adapter UI inside the console
A utility must run with no visible buttonA second flexiPageRegions entry of type Background"Supported for utility bars only" (L67286–67290)
Agents need one-click repetitive actionCreate a Macro + MacroInstruction rows; add the Macros utilityMacros automate multi-step actions inside the active workspace
Agents need standard reply snippetsOne Quick Text record per snippet, all channels on itChannel is a multipicklist (object_reference L238905–238913)
Shared workstations must not inherit open tabsisNavTabPersistenceDisabled = trueConsole-only field, API 54.0+ (L39697–39701)
One-keystroke custom action requestedConfirm developer capacity first, else use defaultShortcutsCustom shortcuts need an addEventListener() handler (L40052–40054)

  1. Inventory the target and fill in the template. Complete templates/service-console-configuration-template.md — every navigation tab, and for each one the parent object and the lookup field that names it. Retrieve any existing app and its utility bar first: sf project retrieve start --metadata CustomApplication:<Name>,FlexiPage:<UtilityBar>. Confirm from AppDefinition.NavType whether you are editing or rebuilding.
  2. Decide build-vs-rebuild before configuring anything. If the existing app's navType is Standard, stop and plan a new app (Gotcha 1). Check SELECT DeveloperName, UtilityBar FROM AppDefinition WHERE UtilityBar != null for utility bars shared with other apps (Gotcha 12).
  3. Write the utility bar FlexiPage first, following references/metadata-examples.md § 4 — visible items with decorator width/height/label, a Background region for listeners. Copy the real template and component names out of the retrieve from step 1; do not type them from memory.
  4. Write the CustomApplication per references/metadata-examples.md § 1 — navType Console, defaultLandingTab, isNavTabPersistenceDisabled, utilityBar, and one workspaceConfig mapping per <tabs> entry. Cross-check every fieldName against the child object's fields, not the parent's (Gotcha 7).
  5. Author Quick Text and Macros as data, per references/metadata-examples.md § 5 — CSVs for QuickText, then Macro, then MacroInstruction with 0-based SortOrder, Operation from the five-value enum, and Target following the documented grammar.
  6. Run the checker before deploying: python3 scripts/check_service_console_configuration.py --manifest-dir force-app/main/default. It fails on a console app with no mappings, a mapping whose fieldName is not a field on that tab's object, a utilityBar pointing at a FlexiPage that is missing or not of type UtilityBar, out-of-enum tabLimitConfig or listPlacement values, and profileActionOverrides referencing a FlexiPage not in the manifest.
  7. Deploy in order and verify in the org. Follow references/metadata-examples.md § 7, then run the § 8 queries — AppDefinition.NavType = Console, the utility bar unshared, MacroInstruction ordered from SortOrder 0, and MacroUsage free of ACCESS failures. Finish by logging in as an agent and confirming a Contact opened from a Case lands as a subtab of the right Account.

Review Checklist

Before marking service console configuration complete:


Salesforce-Specific Gotchas

Full detail, with guide line references, in references/gotchas.md.

  1. navType is "Not updateable" — there is no supported Standard-to-Console conversion; plan a rebuild (Gotcha 1).
  2. A tab with no mapping opens as a primary tab, silently — and mappings is documented as required per tab (Gotcha 6).
  3. fieldName lives on the child object, and nothing validates the direction — a reversed mapping deploys clean and does nothing (Gotcha 7).
  4. isServiceCloudConsole is null on Lightning console apps — audits keyed on it report zero console apps (Gotcha 8).
  5. QuickText.Channel is a multipicklist — one record can serve several channels; duplicating per channel just creates drift (Gotcha 4).
  6. Utility bars are shared between apps — editing one app's footer can change another's (Gotcha 12).
  7. A Flexipage App-Default override cannot be deleted by a destructive change — reset its <type> to default instead (Gotcha 10).
  8. Custom keyboard shortcuts require developer code first and cannot point at a macro (Gotcha 11).
  9. AppWorkspaceConfig and AppComponentList were renamed in API 42.0 — old element names still circulate in blog posts (Gotcha 9).
  10. Omni-Channel and Macros both fail quietly when their prerequisites are missing (Gotchas 2, 3).

Output Artifacts

ArtifactDescription
applications/<Name>.app-meta.xmlCustomApplication with navType Console, workspaceConfig mappings, utilityBar, and isNavTabPersistenceDisabled
flexipages/<Name>.flexipage-meta.xmlThe utility bar, a FlexiPage of type UtilityBar, with decorator sizing and any Background region
permissionsets/<Name>.permissionset-meta.xmlapplicationVisibilities and tabSettings — the app file carries no visibility
QuickText.csvQuick Text records with the Channel multipicklist and IsInsertable
Macro.csv + MacroInstruction.csvMacro definitions and their 0-based, grammar-conformant instruction rows
package.xml + deploy orderWhat ships as metadata, what ships as data, and in what sequence
Verification queriesAppDefinition, MacroInstruction, MacroUsage checks that prove the deploy landed

Reference Files

FileRead it when
references/metadata-examples.mdWriting deployable console CustomApplication XML, the workspaceConfig mappings, the UtilityBar FlexiPage, the Quick Text / Macro CSVs, package.xml, deploy order, and the post-deploy verification queries
references/gotchas.mdThe console app deployed cleanly and behaves wrong — records opening as the wrong kind of tab, a macro that does nothing, a utility bar that changed two apps, or an override that will not delete
references/examples.mdDesigning the console for a persona before any XML exists — a Tier-1 build and an escalation macro, end to end
references/well-architected.mdJustifying single-app vs multi-app, macro-vs-Flow, and utility auto-load tradeoffs, or locating the official source behind a claim in this skill
references/llm-anti-patterns.mdReviewing console guidance an AI assistant produced, especially "change the navigation type" and "set the navigation rule to subtab of current workspace"
templates/service-console-configuration-template.mdRunning workflow step 1 — the tab, mapping, utility, and macro inventory
scripts/check_service_console_configuration.pyWorkflow step 6, before every deploy of a console app or its utility bar

Package files