Tag : tableau de bord

Dashthis des dashboards analytics compréhensibles pour tout le monde

Dashthis est le nouveau projet de Stéphane Guerin qui est un entrepreneur canadien. Stéphane est parti du constat que l’utilisation de Google Analytics était pertinente pour les spécialistes du domaine et que cet outil n’était pas du tout adapté pour les marketeurs, les commerciaux, les ecommerçants…

D’où l’idée de développer Dashthis, un outil basé sur Google Analytics permettant de simplifier et de proposer de l’information adaptée et pertinente à la cible utilisateur mais aussi en fonction de la nature de l’information à analyser. Dashthis permet de générer des tableaux de bord pour les métiers et pour les vues suivantes :

-Small Business Owner
-CxO / Manager
-eMarketing
-Revenues and Costs
-Paid Search
-Mobile
-Social Media
-Lead Generation
-eCommerce
-Publisher / Content Manager
-Custom Dashboard

Notez qu’une marque blanche existe aussi pour les agences qui souhaiteraient proposer ce type d’outil à leurs clients. Par ailleurs, Dashthis sera prochainement aussi proposé en français.

Je trouve que l’outil est simple et fait son boulot, je pense comme Stéphane qu’il y a une vrai place pour des dashboards adaptés qui permettent de déterminer plus facilement un ROI. Pour accéder aux live demos c’est ici.


Utiliser les données de Google Analytics avec Google Docs pour faire un tableau de bord

Je ne sais pas vous mais google analytics peut avoir des limites dans la génération de certains tableaux de bord. Prenons par exemple un site donc le CA n’est pas identifié dans Google Analytics, ce dernier ne pourra pas avoir une vue simple et unique de son trafic et de son chiffre d’affaires.

Si vous utilisez Google Docs voici une solution testée et approuvée pour récupérer les données de votre profil analytics pour les manipuler dans Google Docs.

Premièrement il faut utiliser le template Google Docs de SEOMOZ qui va vous permettre de vous connecter à votre compte GA (Google Analytics). Pour utiliser ce dernier il faut faire « make a copy ». Ensuite vous avez deux possibilités, soit vous utilisez le template et vous construisez votre tableau de bord dedans soit vous avez déjà un tableau de bord et dans ce cas il va falloir ajouter le script de connection (Google Apps Script) : Tools/Script editor/ puis copié/coller de qui suit :

function getGAauthenticationToken(email, password) {

  //Fetches GA authentication token, which can then be used to fetch data with the getGAdata function
//Created by Mikael Thuneberg
    try {
      
        if (typeof email == "undefined") {
            return "Email address missing";
        }
        if (typeof password == "undefined") {
            return "Password missing";
        }
        if (email.length == 0) {
            return "Email address missing";
        }
        if (password.length == 0) {
            return "Password missing";
        }
        password = encodeURIComponent(password);
        var responseStr
        var randnumber = Math.random()*5000;

      Utilities.sleep(randnumber);
      Utilities.sleep(randnumber);

        var response = UrlFetchApp.fetch("https://www.google.com/accounts/ClientLogin", {
            method: "post",
            payload: "accountType=GOOGLE&Email=" + email + "&Passwd=" + password + "&service=analytics&Source=Mikael Thuneberg-GA Google Docs functions-1.0"
        });
        responseStr = response.getContentText();
        responseStr = responseStr.slice(responseStr.search("Auth=") + 5, responseStr.length);
        return responseStr;
    } catch (e) {
        if (e.message.indexOf("CaptchaRequired") != -1) {
            return "Complete CAPTCHA at http://www.google.com/accounts/" + e.message.slice(e.message.indexOf("CaptchaUrl=") + 11, e.message.length);
        } else {
            return "Authentication failed (" + e.message + ")";
        }
    }
}

function getGAaccountData(authToken, dataType, includeHeaders, maxRows, startFromRow) {
//Fetches account data for the authenticated user
//Input authentication token produced by the getGAauthenticationToken function
//If dataType parameter is omitted, the functions fetches a list profiles to which the user has access
//By specifying the dataType parameters as "goals", the functions will fetch a list of goals by profile
//By specifying the dataType parameters as "segments", the functions will fetch a list of advanced segments
//Created by Mikael Thuneberg
  if (typeof authToken == "undefined") {
        return "Authentication token missing";
    }
    dataType = (typeof dataType == "undefined") ? "profiles" : dataType;
    maxRows = (typeof maxRows == "undefined") ? 200 : maxRows;
    maxRows = (typeof maxRows == "string") ? 200 : maxRows;
    startFromRow = (typeof startFromRow == "undefined") ? 1 : startFromRow;
    startFromRow = (typeof startFromRow == "string") ? 1 : startFromRow;
    if (authToken.length == 0) {
        return "Authentication token missing";
    }
    if (dataType.length == 0) {
        dataType = "profiles";
    }
    if (authToken.indexOf("Authentication failed") != -1) {
        return "Authentication failed";
    }
    try {
        authToken = authToken.replace(/\n/g, "");
        dataType = dataType.toLowerCase();
        var URL = "https://www.google.com/analytics/feeds/accounts/default?max-results=" + maxRows + "&start-index=" + startFromRow
        var responseStr;
      
        var response = UrlFetchApp.fetch(URL, {
            method: "get",
            headers: {
                "Authorization": "GoogleLogin auth=" + authToken,
                "GData-Version": "2"
            }
        });
        responseStr = response.getContentText();
        var XMLdoc = Xml.parse(responseStr);
        var lapset2;
        var TempArray = [];
        var RowArray = [];
        var HeaderArray = [];
        if (includeHeaders == true) {
            var rivi = 1;
            if (dataType == "segments") {
                HeaderArray[0] = "Segment ID";
                HeaderArray[1] = "Segment Name";
                HeaderArray[2] = "Segment Definition";
            } else {
                HeaderArray[0] = "Account Name";
                HeaderArray[1] = "Profile Title";
                HeaderArray[2] = "Profile Number";
            }
            TempArray[0] = HeaderArray;
        } else {
            var rivi = 0;
        }
        var sar = 0;
        var lapset;
        var dataFound = false;
        if (dataType == "segments") {
            lapset = XMLdoc.getElement().getElements();
            for (i = 0; i < lapset.length; i++) {
                if (lapset[i].getName().getLocalName() == "segment") {
                    sar = 0;
                    RowArray[0] = lapset[i].getAttribute("id").getValue();
                    RowArray[1] = lapset[i].getAttribute("name").getValue();
                    lapset2 = lapset[i].getElements();
                    for (j = 0; j < lapset2.length; j++) {
                        if (lapset2[j].getName().getLocalName() == "definition") {
                            RowArray[2] = lapset2[j].getText();
                        }
                    }
                    TempArray[rivi] = RowArray;
                    RowArray = [];
                    dataFound = true;
                    rivi++;
                    if (rivi == maxRows) {
                        return TempArray;
                    }
                } else {
                    if (lapset[i].getName().getLocalName() == "entry") {
                        break;
                    }
                }
            }
        } else { // datatype = profiles 
            lapset = XMLdoc.getElement().getElements("entry");
            for (i = 0; i < lapset.length; i++) {
                sar = 0;
                lapset2 = lapset[i].getElements();
                for (j = 0; j < lapset2.length; j++) {
                    if (lapset2[j].getName().getLocalName() == "title") {
                        RowArray[1] = " " + lapset2[j].getText();
                        dataFound = true;
                    } else {
                        if (lapset2[j].getName().getLocalName() == "property") {
                            if (lapset2[j].getAttribute("name").getValue() == "ga:accountName") {
                                RowArray[0] = lapset2[j].getAttribute("value").getValue();
                            }
                            if (lapset2[j].getAttribute("name").getValue() == "ga:profileId") {
                                RowArray[2] = lapset2[j].getAttribute("value").getValue();
                                break;
                            }
                        }
                    }
                }
                TempArray[rivi] = RowArray;
                RowArray = [];
                dataFound = true;
                rivi++;
                if (rivi == maxRows) {
                    return TempArray;
                }
            }
        }
        if (dataFound == false) {
            //return "No data found";
        }
        return TempArray;
    } catch (e) {
        return "0";
    }
}

function getGAdata(authToken, profileNumber, metrics, startDate, endDate, filters, dimensions, segment, sort, includeHeaders, maxRows, startFromRow) {
//Fetches data from the GA profile specified, using the authentication token generated by the getGAauthenticationToken function
//For instructions on the parameters, see http://bit.ly/bUYMDs
//Created by Mikael Thuneberg
  try {
        startDate.getYear();
    } catch (e) {
        return "Invalid start date";
    }
    try {
        endDate.getYear();
    } catch (e) {
        return "Invalid end date";
    }
    try {
        if (typeof authToken == "undefined") {
            return "Authentication token missing";
        }
        if (typeof profileNumber == "undefined") {
            return "Profile number missing";
        }
        if (typeof metrics == "undefined") {
            return "Specify at least one metric";
        }
        if (profileNumber != parseInt(profileNumber)) {
            return "Invalid profile number";
        }
        filters = (typeof filters == "undefined") ? "" : filters;
        dimensions = (typeof dimensions == "undefined") ? "" : dimensions;
        segment = (typeof segment == "undefined") ? "" : segment;
        maxRows = (typeof maxRows == "undefined") ? 100 : maxRows;
        maxRows = (typeof maxRows == "string") ? 100 : maxRows;
        startFromRow = (typeof startFromRow == "undefined") ? 1 : startFromRow;
        startFromRow = (typeof startFromRow == "string") ? 1 : startFromRow;
        if (authToken.length == 0) {
            return "Authentication token missing";
        }
        if (profileNumber.length == 0) {
            return "Profile number missing";
        }
        if (metrics.length == 0) {
            return "Specify at least one metric";
        }
        if (authToken.indexOf("Authentication failed") != -1) {
            return "Authentication failed";
        }
        authToken = authToken.replace(/\n/g, "");
        var startDateString
        var endDateString
        var dMonth
        var dDay
        if (startDate.getMonth() + 1 < 10) {
            dMonth = "0" + (startDate.getMonth() + 1);
        } else {
            dMonth = startDate.getMonth() + 1;
        }
        if (startDate.getDate() < 10) {
            dDay = "0" + startDate.getDate();
        } else {
            dDay = startDate.getDate();
        }
        startDateString = startDate.getYear() + "-" + dMonth + "-" + dDay
        if (endDate.getMonth() + 1 < 10) {
            dMonth = "0" + (endDate.getMonth() + 1);
        } else {
            dMonth = endDate.getMonth() + 1;
        }
        if (endDate.getDate() < 10) {
            dDay = "0" + endDate.getDate();
        } else {
            dDay = endDate.getDate();
        }
        endDateString = endDate.getYear() + "-" + dMonth + "-" + dDay
        if (startDateString > endDateString) {
            return "Start date should be before end date";
        }
        var URL = "https://www.google.com/analytics/feeds/data?ids=ga:" + profileNumber + "&start-date=" + startDateString + "&end-date=" + endDateString + "&max-results=" + maxRows + "&start-index=" + startFromRow;
        if (metrics.slice(0, 3) != "ga:") {
            metrics = "ga:" + metrics;
        }
        metrics = metrics.replace(/&/g, "&ga:");
        metrics = metrics.replace(/ga:ga:/g, "ga:");
        metrics = metrics.replace(/&/g, "%2C");
        URL = URL + "&metrics=" + metrics
        if (dimensions.length > 0) {
            if (dimensions.slice(0, 3) != "ga:") {
                dimensions = "ga:" + dimensions;
            }
            dimensions = dimensions.replace(/&/g, "&ga:");
            dimensions = dimensions.replace(/ga:ga:/g, "ga:");
            dimensions = dimensions.replace(/&/g, "%2C");
            URL = URL + "&dimensions=" + dimensions;
        }
        if (filters.length > 0) {
            if (filters.slice(0, 3) != "ga:") {
                filters = "ga:" + filters;
            }
            filters = filters.replace(/,/g, ",ga:");
            filters = filters.replace(/;/g, ";ga:");
            filters = filters.replace(/ga:ga:/g, "ga:");
            filters = encodeURIComponent(filters);
            URL = URL + "&filters=" + filters;
        }
        if (typeof(segment) == "number") {
            segment = "gaid::" + segment;
        }
        if (segment.length > 0) {
            if (segment.indexOf("gaid::") == -1 && segment.indexOf("dynamic::") == -1) {
                if (segment.slice(0, 3) != "ga:") {
                    segment = "ga:" + segment;
                }
                segment = "dynamic::" + segment;
            }
            segment = encodeURIComponent(segment);
            URL = URL + "&segment=" + segment;
        }
        if (sort == true) {
            URL = URL + "&sort=-" + metrics;
        }
    }
    catch (e) {
        return "0";
    }
    try {
        var response = UrlFetchApp.fetch(URL, {
            method: "get",
            headers: {
                "Authorization": "GoogleLogin auth=" + authToken,
                "GData-Version": "2"
            }
        });
    } catch (e) {
        if (e.message.indexOf("Timeout") != -1) {
            response = UrlFetchApp.fetch(URL, {
                method: "get",
                headers: {
                    "Authorization": "GoogleLogin auth=" + authToken,
                    "GData-Version": "2"
                }
            });
        } else {
            return "0";
        }
    }
    try {
        var responseStr = response.getContentText();
        var XMLdoc = Xml.parse(responseStr);
        var lapset = XMLdoc.getElement().getElements("entry");
        var lapset2;
        var TempArray = [];
        var RowArray = [];
        var HeaderArray = [];
        if (includeHeaders == true) {
            var rivi = 1;
        } else {
            var rivi = 0;
        }
        var sar = 0;
        var dataFound = false;
        for (i = 0; i < lapset.length; i++) {
            sar = 0;
            lapset2 = lapset[i].getElements();
            for (j = 0; j < lapset2.length; j++) {
                if (lapset2[j].getName().getLocalName() == "dimension") {
                    RowArray[sar] = lapset2[j].getAttribute("value").getValue();
                    if (rivi == 1) {
                        HeaderArray[sar] = lapset2[j].getAttribute("name").getValue();
                    }
                    sar++;
                }
                if (lapset2[j].getName().getLocalName() == "metric") {
                    RowArray[sar] = Number(lapset2[j].getAttribute("value").getValue());
                    if (rivi == 1) {
                        HeaderArray[sar] = lapset2[j].getAttribute("name").getValue();
                    }
                    sar++;
                }
            }
            TempArray[rivi] = RowArray;
            RowArray = [];
            dataFound = true;
            rivi++;
        }
        if (dataFound == false) {
            //return "No data found";
        }
        if (includeHeaders == true) {
            TempArray[0] = HeaderArray;
        }
        return TempArray;
    } catch (e) {
        return "0";
    }

}

J’ai volontairement modifié les messages d’erreurs pour afficher des « 0 » afin de pouvoir tout de même faire des graphiques (même avec des erreurs de connection).

Pour vous connecter vous avez besoin de votre email de compte GA, de votre mot de passe (vous pouvez en faire un spécifique pour cet outil c’est un peu plus secure il me semble) et du profil GA pour lequel vous souhaitez avoir les données. Cet id de profil se trouve dans l’url de votre compte GA soit après « id » pour l’ancienne version de GA ou après le « p » pour la nouvelle interface.

Voilà donc pour la partie connection à GA et script à intégrer. Ensuite il faut copier/coller la page du template de SEOMOZ ou alors se faire sa propre page de récupération de données ce qui est finalement assez simple en utilisant les formules du template. De mon côté ce qui m’intéressait c’était d’avoir des données quotidiennes et non mensuelles, j’ai donc modifié la formule en conséquence.

Attention lors de la récupération des données si vous demandez beaucoup d’information GA va vous retourner des erreurs de connection (des « 0 » avec mon script modifié), il faut donc y aller doucement, je dirai que 30 données à chaque fois c’est un max. Il suffit de faire copié/collé sur 30 cellules.

Et voilà le travail (données issues d’un autre site que 2803.fr), on retrouve des données en provenance de GA et d’autres données comme le total sur ce graphique :

Plus d’information ici et .