Getting started on building social Intranets with SharePoint and Yammer

One of the really hot topics cross our customers is the enterprise social and how to build real social intranets in global scale. In Microsoft platform this is commonly done using by a combination of SharePoint and Yammer. Currently natively Yammer however seems pretty disconnected from the SharePoint capabilities, which make the end user experience not so optimal, but we can already today further enhance the native capabilities for enabling real integration between these systems.

This can be achieved by using the great Yammer API capabilities to integrate to the social platform from external systems and we can certainly use this same capability to combine or inject the Yammer capabilities directly to the Intranet portals or collaboration sites. There was numerous session in SharePoint Conference 2014 on the Yammer social capabilities, but personally I really couldn’t find proper “getting started” guidance from conceptual and practical perspective. I love great demos, but to be able to really understand the capabilities we need to also provide the simples possible samples for helping to get started on the development efforts. Simplicity is the key for understanding and then we can move to more complex scenarios.

In general we have great guidance on the MSDN for SharePoint and Yammer has its own developer documentation, but  since I couldn’t really find suitable information at least for me (“Getting started for dummies” level), I wanted to help hopefully on others within their journey on building social Intranet’s with SharePoint and Yammer. Following chapters are explaining the integration possibilities and how they can be technically achieved.

Social Intranet with SharePoint and Yammer concept

Before actually going on to the technical details, let’s first clarify the concept slightly with few pictures and some description. SharePoint 2013 had actually natively some great social capabilities, but roughly on the same time as we released the beta 2 for SharePoint 2013, we announced that we have bought the Yammer. At the time I personally didn’t really get the reason (I’m a simple person), but after working with the Yammer for a while, I seriously felt in love with it… it does provide some great social capabilities and it will dramatically to decrease the email inbox growth, which is great news for me and for many others.

Classic challenge however with the Yammer has been that it feels so disconnected from the collaboration platform, which is commonly SharePoint and there is still some overlapping capabilities even in Office365 SharePoint platform. Obviously this disconnected used experience will be adjusted in the future (you don't need to be oracle to realize that), but already today you can build the needed integrations for the end users with pretty simple customizations.

Following pictures shows an imaginary Intranet concept build on top of the Office Garage (check the series) branding. I’ve just used the Office Garage colors and branding to demonstrate the capabilities and to provide some nice UI elements, but obviously this same concepts is possible to apply with any Intranet in Office365 or in the on-premises. Objective is pretty simple – let’s make the end user experience better by introducing some simple JavaScript integrations between SharePoint and Yammer capabilities so that we can combine the best from both systems..

image

And here’s an example of using Yammer with the team sites on replacing the out of the box SharePoint team site newsfeed discussion.

image

Yammer also in on-premises as the social platform?

Actual initial reason why I got involved on this Yammer integration discussion was requirements from one global on-premises deployment, where the customer was not willing to go to the Office365 due miscellaneous reasons. Customer had three existing SharePoint farms cross the world and as part of the SharePoint 2013 upgrade, they wanted to start using also the different social capabilities from our platform.

Default on-premises social capabilities (SharePoint social) are having some challenges with multi-farm deployments, since user profile and distributed cache information are not shared cross the farms. In this particular case customer was however also interested on seeing the possibilities with Yammer, so we designed the architecture to use Yammer as the social platform, so that we can address the needed social capabilities (messaging, discussions, likes, follows). As a side a note, we also did design a custom user profile property sync between the three farms to ensure that farm specific user profile properties are sync'd between the other farms for people search purposes. This was needed for few other planned functionalities as well and since we don’t have user profile replication engine for SharePoint 2013, this had to be solved with a custom add-on. Details on this custom sync would however require separate blog post, so let’s not go too detailed on overall architecture design and requirements.

In high level the design was as in following picture. Key point was that we would use the Yammer social capabilities from the cloud as the engine for any social functionalities, but still keep the normal collaboration and document management functionalities in on-premises.

image

In many cases using Yammer, but then not using Office365, could be seen as strange, but in this case customer explicitly wanted to have the actual document storage in their on-premises, even though the social capabilities are coming from the cloud. Not necessarily typical setup, but completely valid hybrid design which could be taken based on circumstances.

Yammer Embed option

Let’s move to actually on how to make the needed Yammer integration to happen. Yammer embed option is definitely the most easiest option to get started, since you really don’t need to do anything else than place the right JavaScript function to your SharePoint site and even authentication is taken care of for you automatically. If user has not been yet logged to yammer, he/she will be asked to do so. Key tool for creating or seeing different embed options is the following widget which can be used for solving the right feed or settings what you want to use - https://www.yammer.com/widget/configure.

clip_image003

So – from this widget you’ll be able to get the right embedding code for your JavaScript. In the context of the SharePoint, you can then simply use Script Web part or script embedding capability to show the needed feed in SharePoint. Simply go and add Script Editor Web Part to the page and place the below script to it.

clip_image004

    1: <div id="embedded-feed" style="height:400px;width:500px;"></div>
    2: <script>
    3:     yam.connect.embedFeed({
    4:         container: '#embedded-feed'
    5:         , network: 'veskuonline.com'
    6:         , feedType: ''
    7:         , feedId: ''
    8:         , config: {
    9:                 use_sso: true
   10:                 , header: true
   11:                 , footer: true
   12:                 , showOpenGraphPreview: false
   13:         }
   14:     });
   15: </script>

This will result you the current users latest messages. You can adjust some of the settings on how things are presented, like do we show the header or footer. Check the details on the options from here https://developer.yammer.com/connect.

clip_image005

What’s really cool with the Yammer Embedding is also the support for using dynamically created OpenGraph objects, What this means is that we are able to create dynamically objects which can be then used as “end points” in Yammer side for discussions and other actions. This can be easily achieved by using simply the right configuration for the embedding JavaScript and the object is created dynamically for you. This is excellent capability for creating dynamic discussions or other actions towards any element you can think of… url, file, audio, video… as long as it has unique URL, you can do that. Only difference for initial OpenGraph setup is simply the details on the embedding script. Here’s an example.

    1: <script type="text/javascript"
    2:         src="https://assets.yammer.com/assets/platform_embed.js"></script>
    3:  
    4: <div id="embedded-feed" style="height:400px;width:500px;"></div>
    5: <script>
    6:     yam.connect.embedFeed({
    7:         container: '#embedded-feed'
    8:         , network: 'veskuonline.com'
    9:         , feedType: 'open-graph'
   10:         , feedId: ''
   11:         , config: {
   12:                 use_sso: true
   13:                 , header: false
   14:                 , footer: false
   15:                 , showOpenGraphPreview: false
   16:                 , promptText: 'Another Page'
   17:             }
   18:         , objectProperties: {
   19:             url: 'https://vesaj.sharepoint.com/teams/wcm/another-page'
   20:             , type: 'page'
   21:         }
   22:     });
   23: </script>

And this is how it looks in the page. Notice that you can create this “virtual” OpenGraph object to any item you want. This provides excellent capabilities to integrate basic social capabilities to any system or artefact you might have in SharePoint or in any other system.

clip_image007

This is how OpenGraph object it looks then in the Yammer side… which you most likely won’t be really accessing that often, since you will access the feed and other actions directly from the embedded application side, which in this case is SharePoint. Notice that you can also do following and likes for OpenGraph object, which is great.

clip_image008

But I don’t want to manually add the needed scripts to the web part, since that’s too much work for end users… can we automate this? – Yes… certainly. It’s all about how we include the JavaScript and the elements on the page. You can include the needed JS embedding for example in the master page and then just place the needed code for page level OpenGraph element creation to the page layout. This would easily give you opportunity to have discussion board dynamically for each news article or each page in the in the Intranet.

Second alternative is to place the script editor web part to the pages automatically during the site provisioning. This capability is demonstrated in the Office AMS examples where we use remote provisioning to create SharePoint sites with right branding and with by default having Yammer group discussion for the team site, rather than out of the box SharePoint site feed.

There’s also Yammer app in the Office store to help on using the embedding mechanism called Yammer App for SharePoint, which encapsulates the basic embedding capabilities for you. If you do however want to provide some special things with the embedding, you can certainly write your own SharePoint app for this one as well. In the downloadable code package related on this code, you can find also one app part, which is simply using the my messages embedding option. This is how the embed app part looks if you’re not logged into Yammer using single sign on, cookie or particular browser session.

image

Following picture demonstrates how the same page looks when user is logged to Yammer.

image

You can easily modify this example to use also OpenGraph objects with dynamic URL resolving and whatever is needed for your deployment.

Yammer REST API pattern

Where do I need the REST pattern? – When you need some capabilities which are not available with embed option. We don’t really have that simplified examples out there and only good getting started sample was following blog post, which helped me to the right direction: https://arcsnap.blogspot.fi/search/label/Yammer%20Javascript%20API%20Tutorial%20Post%20Message. I’ve used that sample as my starting point and slightly extended it in the provided examples.

Start by registering an app to the your Yammer network. You can do this on the https://www.yammer.com/client_applications to the yammer network which you’ve registered. Easiest way to get sample Yammer network is to spin up a new Office365 test site, change the domain for it to be something else than onmicrosoft.com and after that you can register that domain as a new Yammer network for testing purposes.

Like mentioned in getting started guidance in yammer developer guidance, you’ll need to ensure that following information is available, since these are required to ensure that app works properly:

  1. Application Name: The app name which will appear in Yammer’s activity stream.
  2. Organization: The name of the organization affiliated with your app.
  3. Website: Your organization’s website.
  4. Support e-mail: An email address which users of your app can contact for support.
  5. Expected Redirect/Redirect URI: Where Yammer will redirect to after the authentication flow is complete.

From here we get the actual app ID which is then registered for that particular network. If you really build global Yammer application, your app ID is then published cross the other networks as part of the app publishing process.

clip_image009

Now we have the needed client ID to access the Yammer on behalf of the user. We’ll need to use that when we operate against the Yammer. I’ve included to this blog post three different examples, which each do one reference operation (post message, read messages, get notifications), but let’s open up them slightly. What we need to have is first reference to the right yammer JS and we can perform the initial configuration in the head of the page.

    1: <head>
    2:     <meta charset="utf-8" />
    3:     <title>Yammer My Messages!</title>
    4:     <script src="https://assets.yammer.com/platform/yam.js"></script>
    5:     <script>
    6:         // initializing script
    7:         yam.config({ appId: "k1oDkFd4HB7fUtmIk3N3lA" });
    8:     </script>
    9: </head>

After this it’s just using the JS APIs using the right pattern… in this case we confirming that the app and user is authenticated to the Yammer and move then forward to the actual function.

    1: function post() {
    2:     yam.getLoginStatus(function (response) {
    3:         if (response.authResponse) {
    4:             get_my_messages();
    5:         } else {
    6:             yam.login(function (response) {
    7:                 if (!response.authResponse) {
    8:                     get_my_messages();
    9:                 }
   10:             });
   11:         }
   12:     });
   13: };

Actual request to get the latest messages for particular user is pretty simple JavaScript post. In the case of getting access, we just render the JSON object out to table format in the example scenarios.

    1: function get_my_messages() {
    2:     yam.request(
    3:         {
    4:             url: "https://www.yammer.com/api/v1/messages.json"
    5:         , method: "GET"
    6:         , success: function (msg) { RenderResults(msg); }
    7:         , error: function (msg) { alert("No Go"); }
    8:         }
    9:     );
   10: };

Here’s the full html page for this particular example, just to show the full html structure. Notice that in this example I’m just outputting the JSON object to html table, but in real life, we would be then formatting this as needed for showing the right information for end users.

    1: <!DOCTYPE html>
    2:  
    3: <html lang="en" xmlns="https://www.w3.org/1999/xhtml">
    4: <head>
    5:     <meta charset="utf-8" />
    6:     <title>Yammer My Messages!</title>
    7:     <script src="https://assets.yammer.com/platform/yam.js"></script>
    8:     <script>
    9:         // initializing script
   10:         yam.config({ appId: "k1oDkFd4HB7fUtmIk3N3lA" });
   11:     </script>
   12: </head>
   13: <body>
   14:     <button onclick='post()'>Get my messages!</button>
   15:     <br />
   16:     <div id="results"></div>
   17:     <script>
   18:         function post() {
   19:             yam.getLoginStatus(function (response) {
   20:                 if (response.authResponse) {
   21:                     get_my_messages();
   22:                 } else {
   23:                     yam.login(function (response) {
   24:                         if (!response.authResponse) {
   25:                             get_my_messages();
   26:                         }
   27:                     });
   28:                 }
   29:             });
   30:         };
   31:  
   32:         function get_my_messages() {
   33:             yam.request(
   34:                {
   35:                    url: "https://www.yammer.com/api/v1/messages.json"
   36:                , method: "GET"
   37:                , success: function (msg) { RenderResults(msg); }
   38:                , error: function (msg) { alert("No Go"); }
   39:                }
   40:            );
   41:         };
   42:  
   43:         // This is just for result output - notice that to keep things simple
   44:         // we don't use any fancy JS libaries... you can and most likely will 
   45:         // be using them in production, but that's another story already...
   46:         function RenderResults(msg) {
   47:             var htmlOutput = CreateTableView(msg.messages);
   48:             document.getElementById("results").innerHTML =
   49:                 '<h1>We got' + msg.messages.length + ' items</h1>' + htmlOutput;
   50:         }
   51:  
   52:         function CreateTableView(objArray) {
   53:  
   54:             // If the returned data is an object do nothing, else try to parse
   55:             var array = typeof objArray != 'object' ?
   56:                                     JSON.parse(objArray) : objArray;
   57:  
   58:             var str = '<table>';
   59:             // table body
   60:             str += '<tbody>';
   61:             for (var i = 0; i < array.length; i++) {
   62:                 str += (i % 2 == 0) ? '<tr class="alt">' : '<tr>';
   63:                 for (var index in array[i]) {
   64:                     str += '<td>' + array[i][index] + '</td>';
   65:                 }
   66:                 str += '</tr>';
   67:             }
   68:             str += '</tbody>'
   69:             str += '</table>';
   70:             return str;
   71:         }
   72:     </script>
   73: </body>
   74: </html>

You can check the downloadable demo code for full html page examples on how to post messages, read messages or read notifications, which is the most commonly used scenarios for the REST APIs. Any other feed or needed information uses the same pattern and you can locate the different REST feed end points from yammer developer documentation at https://developer.yammer.com/restapi.

From the downloadable demo code package you can also find simple SharePoint hosted app versions of the html pages. These are just demonstrating the same JavaScript code as the html pages, but you can use them directly in the SharePoint. Notice that they just demonstrate the API calls and I’ve not done any work on properly outputting any response messages, that’s something you can add there, if you need that. Here’s a screen shot of a SharePoint developer site with the REST API app parts added to it.

image

REST API usage in SharePoint

How would I use this REST API in SharePoint? – There’s multiple different options. You could build App, which is performing the required actions using either JavaScript or .NET code in server side, but in most of the case, you’d be looking to simply place the required JavaScript to the master page or to the page layout used in your portal. This would be providing the maximum flexibility to combine SharePoint CSOM and Yammer capabilities in the context of the particular user, which is anyway the normal case with these capabilities.

Summary and some additional references

Like you can see from the provided information and the downloadable examples, building end user friendly social intranet with Yammer and SharePoint is really not that hard and it can bring lot of value for your deployments. Yammer is yet again one of those excellent services or tools to select for your overall architecture design. Like mentioned in the start of this post, you don’t have to be an oracle to foresee that Office365 and Yammer integration will get closer out of the box in the future as well, but already today you could build real enterprise scale social intranets to the cloud or to the on-premises using the available APIs.

Here’s some additional information on the technical details.

  • Code samples shown in this blog post
    • One Visual Studio 2013 solution containing three html pages with simple Yammer integration samples and same three scenarios provided as app parts in SharePoint hosted app. Solution also contains on embed app part example for showing personal messages from Yammer. Notice that to be able to use these, you’ll need to register the Yammer App ID to your network and to update the examples accordingly.
    • Even though these are provided as SP apps, most likely the best option is to use the JavaScript directly in the page layout/master page for providing the best end user experience. These examples are pretty simple to demonstrate the scenario, but don’t them fool you, those concept pictures shown in this blog post are 100% doable and do not require rocket science degree from JavaScript.
  • Make your SharePoint portal social in 1-2-3!
    • SharePoint Conference 2014 presentation and video (SPC378)
    • Great session on building social intranet with SharePoint and Yammer by Runar Olsen and Thomas Molbach. Session contains details on how to build dynamic and social intranet using also the SharePoint search capabilities with the Yammer.
  • Integrating Yammer and SharePoint using .NET
  • Developing socially connected apps with Yammer, SharePoint and OpenGraph
  • Overview of Yammer app development
  • · Yammer group discussion replacement reference implementation
    • Office AMS samples - Check Contoso.SPOSiteProvisioning sample for details on how to replace the oob site newsfeed with Yammer group based approach. Thanks for Richard diZerega for this particular integration piece… brilliant stuff, which is based on the REST API usage and script editor web part usage in the team site.