StreamHub Integration Guide (Markdown) - pwanglive/mustached-octo-adventure GitHub Wiki
This document describes how to integrate the Livefyre StreamHub Application Application into your webpage, including Single Sign On integration with either a custom identity system or Enterprise Profiles (formerly known as Livefyre Custom Profiles, LFCP).
If you are using both Enterprise Profiles and the Livefyre PHP Wrapper, you may be most interested in the “Using Livefyre Custom Profiles and Livefyre PHP Wrapper” appendix.
###Table of Contents
#Embedding the Comment Stream
To embed LiveComments, you need to add a JavaScript library to the page and
initialize it with some options. From a high level, the integration involves
adding the following to the <head>
of your page:
<!-- Include the LiveComments JavaScript library -->
<script type="text/javascript" src="http://zor.livefyre.com/wjs/v3.0/javascripts/livefyre.js"></script>
<!-- Initialize LiveComments -->
<script>
fyre.conv.load(
{ /* Global Config Object */ },
[{ /* Comment Stream Config Object */ }],
function () { /* onLoad callback function */ }
);
</script>
Note: The livefyre.js
JavaScript library in production environments will use the zor.livefyre.com
domain. For QA purposes, use the zor.t402.livefyre.com
domain (e.g. http://zor.t402.livefyre.com/wjs/v3.0/javascripts/livefyre.js
).
Each of these pieces is described in more detail below.
##Global Config Object
The Global Config Object is a JSON object containing the following parameters, which are all optional:
network
If your site is part of a custom network, provide its name here. If you
don't know what this is, your site is likely part of the default network
(livefyre.com)
Example: “yourname.fyre.co”
authDelegate
An object that is used to customize the authentication system for custom
network users. See Single Sign On.
Note: These parameters are separate from the Comment Stream Config Object because it is possible to put two (or more) LiveComments streams on the same page. Extra widgets use system resources and performance could potentially degrade if there is too much loaded at once on a page. The other config options are specific to each stream, but these options are shared.
##Comment Stream Config Object
The Comment Stream Config Object tells LiveComments what Collection (the set of comments that belong together in a conversation) to display and where it should render the comment stream. It is a JSON object containing the following fields:
siteId (required)
The Livefyre-provided ID for the website or application the collection
belongs to.
Example: “303617”
articleId (required)
This is a string identifier you choose to uniquely
identify a Collection within your Site. Usually, this corresponds to
a database primary key or Post ID within your CMS.
Example: “post-42”
If your CMS does not provide an articleId, LiveComments provides a utility for generating an articleId automatically.
IMPORTANT: There's a 64 character limit on articleId's. If you use the article URL as your articleId, you should ensure the string is MD5 or SHA-1 encoded.
el (required)
The id of a DOM element to render the comment stream to.
collectionMeta (required)
Metadata about the collection, see Collection Metadata.
checksum (optional)
A string that identifies the current state of the collectionMeta. Changing
this value will cause LiveComments to update the data on the server with the
new values in collectionMeta.
anonymousFlaggingEnabled (optional)
A boolean that determines if guest users have the option to flag content. The default is true.
flaggingNoteEnabled (optional)
A boolean that determines if users see the option to leave a note when they flag content.
The default is true.
For more details on creating the config object, please see Creating the Comment Stream Config Object.
###Collection Metadata
The collection metadata serves two purposes:
- Supply data about the page to improve user experience (e.g. include more accurate information in notification emails).
- Allow implementations to sign the Comment Stream Config Object to secure collection creation.
To get the benefit of secure collection creation, your implementation must include some backend server code. See Signing Metadata.
Using either method, the metadata is a JSON object. For signed metadata, the backend code will convert that object into a JWT token. For unsigned metadata, it is used directly. The object contains the following fields:
articleId (required)
A unique ID for the article. See Comment Stream Config Object.
title (required for signed)
The title you wish to apply to the Collection. Usually, this
corresponds to the title of the article, photo, or other piece of
content you’re embedding the Comment Stream on.
Example: “Integration is So Much Fun!”
IMPORTANT: The maximum character length for the title is 255 characters. The title field does not support html entities. Please encode special characters using UTF-8.
url (required)
The canonical absolute URL you wish to attach to this
Collection. This URL will be used to generate links back to the
Comment Stream from Content shared on Facebook and Twitter, email
notifications, and the Livefyre Admin Dashboard.
LiveComments provides a utility for generating a Collection URL automatically..
IMPORTANT: If testing locally, make sure to use a valid base URL domain (e.g., VALID: customer.com, INVALID: loacalhost:5995).
tags
A comma-separated list of single keywords or phrases. Search
collections by tags via the admin interface and the search API.
stream_type (optional)
The type of collection shown on the page. The options are: livecomments, livechat and liveblog. Defaults to livecomments.
For more details on creating the collection meta, please see Creating the Collection Metadata Token.
###Signing Metadata
The collection metadata can be signed using a secret key shared between you and Livefyre. This key must be kept private and not put on the page, so the signed metadata must be generated on the server backend. See Creating the Collection Metadata Token for a PHP example of how to generate a signed token.
You can also use Livefyre’s PHP API to generate signed collectionMeta. See an example here: LiveComments PHP Example
###Creating the Collection Metadata Token
The Collection metadata token is a JSON Web Token (JWT) signed with your Site key that securely encodes the Title and URL attached to a collection. It also contains a checksum that should only change when this metadata changes. Livefyre will only update Collection metadata when it sees a new checksum value.
- Create a “collectionMeta” object which contains the title of the article, the fully qualified URL of the article, and any tags you wish to include (optional, comma-separated).
$metadata = array (
"title" => "The Article Title",
"url" => "http://the.article.title.com/?parameters=sample",
"tags" => "foo,bar",
"stream_type" => "livecomments",
);
- JSON encode the meta object you created above and then generate an md5 checksum for it.
$checksum = md5(json_encode($metadata));
- Add the checksum (from step 2) and the
articleId
as a part of the collectionMeta object
$metadata["checksum"] = $checksum;
$metadata["articleId"] = <ARTICLE ID>;
$metadata["type"] = <STREAM TYPE>;
- Sign the collection object with your secret site key (i.e. create a
JWT token) with the JWT encoding utility. The output will be your
'
collectionMeta
' token string.
$collectionMeta = JWT::encode($metadata, <YOUR SITE KEY>);
###Creating the Comment Stream Config Object
Upon initialization, the Comment Stream is passed a Config Object containing the Collection Metadata, the Collection Metadata checksum, the Livefyre Site ID you’re embedding the Comment Stream on, and the ID of the element you wish to render the Comment Stream in.
- Build the final object to be sent over the wire. This final object contains the checksum you calculated from step 2, the encoded JWT collectionMeta object, the target element (labeled “el” below - default as shown in this documentation is a div with the id of “livefyre”) which the stream will be embedded in, and your siteId.
$config = array(
"el" => "livefyre",
"checksum" => $checksum,
"collectionMeta" => $collectionMeta,
"siteId" => <YOUR SITE ID>,
"articleId" => <ARTICLE ID>
);
- While the final object has been created, the last thing to do is wrap the object in an array and then JSON encode the entire thing. Now it’s ready for the next step: Embedding the Comment Stream.
$commentStreamConfig = json_encode( array($config) );
All together, Collection Metadata and Config Object generation should look something like:
$checksum = md5(json_encode($metaData));
$metaData["checksum"] = $checksum;
$metaData["articleId"] = <ARTICLE ID>;
$metaData["type"] = <STREAM TYPE>;
$collectionMeta = JWT::encode($metaData, <YOUR SITE KEY>);
$config = array(
"el" => "livefyre",
"checksum" => $checksum,
"collectionMeta" => $collectionMeta,
"siteId" => <YOUR SITE ID>,
"articleId" => <ARTICLE ID>
);
$commentStreamConfig = json_encode( array($config) );
To see an example step-wise creation of the comment stream collection config and embed code, please refer to http://ssosandbox.livefyre.com/ssosandbox/lf_sandbox_site/integration/CollectionMetaHelper.php. Please note that the MD5 may be different from the value you create as different languages will create it differently, and that's okay.
##Bringing it all Together
Once the JavaScript is loaded and you have a config object, you can load LiveComments. Here is an example implementation:
<html>
<head>
<script>
var streamConfig = [{"collectionMeta": <YOUR CALC-ED COLLECTION META>,
"checksum": <CHECKSUM>,
"siteId": <YOUR SITE ID>,
"articleId": <YOUR ARTICLE ID>,
"el":"livefyre"}];
var callback = function() {
document.getElementById('livefyre-status').innerHTML = 'LiveComments has loaded!';
}
fyre.conv.load(
{"network": "<YOUR NETWORK>"}, /* This example does not implement custom authentication delegates */
streamConfig,
callback
);
</script>
</head>
<body>
<div id="livefyre-status">LiveComments is not loaded.</div>
<div id="livefyre"></div>
</body>
</html>
#Single Sign On
##Custom Profile Systems
To hook-up Livefyre with your profile system, you'll have to integrate several touch points; these points are what we call "authentication delegates", or auth delegates for short. The Auth delegates that are passed to the widget allow for it to execute arbitrary code that you define in order to trigger events such as sending a user through your authentication flow or logging a user out.
###Set up JavaScript auth delegates
If you’re using a custom profile system, a series of delegates will need to be defined to respond to specific events. These delegates that your application should override are the following:
login
This event is fired when a user clicks on the login button on
the Livefyre Comment Stream.
logout
This event is fired when a user clicks on the logout button
on the Livefyre Comment Stream.
viewProfile
This event is fired when a user clicks on the view
profile hyperlink. You will have access to the following author fields: id
, isCuratedAuthor
, and profileUrl
. Warning: If you are building the profile url off of the user id, be aware that third party curated content will contain a remote profile, but the user id would not link to anything relevant on your side. You can check the value of isCuratedAuthor
, and if true then use the provided profileUrl
.
editProfile
This event is fired when a user clicks on the edit
profile hyperlink.
To register the aforementioned handlers to respond to the events, you’ll be providing custom functions to deal with them and then passing them in to the configuration method.
var authDelegate = new fyre.conv.RemoteAuthDelegate();
authDelegate.login = function (handlers){
/* place custom login code here */
// if the login process completes successfully, call this method: handlers.success();
// if the login process failed for any reason, call this method: handlers.failure();
};
authDelegate.logout = function (handlers) {
/* place custom logout code here */
// when the logout process completes successfully, call this method: handlers.success();
};
authDelegate.viewProfile = function(handlers,author) {
/* place custom view profile code here, below is an example */
console.log('check if the user is native or remote: ',author.isCuratedAuthor);
console.log('here is the user id: ',author.id.split('@')[0]);
handlers.success();
};
authDelegate.editProfile = function(handlers,author) {
/* place custom edit profile code here, could be as simple as setting document.location */
console.log('here is the user id from livefyre: ',author.id);
console.log('here is the external system user id: ',author.id.split('@')[0]);
handlers.success();
};
/* when it comes time to load the conversation... */
fyre.conv.load({network: <YOUR NETWORK>,
authDelegate: authDelegate},
[<Config Object>],
callback
);
You should note that if you want to use the default functionality of the defined delegates in addition to your own code, the function that you pass in must return false or undefined. If you do not want the default behavior to execute, then you must return true.
Log-in a user
If you set a cookie with the Livefyre token or have a token for the user and want to explicitly log a user in, make sure you implement a method to call fyre.conv.login()
and pass in the JWT user token (fyre.conv.login(<JWT TOKEN>)
). This method should be run by adding it to (or making it) the onload handler that is passed to fyre.conv.load()
. An example JavaScript method called doLivefyreAuth
can be found here:
LiveComments PHP Example
Log-out a user
To explicitly log a user out of the Livefyre widget, you need only call fyre.conv.logout()
. This will trigger the logout flow for the Livefyre widget, which means loggin the user out of the widget and removing any cookies or data the widget may have created during the user's session.
Best Practice - Set a cookie on login
The most efficient way to “give” a logged-in user their Livefyre token is to create it upon successful login and store it in a cookie. For example, in PHP you might use (where $expire is set to the same expiration as your other session cookie(s)):
setcookie( ‘livefyre_token’, ‘XXXXXX’, $expire, $cookie_path, $cookie_domain, $secure, false );
Similarly, the ‘livefyre_token’ cookie should be removed/invalidated whenever a user logs out of your system. For more information about generating the token, see the documentation here: Livefyre Authentication Token
##Enterprise Profiles
To integrate with Enterprise Profiles (formerly known as Livefyre Custom Profiles, LFCP), you’ll need only a few lines
of code and one additional JavaScript import. To start, place the
<script>
reference to your Enterprise Profiles JavaScript library (URL
provided by Livefyre) in the head of the document. Make sure to include
it before/above the JavaScript include for the Livefyre Comment Stream.
Next, you’ll need to setup the event handlers for the all of the authorization delegates and provide the context of the Janrain Engage application. To do this, simply add the following code above/before you initialize the Livefyre Comment Stream.
var authDelegate = new fyre.conv.SPAuthDelegate({engage: {app: <YOUR ENGAGE APP>}});
Where <YOUR ENGAGE APP>
is the identifier for your Engage application that you set up.
Finally, you’ll be notifying the Livefyre Comment Stream of the Enterprise Profiles configuration by adding the following to its initialization method:
fyre.conv.load({authDelegate: authDelegate}, appConfig);
This above code assumes that you’re using the basic implementation of the Livefyre Comment Stream and that the “appConfig” is an object created as described in Creating the Comment Stream Config Object.
#Appendix
##Using PHP to Initialize Livefyre
The Livefyre PHP Wrapper can be downloaded from GitHub, and can be used to make integration as easy as possible on PHP platforms. To utilize the Livefyre API, download the code and place it in your deployment directory.
See a complete example here: LiveComments PHP Example
// include the library include(dirname(__FILE__) . “/livefyre-api/libs/php/Livefyre.php”); // set up some values
$cms_content_id = testing123;
$cms_permalink_url = ‘http://example.cbs.com/example.html’;
$cms_title = ‘(testing 1 2 3) This is a test title.’;
$cms_tags = ’’;
$NETWORK = ‘yournetwork.fyre.co’; // REPLACE “yournetwork”
$NETWORK_KEY = ’’; // Fill in with your key, this is the auth_clientkey for the domain you are working on
$SITE_ID = ’’; // Fill in with your site ID
$SITE_KEY = ’’; // Fill in with your site key, this is the site api_secret
$COMMENTS_ELEMENT_ID = ’’; // in which html element (id) should Livefyre appear?
// using Enterprise Profiles? include the JS URL for that library via <script>,
// i.e. -
// include JavaScript - should come after profile JS if you are using Enterprise Profiles
echo $domain->source_js_v3();
// build the rest of the data needed to initialize Livefyre, render initialization JS
$site = $domain->site( $SITE_ID, $SITE_KEY);
$article = $site->article( $cms_content_id, $cms_permalink_url,
$cms_title, $cms_tags);
$conversation = $article->conversation();
echo $conversation->to_initjs_v3($COMMENTS_ELEMENT_ID, array('onload'=>'doLivefyreAuth', 'delegate'=>'authDelegate'));
note that the above assumes you have defined 2 JavaScript objects
doLivefyreAuth
(function) and authDelegate
(dictionary) - see
examples here:
LiveComments PHP Example
##Multiple Conversations on a Page
To get multiple conversations on a page, you need to add 1 or more configurations in an array to the load call depending on the conversations you want to point to.
<html>
<head>
<script>
var config1 = {"collectionMeta": <COLLECTION META 1>,
"checksum": <CHECKSUM 1>,
"siteId": <SITE ID>,
"articleId":"1",
"el":"livefyre1"};
var config2 = {"collectionMeta": <COLLECTION META 2>,
"checksum": <CHECKSUM 2>,
"siteId": <SITE ID>,
"articleId":"2",
"el":"livefyre2"};
var config3 = {"collectionMeta": <COLLECTION META 3>,
"checksum": <CHECKSUM 3>,
"siteId": <SITE ID>,
"articleId":"3",
"el":"livefyre3"};
var callback = function() {
document.getElementById('livefyre-status').innerHTML = 'LiveComments has loaded!';
}
fyre.conv.load(
{"network": "<YOUR NETWORK>"}, /* This example does not implement custom authentication delegates */
[config1, config2, config3],
callback
);
</script>
</head>
<body>
<div id="livefyre-status">LiveComments is not loaded.</div>
<div id="livefyre1"></div>
<div id="livefyre2"></div>
<div id="livefyre3"></div>
</body>
</html>
Note: if you're interested in including a Live Blog / Live Chat on the same page as our comment widget, you can use the above code for including multiple conversations on a page then switch particular conversations to a Live Blog (or Live Chat) via the Livefyre admin panel.