[app script] Synchroniser les notes de reMarkable sur Google Drive via un alias Gmail

Voici un script inspiré de celui fait Google app script.org : Fetch Gmail Attachment to Google Drive using Google Apps Script. Je l’ai modifié pour qu’il corresponde aux besoins des utilisateurs de reMarkable.


Ce script permet de récupérer les pièces jointes envoyées vers un alias Gmail et les stocker sur Google Drive


Il utilise les APIs de Gmail & Google Drive. Je n’aurai pas la main sur vos comptes car le script est à installer vous-même sur votre espace personnel sur script.google.com. C’est un manière semi-automatique de synchroniser les notes car c’est à vous d’envoyer régulièrement vos notes vers votre alias Gmail. Ensuite, le script s’occupe de les mettre sur Google Drive à intervalle régulière.

1- Créez un nouveau project sur script.google.com

2- Dans l’Editor, copiez/collez mon script

from this
to this

3- Il y a certaines choses à customiser avant de lancer le script.

Ligne 9. Votre alias Gmail. Créez un alias Gmail pour envoyer uniquement vos notes remarkable sur cette adresse. Cela permet au script de lire uniquement les messages envoyés à cette adresse, au lieu d’analyser toute votre boîte email. L’exécution se fera plus rapidement ainsi. Apprenez à créer un alias Gmail ici. Votre alias aura une forme similaire à : janedoe+rmk@gmail.com (après le +, vous mettez ce que vous voulez)

var yourMail = 'YOUR_GMAIL_ALIAS_HERE';

Vous pouvez modifier le type de fichiers que vous voulez synchroniser sur Google Drive. Par défaut, cela inclut tous les formats disponibles sur reMarkable, à savoir PDF, SVG, et PNG. Ligne 12.

var fileTypesToExtract = ['pdf', 'svg', 'png'];

Ligne 14. Nom du dossier Google Drive où vous trouverez le fichier. Ne vous inquiétez pas, si ce dossier n’existe pas encore, le script va le créer automatiquement pour vous.

var folderName = 'reMarkabletoDrive';

Ligne 16. Nom du libellé qui sera appliqué sur les messages traités par le script. Ne vous inquiétez pas, si le libellé n’existe pas encore, le script va le créer automatiquement pour vous.

var labelName = 'fetchedToDrive';

4- Renommez votre script. Save puis Debug.

5- Donnez les autorisations nécessaires pour l’accès à Gmail et Google Drive.

cliquez sur « advanced »

continuez

Allow

6- Sur le menu à gauche, cliquez sur « Triggers »

Pour que le script fonctionne bien et synchronise régulièrement le contenu de votre Gmail et Google Drive, il faut le lancer toutes les 15 minutes. Choisissez aussi de recevoir une alerte si quelque chose ne marche pas.

7- Si vous êtes impatient de voir le script à l’oeuvre, après avoir configuré tout ça, revenez dans l’éditeur et cliquez sur « run »

/*
 * This script is based on Apps Script Development's script : http://www.googleappsscript.org/home/fetch-gmail-attachment-to-google-drive-using-google-apps-script
 * It has been edited by nomadbento.com to match reMarkable users' needs
 */

// GLOBALS
//Enter your customized reMarkable alias gmail 
/*****************COMPULSORY********************/
var yourMail = 'YOUR_GMAIL_ALIAS_HERE';
/*****************THANK YOU********************/
//Array of file extension which you would like to extract to Drive
var fileTypesToExtract = ['pdf', 'svg', 'jpg'];
//Name of the folder in google drive in which files will be put
var folderName = 'reMarkabletoDrive';
//Name of the label which will be applied after processing the mail message
var labelName = 'fetchedToDrive';


function GmailToDrive(){
  //build query to search emails
  var query = '';
  //filename:pdf OR filename:svg OR filename:jpg 
  for(var i in fileTypesToExtract){
 query += (query === '' ?('filename:'+fileTypesToExtract[i]) : (' OR filename:'+fileTypesToExtract[i]));
  }
  query = 'in:inbox has:attachment to:'+yourMail+' '+ query;
  var threads = GmailApp.search(query);
  var label = getGmailLabel_(labelName);
  var parentFolder;
  if(threads.length > 0){
    parentFolder = getFolder_(folderName);
  }
  var root = DriveApp.getRootFolder();
  for(var i in threads){
    var mesgs = threads[i].getMessages();
    var threadlabels = threads[i].getLabels();
    if (checkIfContainsLabel(threadlabels)=="ok"){
      for(var j in mesgs){
          // get the names of the labels attached to the message
          var recipient = mesgs[j].getTo();
          //check email address
          if (checkRecipient(recipient)=="ok"){
              //get attachments
              var attachments = mesgs[j].getAttachments();
            for(var k in attachments){
              var attachment = attachments[k];
              //check attachements extension
              var isDefinedType = checkIfDefinedType_(attachment);
              if(isDefinedType){
                var attachmentBlob = attachment.copyBlob();
                    var file = DriveApp.createFile(attachmentBlob);
                    parentFolder.addFile(file);
                    root.removeFile(file);
              }
            }
          }  
      }
      threads[i].addLabel(label);
    }
 
  }
}

//This function will get the parent folder in Google drive
function getFolder_(folderName){
  var folder;
  var fi = DriveApp.getFoldersByName(folderName);
  if(fi.hasNext()){
    folder = fi.next();
  }
  else{
    folder = DriveApp.createFolder(folderName);
  }
  return folder;
}


function getGmailLabel_(name){
  var label = GmailApp.getUserLabelByName(name);
  if(!label){
 label = GmailApp.createLabel(name);
  }
  return label;
}

//this function will check for filextension type.
// and return boolean
function checkIfDefinedType_(attachment){
  var fileName = attachment.getName();
  var temp = fileName.split('.');
  var fileExtension = temp[temp.length-1].toLowerCase();
  if(fileTypesToExtract.indexOf(fileExtension) !== -1) return true;
  else return false;
}


function checkIfContainsLabel(allLabels){
  var check = "ok"; 
  for (var index = 0; index < allLabels.length; index++) {  
    var messageLabel = allLabels[index].getName();
    var temp = messageLabel.split('/');
    for (var l = 0; l < temp.length; l++){
      var nameLabel = temp[l];
      if (nameLabel.indexOf(labelName) == 0) {
        check = "nok";
      }
    }
  }
  return check;

}


function checkRecipient(allRecipients){
    var check = "nok";
    var temp = allRecipients.split(',');
    for (var m = 0; m < temp.length; m++){
      var emailRecipient = temp[m].toLowerCase();
      if (emailRecipient.indexOf(yourMail.toLowerCase()) != -1){
        check = "ok";
      }
    }

  return check;  
}

[ADWORDS] Script Adwords pour ajouter en masse des listes de mots-clés négatifs

Bonjour,
Voici un petit script pour ajouter en masse des listes de mots-clés négatifs.
Préparez sur Google Sheets un fichier ayant une tête suivante :
script_list_mots_clés_négatifs
La colonne 3 doit absolument avoir comme valeurs : EXACT, PHRASE ou BROAD (écrit en majuscule sinon tout sera mis par défaut en PHRASE).

A savoir avant de mettre en place ce script :

  1. C’est un script à mettre au niveau MCC, mais les listes de mots-clés négatifs se trouveront au niveau des comptes (c’est comme ça, Google ne permet pas encore de le faire au niveau MCC, avec des scripts en tout cas)
  2. Il faut mettre à jour le paramètre ID_DES_COMPTES_ICI_SEPARES_PAR_UNE_VIRGULE
  3. Si vous mettez plusieurs ID de comptes ici, les listes seront déployées sur l’ensemble de ces comptes
  4. Il faut mettre à jour le paramètre ID_DU_SPREADSHEET_ICI (exemple 1sjlkou9879JJKJIxxx), c’est l’ID du fichier Google Sheet que vous venez de créer
  5. Google limite à 20 le nombre de listes de mots-clés négatifs/compte et 5000 mots-clés négatifs/liste, à prendre donc en compte quand vous créez votre liste

Ensuite, quand ces listes seront créées, soit il faut écrire un autre script pour les appliquer aux campagnes que vous souhaitez, soit vous le faites à la main.

Si vous avez des questions, n’hésitez pas !

//le prob avec ce script c'est qu'on ne peut pas avoir plus de 20 listes partagées
//et pas plus de 2000 kw par liste
 
 
function main() {
 // Get an account iterator.
  var accountIterator = MccApp.accounts().withIds(['ID_DES_COMPTES_ICI_SEPARES_PAR_UNE_VIRGULE']).get();
  while (accountIterator.hasNext()) {
   // Get the current account.
   var account = accountIterator.next();
 
   // Select the child account.
   MccApp.select(account);
 
 
 
   // Run reports against child account.
   addsharednegativekeywords();
 
 
  }
}
 
function addsharednegativekeywords(){
 
  //get sheets
  var sheet = getSpreadsheet('ID_DU_SPREADSHEET_ICI').getActiveSheet();
  var data = sheet.getDataRange().getValues();
 
  var allneglist = [];
  var allnameneglist = [];
 
  for (var i=1;i<data.length;i++){
    var nameneglist = data[i][0];
    var negkw = data[i][1];
    var matchtype = data[i][2];
    negkw = transformnegkw(negkw, matchtype);
 
 
 
    if (!allneglist[nameneglist]){ 
      allneglist[nameneglist] = [];
      allnameneglist.push(nameneglist);
      allneglist[nameneglist].push(negkw);
 
    } else {
 
      allneglist[nameneglist].push(negkw);
    }
 
 
  }
 
 
  //build negative keywords
 
  for (var index = 0;index<allnameneglist.length;index++){
 
    var nom = allnameneglist[index];
    //Logger.log(nom);
    var tableaunegkw = allneglist[nom];
    //Logger.log(tableaunegkw);
 
    addnegkw(nom, tableaunegkw);
 
  }
 
}
 
 
function addnegkw(nameneglist, arraynegkw){
 
  var arraynegativeKeywordList = [];
 
  //get all negativekeywordlists
  var negativeKeywordListSelector = AdWordsApp.negativeKeywordLists().get();
 
  while (negativeKeywordListSelector.hasNext()) {
    var negativeKeywordList = negativeKeywordListSelector.next();
 
    arraynegativeKeywordList[negativeKeywordList.getName()]= negativeKeywordList.getId();
  }
 
 
  //if this list doesn't exist yet
  if (!arraynegativeKeywordList[nameneglist]){
 
    //create new list
 
    var negativeKeywordListOperation =
        AdWordsApp.newNegativeKeywordListBuilder()
    .withName(nameneglist)
    .build();
    var newnegativeKeywordList = negativeKeywordListOperation.getResult();
 
    if (!newnegativeKeywordList){
      Logger.log("problème de création")
    } else {
 
    newnegativeKeywordList.addNegativeKeywords(arraynegkw);
 
 
    }
 
  } else {
 
    //if it exists
 
    var mynegativeKeywordList = AdWordsApp.negativeKeywordLists().withCondition("Name = '"+nameneglist+"'").get();
    if (mynegativeKeywordList.hasNext()){
      var mynegativeKeywordList2 = mynegativeKeywordList.next();
      mynegativeKeywordList2.addNegativeKeywords(arraynegkw);
    }
 
  }
 
 
}
 
 
function transformnegkw(kw, matchtype){
 
  switch(matchtype) {
      case 'PHRASE':
          kw = '\"'+kw+'\"';
          break;
      case 'EXACT':
          kw = '['+kw+']';
          break;
      case 'BROAD':
          kw = kw;
          break;
      default:
          kw = '\"'+kw+'\"';
  }
 
  return(kw);
 
}
 
 
 
 
function getSpreadsheet(spreadsheetUrl) {
  return SpreadsheetApp.openById(spreadsheetUrl);
}

[Adwords] Petit script pour suivre les dépenses & trafic

A part les outils automatisés, j’ai une autre passion : faire des bijoux en argent. J’ai suivi un super stage de bijoux de 5 jours à Paris chez Thierry Grave en 2016 et ça s’est tellement bien passé qu’on est devenus amis. Je lui ai proposé de créer pour lui une petite campagne Adwords.

Un an plus tard, je suis repassée le voir dans son atelier près des Abbesses et il m’a appris que celle-ci était un vrai succès.

Si vous aussi, vous avez envie de vous lancer pour aider un ami, n’hésitez plus ! On peut lancer très rapidement une campagne, la suivre sans trop d’effort, et dépenser au minimum.

TUTO : Comment créer une campagne Adwords pour un ami avec seulement 25€

Etape 1 : Demander un coupon Adwords

Il faut créer un nouveau compte (j’en crée un directement à partir de mon MCC) et demander :

J’ai donc choisi l’offre 75€ offerts pour 25€ dépensés (25€HT soit à partir 31€ TTC environ).

Ainsi, Thierry a pu bénéficier de 100€ de budget publicitaire.

Etape 2 : Créer une campagne

Mots-clés : Keyword Planner est mon ami.

La création des annonces a pris plus de temps car je voulais absolument que Thierry checke les annonces. Et pour quelqu’un qui n’a jamais fait d’Adwords, les notions d’annonces pertinentes façon Google Adwords, nombre de caractères max. sont un peu difficiles à comprendre.

J’ai utilisé énormément de balise KeyWord dans le premier titre de l’annonce.

Pour les extensions, je me suis amusée à lui ajouter tout ce que je pouvais : extension SMS, extension d’appel, extensions de prix, call-out extensions, sitelinks.

Etape 3 : Optimiser & suivre les campagnes de loin

Pour passer un minimum de temps sur ces campagnes, j’ai utilisé énormément les fonctionnalités dispos dans « Bibliothèque partagée » : le budget partagé, stratégie d’enchères « Optimiser les clics » et la rotation des annonces « optimiser pour les clics ».

Dans la bibliothèque partagée :

  • j’ai déjà une liste de KW négatifs standard au niveau MCC (insultes, autres sites e-commerce, emploi, recrutement etc.)
  • J’exporte la liste des KW exacts éligibles pour les appliquer en négatif aux campagnes Broad (au fait, il faut que je fasse un script pour ça, bonne idée !)

Pour garder quand même un œil sur les dépenses et la perf, je mets en place un script qui envoie tous les jours un mail à Thierry (ça lui fait plaisir) et moi :

  • Le nombre de clics & les dépenses de la veille (YESTERDAY)
  • Le nombre de clics & les dépenses depuis la création du compte (ALL_TIME). Vous pouvez aussi remplacer par (THIS_MONTH) si vous souhaitez suivre les dépenses du mois en cours

Le script est mis en place au niveau du compte MCC. Pensez à modifier les valeurs de « ID_DU_COMPTE » et « VOTRE_EMAIL_ICI ».

P/s : vous recevrez autant de mails que de comptes. Pour tout regrouper dans un seul mail, adaptez mon script de suivi budgétaire complet dispo ici.

Voilà, c’est cadeau !

function main() {
 // Get an account iterator.
 var accountIterator = AdsManagerApp.accounts().withIds(['ID_DU_COMPTE']).get();
 while (accountIterator.hasNext()) {
   // Get the current account.
   var account = accountIterator.next();
 
   // Select the child account.
   MccApp.select(account);
 
   costreporting();
 
 }
}
 
function costreporting() {
  var cost = 0;
  var click = 0;
  var costAllTime = 0;
  var clickAllTime = 0;
 
 
  // Get a campaign iterator
  var campaignIterator = AdsApp.campaigns()
      .get();
 
  while (campaignIterator.hasNext()) {
    var campaign = campaignIterator.next();
    cost += campaign.getStatsFor('YESTERDAY').getCost();
    costAllTime += campaign.getStatsFor('ALL_TIME').getCost();
    click += campaign.getStatsFor('YESTERDAY').getClicks();
    clickAllTime += campaign.getStatsFor('ALL_TIME').getClicks();
  }
 
  /*
  Logger.log(cost);
  Logger.log(costAllTime);
  Logger.log(click);
  Logger.log(clickAllTime);
  */
 
  if (click>0){
    MailApp.sendEmail('VOTRE_EMAIL_ICI',
                    'Dépenses Campagnes Google Compte xxx',
                    'Bonjour, Hier les campagnes ont dépensé '+cost+'€ et généré '+click+' clics. '+
                      ' Depuis le lancement des campagnes, nous avons dépensé '+costAllTime+'€ et généré '+clickAllTime+' clics');
  }
 
}

Comment devenir une agence Google Partner

Première étape : Inscrire votre agence

  1. Créez un compte MCC (obligatoirement) utilisant une adresse email type xxx@votrenomdedomaine.fr Il est très important d’utiliser une adresse email de ce type au lieu de @gmail.com pour prouver que vous travaillez effectivement pour cette entreprise
  2. Donnez à l’adresse xxx@votrenomdedomaine.fr en question les droits « owner » sur Google Search Console.
  3. Inscrivez-vous en tant que Partner sur https://www.google.ch/partners/
  4. Cliquez sur « Associer maintenant »
  5. Entrez le nom de votre entreprise dans le champ « Affiliation Entreprise » puis « Ajouter une entreprise »
  6. Remplissez le formulaire
  7. Remplissez le profil de l’entreprise sur Google Partners

Deuxième étape : Obtenir le badge

  1. Passez les certifications Google Adwords (2 examens réussis minimum) ou associez au moins un profil personnel certifié Adwords à votre entreprise
  2. Associez tous les comptes Adwords que vous gérez à ce compte MCC xxx@votrenomdedomaine.fr ASAP
  3. Attendez 3 mois. Au cours de ces 3 mois, si vous :
    1. comptabilisez au moins 60 jours d’activités financières au cours des 90 derniers jours ;
    2. avez dépensé au moins 10 000 USD (ou l’équivalent dans la devise locale) de dépenses publicitaires au total au cours des 90 derniers jours calendaires.
  4. Et que vous remplissez les critères diverses liés à la qualité de gestion de vos campagnes ainsi que l’augmentation des dépenses/nouveaux clients

…. vous êtes susceptible d’obtenir le badge

 

Plus d’infos sur le site Google Partners : https://www.google.ch/partners/#p_content;idtf=5807b069a2aded886ef34340236fe418;lang=fr

[AdWords] Balise Keyword Google, comment ça marche ?

En fouillant sur mon Analytics, je m’aperçois qu’il y a pas mal de recherches sur les balises keyword alors que j’en ai parlé qu’une seule fois, furtivement, sur mon blog. Vous vous en doutez, mon métier consiste aussi à analyser les requêtes. Alors je me suis dépêchée de répondre à vos questions, posées par l’intermédiaire de vos requêtes.

Il y a une sorte de mythe autour des balises keyword, qui fait très peur aux clients. Raison : ils ont un jour aperçu des annonces avec des fautes d’orthographe et ont peur que leurs annonces utilisant des balises Keyword s’affichent mal et que ça fasse « pas pro ». Il y a une explication à ça et il est tout à fait possible d’éviter des annonces « pas pro » en faisant attention.

Comment ça marche

Imaginez que vous créez un groupe d’annonces pour une association qui propose des adoptions de chats/chatons. Pour cela, vous créez un groupe contenant les mots-clés suivants :

« adoption chat »
« adoption chats »
« adoption chaton »
« adoption chatons »

Vous voulez des titres qui collent le plus aux requêtes. Au lieu de créer 4 annonces avec 4 titres différents : « Journée adoption chat », « Journée adoption chats », « Journée adoption chaton », « Journée adoption chatons », il suffit d’utiliser la balise keyword

Titre : Journée {KeyWord:Adoption Chats}

AdWords tentera de remplacer ce code par l’un des mots clés de votre groupe d’annonces (« adoption chat », « adoption chats »). Toutefois, lorsque ce n’est pas possible (si cela fait dépasser le nombre de caractères), la partie après KeyWord sera affichée (Adoption Chats).

Vous l’avez bien lu, ce code est remplacé par l’un des mots-clés achetés (celui qui fait afficher votre annonce) et NON la requête tapée par l’internaute. Encore heureux, imaginez, si quelqu’un tape « adoption chat arnaque », vous n’avez pas envie que votre titre affiche fièrement « Journée Adoption Chat Arnaque » !! Si vous achetez en BMM: +adoption +chat, le titre affichera « Journée Adoption Chat » (sans les +).

Question : Mais alors pourquoi quand je tape une requête avec des fautes d’orthographe, l’annonce comporte aussi des fautes d’orthographe ?

Réponse : Parce que l’advertiser a probablement acheté des misspellings (mots-clés avec fautes d’orthographe).

Question : Pourquoi je vois des annonces avec {keyword : blablabla} écrites en dur ?

Réponse : La faute vient du fait qu’il y ait un espace entre keyword et les :
Attention on écrit {KeyWord:blablabla} (sans espace)

Les majuscules

Ensuite, il y a d’autres subtilités quant à l’utilisation des majuscules au sein de la balise keyword

  • Pour mettre votre mot clé en minuscules, utilisez keyword : le titre affichera « adoption chat »
  • Pour mettre une majuscule au début de l’expression, utilisez Keyword : le titre affichera « Adoption chat »
  • Pour mettre une majuscule à la première lettre de chaque mot (et c’est la solution que je préfère), utilisez KeyWord pour « Adoption Chat »

Autres utilisations déconseillées :

  • Pour mettre une majuscule aux premières lettres, puis à la première lettre de chaque mot, utilisez KEYWord (déconseillé) « ADOPTION Chat ».
  • Pour mettre une majuscule à la première lettre de chaque mot, puis à toutes les lettres, utilisez KeyWORD (déconseillé) « Adoption CHAT » (aïe ça fait mal aux yeux)

Pour aller plus loin

Et enfin, la compatibilité de l’insertion de mots-clés avec d’autres éléments de l’annonce, que les gens ne connaissent pas toujours :

  • (je précise au cas où) Elle est aussi compatible avec les lignes descriptives de l’annonce
  • Elle est compatible avec les URL d’affichage : oui oui ! mydomain.com/{KeyWord:Journee-Adoption} est tout à fait acceptable comme URL d’affichage
  • Elle est compatible avec les URLs finales : eh oui ! http://www.domain.com/adoption.php?kw={keyword} est tout à fait envisageable. Il faudra cependant avoir une petite discussion avec le web developer pour que ce type d’URL soit fonctionnel

Conclusion

Pour ne plus avoir peur de la balise keyword :

  • Ne pas utiliser la balise keyword pour les groupes d’annonces contenant des mots-clés mal orthographiés
  • Utiliser la balise keyword dans les adgroups contenant des mots-clés achetés en Exact, BMM (broad match modified), ou Expression mais pas en large
  • S’assurer que la landing page utilisant la balise {keyword} soit fonctionnelle & adaptée. Pour cela, lisez cet article
  • Bien utiliser les majuscules
  • {KeyWord:xxx} sans espace entre KeyWord et : SVP !
  • Si vous achetez les noms de vos concurrents, oubliez la balise keyword

 

[AdWords] Les enchères automatiques Google, ça marche vraiment !

Les nouvelles « it-features » des Account Managers Google, tout le monde en a entendu parler : ce sont des enchères autos au CPA/ROAS et les conversions cross-device. Le problème c’est qu’ils ont essayé de nous vendre tellement de fonctionnalités qui ne sont pas forcément quali qu’on se demande tous : est-ce que ça marche vraiment ou … ???

enchesautomatiquesgoogle

Pour avoir mis en place des enchères automatiques – eCPC (ou optimiseur CPC), enchères au CPA/ROAS – pendant très très longtemps sur des comptes à la perf, je peux vous affirmer que les enchères automatiques Google marchent VRAIMENT.

Pourquoi il faut faire confiance aux enchères automatiques de Google ?

S’il faut vous donner juste un argument pour défendre les enchères auto de Google, je donnerai le suivant : les enchères sont automatiquement déterminées selon prédiction de performances pour chaque requête => real-time donc. Personne d’autre (outils SEA, machine learning) ne peut proposer la même fonctionnalité, à moins d’avoir une structure 100% achetée en exact, des ajustements d’enchères par minute/seconde et par coordonnées GPS… (et même!)

A part la requête, d’autres facteurs sont également pris en compte : géo, heure de la durée, jour de la semaine, device, audiences… d’autant de bid ajustments qu’on ne peut pas croiser.

Par exemple, grâce aux analyses, je sais que les internautes à Bordeaux convertissent bien. Les mobinautes convertissent bien aussi. Je vais donc faire un bid adjustment pour Bordeaux & pour mobile. Mais si l’algorithme détermine que la combinaison des deux : mobinaute à Bordeaux, ne convertit pas bien; il saura réduire l’enchère automatiquement sur les mobinautes à Bordeaux. Chose que, techniquement, je ne pourrai pas faire moi-même, sauf si je crée une campagne à part ciblant uniquement Bordeaux – pour compliquer davantage ma vie.

S’ajoutent à ça d’autres arguments d’ordre « time efficiency » : les enchères auto vous permettent de profiter gratuitement des algorithmes de machine learning de Google, développés et testés par les statisticiens, mathématiciens au Bac+20 qui bossent pour Google; soit des heures et des heures économisées sur votre temps car vous n’aurez plus à créer vous-même votre algorithme 🙂

Mais alors, à quoi je sers maintenant ?

Les enchères auto vont encore mieux fonctionner si vous faites aussi du « human learning ». Analysez les termes de recherche : Sur quelles requêtes le système vous fait afficher ? les avez-vous ajoutés en exact ? sur quelle position il affiche vos annonces ? est-ce les CPC horaires, géo, démo, RLSA… correspondent aux ajustements que vous avez mis en place ? Combinez le budget partagé avec les enchères autos au CPA, comment il répartit votre budget vs. votre répartition ? Comparez le délai de conversions vs. avant. Les enchères auto permettent désormais d’optimiser aussi les conversions cross-device. Est-ce que cela permet un uplift de conversions sur votre site (toutes sources de trafic confondues) ? Challengez le système : variez les CPA cibles, les limites de CPC, le ROAS cible.

Et si tout ça est fait et vous vous ennuyez à mort, auditez vos propres comptes, vous trouverez toujours plein de cadavres.

[Adwords] Upgraded URL : Comment migrer manuellement via Adwords, Editor ou Marin Software

Plusieurs raisons peuvent vous pousser à migrer manuellement vos URLs. Ce n’est pas très fun, surtout si vous avez un redirect dans vos URLs, mais sachez que c’est possible.

Migration manuelle, avec Adwords

Pour cela, on utilise la méthode d’Opérations groupées d’Adwords.
Dans le menu déroulant Modifier de n’importe entité (Campagnes, Groupes, Mots-clés, Annonces), sélectionnez Télécharger une feuille de calcul et cochez les cases « ID » et « toutes les colonnes modifiables ».

Remplissez soigneusement les colonnes URL finale, Modèle de suivi si besoin, ainsi que les Paramètres de suivi.
Uploadez via Opérations groupées ou via le menu déroulant Modifier, en sélectionnant Importer la feuille de calcul.

Migration manuelle, avec Editor

Cette méthode n’est pas conseillée car elle ne permet pas de faire des bulks « massifs » en mode copier/coller.
Il faut sélectionner toutes les lignes qu’on veut modifier, supprimer les URLs de destinations & remplacer par les URLs finales. Bref, autant de tri que d’URLs finales uniques.

Mais si vous n’avez que quelques URLs finales uniques, téléchargez la nouvelle version d’Adwords Editor et suivez la méthode indiquée ici (partie « Utilisation d’Adwords Editor ») ou la méthode exposée ici (équivalent d’un Ctrl+H)

Migration manuelle, avec Marin Software

Les modèles de suivi sont proposés par Marin depuis mi-mai. Si pour une raison quelconque, vous souhaitez migrer certains éléments à la main, c’est possible.
Les modèles de suivi conseillés par Marin sont disponibles sur le Migration Portal
https://migration.marinsoftware.com
Cliquez sur Migration Details et vous aurez toutes les informations sur les modèles de suivi & paramètres personnalisés.

DSA : Landing Page : {lpurl}, et Custom parameters : {_mkwid}=INSERER_ICI_LA_VALEUR_UNIQUE_ID_DE_LANNONCE (attention 0 espace s’il vous plaît). Les colonnes unique id, campaign, group sont indispensables pour faire ces modifications, sans créer de nouvelles annonces.
Pour récupérer les unique id, il faut juste sortir la liste des annonces DSA. La colonne unique id est la première colonne du rapport.
Si cela ne marche pas, il vous reste Adwords, mais dans ce cas, il faut copier/coller la valeur des unique id Marin Software à la main.

PLA : Idem, on récupère les unique id des Product types. Si le modèle de suivi est déjà renseigné au niveau campagne, il suffit juste de renseigner la colonne Custom Parameters : {_mkwid}=INSERER_ICI_LA_VALEUR_UNIQUE_ID_DES_PRODUCT_TYPES. Bien évidemment, les colonnes unique id, campaign, group sont nécessaires pour effectuer les modifications.

Sitelinks : La migration sera gérée par Marin Software mais si besoin, une autre méthode est indiquée ici (partie : Comment mettre à jour les URL qui utilisent le paramètre ValueTrack {copy} ?). L’idée est de remplacer le ValueTrack {copy} dans les sitelinks actuels par {_mkwid} et le ValueTrack {creative}, ce qui nécessite une modification du modèle de suivi pour les sitelinks et l’ajout du paramètre {_mkwid}=[uniq_id] pour tous les mots-clés.

Annonces : Colonnes indispensables pour une migration réussie : Unique ID; Campaign; Group; Landing Page (Page de destination en français); Custom Parameters
On renseigne les custom parameters proposés par Marin. Par exemple, si au niveau annonces, j’ai {_mkwid}=[uniq_id], je dois juste copier/coller {_mkwid}=[uniq_id] dans la colonne Custom Parameters. Tout ce qui est entre [], en l’occurence la valeur de uniq_id sera dynamiquement générée par Marin Software.

Mots-clés : Colonnes indispensables pour une migration réussie : Keyword; Match type; Campaign; Group; Landing Page (Page de destination en français); Custom Parameters
Comme pour les annonces, on copie/colle les custom parameters proposés par Marin dans la colonne Custom Parameters. Pour la plupart des comptes, c’est juste {_mkwid}=[uniq_id]

Note : Si les custom parameters contiennent des valeurs des dimensions, exemple {_typecampagnes}=[typecampagnes]
typecampagnes est une dimension Marin. Asssurez-vous que cette dimension est remplie pour tous les éléments concernés (campagnes, groupes, mots-clés, annonces), sinon votre paramètre personnalisé {_typecampagnes} sera vide.

Note 2 : Si {lpurl} est suivie d’un custom parameter, il est possible que vous soyez obligés d’ajouter un ? à la fin de la landing page. Testez votre modèle de suivi sur une campagne test avant de migrer manuellement.

Et dernière chose : bon courage !

[Adwords] Comprendre & Apprendre à coder les scripts Adwords

Les scripts Adwords utilisent le JavaScript.
Si la plupart des scripts écrits par Google sont faciles à customiser (ils contiennent souvent une ou deux lignes précisant « INSERT_SPREADSHEET_URL_HERE »), vous gagnerez davantage en efficacité et précision en ayant quelques notions en JavaScript.
Voici quelques liens utiles pour au moins comprendre les scripts et éventuellement les modifier

Niveau 1

Les 3 articles du Search Engine Land vous seront très utiles pour apprendre à lire le code et le personnaliser, si besoin

Niveau 2

Je trouve les scripts de Russell Savage très faciles à comprendre et bien commentés; contrairement aux scripts de Google, très bien codés, mais trop souvent difficiles à comprendre pour les non-développeurs. Si vous avez des questions sur ces scripts, il suffit de les poser à l’auteur, qui est très disponible et présent dans les commentaires.

Niveau 3

Développer from scratch est une solution assez tentante, surtout que le JavaScript n’est pas si difficile que ça à apprendre.
Je vous conseille le fameux cours du Site du zéro (devenu OpenClassrooms), rempli d’exercices pratiques. Pour tester vos codes, passez par l’outil du W3Schools. En cas de doutes sur la syntaxe ou les fonctions, consultez le site du W3Schools.
Ensuite, imprimez ce code écrit par Russell Savage, une synthèse des notions fondamentales du JavaScript. A travers un exemple drôle (créer un programme pour le Fight Club, déclarer les noms des membres et organiser les combats), on apprend la syntaxe.
Enfin, appuyez-vous sur les scripts développés par Google (des plus simples aux plus complexes) et essayez de comprendre chaque ligne.
Une astuce pour bien comprendre ce que fait telle ou telle commande est d’ajouter un
Logger.log(nom_du_variable_ici);
après chaque bloc de codes. Exécutez le code en mode « Preview » et consultez les Journaux.
Ceci permet de comprendre, par exemple, que le sélecteur
var ags = AdWordsApp.adGroups().withCondition('Name CONTAINS "test"').get();
ne permet que scanner l’ensemble des adgroups remplissant telle ou telle condition; et que pour sélectionner ces adgroups, un à un, il faut aussi utiliser ce code :
while (ags.hasNext()){ var ag = ags.next();}

Bon courage ! Et si besoin, deux employés de Google répondent à vos questions sur les scripts ici.

[Adwords] Script MCC : Suivi Budgétaire quotidien

Une des tâches quotidiennes (et assez répétitive) est de suivre les trends de dépenses et ajuster les budgets en conséquence.
Il est possible de faire ce suivi à l’aide d’un script Adwords au niveau MCC. Les dépenses sont affichées sur un fichier hébergé sur Google Drive, une ligne par compte.

Voici les données affichées : Les dépenses
– d’il y a 3 jours (J-3)
– d’il y a 2 jours (J-2)
– la veille
– cumul du mois (1er du mois en cours jusqu’à la veille). Si le script est lancé le premier du mois, le cumul du mois en cours est de 0€

Il m’a semblé indispensable d’afficher les dépenses des 3 derniers jours au lieu des dépenses de la veille uniquement.
Le budget mensuel ainsi que la date de fin doivent être renseignés manuellement sur le fichier.
Le script permettra de calculer le budget restant du mois, le trend idéal ainsi que les ajustements (si besoin) par rapport aux dépenses de la veille.

Pour cela, suivez les étapes suivantes :

1. Faites une copie de ce fichier sur votre Drive

2. ONGLET BUDGET : Entrez les noms des comptes, tels qu’ils sont écrits au sein du MCC.

3. ONGLET BUDGET : Renseignez les budgets mensuels pour chaque compte
budgetmensuel

4. Copiez/collez le script ci-dessous au niveau du MCC. Pensez à renseigner l’ID de votre fichier Drive dans le script à l’emplacement prévu : INSERT_YOUR_SPREADSHEET_ID

5. Lancez le script une première fois pour qu’il remplisse l’onglet SUIVI avec les noms des comptes
suivi

6. ONGLET SUIVI : Renseignez la date de fin pour chaque compte (par rapport au mois en cours. Par exemple, si on est en Novembre, le chiffre 30 indique que le budget renseigné est valable jusqu’au 30 Novembre)
suivi2

7. Lancez le script une deuxième fois

8. Enfin, programmez le script pour qu’il s’exécute tous les jours vers 7h

Admirez le résultat
suivi3

Voici le code :

function main() {
 
 
  //declare Spreadsheet variables
  var urlBulk = 'INSERT_YOUR_SPREADSHEET_ID'; //insert your ID here, for ex 1IHmWJdaXujbLpmBNOMBddus3vJmU-RaOQNMnqAQpz5s
  var spreadsheetBulk = getSpreadsheet(urlBulk);
  var sheet = spreadsheetBulk.getSheetByName('SUIVI');
  var row = 4;
 
  //current month
  var currentmonth = getcurrentmonth();
  sheet.getRange("B2").setValue(currentmonth);
 
 
  //columns names
  var columns = [
  "Compte", "J-3", "J-2", "Hier", "Cumul du mois en cours", "Budget", "Date de fin", "Budget restant", "Jours restants", "Trend journalier idéal", "Ajustement"
  ];
 
  for (var i = 1; i < 12; i++){
     sheet.getRange(3, i).setValue(columns[i-1]);
  }
 
  //Dates
 
var now = new Date(Utilities.formatDate(new Date(), "CET", 'MMM dd,yyyy HH:mm:ss'));
now.setHours(12);
var nowdate = now.getDate();
var yesterday = new Date(now.getTime() - 24 * 3600 * 1000);
yesterday.setHours(12);
var twodaysago = new Date(yesterday.getTime() - 24 * 3600 * 1000);
twodaysago.setHours(12);
var threedaysago = new Date(twodaysago.getTime() - 24 * 3600 * 1000); 
threedaysago.setHours(12);
var firstDay = new Date(yesterday.getFullYear(), yesterday.getMonth(), 1);
firstDay.setHours(12);
 
yesterday = Utilities.formatDate(yesterday, "CET", "yyyyMMdd");
twodaysago = Utilities.formatDate(twodaysago, "CET", "yyyyMMdd");  
threedaysago =   Utilities.formatDate(threedaysago, "CET", "yyyyMMdd"); 
firstDay = Utilities.formatDate(firstDay, "CET", "yyyyMMdd"); 
 
  // Get an account iterator. 
  var accountIterator = MccApp.accounts().get();
  while (accountIterator.hasNext()) {
 
   // Get the current account.
   var account = accountIterator.next();
 
   // Select the child account.
   MccApp.select(account);
 
   // Run reports against child account.
 
 
  //YESTERDAY report  
  var query = 'SELECT Cost from ACCOUNT_PERFORMANCE_REPORT during YESTERDAY';
  var report = AdWordsApp.report(query);
 
  // report
  var rowss = report.rows();
    while (rowss.hasNext()) {
    var rows = rowss.next();
    var accountName = account.getName();
    sheet.getRange("A" + row).setValue(accountName);
 
    //get costs  
    var cost = parseFloat(rows["Cost"].replace(",",""));
    sheet.getRange("D" + row).setValue(cost);
    var stats = account.getStatsFor(threedaysago, threedaysago);
    sheet.getRange("B" +row).setValue(stats.getCost());
    var stats = account.getStatsFor(twodaysago, twodaysago);
    sheet.getRange("C" +row).setValue(stats.getCost());
 
    //get current month's cost
    if (now == 1){
      sheet.getRange("E" +row).setValue(0);
    } else {
      var stats = account.getStatsFor(firstDay, twodaysago);
      sheet.getRange("E" +row).setValue(stats.getCost()+cost); 
    }  
 
    //get current month's budget  
    sheet.getRange("F" +row).setFormula("vlookup(A"+row+";BUDGET!$A:$M;match($B$2;BUDGET!$B$2:$M$2;0)+1;false)");   
 
 
    //leftover budget
    sheet.getRange("H" +row).setFormula("F"+row+"-E"+row);
 
    var datefin = sheet.getRange("G"+row).getValue();
    if (datefin > now){ 
      sheet.getRange("I" +row).setFormula("G"+row+"-"+now+"+1"); 
      //ideal trend
      sheet.getRange("J" +row).setFormula("H"+row+"/I"+row);
      //Ajustement
      sheet.getRange("K" +row).setFormula("J"+row+"-D"+row);
 
    } else { sheet.getRange("I" +row).setValue("Terminé");
      //ideal trend
      sheet.getRange("J" +row).setValue("Terminé");
      //ajustement
      sheet.getRange("K" +row).setValue("Terminé");     
 
 
           }
     row++;
  }
 }
}
 
 
function getSpreadsheet(spreadsheetUrl) {
  return SpreadsheetApp.openById(spreadsheetUrl);
}
 
 
// returns noon in the timezone of the account
function getYesterday() {
  var now = new Date(Utilities.formatDate(new Date(),
      AdWordsApp.currentAccount().getTimeZone(), 'MMM dd,yyyy HH:mm:ss'));
  var yesterday = new Date(now.getTime() - 24 * 3600 * 1000);
  yesterday.setHours(12);
  return yesterday;
}
 
function getToday() {
  var now = new Date(Utilities.formatDate(new Date(),
      AdWordsApp.currentAccount().getTimeZone(), 'MMM dd,yyyy HH:mm:ss'));
  return now;
}
 
function getcurrentmonth(){
  var mois = getToday();
  mois = mois.getMonth() + 1;
  var month = [
  "Janvier", "Février", "Mars", "Avril", "Mai", "Juin",
  "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"
  ];
  var mois = month[mois - 1];
  return mois;
}

[ADWORDS] Scripts Adwords pour les campagnes Shopping

Les scripts Adwords pour les nouvelles campagnes Shopping sont disponibles depuis longtemps mais buggaient pas mal. Maintenant, ils sont 100% fonctionnels.

Vous pouvez les trouver sur https://developers.google.com/adwords/scripts/docs/examples/shopping ou directement depuis votre interface de création de Scripts

scriptsadwordsshopping

Attention, les scripts de création de groupes de produits ci-dessus ne marchent que si vos groupes/campagnes, ne comportent aucun groupe de produits.

Code pour modifier l’hiérarchie

Si votre structure est déjà créée, il va falloir traverser l’hiérarchie et ajouter par exemple un deuxième niveau.
Voici un exemple de code, j’ai déjà un premier niveau BRAND dont le nom est cardcow.
Je veux maintenant ajouter un deuxième niveau avec le custom label « test ».
Je ne veux pas ajouter ce custom label au product group « tout le reste »

function main() {
  var campaignName = 'test'; // nom de la campagne
  var adGroupName = 'test2'; // nom de l'adgroup
 
  var shoppingAdGroup = AdWordsApp.shoppingAdGroups()
                                  .withCondition("CampaignName = '" +
                                                 campaignName +
                                                 "' and AdGroupName = '" +
                                                 adGroupName + "'")
                                  .get()
                                  .next();
 
  var rootProductGroup = shoppingAdGroup.rootProductGroup();
  var childProductGroups = rootProductGroup.children().get();
  while (childProductGroups.hasNext()) {
    var childProductGroup = childProductGroups.next();
 
    if (childProductGroup.isOtherCase()) { // si le product group est un groupe "tout le reste" 
      Logger.log('pas de modif pour les product groups "autres"'); // ici aucune action n'est effectuée mais on peut par exemple exclure ces groupes
 
    } else if (childProductGroup.getDimension() == 'BRAND') { 
        // on entre dans le product groupe de type BRAND
        var customItems = childProductGroup.newChild()
                       .customLabelBuilder().withType("CUSTOM_LABEL_0") // on crée un deuxième niveau avec le custom label niveua 0
                       .withValue("test")
                       .withBid(0.13).build();
 
 
       }
 
     }
}

L’exécution du script ci-dessus donne ça :
scriptsadwordsshopping2

Rapport Campagnes Shopping

Le rapport qui nous intéresserait tous est celui qui inclut la part de voix par groupe de produits.
Malheureusement, le rapport automatique de Google (ReportType: SHOPPING_PERFORMANCE_REPORT) ne permet pas d’extraire ces données, cf. la liste des données disponibles pour ce type de rapport.

Edit : Le rapport automatique Product Partition Report le permet et inclut également les données de Benchmark (CTR, CPC).