0

SharePoint 2010 has beautiful feature site web analytics which shows pages visited , recent visitors, most visited and lot more information on web analytics page. Why SharePoint 2016 has taken it away. Every version upgrade on any tool should bring user preference and friendliness but why SharePoint is making such a drastic back steps? Is there any alternates they have provided for this or we just need to find alternate third party tools to suffice our needs. Too frustrating from user stand point.

2 Answers 2

0

I have spent a great deal of time trying to find out the same thing for my SharePoint 2013 installation. What I have concluded is that Microsoft is pushing people to Office 365 and SharePoint Online. The reporting tools there are incredible.

I've investigated the 3rd party options and only found a company called HarePoint. I believe 3rd party vendors feel it's too risky to develop reporting software at this point given Office 365 has it all.

The only alternative is to build reports yourself. You'll have to convince IT to turn on Audit Logs, export the data and create your own.

1
  • Saying that MS is making sure to use Office 365 forcibly by users, then what would be the point of putting on Premises then? It would be an absolute set back by MS.
    – SPLearner
    Jun 14, 2018 at 15:44
0

A great deal of the analytics have been moved to the search service, and can be accessed without third party tools. However, the user interface is lacking (arguably non-existent) and the API is not super well-documented at this time.

The search service data can be exposed through certain web parts, like the Content Search Web Part, or programmatically using JavaScript and the search API.

What's available

Certain properties available in the search service can tell us how many views a page/document had over a given time period.

  • ViewsLast1Days - How many times the document was viewed yesterday.
  • ViewsLast1DaysUniqueUsers - How many individuals viewed the document yesterday.
  • ViewsLast2Days - How many times the document was viewed two days ago (does not include numbers from following days)
  • ViewsLast2DaysUniqueUsers - How many individuals viewed the document two days ago.
  • ViewsLast3Days - How many times the document was viewed three days ago.
  • ViewsLast3DaysUniqueUsers - How many individuals viewed the document three days ago.
  • ViewsLast4Days - How many times the document was viewed four days ago.
  • ViewsLast4DaysUniqueUsers - How many individuals viewed the document four days ago.
  • ViewsLast5Days - How many times the document was viewed five days ago.
  • ViewsLast5DaysUniqueUsers - How many individuals viewed the document five days ago.
  • ViewsLast6Days - How many times the document was viewed six days ago.
  • ViewsLast6DaysUniqueUsers - How many individuals viewed the document six days ago.
  • ViewsRecent - How many times the document was viewed within the last 14 days.
  • ViewsRecentUniqueUsers - How many indivduals views the document within the last 14 days
  • ViewsLastMonths1 - How many times the document was viewed between the 1st day and the last day of the month last month.
  • ViewsLastMonths1Unique - How many individuals viewed the document between the 1st day and the last day of the month last month.
  • ViewsLastMonths2 - How many times the document was viewed between the 1st day and the last day of the month before last (two months ago).
  • ViewsLastMonths2Unique - How many individuals viewed the document between the 1st and last day of the month before last.
  • ViewsLastMonths3 - How many times the document was viewed between the 1st day and the last day of the month three months ago
  • ViewsLastMonths3Unique - How many individuals viewed the document between the 1st and last day of the month three months ago
  • ViewsLifetime - How many times the document has been viewed since the search service started tracking views.
  • ViewsLifetimeUniqueUsers - How many individuals viewed the document each month, cumulatively, since the search service started tracking views.

Exposing the data through the Content Search web part

The content search web part lets you specify a search query (which determines what items are displayed in the web part) and property mappings (which determine what data is displayed for each item).

Without custom development, you can configure it to show three properties at a time for every item returned by a search query.

Exploring the data through the Search Query API

The search query API is accessed through the following format: [site url]/_api/search/query?querytext=%27**[search query]%27&selectproperties=%27[properties to retrieve]%27&orderBy=[property to sort by]**&trimDuplicates=false&rowlimit=5000

You can navigate to such a URL directly if you want to see the data or experiment with different queries, but it's not very friendly.

Setting up an interface for the search query API using HTML/JavaScript

You can use a script editor web part to add HTML and JavaScript to a page that exposes the information from the search service in an easy-to-read format for your users. This would also work in a content editor web part if you save the code in a text or HTML file and upload it to a library, then use the content editor web part's "content link" property to embed the code on the page.

<style>
    #sideNavBox{display:none;}
    #contentBox{margin-left:0px; margin-right:0px;}
    #contentRow{padding-top:0px;}
    #AnalyticsOutput{
        display:table;
        width:100%;
        border-top:1px solid black;
    }
    .row{
        display:table-row;       
    }
    .row:nth-of-type(even){
        background-color:#efefef;
    }
    .cell{
        display:table-cell;
        text-align:center;
    }
    .cell.path{
        text-align:left;
    }
    .header{
        font-weight:bold;
        background-color:#dfdfdf;        
    }
    .header .cell{
        border-bottom: 1px solid black;
        text-align:center;
        border-left: 1px dotted black;
        cursor:pointer;
    }
    .header .cell:hover{
        background-color:white;
    }
    .boundaryLeft, .header .cell.boundaryLeft{
        border-left: 1px solid black;
    }
    #inputSearchQuery{
        width:500px;
    }
    fieldset{
        display:inline-block;
    }
    .showAverages .aboveaverage:after{
        content:" ↑";
        color:green;
    }
    .showAverages .belowaverage:after{
        color:darkred;        
        content:" ↓";
    }
    .dailyaverage{
        display:none;
    }
    .showAverages .dailyaverage{
        display:inline-block;
        font-size:0.9em;
        font-style:italic;
        color:gray;
        cursor:default;
    }
    .dailyaverage:hover{
        color:black;
    }
</style>
<div id="AnalyticsControls">
    <fieldset>
        <legend>Search Query</legend>
        <input id="inputSearchQuery" type="text" value="" />
        <input id="btnSearchQuery" type="button" value="Retrieve Data" />
        <input type="checkbox" id="chkShowAvg" name="chkShowAvg"/>
        <label for="chkShowAvg">Show Averages</label>
    </fieldset>
</div>
<div id="AnalyticsOutput"></div>
<script>
(function(){    
    var chkShowAvg = document.getElementById("chkShowAvg");
    chkShowAvg.onchange = function(){document.getElementById("AnalyticsOutput").className = chkShowAvg.checked ? "showAverages" : "" ;};
    var inputSearchQuery = document.getElementById("inputSearchQuery");
    inputSearchQuery.value = "Path:"+_spPageContextInfo.webAbsoluteUrl+"*";
    document.getElementById("btnSearchQuery").onclick = retrieveData;
    retrieveData();
    function retrieveData(){
        getSearchResults(
            inputSearchQuery.value,
            [
                "Path","ViewsLast1DaysUniqueUsers","ViewsLast2DaysUniqueUsers","ViewsLast3DaysUniqueUsers",
                "ViewsLast4DaysUniqueUsers","ViewsLast5DaysUniqueUsers","ViewsLast6DaysUniqueUsers","ViewsRecentUniqueUsers",
                "ViewsLastMonths1Unique","ViewsLastMonths2Unique","ViewsLastMonths3Unique","ViewsLifetimeUniqueUsers"
            ], 
            processResults, 
            function(message){alert(message);}
        );
    }

    function processResults(data){
        var results = data.query.PrimaryQueryResult.RelevantResults;
        var resultArray = [];
        if(results.RowCount > 0){
            var records = results.Table.Rows.results;
            for(var i = 0, len = records.length; i < len; i++){
                var row = records[i];
                var resultMap = {};
                for(var j = 0, jlen = row.Cells.results.length, cells = row.Cells.results; j < jlen; j++){
                    var cell = cells[j];
                    resultMap[cell.Key] =  (cell.Key.indexOf("Views")==0) ? +(cell.Value) : cell.Value;
                }
                resultArray.push(resultMap);
            }
            resultArray.sort(function(a,b){
                return a.ViewsRecentUniqueUsers > b.ViewsRecentUniqueUsers ? -1 : 1;
            });
            renderResults(resultArray);
        }else{
            document.getElementById("AnalyticsOutput").innerHTML = "no results found";
        }
    }

    function renderResults(results){
        var outputElement = document.getElementById("AnalyticsOutput");
        clearChildren(outputElement);
        var header = outputElement.appendChild(document.createElement("div"));
        header.className = "row header";
        var cell = header.appendChild(document.createElement("div")); cell.className = "cell path";
        cell.innerHTML = "Path"; cell.onclick = function(){ results.sort(function(a,b){ return a.Path < b.Path ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell boundaryLeft";
        cell.innerHTML = "Visitors<br/>yesterday"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsLast1DaysUniqueUsers > b.ViewsLast1DaysUniqueUsers ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell";
        cell.innerHTML = "Visitors two days ago"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsLast2DaysUniqueUsers > b.ViewsLast2DaysUniqueUsers ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell";
        cell.innerHTML = "Visitors three days ago"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsLast3DaysUniqueUsers > b.ViewsLast3DaysUniqueUsers ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell";
        cell.innerHTML = "Visitors four days ago"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsLast4DaysUniqueUsers > b.ViewsLast4DaysUniqueUsers ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell";
        cell.innerHTML = "Visitors five days ago"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsLast5DaysUniqueUsers > b.ViewsLast5DaysUniqueUsers ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell";
        cell.innerHTML = "Visitors six days ago"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsLast6DaysUniqueUsers > b.ViewsLast6DaysUniqueUsers ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell boundaryLeft";
        cell.innerHTML = "Visitors last 14 days"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsRecentUniqueUsers > b.ViewsRecentUniqueUsers ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell boundaryLeft";
        cell.innerHTML = "Visitors this month"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsLastMonths1Unique > b.ViewsLastMonths1Unique ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell";
        cell.innerHTML = "Visitors last month"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsLastMonths2Unique > b.ViewsLastMonths2Unique ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell";
        cell.innerHTML = "Visitors month before last"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsLastMonths3Unique > b.ViewsLastMonths3Unique ? -1 : 1;}); renderResults(results); };
        cell = header.appendChild(document.createElement("div")); cell.className = "cell boundaryLeft";
        cell.innerHTML = "Visitors Lifetime"; cell.onclick = function(){ results.sort(function(a,b){ return a.ViewsLifetimeUniqueUsers > b.ViewsLifetimeUniqueUsers ? -1 : 1;}); renderResults(results); };
        for(var i = 0, len = results.length; i < len; i++){
            row = results[i];
            var avg14day = row.ViewsRecentUniqueUsers / 14;
            outputElement.insertAdjacentHTML("beforeend",
                "<div class='row'>"+
                    "<div class='cell path'>"+row.Path+"</div>"+
                    "<div class='cell boundaryLeft "+ (row.ViewsLast1DaysUniqueUsers > avg14day ? "aboveaverage" : (row.ViewsLast1DaysUniqueUsers < avg14day ? "belowaverage" : "") ) + "'>"+row.ViewsLast1DaysUniqueUsers+"</div>"+
                    "<div class='cell "+ (row.ViewsLast2DaysUniqueUsers > avg14day ? "aboveaverage" : (row.ViewsLast2DaysUniqueUsers < avg14day ? "belowaverage" : "") ) + "'>"+row.ViewsLast2DaysUniqueUsers+"</div>"+
                    "<div class='cell "+ (row.ViewsLast3DaysUniqueUsers > avg14day ? "aboveaverage" : (row.ViewsLast3DaysUniqueUsers < avg14day ? "belowaverage" : "") ) + "'>"+row.ViewsLast3DaysUniqueUsers+"</div>"+
                    "<div class='cell "+ (row.ViewsLast4DaysUniqueUsers > avg14day ? "aboveaverage" : (row.ViewsLast4DaysUniqueUsers < avg14day ? "belowaverage" : "") ) + "'>"+row.ViewsLast4DaysUniqueUsers+"</div>"+
                    "<div class='cell "+ (row.ViewsLast5DaysUniqueUsers > avg14day ? "aboveaverage" : (row.ViewsLast5DaysUniqueUsers < avg14day ? "belowaverage" : "") ) + "'>"+row.ViewsLast5DaysUniqueUsers+"</div>"+
                    "<div class='cell "+ (row.ViewsLast6DaysUniqueUsers > avg14day ? "aboveaverage" : (row.ViewsLast6DaysUniqueUsers < avg14day ? "belowaverage" : "") ) + "'>"+row.ViewsLast6DaysUniqueUsers+"</div>"+
                    "<div class='cell boundaryLeft'>"+row.ViewsRecentUniqueUsers+" <span title='daily average' class='dailyaverage'>"+Math.floor(avg14day)+"</span></div>"+
                    "<div class='cell boundaryLeft'>"+row.ViewsLastMonths1Unique+" <span title='daily average' class='dailyaverage'>"+Math.floor(row.ViewsLastMonths1Unique / new Date().getDate())+"</span></div>"+
                    "<div class='cell'>"+row.ViewsLastMonths2Unique+" <span title='daily average' class='dailyaverage'>"+Math.floor(row.ViewsLastMonths2Unique / new Date(new Date().getFullYear(), new Date().getMonth(), 0).getDate())+"</span></div>"+
                    "<div class='cell'>"+row.ViewsLastMonths3Unique+" <span title='daily average' class='dailyaverage'>"+Math.floor(row.ViewsLastMonths3Unique / new Date(new Date().getFullYear(), new Date().getMonth(), 0).getDate())+"</span></div>"+
                    "<div class='cell boundaryLeft'>"+row.ViewsLifetimeUniqueUsers+"</div>"+
                "</div>"
            );
        }
    }

    function getSearchResults(queryText,fields, onSuccess, onFailure, orderBy){
        orderBy = typeof orderBy == "undefined" ? "ViewsRecent" : orderBy;
        var webUrl = _spPageContextInfo.webAbsoluteUrl;
        var xhr = new XMLHttpRequest();
        var verb = "GET";
        var url = (webUrl[webUrl.length - 1] == "/" ? webUrl.substring(0, webUrl.length - 1) : webUrl) +
            "/_api/search/query?querytext=%27"+queryText+"%27&selectproperties=%27"+fields.join(",")+"%27&orderBy="+orderBy+
            "&trimDuplicates=false&rowlimit=5000";

        xhr.open(verb, url, true);
        xhr.setRequestHeader("Content-Type", "application/json; odata=verbose");
        xhr.setRequestHeader("Accept", "application/json; odata=verbose");
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                    var resultObject = JSON.parse(xhr.responseText);
                    onSuccess(resultObject.d);
                } else {
                    onFailure(xhr.status + ":\n " + xhr.responseText);
                }
            }
        };
        xhr.send();
    }
    function clearChildren(element) {
        for (var i = element.childNodes.length - 1; i >= 0; i--) {
            element.removeChild(element.childNodes[i]);
        }
    }
})();
</script>

Screenshot of HTML interface for search-based analytics

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.