Salesforce for Slack – Unlock collaboration across sales and service

Streamlining Communication and Collaboration: Integrating Salesforce with Slack

In today’s fast-paced business environment, effective communication and collaboration are paramount to success. Companies are constantly on the lookout for innovative ways to bridge the gap between their various platforms and tools, ensuring seamless information flow. One such powerful integration is between Salesforce, the leading customer relationship management (CRM) platform, and Slack, a popular team communication app. In this blog post, we’ll dive into a specific use case that highlights the potential of this integration: notifying Slack users about important updates within Salesforce using the @mention chatter feed feature.

The Use Case: Salesforce Integration with Slack App 

Imagine you’re a sales professional working with Salesforce to manage your customer interactions, deals, and opportunities. On the other hand, your team relies on Slack for real-time communication and collaboration. Now, consider a scenario where you want to keep your team updated about the status of deals in Salesforce without having to switch back and forth between platforms. This is where the integration between Salesforce and Slack comes to the rescue.

Seamless @Mentions via Chatter Posts

Salesforce offers a robust feature called Chatter, which allows users to collaborate and communicate within the CRM platform. You can use Chatter to make posts and comments related to various records, including deals, leads, and contacts. With the integration set up, you can now leverage the @mention functionality in Chatter posts to bring the attention of specific team members to important updates.

For instance, let’s say you’ve just closed a deal that was being managed in Salesforce. Instead of sending separate emails or messages to your team members, you can create a Chatter post and @mention relevant users. For example, you can write a post like, “@gaurav Hii, we have a big deal please close asap !”  This simple action ensures that Gaurav receives a notification about the update.

Instant Notifications on Slack

Here’s where the integration’s magic truly shines. As soon as you hit the “Post” button on your Chatter update, the integration between Salesforce and Slack springs into action. The mentioned user, in this case, Gaurav, will receive a notification directly on Slack. This means that Gaurav doesn’t need to keep checking Salesforce for updates; the information comes to him in a platform he’s actively engaged with.

Setting Up the Integration

Setting up this integration doesn’t have to be a daunting task. Both Salesforce and Slack offer user-friendly methods to connect the two platforms. By using Salesforce’s AppExchange and Slack’s App Directory, you can find pre-built integrations or connect the platforms using APIs if you require more customized functionality. Follow the step-by-step guides provided by both platforms to ensure a smooth and secure integration process.

In Conclusion

The integration between Salesforce and Slack offers a powerful solution for enhancing communication and collaboration within your organization. By harnessing the capabilities of Chatter’s @mention feature and the instant notification system in Slack, you can keep your team members informed about important updates without any friction. This streamlined process not only saves time but also ensures that everyone is on the same page when it comes to crucial deals and customer interactions. So, whether you’re a sales professional, a project manager, or anyone looking to optimize their workflow, consider integrating Salesforce with Slack to experience a new level of efficiency and connectivity.

Step 1: Install and Authorize

The first step in the integration process is to install the Slack app and grant the necessary permissions. Follow these steps:

  • Install Slack App: Head over to your Salesforce account’s AppExchange and search for the Slack integration app.or you can click the link Once you’ve found it, click on the “Get It Now” button and follow the installation instructions. This will ensure the app is added to your Salesforce instance.
  • Authorize Slack App: After installation, open the Slack app from your Salesforce account. You’ll be prompted to authorize the app to access your Slack workspace. This step is crucial for enabling data sharing between the two platforms. Click “Authorize” and follow the authentication steps provided.

Step 2: Create a Custom Field

To effectively link the Slack user IDs with Salesforce records, you’ll need to create a custom field in the User object. Here’s how:

  • Navigate to Object Manager: From your Salesforce homepage, click on the “App Launcher” (grid icon) and search for “Object Manager.” Select “User” from the list of objects.
  • Create a Custom Field: In the User object, click on “Fields & Relationships” and then “New.” Choose the data type as “Text” and give the field a meaningful name like “Slack ID.”
  • Field Properties: Set the field properties according to your preferences. You can choose whether the field should be visible to all users, required, or unique.

Step 3: Authorize your workspace

Click 9 dots in your salesforce org  search the slack setup app click and authorize to your workspace.

Step 4: Click the automatic configuration

Click the new Message Destination button A modal will appear to provide the necessary information.

Like MessageDestination Name, Slack workspace, Slack channel, or person Name, And Hit save.

Step 4: Mapping IDs

Now that you have the necessary components in place, it’s time to establish a connection between the Slack user IDs and Salesforce records:

  • Gather Slack User IDs: In your Slack app, find the user IDs that correspond to each user in your Salesforce organization. These IDs are unique identifiers within Slack and will help establish the link.
  • Copy the message destinationId and Update Salesforce User Records: Go to the user profiles in Salesforce one by one. In the newly created “Slack ID” field, input the corresponding Slack user ID. This step effectively maps each user’s Salesforce profile with their Slack identity.

Now Create a Record-Trigger flow  To Feed Item Object  

Follow these steps to create a flow:

Final will Look like this

 *	Author Name: Gaurav Kumar
	Date: 30-Aug-2023
	Purpose: Purpose for the method to get the chatter post text items,and mention user 
public class feedinvocable {
    @InvocableMethod(Label='get the feed items')
    public static List<List<Id>> getfeed(List<FeedItem> lstfeed){
        List<List<Id>> lstId = new List<List<Id>>();
        String communityId = null;
        List<Id> mentionUser =new List<Id>(); 
            for(FeedItem fd : lstfeed){
            ConnectApi.FeedElement feedItem = ConnectApi.ChatterFeeds.getFeedElement(communityId,;
            List<ConnectApi.MessageSegment> messageSegments = feedItem.body.messageSegments;
            for (ConnectApi.MessageSegment messageSegment : messageSegments) {
                if (messageSegment instanceof ConnectApi.MentionSegment) {
                    ConnectApi.MentionSegment mentionSegment = (ConnectApi.MentionSegment) messageSegment;
                    System.debug('Mentioned user name: ' +;
                    System.debug('Mentioned user id: ' +;
        return lstId;
        }catch(Exception e){
            System.debug('exception occuurred is '+e.getMessage());
            System.debug('exception occuurred is '+e.getLineNumber());
            return null;


The feedinvocable class is an Apex class in Salesforce that contains an invocable method used to extract mentioned user IDs from Chatter feed items.

Invocable Method: getfeed

The getfeed method is an invocable method within the feedinvocable class. It takes a list of FeedItem objects as input and returns a list of lists of user IDs.


public static List<List<Id>> getfeed(List<FeedItem> lstfeed)


  • lstfeed (Type: List<FeedItem>) – A list of FeedItem objects representing Chatter feed items from which mentioned user IDs need to be extracted.

Return Value

  • Type: List<List<Id>> – A list of lists of user IDs. Each inner list corresponds to the user IDs mentioned in a particular feed item.


The getfeed method iterates through the input list of FeedItem objects. For each FeedItem, it retrieves the associated Chatter feed element using the ConnectApi.ChatterFeeds.getFeedElement method. It then extracts mentioned user IDs from the feed element’s body message segments.

The method specifically looks for ConnectApi.MentionSegment instances within the message segments. For each mention found, the mentioned user’s ID is extracted and added to the mentionUser list. After processing all message segments in a feed item, the mentionUser list is added to the lstId list.

Finally, the lstId list, containing lists of mentioned user IDs, is returned

If an exception occurs during the process, the method catches the exception, logs relevant debug information (error message and line number), and returns null.


The feedinvocable class provides a convenient way to extract mentioned user IDs from Chatter feed items using the getfeed invocable method. It can be utilized in Salesforce applications to enhance collaboration and communication among users

Custom KanBan Using Lwc with Apex Cotroller

KanBan Gif

Welcome to the technical documentation for the Drag-and-Drop Lightning Web Component (LWC). This guide will walk you through the implementation and usage of this component, which provides a streamlined interface for managing opportunities using a Kanban-style view, with our own custom customization

Installation and Setup

  • Salesforce Environment Setup: Before you begin, make sure you have a Salesforce environment set up for Lightning Component development.
  • Deploy the LWC: To use the Drag-and-Drop LWC in your org, follow these steps:
    • Retrieve the source code of the component.
    • Deploy the component to your Salesforce org using Salesforce CLI or another appropriate deployment method.

Component Architecture

The Drag-and-Drop LWC is structured as follows:

  • dragAndDropLwc Folder:
    • dragAndDropLwc.html: This file contains the HTML template for the component’s user interface,and child componet of drag-and-drop-list
    • dragAndDropLwc.js: The JavaScript file holds the component’s logic, including data fetching, drag-and-drop handling, and stage updates.
    • dragAndDropLwc.css: CSS styling to enhance the component’s visual appearance.
  • dragAndDropList Folder:
    • dragAndDropList.html: This file contains the HTML template for the component’s user interface.
    • dragAndDropList.js: The JavaScript file holds the component’s logic.
  • dragAndDropCard Folder:
    • dragAndDropCard.html: This file contains the HTML template for the component’s user interface.
    • dragAndDropCard.js: The JavaScript file holds the component’s logic,

The primary purpose is to create an interactive interface where stages are displayed as tab-like elements, each showing the stage’s name and the count of records associated with it. Users can engage with these stages using drag-and-drop functionality. The component’s structure includes an iteration loop to dynamically generate these elements for each stage. Additionally, the component utilizes a nested child component, c-drag-and-drop-list, to display and manage the records associated with each stage. The main goal is to provide an intuitive way for users to view, interact with, and rearrange records across different stages through a visually engaging and user-friendly interface.

    <div class="card_Design">
        <template for:each={pickVals} for:item="item">
            <div class="slds-tabs--path"  role="application" key={item}  style = {equalwidthHorizontalAndVertical}>
                <ul class="slds-tabs--path__nav" role="tablist">
                <li class="slds-tabs--path__item slds-is-incomplete  slds-path__item slds-is-current slds-is-active "  role="presentation">
                    <a class="slds-tabs--path__link slds-button_brand " tabindex="-1" role="tab" >
                        <span class="slds-tabs--path__title" >
                                <div class="stage-info">
                                    <span class="stage-name">{item.stage}</span>
                                    <span class="record-count">({item.noRecords})</span>
            <c-drag-and-drop-list records={records} stage={item.stage}


import { LightningElement, wire } from 'lwc';
import {getObjectInfo } from 'lightning/uiObjectInfoApi';
import OPPORTUNITY_OBJECT from '@salesforce/schema/Opportunity'
import STAGE_FIELD from '@salesforce/schema/Opportunity.StageName'
import ID_FIELD from '@salesforce/schema/Opportunity.Id';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import getTopOpportunities from '@salesforce/apex/OpportunityKanbanController.getTopOpportunities';
import updateOpprtuity from '@salesforce/apex/OpportunityKanbanController.updateOpprtuity';
export default class DragAndDropLwc extends LightningElement {

    @wire(getObjectInfo, {objectApiName:OPPORTUNITY_OBJECT})

       connectedCallback() {
            .then(result => {
                console.log("Inside ConnectedCallback");
                this.records = result.opportunities;
                this.pickVals = result.pickVals;
            .catch(error => {
                console.log('getTopOpportunities error==>',JSON.stringify(error));

    get equalwidthHorizontalAndVertical(){
        let len = this.pickVals.length +1
        return `width: calc(100vw/ ${len})`

        this.recordId = event.detail

        let stage = event.detail
        const fields = {};
        fields[ID_FIELD.fieldApiName] = this.recordId;
        fields[STAGE_FIELD.fieldApiName] = stage;
        const recordInput ={fields}
        updateOpprtuity({ recordId: this.recordId, stageName: stage })
            .then(result => {
                console.log("Updated Successfully");
                this.records = result.opportunities;
                this.pickVals = result.pickVals;
            .catch(error => {

            new ShowToastEvent({
                message:'Stage updated Successfully',



    padding: 0.5rem;
    display: flex;
    justify-content: space-around;
    background: #fff;
    padding: 0.5rem 0.25rem;
    font-size: 16px;
    background: #005fb2;
    color: #fff;
    margin-bottom: 1rem;
    border: 2px solid #d8dde6;
    margin: 0.05rem;
    border-radius: .25rem;
    font-size: 8 px;
    text-align: left;
    align-items:left ;
    text-align: left;

.stage-info {
        display: flex;
        flex-direction: column;
        align-items: left;
        text-align: center;

.stage-name {
       font-size: 13 px;
        line-height: 15px;

.record-count {
        font-size: 13 px;
        line-height: 16px;
        align-items: center;


public with sharing class OpportunityKanbanController {
    public static OpportunityKanbanController.wrapper  getTopOpportunities(){
        OpportunityKanbanController.wrapper wrapperResponse = new OpportunityKanbanController.wrapper();
          List<Opportunity>  opps= [
                SELECT Id, Name,Priority__c,CloseDate,, StageName FROM Opportunity 
                 ORDER BY LastModifiedDate DESC NULLS LAST ];    
            List<Opportunity> oppList = new List<Opportunity>();
        for(Opportunity op : opps){
            if( op.Priority__c !=null && op.Priority__c=='High' ){
         for(Opportunity op : opps){
            if( op.Priority__c == null ){
        wrapperResponse.opportunities = oppList;

            String objectName = 'Opportunity';
            String fieldName ='StageName';
            Map<String,Integer> stageNameMap = new Map<String,Integer>();
            Schema.SObjectType s = Schema.getGlobalDescribe().get(objectName) ;
            Schema.DescribeSObjectResult r = s.getDescribe() ;
            Map<String,Schema.SObjectField> fields = r.fields.getMap() ;
            Schema.DescribeFieldResult fieldResult = fields.get(fieldName).getDescribe();
            List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
            for( Schema.PicklistEntry pickListVal : ple){
                    stageNameMap.put(pickListVal.getValue(), 0);
            for(Opportunity opp: oppList){
                    Integer count = 0;
                    count = stageNameMap.get(opp.StageName);
                    stageNameMap.put(opp.StageName, ++count);
            List<OpportunityKanbanController.stageObject> pickValList = new List<OpportunityKanbanController.stageObject>();
            for(String stage: stageNameMap.keySet()){
                OpportunityKanbanController.stageObject pickVal = new OpportunityKanbanController.stageObject();
                pickVal.stage = stage;
                pickVal.noRecords = stageNameMap.get(stage);
            wrapperResponse.pickVals = pickValList;

        return wrapperResponse;
    public static OpportunityKanbanController.wrapper updateOpprtuity(String recordId, String stageName){
        if(recordId != null && stageName != null){
            Update new Opportunity(id = recordId , StageName = stageName);
        return OpportunityKanbanController.getTopOpportunities();
    public class wrapper{
        public List<Opportunity> opportunities = new List<Opportunity>(); 
        public List<OpportunityKanbanController.stageObject> pickVals = new List<OpportunityKanbanController.stageObject>();

    public class stageObject{
        public String stage = '';
        public Integer noRecords = 0;


     <ul class="slds-has-dividers_around-space dropZone" 
    style="height:70vh; overflow-y:auto;">
        <template for:each={records} for:item="recordItem">
            <c-drag-and-drop-card stage={stage} record={recordItem} 
            key={recordItem.Id} onitemdrag={handleItemDrag}>



import { LightningElement, api } from 'lwc';

export default class DragAndDropList extends LightningElement {
    @api records
    @api stage
        const event = new CustomEvent('listitemdrag', {
            detail: evt.detail
        const event = new CustomEvent('itemdrop', {
            detail: this.stage


<template if:true={isSameStage} for:index="index">
   <li class="slds-item slds-var-m-around_small" draggable="true" ondragstart={itemDragStart} >
       <article class="slds-tile slds-tile_board">
           <h3 class="slds-truncate" title={record.Name}>
               <a href="#" data-id={record.Id} onclick={navigateOppHandler}>
                   <span class="slds-truncate" data-id={record.Id}>
           <div class="slds-tile__detail slds-text-body_small">
               <p class="slds-text-heading_small">Priority:{record.Priority__c}</p>
               <p class="slds-truncate" title={record.AccountName}>
                    <a href="#" data-id={record.AccountId} onclick={navigateAccHandler}>
                    <span class="slds-truncate" data-id={record.AccountId}>

               <p class="slds-truncate" title={record.StageName}>{record.StageName}</p>
.slds-item {
    border: 1px solid #d8dde6;
    border-radius: 0.25rem;
    background-clip: padding-box;
    padding: 0.45rem;
    margin: 0.25rem;
import { LightningElement, api } from 'lwc';
import { NavigationMixin } from 'lightning/navigation'
export default class DragAndDropCard extends NavigationMixin(LightningElement) {
    @api stage
    @api record

    get isSameStage(){
        return this.stage === this.record.StageName
        this.navigateHandler(, 'Opportunity')
        this.navigateHandler(, 'Account')
    navigateHandler(Id, apiName) {
            type: 'standard__recordPage',
            attributes: {
                recordId: Id,
                objectApiName: apiName,
                actionName: 'view',
        const event = new CustomEvent('itemdrag', {
            detail: this.record.Id

Code Explanation

Let’s dive into the code that powers the Drag-and-Drop LWC. JavaScript

Fetching Opportunities and Stages

The connectedCallback method is called when the component is connected to the DOM. Inside this method, the getTopOpportunities Apex method is used to fetch a list of opportunities and their associated stages. The fetched data is stored in the records and pickVals properties.

connectedCallback() {


        .then(result => {

            this.records = result.opportunities;

            this.pickVals = result.pickVals;


        .catch(error => {

            console.error(‘Error fetching opportunities:’, error);



Rendering Kanban-Style Stages

The for:each loop in the HTML template iterates over each stage in the pickVals array and renders a tab for each stage. The equalwidthHorizontalAndVertical getter calculates the width of each tab based on the number of stages.

<template for:each={pickVals} for:item=”item”>

    <div class=”slds-tabs–path” role=”application” key={item} style={equalwidthHorizontalAndVertical}>

        <!– Render stage tabs here –>



Drag-and-Drop Functionality

The handleListItemDrag method is triggered when an opportunity is dragged within the list. It captures the ID of the dragged opportunity.

handleListItemDrag(event) {

    this.recordId = event.detail;


Updating Opportunity Stages

The handleItemDrop method is called when an opportunity is dropped onto a new stage. This method triggers the updateHandler to update the opportunity’s stage.

handleItemDrop(event) {

    const stage = event.detail;



Class: OpportunityKanbanController


This class provides backend functionality for retrieving and managing data related to Opportunities in a Kanban view within a Salesforce Lightning component.



Description: Retrieves a list of opportunities categorized by priority and stage. Also, provides a count of opportunities in each stage.

Return Type: OpportunityKanbanController.wrapper

updateOpprtuity(String recordId, String stageName)

Description: Updates the stage of an Opportunity given its record ID.


  • recordId (Type: String) – The ID of the Opportunity record to update.
  • stageName (Type: String) – The new stage name to set for the Opportunity.

Return Type: OpportunityKanbanController.wrapper

Inner Classes


Description: A wrapper class to hold the response data for both opportunities and stage information.


  • opportunities (Type: List<Opportunity>) – List of Opportunity records.
  • pickVals (Type: List<OpportunityKanbanController.stageObject>) – List of stageObject instances containing stage names and counts.


Description: Represents a stage in the Kanban view along with the number of opportunities in that stage.


  • stage (Type: String) – The name of the stage.

noRecords (Type: Integer) – The count of opportunities in the stage.