How to integrate YouTube with Salesforce

 

In this article we demonstrate the use case of intuitive knowledge articles. Unlike the text based knowledge article, we display YouTube videos searched based on the Subject of a sample Case. The demo also brings in data such as likesdislikes and views of a particular video.

The Lightning Component is configurable such that it can be dragged and dropped on any objects (standard/custom) record page and it will fetch videos based on the text from the field whose API name is configured in a custom metadata created for this purpose.  Below is a snapshot of some sample metadata records for few objects. Take a look at fieldName for Case object, configured with Subject field - hence the videos on Case record page will fetch videos based on the text in the Subject field.

image Sample Custom Metadata records to configure YouTube Lightning Component for different objects

image Snapshot of YouTube Lightning Component

Firstly, few things to setup in Google Cloud Platform

We need a Google Account to access the Google API Console, request an API key, and register our application.

  1. Create a project in the Google Developers Console and obtain authorization credentials so your application can submit API requests.

image

After creating your project, make sure the YouTube Data API is one of the services that your application is registered to use:

  1. Go to the API Console and select the project that you just registered.
  2. Visit the Enabled APIs page and follow below steps to obtain the key

image API Console image Search for "youtube api" and click YouTube Data API v3 image Click Enable and in the following screen click under Credentials option click + CREATE CREDENTIALS image The generated API key will be used in the callout code.

The API Request & Response structure and Code Snippets


Part I : Fetch videos based on the Subject field of Case record

Below is a sample callout code using the YouTube Data API v3 and following is the response from the API.

HttpRequest request = new HttpRequest();
HttpResponse response = new HttpResponse();
Http http = new Http();
request.setEndpoint('https://www.googleapis.com/youtube/v3/search?maxResults=5&part=snippet&q='+searchResults.replaceAll(' ', '+')+'&type=video&key={YOUR_API_KEY}');
request.setMethod('GET');
try{
    response = http.send(request);
    System.debug(response.getBody());
    }catch(System.CalloutException e) {
        System.debug('Callout error: '+ e);
        System.debug(response.toString());
}

Below is the JSON response for video search results based on the Subject of a sample case record.

{
  "kind": "youtube#searchListResponse",
  "etag": "\"xwzn9fn_LczrfK9QS3iZcGzqRGs/2ptDzqXXFWnBe5A1b1ypvIdH8NM\"",
  "nextPageToken": "CAUQAA",
  "regionCode": "US",
  "pageInfo": {
    "totalResults": 1000000,
    "resultsPerPage": 5
  },
  "items": [
    {
      "kind": "youtube#searchResult",
      "etag": "\"xwzn9fn_LczrfK9QS3iZcGzqRGs/XAQjwNlxoLq_epHnE2XFJB2G2sk\"",
      "id": {
        "kind": "youtube#video",
        "videoId": "AHX6tHdQGiQ"
      },
      "snippet": {
        "publishedAt": "2018-03-15T15:27:07.000Z",
        "channelId": "UCbxQcz9k0NRRuy0ukgQTDQQ",
        "title": "Ink Cartridges Are A Scam",
        "description": "Printer companies are ripping us off, and it's high time we did something about it. Join me in starting the revolution.",
        "thumbnails": {
          "default": {
            "url": "https://i.ytimg.com/vi/AHX6tHdQGiQ/default.jpg",
            "width": 120,
            "height": 90
          },
          "medium": {
            "url": "https://i.ytimg.com/vi/AHX6tHdQGiQ/mqdefault.jpg",
            "width": 320,
            "height": 180
          },
          "high": {
            "url": "https://i.ytimg.com/vi/AHX6tHdQGiQ/hqdefault.jpg",
            "width": 480,
            "height": 360
          }
        },
        "channelTitle": "AustinMcConnell",
        "liveBroadcastContent": "none"
      }
    },
    {
      "kind": "youtube#searchResult",
      "etag": "\"xwzn9fn_LczrfK9QS3iZcGzqRGs/kZJUmeb5Su2YvYD_s8U0NOD7exs\"",
      "id": {
        "kind": "youtube#video",
        "videoId": "wW6cw4ydn-o"
      },
      "snippet": {
        "publishedAt": "2008-09-28T17:25:10.000Z",
        "channelId": "UCQlGBspQdj17WOPBQMT1k9A",
        "title": "Computer Upgrades & Repairs : How to Change Cartridges on an Inkjet Printer",
        "description": "Change cartridges on an Inkjet printer by opening the printer door and lifting up on the flap to unlock the cartridge. Remove and replace an Inkjet printer ...",
        "thumbnails": {
          "default": {
            "url": "https://i.ytimg.com/vi/wW6cw4ydn-o/default.jpg",
            "width": 120,
            "height": 90
          },
          "medium": {
            "url": "https://i.ytimg.com/vi/wW6cw4ydn-o/mqdefault.jpg",
            "width": 320,
            "height": 180
          },
          "high": {
            "url": "https://i.ytimg.com/vi/wW6cw4ydn-o/hqdefault.jpg",
            "width": 480,
            "height": 360
          }
        },
        "channelTitle": "expertvillage",
        "liveBroadcastContent": "none"
      }
    },
    {
      "kind": "youtube#searchResult",
      "etag": "\"xwzn9fn_LczrfK9QS3iZcGzqRGs/NmUS9NDUZ8TYGWot_MqUes4sCSw\"",
      "id": {
        "kind": "youtube#video",
        "videoId": "_S2lYXf-uu0"
      },
      "snippet": {
        "publishedAt": "2019-08-10T15:00:04.000Z",
        "channelId": "UCcyq283he07B7_KUX07mmtA",
        "title": "Why Printer Ink Is So Expensive | So Expensive",
        "description": "Printer ink can sometimes cost more than the printer itself. We talk with a former editor of the Recycler to find out why printer ink is so expensive. MORE SO ...",
        "thumbnails": {
          "default": {
            "url": "https://i.ytimg.com/vi/_S2lYXf-uu0/default.jpg",
            "width": 120,
            "height": 90
          },
          "medium": {
            "url": "https://i.ytimg.com/vi/_S2lYXf-uu0/mqdefault.jpg",
            "width": 320,
            "height": 180
          },
          "high": {
            "url": "https://i.ytimg.com/vi/_S2lYXf-uu0/hqdefault.jpg",
            "width": 480,
            "height": 360
          }
        },
        "channelTitle": "Business Insider",
        "liveBroadcastContent": "none"
      }
    },
    {
      "kind": "youtube#searchResult",
      "etag": "\"xwzn9fn_LczrfK9QS3iZcGzqRGs/ykbIv6fovakqi13OenCoJ0fO6ko\"",
      "id": {
        "kind": "youtube#video",
        "videoId": "kaHHvDuuGV0"
      },
      "snippet": {
        "publishedAt": "2008-09-28T17:15:59.000Z",
        "channelId": "UCQlGBspQdj17WOPBQMT1k9A",
        "title": "Computer Upgrades & Repairs : How to Change a Laser Printer Cartridge",
        "description": "Change a laser printer cartridge by opening the printer door and detaching the cartridge from the system. Remove and replace a laser printer cartridge with tips ...",
        "thumbnails": {
          "default": {
            "url": "https://i.ytimg.com/vi/kaHHvDuuGV0/default.jpg",
            "width": 120,
            "height": 90
          },
          "medium": {
            "url": "https://i.ytimg.com/vi/kaHHvDuuGV0/mqdefault.jpg",
            "width": 320,
            "height": 180
          },
          "high": {
            "url": "https://i.ytimg.com/vi/kaHHvDuuGV0/hqdefault.jpg",
            "width": 480,
            "height": 360
          }
        },
        "channelTitle": "expertvillage",
        "liveBroadcastContent": "none"
      }
    },
    {
      "kind": "youtube#searchResult",
      "etag": "\"xwzn9fn_LczrfK9QS3iZcGzqRGs/0uDr-nCvxGVm4yx-KYXrJ0ioCaE\"",
      "id": {
        "kind": "youtube#video",
        "videoId": "wqmA8jpJae4"
      },
      "snippet": {
        "publishedAt": "2015-08-04T19:33:12.000Z",
        "channelId": "UCgFb3rcjC_J7o97bM10cPqg",
        "title": "How to get more out of your ink cartridge",
        "description": "In this video, we show you how you can extend the life of an ink cartridge by resetting the memory of the cartridge. Follow the steps to reset the ink cartridge ...",
        "thumbnails": {
          "default": {
            "url": "https://i.ytimg.com/vi/wqmA8jpJae4/default.jpg",
            "width": 120,
            "height": 90
          },
          "medium": {
            "url": "https://i.ytimg.com/vi/wqmA8jpJae4/mqdefault.jpg",
            "width": 320,
            "height": 180
          },
          "high": {
            "url": "https://i.ytimg.com/vi/wqmA8jpJae4/hqdefault.jpg",
            "width": 480,
            "height": 360
          }
        },
        "channelTitle": "Inkjet Star, Inc.",
        "liveBroadcastContent": "none"
      }
    }
  ]
}

Part II : Fetching likes, dislikes and views of the videos fetched in Part I

We can get statistics based on video-Id. Below is a sample callout code and following is the response structure. To fetch stats for multiple videos we need to pass comma separated string of video-Ids

HttpRequest request = new HttpRequest();
HttpResponse response = new HttpResponse();
Http http = new Http();
request.setEndpoint('https://www.googleapis.com/youtube/v3/videos?part=statistics&id='+searchkeyword+'&key={YOUR_API_KEY}');
request.setMethod('GET');
try{
    response = http.send(request);
    System.debug(response.getBody());
}catch(System.CalloutException e) {
    System.debug('Callout error: '+ e);
    System.debug(response.toString());
}

Below is JSON response for the statistics of videos that were fetched for a sample case record in the previous section.

{
  "kind": "youtube#videoListResponse",
  "etag": "\"xwzn9fnLczrfK9QS3iZcGzqRGs/4F-j0jHUNnpEF28bWSk1U5QR6yc\"",
  "pageInfo": {
    "totalResults": 5,
    "resultsPerPage": 5
  },
  "items": [
    {
      "kind": "youtube#video",
      "etag": "\"xwzn9fnLczrfK9QS3iZcGzqRGs/QI9T-hGUzWJ3O4obR6JVd89ub44\"",
      "id": "wW6cw4ydn-o",
      "statistics": {
        "viewCount": "2253",
        "likeCount": "3",
        "dislikeCount": "1",
        "favoriteCount": "0",
        "commentCount": "1"
      }
    },
    {
      "kind": "youtube#video",
      "etag": "\"xwzn9fnLczrfK9QS3iZcGzqRGs/d9JBVFPfaMPeRR5lnpStZUfr5J0\"",
      "id": "AHX6tHdQGiQ",
      "statistics": {
        "viewCount": "6783848",
        "likeCount": "409704",
        "dislikeCount": "8360",
        "favoriteCount": "0",
        "commentCount": "33588"
      }
    },
    {
      "kind": "youtube#video",
      "etag": "\"xwzn9fnLczrfK9QS3iZcGzqRGs/fpZ1NnnKDFBKSB44bRAXwp-ORRQ\"",
      "id": "kaHHvDuuGV0",
      "statistics": {
        "viewCount": "3789",
        "likeCount": "2",
        "dislikeCount": "4",
        "favoriteCount": "0",
        "commentCount": "0"
      }
    },
    {
      "kind": "youtube#video",
      "etag": "\"xwzn9fnLczrfK9QS3iZcGzqRGs/QgSbp0b85uXwldHjwTcDRwvbTY\"",
      "id": "S2lYXf-uu0",
      "statistics": {
        "viewCount": "1544592",
        "likeCount": "30921",
        "dislikeCount": "634",
        "favoriteCount": "0",
        "commentCount": "2507"
      }
    },
    {
      "kind": "youtube#video",
      "etag": "\"xwzn9fnLczrfK9QS3iZcGzqRGs/b5l8HC-8KjG-rCu5CNMzSzQBBM8\"",
      "id": "q3n7YYkRhVU",
      "statistics": {
        "viewCount": "24293",
        "likeCount": "202",
        "dislikeCount": "18",
        "favoriteCount": "0",
        "commentCount": "59"
      }
    }
  ]
}

The callout code snippets goes into the controller associated to the component - Youtube_API_V3 here

The component code

<aura:component controller="Youtube_API_V3" implements="force:hasSObjectName,force:hasRecordId,force:lightningQuickAction,force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,forceCommunity:availableForAllPageTypes" access="global">   
    
    <aura:attribute name="recordId" type="String" />
    <aura:attribute name="sObjectName" type="String" />
    
    <aura:attribute name="videoIds" type="Map"/>
    <aura:attribute name="videoIds1" type="Map"/>
    <aura:attribute name="searchKeyword" type="String"/>
    <aura:attribute name="Message" type="boolean" default="false"/>
    
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <lightning:spinner variant="brand" size="large" aura:id="Id_spinner" class="slds-hide" />
    
    <article class="slds-post" style="padding-top: 20px;border-radius: 5px;border: 1px solid #ccc;">
        <div class="slds-card__body">
            <aura:iteration items="{!v.videoIds}" var="video">
            
            <div class="slds-feed">
                <ul class="slds-feed__list">
                    <li class="slds-feed__item">
                        <article class="slds-card">
                                <div class="slds-card__body slds-card__body_inner">
                                    <div style="margin-bottom:10px">
                                        <h3 style="color: rgb(0, 109, 204);font-weight: bold;font-size: 14px;"> <aura:unescapedHtml value="{!video.value}"/></h3>
                                    </div>
                                    <div class="slds-post__payload">
                                        <a href="javascript:void(0);" class="slds-media slds-box slds-grow slds-text-link_reset">
                                            <div class="slds-media__figure slds-medium-show">
                                                <div class="slds-file slds-size_small">
													<iframe frameborder="10" src="{!'https://www.youtube.com/embed/'+video.key}" width="150" height="100" style="border:0px solid #ccc;border-radius:5px;"></iframe>
                                                </div>
                                            </div>
                                            <div class="slds-media__body">
                                                <!--<h3 class="slds-text-heading_small">{!video.value}</h3>-->
                                                <!--<p>{!video.value}</p>-->
                                                <span class="slds-text-body_small" style="width: 183px;margin-left: -90px;display: block;">{!video.description}</span>
                                            </div>
                                        </a>
                                    </div>
                            	</div>
                            
                            <footer class="slds-post__footer">
                                <ul class="slds-post__footer-actions-list slds-list_horizontal">
                                    
                                </ul>
                                <ul style="padding:0 20px 10px 0px" class="slds-post__footer-meta-list slds-list_horizontal slds-has-dividers_right slds-text-title">
                                    <li class="slds-item" id="{!video.key+'-shares'}">{!video.viewCount} views</li>
                                    <li class="slds-item">{!video.likeCount} likes</li>
                                    <li class="slds-item">{!video.dislikeCount} dislikes</li>
                                </ul>
                            </footer>
                        </article>
                    </li>
                </ul>
                
            </div>
            
        </aura:iteration>
        </div>
    </article>
</aura:component>

 

The component controller code

({
	doInit:function(component, event, helper) {
        
        var action1 = component.get('c.getResponse');
        
        action1.setParams({
            "RecordId": component.get("v.recordId"),
            "sObjectName" : component.get("v.sObjectName")
        });
        
        action1.setCallback(this, function(response){
            
            var state = response.getState();
            if((state === 'SUCCESS')){                
                var custs = [];
                var conts = response.getReturnValue();
                for ( var key in conts ) {
                    var title = conts[key].split('!@#$')[0];
                    var description = conts[key].split('!@#$')[1];
                    var viewCount = conts[key].split('!@#$')[2];
                    var likeCount = conts[key].split('!@#$')[3];
                    var dislikeCount = conts[key].split('!@#$')[4];
                             custs.push({value:title,key:key,description:description,viewCount:viewCount,likeCount:likeCount,dislikeCount:dislikeCount});
                }
                component.set("v.videoIds", custs);
                                
            } else if( state === 'INCOMPLETE'){
                console.log("User is offline, device doesn't support.");
            } else if( state === 'ERROR'){
                console.log('Problem , error: ' +
                            JSON.stringify(response.getError()));
            } else{
                console.log('Unknown problem, state: ' + state +
                            ', error: ' + JSON.stringify(response.getError()));
            }
        });
        
        $A.enqueueAction(action1);
    },
})

YouTube statistics: https://www.oberlo.com/blog/youtube-statistics

This is Open Community Blogger Platform and community forum of SFDC professionals interested to share their experiences, ideas, and thoughts or any content invaluable to help others in this domain.

Archives