How to
Adding Console to Salesforce records

Malcolm Jacobson
Malcolm Jacobson
  • Updated

The Pendula Console component can be placed on any Salesforce record page — not just Contact, Lead, User, or Person Account pages. When placed on objects like Case, Opportunity, or custom objects, it resolves related person entities (Contacts, Leads, Users, Person Accounts) by following relationship paths you configure.

Configuration is done by creating Recipient Lookup Path custom metadata records. No code changes are required.


How It Works

  1. A user opens a record page (e.g. a Case) that has the Pendula Console component
  2. The component reads all active Recipient Lookup Path records for that object type
  3. It follows each configured relationship path to find related person entities
  4. If multiple people are found, a dropdown arrow appears next to the recipient name — the user clicks it to switch between conversation partners

On person entity pages (Contact, Lead, User, Person Account), the page record itself is always auto-included as the first recipient. Custom Metadata Types (CMDT) paths can add more.


Creating Recipient Lookup Path Records

Navigate to Setup → Custom Metadata Types → Recipient Lookup Path → Manage Records → New.

Fields

FieldDescription
LabelAdmin-friendly name (e.g. "Case — Primary Contact")
Source ObjectAPI name of the page object (e.g. Case, Opportunity, My_Custom_Object__c)
Target EntityThe type of person to resolve: Contact, Lead, User, or PersonAccount
Relationship PathThe lookup path to follow (see syntax below)
Role LabelDisplay label shown in the dropdown (e.g. "Primary Contact", "Case Owner")
Is ActiveChecked = active. Uncheck to disable without deleting
Sort OrderControls display order in the dropdown. Lower numbers appear first
Max ResultsMaximum records returned for this path. Default 10

Relationship Path Syntax

The Relationship Path field supports three patterns.

Pattern 1: Direct Lookup

Use when the source object has a lookup field that points directly to a Contact, Lead, or User.

Syntax: <LookupFieldApiName>

Example: ContactId on Case points to a Contact. The resolver queries:

SELECT Id, Name, MobilePhone FROM Contact WHERE Id = <value of Case.ContactId>

Pattern 2: Parent → Children

Use when you need to traverse through an intermediate object. The source record has a lookup to a parent, and the parent has child records of the target entity type.

Syntax: <LookupFieldApiName>.<ChildRelationshipName>

Example: AccountId.Contacts on Case — first resolve the Case's AccountId, then find all Contacts under that Account. The resolver queries:

SELECT Id, Name, MobilePhone FROM Contact WHERE AccountId = <value of Case.AccountId> LIMIT <Max Results>

The second segment (Contacts) is the child relationship name as defined on the parent object, not a field API name. You can find it in Setup → Object Manager → [Parent Object] → Fields & Relationships → [Lookup Field] → Child Relationship Name.

Pattern 3: Self Children

Use when the source object itself is the parent and you want its child records. The path is simply the child relationship name on the source object.

Syntax: <ChildRelationshipName>

Example: Contacts on Account — finds all Contacts that belong to the Account. The resolver queries:

SELECT Id, Name, MobilePhone FROM Contact WHERE AccountId = <source Account Id> LIMIT <Max Results>

The resolver detects that Contacts is a child relationship name (not a lookup field) on Account and uses the source record's own Id as the parent.

Person Account Paths

For Person Accounts, set Target Entity to PersonAccount and use the lookup field that points to the Account.

Syntax: <LookupFieldApiName> (direct) or <LookupFieldApiName>.PersonContact

The resolver automatically checks IsPersonAccount = true and returns PersonMobilePhone instead of MobilePhone. In orgs without Person Accounts enabled, these paths return no results (no errors).


Examples with Standard Objects

Case

A typical Case configuration resolves the primary contact, all contacts under the related account, the case owner, and a person account if applicable.

LabelSource ObjectTarget EntityRelationship PathRole LabelSort Order
Case — Primary ContactCaseContactContactIdPrimary Contact1
Case — Account ContactsCaseContactAccountId.ContactsAccount Contact2
Case — OwnerCaseUserOwnerIdCase Owner3
Case — Person AccountCasePersonAccountAccountIdPerson Account4

Behaviour:

  • If the Case has a ContactId set and no other contacts on the Account → single recipient, no dropdown
  • If the Case has a ContactId and the Account has 3 Contacts → 3 recipients shown (the primary contact appears once thanks to deduplication), dropdown arrow visible
  • If the Case has no ContactId and no Account → no recipients resolved

Account

An Account page can resolve its own child Contacts directly using the child relationship name.

LabelSource ObjectTarget EntityRelationship PathRole LabelSort Order
Account — ContactsAccountContactContactsAccount Contact1
Account — OwnerAccountUserOwnerIdAccount Owner2
Account — Person AccountAccountPersonAccountIdPerson Account3

Behaviour:

  • If the Account has 3 Contacts → 3 recipients shown, dropdown arrow visible
  • If the Account is a Person Account → the Person Account is auto-included at sort order 0 (before the CMDT paths)
  • The Contacts path uses the child relationship name directly — no intermediate lookup needed

Opportunity

LabelSource ObjectTarget EntityRelationship PathRole LabelSort Order
Opp — Account ContactsOpportunityContactAccountId.ContactsAccount Contact1
Opp — OwnerOpportunityUserOwnerIdOpportunity Owner2
Opp — Person AccountOpportunityPersonAccountAccountIdPerson Account3

Contact (adding related people)

On a Contact page, the Contact itself is auto-included as the first recipient (sort order 0). You can add more:

LabelSource ObjectTarget EntityRelationship PathRole LabelSort Order
Contact — Created ByContactUserCreatedByIdCreated By1
Contact — OwnerContactUserOwnerIdContact Owner2
Contact — Account ContactsContactContactAccountId.ContactsAccount Contact3

Behaviour:

  • The Contact page record appears first as "Contact" (auto-included, sort order 0)
  • The Created By user appears second (sort order 1)
  • The Contact Owner appears third (sort order 2)
  • Other Contacts under the same Account appear with sort order 3
  • The page Contact is deduplicated from the Account Contacts list
  • The dropdown arrow appears because there are multiple recipients

Lead

On a Lead page, the Lead is auto-included. Additional paths:

LabelSource ObjectTarget EntityRelationship PathRole LabelSort Order
Lead — OwnerLeadUserOwnerIdLead Owner1
Lead — Created ByLeadUserCreatedByIdCreated By2

Custom Objects

For a custom object Project__c with lookup fields to Contact and Account:

LabelSource ObjectTarget EntityRelationship PathRole LabelSort Order
Project — Primary ContactProject__cContactPrimary_Contact__cPrimary Contact1
Project — SponsorProject__cContactSponsor__cProject Sponsor2
Project — Account ContactsProject__cContactAccount__c.ContactsAccount Contact3
Project — OwnerProject__cUserOwnerIdProject Owner4

Note: for custom lookup fields, use the field API name including the __c suffix (e.g. Primary_Contact__c). For parent→children paths with custom relationships, the child relationship name typically ends in __r (e.g. Account__c.Project_Members__r).


Finding the Right API Names

Lookup Field API Name (first segment)

  1. Go to Setup → Object Manager → [Your Object] → Fields & Relationships
  2. Find the lookup field (e.g. "Contact" on Case)
  3. The Field Name column shows the API name (e.g. ContactId)
  4. For custom fields, the API name ends in __c (e.g. Primary_Contact__c)

Child Relationship Name (second segment)

  1. Go to Setup → Object Manager → [Parent Object] (e.g. Account)
  2. Go to Fields & Relationships
  3. Find the lookup field on the child object that creates the relationship (e.g. the AccountId field on Contact)
  4. Click it → the Child Relationship Name is shown (e.g. Contacts)
  5. For custom relationships, this typically ends in __r

Deduplication

If the same person is resolved by multiple paths (e.g. a Contact found via both ContactId and AccountId.Contacts), they appear only once in the dropdown. The first occurrence (lowest sort order) wins.

On person entity pages, the page record is always included with sort order 0 and is deduplicated from any CMDT results.


Limits and Considerations

  • Max 2-hop traversal: Paths support at most one intermediate object (e.g. AccountId.Contacts). Three-hop paths like AccountId.ParentId.Contacts are not supported.
  • Governor limits: Each path executes 1 SOQL query. With 5 paths configured, that's ~6 queries total (including the source record query). Well within the 100-query limit per transaction. If you configure many paths, use Is Active and Max Results to tune.
  • Field-Level Security: All queries run in USER_MODE, so users only see records and fields they have access to.
  • Person Accounts: Paths targeting Person Accounts silently return no results in orgs where Person Accounts are not enabled. No errors.
  • Caching: Results are cached by the Lightning Data Service. Changes to relationships (e.g. reassigning a Case contact) are reflected after a page refresh or when the user clicks the Refresh option in the Console settings menu.