Friday, December 17, 2021

Salesforce: Retrieve Report Metadata

Here is the use case, you are presented with a report with duplicate fields label, whether from the same object or different objects, but how can you easily identify each field? See a sample from the below screenshot, there is no way to tell which Created By and Created Name are from which object.

Even by editing the report, it will not tell you, of course, you can remove and add the fields back, but you are supposed not to change the report.

The answer is to check the metadata of that report, unfortunately, Salesforce does not offer to get this without using tools, such as VS Code or other IDE. But, we can use Workbench to retrieve it.

You can follow this blog to prepare the package.xml file, and retrieve the metadata using Workbench.

1. Get the "fullName"

The report should not be stored in the Private Reports folder, otherwise, you will not see the report here.

2. Prepare XML file

Copy the following XML and save it as a file called "package.xml"

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="">

If you would like to retrieve metadata from multiple reports, you can add them to the XML file.

What is this mean <members>Johan_Change/Opty_and_Acct</members>

Text in red is the report folder API name, you can get the report folder API name from Folder Unique Name from rename folder. While the blue text is the report API name, you can get the report API name from the Report Unique Name in the report properties.

If the folder is Public Reports, use unfiled$public as the report API folder name in the Package.XML file, also you will not see that folder in Workbench step (1).

3. Retrieve Package

Open workbench:
  • select migration | Retrieve
  • select the XML file prepared in step 2
  • select "Single Package"
  • click the Next button then click the Retrieve button
  • when done, click the "Download ZIP File" link
  • extract the zip file and looks for the report
  • open the file with any text editor

<?xml version="1.0" encoding="UTF-8"?>
<Report xmlns="">
    <name>Opty and Acct</name>

The report metadata tell us that the 1st and 2nd field are from Opportunity, while the 3rd and 4th fields are from Account.

Here is the list of Metadata Type supported by Metadata API:

Some metadata types support using wildcard character (*), so you can retrieve all items without the need to mention each member name: 

As you see from the above URL, Report and ListView are No, but Profile and PermissionSet are Yes.
Sample XML file:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="">

Monday, December 13, 2021

Salesforce - Teams integration

Salesforce apps in Microsoft Teams allow you to searchmention, and preview Salesforce records in Teams chats between users, and Teams channel. Any Salesforce records, from Account, Contact, Opportunity, Case, Lead, etc. can be used for mention in chat and can be added as a tab.

Adding Salesforce records as tabs in the Teams allow you to:

  • View and edit record details
  • Access Chatter activities, including creating new posts
  • Access Activity histories related to the record
  • View the related records and open in Salesforce
  • Optionally, you can rename the tab name in Teams


  • Convenient Data Sharing, you can share Salesforce records in your Teams channels and chats easily with the Salesforce Teams Integration. This enables you to start a conversation on any record. The members of your Teams channel who have the access to Salesforce can conveniently work and access Salesforce records without leaving Teams.

  • Convenient Data Access, the Salesforce - Teams integration enables your Teams users to interact with Salesforce records not only through conversations but also via channel tabs. Adding a Salesforce record as a tab allows users in the Teams can easily view details, related lists, activity timeline, and Chatter right in the Teams tab.

  • Salesforce Records Preview, if someone mentions a Salesforce record in a Teams conversation, the other users can easily preview the record without leaving Teams. As a result, users can save their time and avoid juggling between Microsoft Teams and Salesforce.

  • Editing Salesforce Records, don’t waste your time and do not jump from Microsoft Teams to Salesforce. You can edit the record details without changing your work environment to avoid the loss of any important updates.

Enable in Salesforce  

1. Go to setup menu and search for Teams Integration, then enable it. You may need to reach out to your AE to enable this feature.

2. Assign permission set called "Use Teams Integration" to users that need to access Salesforce data from Teams.

Adding the Salesforce app in Teams

1. Open Teams, click the Apps icon at the bottom left (1), type Salesforce in Apps search box (2), and click Salesforce icon (3) to install

2. Next, click Add button (4)

3. From the login page, enter your Salesforce username and password.

4. Done, now you should see the Salesforce icon when a chat with someone, or in a team channel.

Search, mention, and preview Salesforce record in Chat

1. Open a chat window with someone and click the Salesforce icon

2. Search for a record, the system will show the recent records that you access in SFDC

3. Select the record and click the Mention Record button

4. Type your message in the chat window then hit the “enter” key or Send icon

5. If the receivers have the Salesforce license and Salesforce app installed in Microsoft Teams, the users will be able to Preview the record sent, click “View in Salesforce” to open the record in

6. The same action can be performed in the Teams channel under Posts, click “New conversation” button, and you will see the same set of icons as above screenshot

Adding Salesforce record as a tab

1. From a Chat or Teams channel, click + icon on the top 

2. Click the Salesforce icon, if you do not see the Salesforce icon, type Salesforce in the search box at the upper right corner

3. Search for a record, the system will show the recent records that you access in Salesforce

4. Select the record and click the Save button

5. Click the arrow next to the new tab added, you can rename or remove the tab added

6. The selected record added as a tab in a Chat or Teams Channel

7. You will be able to edit the record, do Chatter posts, view Activity, see the Related records, click the link to open the related record


Thursday, November 11, 2021

Salesforce: Account Team List View and Opportunity Team List View

Many years back, we wrote a blog on options in reports to show the account team and in the opportunity team, the similar options are available in List View too, let's check out:

In the Account report type, we have the option to show:
  1. All accounts
  2. My accounts
  3. My accounts team's accounts
  4. My accounts team and my accounts
  5. My team's accounts

In Account list view:
  1. All accounts
  2. My accounts
  3. My accounts teams
The first two options are clear, show all accounts or my accounts.
"My accounts teams", is similar to "My accounts team's accounts" in the report type, where the result ONLY accounts where you are in the Account Team.

The same applies in the Opportunity Team list view too, in the Opportunity report type, we have:
  1. All opportunities
  2. My opportunities
  3. My team-selling opportunities
  4. My team-selling and my opportunities 
  5. My team's opportunities
  6. My team-selling and their opportunities

In the Opportunity List view:
  1. All opportunities
  2. My opportunities
  3. My opportunities teams
  4. My team's opportunities
The first two options are clear, show all accounts or my accounts.
"My opportunities teams" -- all opportunities where you are in the Opportunity Team, this is similar to "My team-selling opportunities" in the report.

"My team's opportunities" -- all opportunities owned by me and owned by users below my role hierarchy, including all that report to my direct reports.


Sunday, October 24, 2021

Salesforce: Topic in Lightning

Topic is another Salesforce feature that is probably not so well-known, but with good governance and maintenance, it served as a good tool to organize posts and records. Topics are case insensitive. 

Where to add Topics?
Topic is enabled by default for Chatter Post in Lightning. Topic also can be enabled for objects, follow this link to enable it.

To add topics in Chatter post:
  • start with # continue with the topic, for example, hello world, hit enter key then continue with the post, in this case, the topic is 2 words - hello world
  • You can have multiple topics in chatter port. 
  • As you type after #, the system will look for existing topics and you can simply select the existing topic.
To add topics into a record object:
  • Do not need to start with #, just type the topic and hit enter when done. 
  • Need to type in the Topics component in lightning, see post below for Topics component. 
  • You need to have edit permission on the record to be able to add topics to that record. 
  • Same with adding topics in the Chatter post, you can add multiple topics for a record, also as you type, the system will look for existing topics and you can simply select the existing topic.

If you open a topic, the topic in the Chatter post will show under Feed, while topics added to records will show under the Related tab.

Topics Component
Once you enabled Topics for an object, you need to add the component to the Lightning page, so your users can use it.

You can run a report on Topic to see the usage, including the related records, you need to create a custom report type with Topic Assignments as the primary object.

If you do not have access to the record, you will not see the topic in the report too.

You can search a topic from the global search box, you do not need to add # before the topics. see screenshot below, the one on the top is correct.

Deleting Topics
Only users with Delete Topics permission are able to delete a topic, this is only for the topic that relates to a record (not for a topic related to a Chatter post). Once the topic is deleted, topics added in the related record will be removed.


Sunday, October 17, 2021

Tableau CRM: Getting Started with Recipe a.k.a Data Prep 3.0

Recipe has existed in Tableau CRM for a long time, but not really used a lot because Dataflow offers more powerful data transformation, although there are functions which only available in Recipe, such as Join. However, in the last few releases, Salesforce introduced a new term called "Data Prep 3.0", which actually is Recipe, and stop to enhance everyone's darling "dataflow".

When Data Prep 3.0 was introduced (I have no idea if there was Data Prep 2.0 and 1.0), it was not so popular because of the lack of functionalities, such as support to upload/download JSON, use SAQL, etc. Since then, in every release, more and more features are added to the Data Prep/Recipe, so it may be worth starting to look at it.

As per the Winter '22 release, at a glance, Recipe now looks quite promising, it supports many things: 

  • Download/upload recipe in JSON -- same with Dataflow
  • Formula with query -- comparable with computeExpression in Dataflow
  • Multiple row formula -- comparable with computeRelative in Dataflow

Here are things that are better in Recipe compare to Dataflow

  • Join (Left, Right, Inner, Outer) -- this is not available in Dataflow
  • Preview -- we cannot preview data in Dataflow
  • Layout stay when save -- you need EADashboardHelper in Dataflow
  • Multiple actions in a Transform node -- less node compare to Dataflow
  • Aggregate
  • Sentiments, Predict Missing Values, Cluster
  • Trim, Substring, Split, Uppercase, Lowercase, Replace -- some of them can be achieved with computeExpression in Dataflow
  • Format Dates, Bucket, Edit Attributes

Here are things that can be improved in Recipe
  • Ability to re-order items in Transform node 
  • Ability to re-order column in Preview data
  • Ability to sort and filter Preview data
  • Running a recipe does not show details in Monitor

A sample of Recipe

Formula in Transform node is based on TCRM SQL, so this is not SAQL, or SOQL.
for example: SQL
when LeadSource = 'Partner' OR  LeadSource = 'Web'
then 'Partner Web'
else LeadSource

for example: SAQL
when LeadSource == "Partner" OR  LeadSource == "Web"
then "Partner Web"
else LeadSource

Direct Data in Recipe

Winter '22 release also make Direct Data in Recipe become General Available. With Data Direct, you can access Salesforce live data in the recipe, not accessing data stored in Tableau CRM via sync. However, but sync needs to be enabled in the Tableau CRM to use this.

Another catch is, you cannot use direct data when the object has been sync to Tableau CRM, example: you have dataflow or recipe that sync Opportunities, then Opportunities will no longer be available for Data Direct, which is quite sad, sometimes we need to access the real-time data directly, not "obsolete" stored data in Tableau CRM.

When I search "Opportunity". because the opportunity object already syncs in Tableau CRM from other dataflow/recipe, it will only be available via Connected (in yellow), not Direct (in green)

If you have more things that not cover here or the information shared here is wrong, feel free to comment on this blog or reach me.

Wednesday, October 13, 2021

Salesforce: Email Template with Hyperlink

We shared about the Lightning Email Template seven months ago, as you read, it is easy to create an email template with merged fields, such as Account Name, Opportunity Name, etc.

However, those merge fields are not clickable (not hyperlink), so if the email sent is to your internal Salesforce users, it will be ideal if recipients are able to open the link directly from the email received.

Let's do a quick hands-on, in this example, I would like to build an email template for Case, contain 2 hyperlinks:

  • Case Number, to open the case
  • Account Name, to open the Account in the case

Here is the step:

1. Create the email template 

Create the email template as per normal, add all merged fields needed

2. Case Number hyperlink

Open a case from your browser and grab the URL and copy to a text editor, for example,

Change the Case ID (as in red) and replace with {{{Case.Id}}}, now we have{{{Case.Id}}}/view

Copy the above URL, select {{{Case.CaseNumber}}} from the email template, then click the Link icon (2nd from right) and paste the URL above (in the yellow background) here, then click the Save button.

3. Account Name hyperlink

Repeat the same for Account Name, get the URL and change the Account Id, so it will look like{{{Case.AccountId}}}/view 

Copy the above URL, select {{{Case.Account__c}}} from the email template, then click the Link icon (2nd from right) and paste the URL above, then click the Save button.

If you notice I use Case.Account__c, this is simply telling that I have a formula field in Case to get Account Name from AccountId.

4. Sending Email

Open a case and click the Email tab, select the email template created, and notice the email body is auto-populated with hyperlinks.


Friday, October 1, 2021

Salesforce: Clone & Fields in Page Layout

  • When you clone a record, by default, fields that are not in the page layout will not copy to the new record.
  • If the record you’re cloning or a related record contains a field you don’t have access to, the field in the new record is blank.
  • If the record you’re cloning contains a field you have read-only access to, the field in the new record is blank.
  • If a related record contains a field you have read-only access to, the field value is copied into the new record.

Related List
When you create a child record from the parent Related List, even the parent field is not in the child page layout, the parent value will be populated.


Sunday, September 19, 2021

Salesforce: Sharing Detail

More than 5 years ago, we wrote about Sharing Button URL, where you can check Sharing Detail and Access, which is useful to troubleshoot why a user is able to view or edit a record.

On the Sharing Detail page, it will show you all User, Public Group, Role, Role and Internal Subordinates and the access level. In this blog I am using Opportunity as a sample, Opportunity visibility in my org is Private.

We can get the same result from SOQL: SELECT Id, OpportunityAccessLevel, RowCause, UserOrGroupId FROM OpportunityShare WHERE OpportunityId = '0062H0000123456QAN' ORDER BY UserOrGroupId 

Let us compare from Sharing Detail page:
  1. Sharing Detail #1 = SOQL row #7, reason = Account Sharing which = Implicit Child [in Account Sharing Rules, to Role]
  2. Sharing Detail #2 = SOQL row #6, reason = Opportunity Sharing Rule which = Rule [in Opportunity Sharing Rules, to Role and Internal Subordinates]
  3. Sharing Detail #3 = SOQL row #5, reason = Account Sharing which = Implicit Child [in Account Sharing Rules, to Role and Internal Subordinates]
  4. Sharing Detail #4 = SOQL row #4, reason = Opportunity Sharing Rule which = Rule [in Opportunity Sharing Rules, to Public Group] 
  5. Sharing Detail #5 = SOQL row #1, reason = Account Sharing which = Implicit Child [User is Account Owner] 
  6. Sharing Detail #6 = SOQL row #2, reason = Owner which = Owner [User is Opportunity Owner]
  7. Sharing Detail #7 = SOQL row #3, reason = Opportunity Team with Split which = Team [User in Opportunity Split]
  8. Sharing Detail #8 = SOQL row #8, reason = Account Sharing which = Implicit Child [in Account Sharing Rules, to Public Group]

Access level comparison:
- In Sharing Detail, Full Access = All in SOQL
In Sharing Detail, Read/Write = Edit in SOQL
In Sharing Detail, Read Only = Read in SOQL

Copy from Sharing Detail

  • Full Access - User can view, edit, delete, and transfer the record. User can also extend sharing access to other users.
  • Read/Write - User can view and edit the record, and add associated records, notes, and attachments to it.
  • Read Only - User can view the record, and add associated records to it. They cannot edit the record or add notes or attachments.
  • Private - User cannot access the record in any way.

  • Sharing Detail page will only show User, Public Group, Role, Role and Internal Subordinates, but does not show: users in the higher role hierarchy of another user, users in the higher role hierarchy of a role hierarchy, users in the higher role hierarchy of user in Public Group. Click the Expand List button to see each user, access level, and the why.
  • Query to OpportunityShare will show the same thing as on Sharing Detail page, so you can't just depend on OpportunityShare to determine all users that have access to a record.


Thursday, September 16, 2021

Tableau CRM : using Source Field in computeRelative node

The computeRelative node is useful to traverse across rows to identify something or calculate something.

Three important items in a computeRelative node:
  1. Partition By
  2. Order By
  3. Sort Direction (for 2 - Order By)

From the above screenshot:
- It is Opportunity 
- Partition By Account Id
- Order by CreatedDate and sort by Descending

The result in the calculated fields: 
- the first record in the partition would be the Last Opportunity created for an Account
- the last record in the partition would be the First Opportunity created for an Account
This is because we order by Descending.

There is two Expression Type in the calculated field for computeRelative: 
2. Source Field

Use Case: to identify the First or Last or Previous record

using SAQL
SAQL Expression = case when previous(Id) is null then "Yes" else "No" end
* Id in above SAQL can be any field (always with value), as it is just used to check if any previous record exists.

using Source Field
In this method, the new calculated field will contain "Yes" if that's the first row, the rest will be the Id from the previous record, which is not important.

Based on my testing, using Source Field is faster than SAQL in the dataflow. In the below example, the dataflow processing close to 1.6 million rows

Monday, September 13, 2021

Happy Sweet 17teen

Oh, this is not a blog about teen turn adult, but a celebration of the 17th anniversary of my 1st Salesforce org., which is still active till now.

If this org is a human, today it is officially an adult (in many parts of countries). While the org has been evolved a lot, at least from the shape which is the user interface. I did not screenshot every year, but here are a few milestones:

super old user interface  image credit to

Theme 2 — The Salesforce Classic 2005 user interface — Its Summer 21

Theme 3 — The current Salesforce Classic user interface (a.k.a. Aloha)

The current Salesforce Lightning user interface 


Friday, September 10, 2021

Tableau CRM: Nodes with no data in Dataflow


First, it sounds weird when you said that your dataflow processed no data, but that could happen when you put a filter that clears off all data. What happened with the further nodes that create fields in the dataflow:

Augment with Right node has no data
  • Warning: The dataflow was completed, but the NodeName node didn't augment any columns. Either the node didn't find any matches, or a join key contains only null values.
  • Augment fields are created

Augment with Left node has no data
  • Warning: The dataflow was completed, but the NodeName node didn't augment any columns. Either the node didn't find any matches, or a join key contains only null values.
  • Augment fields are created

  • No error and no warning
  • ComputeExpression field is created

ComputeRelative with Expression Type = Source Field
  • No error and no warning
  • ComputeRelative field is created

ComputeRelative with Expression Type = SAQL
  • No error and no warning
  • ComputeRelative field is NOT created, because the field is not created, if you have any further transformation node that includes the new field, such as in slice, augment, etc., the dataflow will error. As per Salesforce, this is a defect, but no KI is created yet, the KI has been created, so feel free to "subscribe".

Monday, September 6, 2021

Salesforce Dashboard: Dynamic Gauge Charts

In Winter 22 release, Salesforce releases Dynamic Gauge Charts in Dashboard, even still beta. Before this, all segments (low, medium, high) values must be entered manually by editing the component. With Dynamic Gauge Charts, you just need to update a field and the segment target changed.

To use Dynamic Gauge Chart, you need to enable the feature from Reports and Dashboards Settings in the setup menu. 

The concept

You need to have a target value, this is the max value of the gauge chart. The value should be defined in an object, within a record, and in a field. Let say you use the Opportunity report for the component, it does not make sense to put the target in the Opportunity object. 

So, here is my idea:
- Create a custom object
- Create a number field: this to store the value or target
- Create a text field: this field used to store description

Notes: thanks to Nicholas Sullivan from the Trailblazers community for the idea to use a custom field in the User object to store each user target.

The component

Once "Enable Dashboard Dynamic Gauge Charts (Lightning Experience only)" is enabled, you will see Mode: Standard and Dynamic when editing a Gauge component. Standard = existing mode where you need to enter values for each segment, while Dynamic is the new one, where the segment is divided by % of target.

Object = which object to refer to chart target
Record = which record that holds the value for this component
Field = which field from the above record holds the value

Instead of value as per normal, we need to enter % for each segment to divide segments of the low, medium, high.

Footer: once you select "dynamic" mode, you cannot make use of the footer by entering any text, it will be locked and will show the description, for example, Sum of Amount (USD) compared to Target (Dynamic: Rec-1)

  • Sum of Amount (USD) = the needle of gauge chart, which is the current value in the database
  • Target = field name
  • Dynamic = object name
  • Rec-1 = record name


Sunday, August 29, 2021

Salesforce Joined Report: Add Cross-Block Summary Formula

We shared how to add the same report type in Joined Report (in Classic) back in 2013. Despite the hate and love of joined reports, there is a feature that is not utilized by many users in the joined report, called Cross-Block Summary Formula.

Cross-Block Summary Formula is pretty similar to Summary Formula, with only different fields to be calculated from across blacks.

Not going to talk much about what is a summary formula is, but here is the sample on using Cross-Block Summary Formula. In this blog, I am going to calculate the percentage of Closed opportunities compare to All opportunities by the Opportunity Owner.

Add from Cross-Block Summary Formula, the field will be added to the selected block

Percentage number of closed opportunities compare to all.
formula B0#RowCount/B1#RowCount

My first block is filtered by closed opportunity, and the second block is all opportunity.

Percentage Amount of closed opportunities compare to all.


To move the fields to a new block on their own, add a new block and add a name field. To avoid duplication, you can remove the fields from created earlier.

Here is the complete report

Here is the result

Here are a few notes related to cross-block custom summary formulas:
  • You can add a cross-block formula to any block in the report.
  • In Lightning Experience, cross-block formulas are automatically added to the report when you create them. In Salesforce Classic, cross-block formulas aren't automatically added to the report when you create them. To add a cross-block formula in Salesforce Classic, drag it to a block.
  • When you add cross-block formulas to a block, they appear to the right of standard ones in the order in which you add them to the block.
  • The results of cross-block formulas are affected by the filter options applied to the blocks in the report. As a result, a cross-block formula can yield different results when you change filter options.
  • Each joined report can have up to 10 cross-block custom summary formulas.
  • Deleting a block that’s used in a cross-block formula also deletes the formula from both the Fields pane and any remaining blocks containing it.
  • Each cross block formula must have a unique name. However, standard and cross-block custom summary formulas can have the same name.
  • Cross-block formula names can't include brackets (“[“ or “]”).


Thursday, August 19, 2021

Salesforce: Personalize Order of items in Related List

Salesforce admin can set the order of the related list in page layout. The screenshot below is an example from the Account page.

How can I change Opportunities as the 1st tab instead of Contacts? You can personalize this for yourself.

1. Click your avatar, select Settings

2. Click Display & Layout, then Customize My Pages

3. Select Accounts from dropdown, then click Customize Page button

4. Move Opportunities above Contacts

5. Click the Save button

Now you have personalized your Opportunities in the related list above Contacts, and this does not impact anyone else.

Friday, August 13, 2021

Salesforce: Extract Fields using Report

As a Salesforce admin, sometimes we need to extract the list of all fields from an or multiple objects, for audit, clean-up, documentation, checking, and so on. 

In Classic, we can simply copy and paste the fields list to an Excel file, but in Lightning, it is not so easy when you have lots of fields in an object. What is the alternative?

This blog will discuss how to create Salesforce reports to get the list of objects and fields.

1. Create a Report type
Select the Primary Object = Entity Definitions, then relate to Field Definitions. Deploy it if you want to share the report with your users.

2. Create a Report
Create a new report as normal, use the report type created in (1), and of course as per normal Salesforce report, you can export the report to an Excel file.

In the screenshot below, I want to get all fields from the Opportunity object, add a filter to the report Master Label = Opportunity. make sure the Master Label in the filter is from Entity Definitions, not from Field Definitions.

Few interesting information of field can be gathered here:
- Relationship Name: what object does the field refer to
- Calculated Formula Field References: list of all fields used in the formula 

You also can add Description, Last Modified Date, if the field is sortable, filterable, calculated,  indexed, etc.

One of the drawbacks of using a report to get fields in the object, if your Profile does not have access to the field (Field-Level Security), you will not see those fields in the report.

Page-level ad