Un hit de conversion Rakuten (LinkShare) tient en une longue ligne de signes pourcent, de barres verticales et de chiffres. Il contient exactement ce que le réseau a reçu de la commande : quels produits, en quelle quantité, pour combien.
Ce guide montre comment en lire un en une trentaine de secondes, à partir d’un vrai hit de commande dont la marque, les noms de produits et le numéro de commande ont été remplacés par des valeurs fictives. Il s’adresse aux consultants tracking et analytics et aux équipes e-commerce qui doivent répondre à la question : « pourquoi le rapport d’affiliation ne correspond-il pas à notre panier ? ».
Pourquoi l’URL est illisible : percent-encoding, pas entités HTML
Le hit est une URL, donc ses caractères spéciaux sont encodés en pourcentage : chaque octet qui ne peut pas apparaître tel quel devient un signe % suivi de deux chiffres hexadécimaux. MDN décrit encodeURIComponent() comme le remplacement de caractères par une à quatre séquences d’échappement représentant leur encodage UTF-8, et decodeURIComponent() fait l’inverse.
Les entités HTML sont un autre mécanisme, avec un autre rôle : elles vivent dans les documents HTML et commencent par une esperluette (référence nommée comme & ou numérique comme '). Le même caractère s’écrit différemment dans chaque système.
| Ce que vous voyez | Où ça vit | Ce que ça veut dire |
|---|---|---|
%20 | URL (percent-encoding) | une espace (octet 0x20) |
%3E | URL | le caractère > |
%27 | URL | une apostrophe |
%C2%A0 | URL | une espace insécable : deux octets UTF-8, C2 et A0 |
& | HTML (référence nommée) | une esperluette |
' | HTML (référence numérique) | une apostrophe, écrite par son point de code |
| HTML (référence nommée) | une espace insécable |
Deux détails comptent pour les URL de pixel. URLSearchParams lit un signe plus dans une chaîne de requête comme une espace : une valeur contenant un vrai plus doit être envoyée en %2B. Et decodeURIComponent() lève une URIError quand un % n’est pas suivi de deux chiffres hexadécimaux : un hit tronqué peut donc casser un décodeur.
Étape 1 : découper les paramètres
On coupe l’URL au point d’interrogation, puis à chaque esperluette. Le hit de l’exemple part vers track.linksynergy.com/ep et porte ces paramètres :
mid=37335,ord=ORDER_12345(identifiant de commande, remplacé ici),landettr: champs d’identification et de contexte. Selon MetaRouter, Rakuten attend un ordre commençant par mid, ord, tr et land.cur=GBP: la devise.discount=18.72etdisamt=18.72: la remise.ordstatus=new,source=scat,img=1,spi=3.4.1: d’autres indicateurs qui ne changent pas la lecture des listes.- Six listes séparées par des barres verticales :
skulist,qlist,amtlist,namelist,catlist,brandlist.
Le guide de Tealium indique que la bibliothèque Rakuten construit skulist, namelist, qlist et amtlist à partir des lignes de la commande. Chaque produit apparaît donc à la même position dans toutes les listes, ce qui rend possible l’alignement de l’étape 2.
Étape 2 : aligner les listes en une ligne par produit
La première valeur de chaque liste appartient au premier produit, la deuxième au deuxième, et ainsi de suite. Le script ci-dessous fait l’alignement. Il découpe chaque liste sur la barre verticale avant de décoder, pour qu’une barre encodée dans un nom de produit ne crée pas de fausse colonne. Il signale ensuite toute liste de longueur différente et tout montant vide.
function decodeHit(hitUrl) {
const dec = (s) => decodeURIComponent(s.replace(/\+/g, " "));
const raw = Object.fromEntries(
new URL(hitUrl).search.slice(1).split("&").map((pair) => {
const i = pair.indexOf("=");
return [pair.slice(0, i), pair.slice(i + 1)];
})
);
const listKeys = ["skulist", "qlist", "amtlist", "namelist", "catlist", "brandlist"];
const columns = {};
for (const k of listKeys) {
columns[k] = (raw[k] ?? "").split("|").map(dec);
}
const n = Math.max(...Object.values(columns).map((c) => c.length));
const rows = Array.from({ length: n }, (_, i) =>
Object.fromEntries(listKeys.map((k) => [k, columns[k][i] ?? ""]))
);
const issues = [];
for (const k of listKeys) {
if (columns[k].length !== n) issues.push(`${k}: ${columns[k].length} values, expected ${n}`);
}
rows.forEach((r, i) => {
if (r.amtlist === "") issues.push(`row ${i + 1} (${r.skulist}): empty amtlist`);
});
return { rows, issues };
}
Exécuté sur le hit d’exemple, il donne ce tableau :
| # | skulist | qlist | amtlist | namelist | catlist | brandlist |
|---|---|---|---|---|---|---|
| 1 | 80098955 | 2 | 1544 | Product A | Category A | Brand |
| 2 | 80081183 | 1 | 550 | Product B | Category A | Brand |
| 3 | 80082077 | 1 | (vide) | Product C | Samples | Brand |
| 4 | 80083079 | 1 | (vide) | Product D | Samples | Brand |
| 5 | 80124257 | 1 | (vide) | Product E | Samples | Brand |
| 6 | 80104514 | 1 | 1540 | Product F | Category A | Brand |
Ce que montre le tableau
La commande compte six lignes, mais amtlist est vide pour trois d’entre elles (lignes 3 à 5), et ces trois lignes sont dans la catégorie « Samples ». Ce sont très probablement des échantillons gratuits ajoutés au panier à un prix de zéro. Deux conséquences.
D’abord, le réseau ne reçoit jamais de montant pour ces lignes. C’est peut-être exactement ce que vous voulez, mais cela doit être une décision, pas un accident de la façon dont le tag lit le panier.
Ensuite, les montants ne sont pas dans les unités de la boutique. La documentation Rakuten de MetaRouter indique que amtlist est exprimé en centimes, multiplié par 100 pour la plupart des devises et pas pour le yen japonais. Sur cette base, les trois lignes tarifées font 1544 + 550 + 1540 = 3634, soit 36,34 GBP, alors que les champs de remise affichent 18.72. Je n’ai trouvé aucune page Rakuten qui énonce l’unité ou explique le traitement des entrées vides : confirmez les deux avec votre account manager Rakuten avant de vous y fier. Vérifiez aussi si 1544 sur la ligne 1, dont la quantité est 2, est un total de ligne ou un prix unitaire.
MetaRouter documente également une convention où la remise voyage comme une ligne supplémentaire avec le SKU « Discount ». Ce hit envoie la remise dans des paramètres séparés, sans cette ligne. Savoir si c’est correct pour votre programme est une question à poser au réseau.
Checklist pour tout hit de conversion d’affiliation
| Contrôle | Ce qu’il faut chercher |
|---|---|
| Longueur des listes | Les six listes ont le même nombre de valeurs que skulist. |
| Montants vides | Chaque case vide d’amtlist a une raison connue (échantillon gratuit, cadeau, composant de lot). |
| Quantité et montant | Le montant est le total de ligne ou le prix unitaire, de façon cohérente sur toutes les lignes. |
| Totaux | La somme d’amtlist, moins la remise, correspond au total de commande de votre back-office. |
| Unités | amtlist et les paramètres de remise utilisent les unités attendues par la documentation pour la devise. |
| Encodage | Aucune valeur ne montre %25 suivi de deux chiffres hexadécimaux, ce qui signalerait un double encodage. |
L’auditer sur votre site
Ouvrez le panneau réseau du navigateur, filtrez sur le domaine du réseau, passez une commande de test incluant un article gratuit et copiez l’URL de la requête. Exécutez le script dessus et comparez le résultat à la confirmation de commande. Recommencez avec un code promo, avec une ligne à quantité multiple et avec un produit dont le nom contient un accent ou une apostrophe, car ce sont les cas où l’encodage se passe mal.
Si vous préférez ne pas coller de code, le décodeur d’URL gratuit de ce site découpe et décode un hit dans le navigateur.
Sources
- MDN : encodeURIComponent()
- MDN : decodeURIComponent()
- MDN : URLSearchParams
- MDN : Character reference
- RFC 3986 : Uniform Resource Identifier (URI) Generic Syntax
- MetaRouter : Rakuten conversions (documentation tierce)
- Tealium : guide de configuration du tag Rakuten Advertising
- Commanders Act : Rakuten events
Pour aller plus loin, lisez la version complète de l’article (en anglais) : Decoding Affiliate Pixel URLs: Read a Rakuten (LinkShare) Conversion Hit in 30 Seconds.
Besoin d’aide sur ce sujet ? Consultant GA4 et audit analytics.