Les lancements de campagne ne commencent pas dans un tableau de bord. Ils commencent dans une feuille de calcul que quelqu'un a partagée sur Slack. Les URL vivent dans la colonne A, les métadonnées UTM remplissent les colonnes B à G, les slugs sont dans la colonne H, et le brief dit que le lancement est demain. La partie la plus lente de tout le processus est de copier chaque ligne dans une UI de raccourcisseur un lien à la fois - non pas parce que quoi que ce soit est techniquement difficile, mais parce qu'il n'y a aucune raison de procéder ainsi.
Cet article est le workflow direct : à quoi ressemble la feuille, comment elle se mappe à l'endpoint d'import en masse d'Elido, trois chemins d'import selon le nombre de lignes, l'étape de dry-run qui attrape les erreurs avant qu'elles n'arrivent en production, et un snippet Apps Script qui automatise tout ça sur un déclencheur. Pour le contexte plus large sur l'hygiène UTM de bout en bout, le cornerstone du tracking UTM couvre les templates de workspace et le transfert de conversion côté serveur en profondeur. Cet article-ci est la tranche sheet-to-short-links de ce pipeline.
TL;DR#
- Gardez une feuille par campagne :
target_url,slug,utm_source,utm_medium,utm_campaign,tagscomme colonnes nommées. Les colonnes UTM laissées vides sont remplies depuis votre template de workspace. - Trois chemins d'import : coller les lignes dans l'UI (jusqu'à 1 000 lignes), upload CSV (jusqu'à 10 000 lignes), ou l'API via un script (illimité, répétable).
- Lancez toujours d'abord avec
dry_run=true. La preview montre le lien court résolu et la chaîne de requête UTM entièrement rendue sans rien committer. - Préfixez les slugs de campagne (
q2-,jun-) pour les nommer dans un espace de noms. Les collisions remontent au dry-run, pas en plein import.
Forme de la feuille#
Les colonnes obligatoires sont target_url et l'une de slug ou auto_slug. Tout le reste est optionnel mais a une interprétation définie quand présent.
| Colonne | Obligatoire | Notes |
|---|---|---|
target_url | oui | URL de destination complète y compris le schéma |
slug | une des deux | Préféré - vous donne des URL courtes prévisibles |
auto_slug | une des deux | Réglez à true et Elido génère un slug |
utm_source | optionnel | Écrase la valeur du template de workspace |
utm_medium | optionnel | Écrase la valeur du template de workspace |
utm_campaign | optionnel | Écrase la valeur du template de workspace |
utm_content | optionnel | Généralement la variante créative |
utm_term | optionnel | Mot-clé payant ou segment d'audience |
tags | optionnel | Séparés par virgule, appliqués au lien |
title | optionnel | Affiché dans la liste de liens du tableau de bord |
La règle UTM est simple : si target_url contient déjà un paramètre de requête ?utm_source= (ou tout utm_*), ces valeurs sont passées telles quelles. Pas d'écrasement, pas de fusion. Si l'URL de destination n'a pas de paramètres UTM, Elido les construit depuis les colonnes UTM, en revenant à votre template de workspace pour toute colonne vide. Cela compte en pratique - certaines équipes maintiennent des URL de destination pré-marquées pour leur fournisseur d'email, et un outil d'import en masse qui les re-marque silencieusement produit des analytics cassés. Elido avertit sur les lignes en mode mixte (certains UTM présents, certains absents) et vous demande de confirmer.
La colonne tag mérite sa propre note. Les valeurs sont des chaînes séparées par virgule : campaign:q2-spring, channel:paid-social, variant:hero-a. Cette forme à trois parties (dimension:value) vous donne des axes filtrables dans le tableau de bord sans avoir besoin d'une config taxonomie séparée. Plus sur ce sujet dans la section taxonomie de tags ci-dessous.
Les trois chemins d'import#
Coller les lignes dans l'UI d'import en masse (jusqu'à 1 000 lignes)#
Pour tout ce qui est sous 1 000 lignes, le chemin le plus rapide est de copier la plage de la feuille et coller dans la zone de texte d'import en masse. L'UI d'Elido auto-détecte les valeurs séparées par tabulation d'un collage de feuille de calcul et mappe les colonnes par en-tête. Vous n'exportez pas de CSV ; vous collez simplement.
Cela fonctionne bien pour le cas le plus courant : un brief de campagne qui vit déjà dans Sheets, une deadline de lancement dans une heure, et aucun appétit pour le scripting. L'UI montre une preview de toutes les lignes avant le commit (le même dry-run que vous auriez de l'API) et vous laisse corriger les lignes échouées en ligne avant de procéder.
Un piège : si votre feuille a des cellules fusionnées ou un formatage complexe, le collage peut produire une sortie déformée. Le mouvement sûr pour toute feuille avec une structure non triviale est de copier vers une feuille propre d'abord (coller-comme-valeurs), puis coller la plage nettoyée dans l'UI d'import.
Upload CSV (jusqu'à 10 000 lignes)#
Pour les lancements avec plus de 1 000 lignes (grandes campagnes de catalogue, codes d'événement, liens personnalisés), le chemin d'upload CSV gère jusqu'à 10 000 lignes. Exportez la feuille en CSV (Fichier > Télécharger > CSV) et téléchargez-le dans la boîte de dialogue d'import. Le mappage en-tête-colonne est le même ; la différence est que les gros uploads traitent de manière asynchrone et rapportent leur statut via un webhook ou un endpoint poll.
L'export CSV via l'API Google Sheets (consulté le 2026-05-12) prend en charge l'export d'une plage nommée plutôt que de toute la feuille, ce qui est utile quand votre feuille de campagne a plusieurs onglets ou lignes d'en-tête que vous ne voulez pas nettoyer manuellement.
Appel d'API depuis un script (plus de 10 000 lignes, ou exécutions répétées)#
Pour les gros catalogues, ou pour les campagnes qui tournent chaque semaine et ont besoin du même processus automatisé, le chemin API est le bon. Deux implémentations courantes : Apps Script (pas d'outillage local requis, tourne dans le navigateur) et Python (meilleur pour les équipes avec des pipelines de données existants). L'endpoint est le même dans tous les cas.
curl -X POST \
https://api.elido.app/v1/links/bulk \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-H "Content-Type: multipart/form-data" \
-F "csv=@q2_spring_links.csv" \
-F "campaign_id=cmp_8a2f" \
-F "dry_run=false" \
-F "on_conflict=skip"
Le paramètre on_conflict contrôle ce qui se passe quand un slug existe déjà : skip laisse le lien existant en place et enregistre un avertissement, fail abandonne l'import entier à la première collision, et replace met à jour la destination du lien existant. Pour la plupart des imports de campagne, skip est le bon défaut : une réexécution du même CSV ne va pas écraser des liens que vous avez déjà créés.
L'API accepte jusqu'à 10 000 lignes par appel. Pour de plus gros catalogues, regroupez en chunks de 5 000 lignes ; chaque appel est indépendant et idempotent si vous utilisez des slugs stables.
Dry-run pré-import#
Lancez chaque import avec dry_run=true avant le commit. La réponse est identique à l'import live (chaque ligne montre son lien court résolu, la chaîne de requête UTM parsée, la liste de tags, et tout avertissement) mais rien n'est écrit dans la base de données.
Les choses que le dry-run attrape et que vous n'attraperez pas autrement avant le lancement :
- Un slug à la ligne 14 qui entre en collision avec un lien existant dans votre workspace (remonté comme avertissement de conflit)
- Une colonne UTM laissée vide par accident (Elido signale
utm_mediummanquant comme avertissement, pas erreur dure, mais que vous voulez savoir avant le lancement) - Une
target_urlavec une espace en fin qui a survécu à la copie de feuille de calcul (l'URL résolue a l'air bien dans le CSV mais la destination réelle a%20ajouté) - Des valeurs de tag qui excèdent 32 caractères (silencieusement tronquées ; le dry-run rend la valeur stockée visible)
La réponse du dry-run est paginée dans le même format qu'un résultat d'import réel. Ouvrez la première page, vérifiez la ligne 2 (la première ligne de données après votre probablement-parfaite ligne 1) et la dernière ligne. Puis regardez toutes les lignes qui signalent un avertissement. Deux minutes de relecture attrapent les erreurs qui ressortiraient autrement comme « pourquoi ce lien de campagne fait 404 ? » au lendemain du lancement.
Conflits de slugs#
Les conflits de slugs surviennent quand un slug que vous essayez d'importer existe déjà dans votre workspace ou sur votre domaine personnalisé. L'import les fait remonter dans la réponse de dry-run avec le type de conflit (same_workspace, same_domain, reserved) et l'URL de destination du lien existant.
Le remède pratique est le namespacing. Préfixez les slugs de campagne avec un identifiant court : q2-, jun26-, sm- (pour social media), em- (pour email). Un slug comme q2-spring-hero-a a peu de chances d'entrer en collision avec quoi que ce soit d'une campagne précédente. Les préfixes rendent aussi le filtre du tableau de bord évident - tous les liens taggés q2-* appartiennent à un trimestre de campagne.
Un cas qui mérite d'être mentionné : si vous migrez depuis un autre raccourcisseur et voulez préserver les slugs hérités, importez-les d'abord sans préfixe, puis utilisez des slugs préfixés pour le nouveau contenu de campagne. L'import en masse d'Elido vous dira au dry-run si l'un des slugs hérités entre en conflit avec ceux déjà dans le workspace.
Taxonomie de tags#
Les tags appliqués au moment de l'import obtiennent la même structure à trois parties que les colonnes de feuille qui les ont conduits : campaign:q2-spring, channel:email, variant:hero-a. Quand vous ouvrez le tableau de bord plus tard et filtrez par channel:email, vous ne fouillez pas dans des chaînes en texte libre - vous interrogez une taxonomie cohérente.
Les noms de dimension (campaign, channel, variant) viennent de la convention de votre équipe, pas d'un schéma imposé par Elido. La contrainte est le format : un séparateur deux-points, pas d'espaces dans la clé, valeurs sous 32 caractères. Les équipes qui appliquent ceci dans la feuille (une colonne tags qu'une formule construit comme "campaign:"&E2&", channel:"&F2) n'ont jamais de tags mal formés dans le tableau de bord. Les équipes qui laissent la colonne tags être en texte libre ont un problème de nettoyage en trois campagnes.
Pour la vue d'ensemble de la fonctionnalité campagnes, le regroupement par tag est la façon principale dont Elido regroupe les clics par dimension de campagne dans le panneau d'analytics - donc la taxonomie que vous définissez dans la feuille est la taxonomie par laquelle vous filtrerez en reporting.
Automatisation Apps Script#
Pour les équipes qui font tourner la même structure de campagne chaque semaine (liens newsletter, liens social payant, variantes email), le bon mouvement est d'automatiser entièrement l'import. Google Apps Script tourne dans le navigateur, a accès aux données de feuille, et peut déclencher sur un cron basé sur le temps ou la soumission de formulaire.
Le pattern : un déclencheur se déclenche, le script lit toutes les lignes de la feuille qui n'ont pas de valeur short_link dans la colonne I, fait un POST vers l'API d'import en masse, et écrit les liens courts créés en retour dans la colonne I. Au déclencheur suivant, les lignes déjà importées sont sautées parce que la colonne I est peuplée.
// Google Apps Script - bulk import new rows via Elido API
// Trigger: time-driven, every hour (or on form submit)
// Docs: https://developers.google.com/apps-script/guides/triggers (accessed 2026-05-12)
function importNewLinks() {
const sheet =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Q2 Spring");
const data = sheet.getDataRange().getValues();
const headers = data[0];
const urlCol = headers.indexOf("target_url");
const slugCol = headers.indexOf("slug");
const srcCol = headers.indexOf("utm_source");
const medCol = headers.indexOf("utm_medium");
const campCol = headers.indexOf("utm_campaign");
const tagsCol = headers.indexOf("tags");
const doneCol = headers.indexOf("short_link"); // write back here
const newRows = [];
const rowIndexes = [];
for (let i = 1; i < data.length; i++) {
const row = data[i];
if (!row[urlCol] || row[doneCol]) continue; // skip empty or already imported
newRows.push({
destination: row[urlCol],
slug: row[slugCol] || undefined,
utm_source: row[srcCol] || undefined,
utm_medium: row[medCol] || undefined,
utm_campaign: row[campCol] || undefined,
tags: row[tagsCol]
? String(row[tagsCol])
.split(",")
.map((t) => t.trim())
: [],
});
rowIndexes.push(i);
}
if (!newRows.length) return;
const payload = JSON.stringify({
links: newRows,
campaign_id: "cmp_8a2f",
on_conflict: "skip",
});
const resp = UrlFetchApp.fetch("https://api.elido.app/v1/links/bulk", {
method: "post",
contentType: "application/json",
headers: {
Authorization:
"Bearer " +
PropertiesService.getScriptProperties().getProperty("ELIDO_TOKEN"),
},
payload: payload,
muteHttpExceptions: true,
});
const result = JSON.parse(resp.getContentText());
const created = result.links || [];
// Write short links back into column I
created.forEach((link, idx) => {
if (!link.short_url) return;
const sheetRow = rowIndexes[idx] + 1; // 1-indexed
sheet.getRange(sheetRow, doneCol + 1).setValue(link.short_url);
});
}
Quelques notes d'implémentation :
Stockez le token d'API dans PropertiesService.getScriptProperties(), pas en dur dans le script. La documentation des triggers Apps Script (consulté le 2026-05-12) couvre la configuration des déclencheurs à la fois basés sur le temps et basés sur des événements. Pour une feuille de campagne qu'une équipe remplit collaborativement, un déclencheur onEdit se lance quand la colonne A est peuplée ; le lien court apparaît dans la colonne I quelques secondes après avoir tapé l'URL de destination.
Le flag muteHttpExceptions: true est important. Sans lui, un 422 de l'API lève une exception au niveau du script et le déclencheur arrête de retenter. Avec lui, vous obtenez le corps de l'erreur et pouvez le logger à la place.
Pour une intégration plus lourde (un script Python, une étape CI qui lit une feuille via l'API Sheets, ou un job planifié dans votre pipeline de données existant), l'endpoint spreadsheets.values.get de l'API Sheets (consulté le 2026-05-12) vous donne directement du JSON. À partir de là, la forme de l'appel d'import en masse est identique à l'exemple curl ci-dessus.
Erreurs courantes#
Espace en fin dans les slugs. Un slug copié depuis une cellule de feuille de calcul peut avoir une espace en fin invisible dans l'UI. Elido le permet (le slug est techniquement valide), mais go.example.com/q2-promo avec une espace en fin est une URL laide et la copie du presse-papier depuis la barre d'adresse du navigateur la dépouille généralement, donc la personne qui colle le lien court plus tard obtient un 404. Le remède est une formule =TRIM(H2) sur la colonne slug avant export.
utm_medium manquant. Elido avertit mais ne bloque pas sur un utm_medium manquant parce que certaines campagnes le sautent intentionnellement. Mais un medium manquant est presque toujours une erreur : GA4 route tout ce qui en est dépourvu vers le canal (none), ce qui rend l'attribution de canal inutile. La référence canonique du URL builder GA4 (consulté le 2026-05-12) liste utm_medium comme requis pour que l'attribution de campagne fonctionne correctement. Si votre template de workspace a un défaut utm_medium, les cellules vides dans la colonne en héritent ; sinon, l'avertissement du dry-run est votre dernière chance de l'attraper.
Valeurs de tag de plus de 32 caractères. Elido tronque silencieusement les valeurs de tag qui excèdent 32 caractères. La troncature est invisible dans les avertissements du dry-run à moins que vous ne la cherchiez (la réponse montre la valeur stockée, pas l'originale). Les longues valeurs de tag viennent généralement de coller les noms de campagne UTM dans la colonne tags : spring-2026-dach-email-reactivation-week3 fait 42 caractères et deviendra spring-2026-dach-email-reactivation-we dans le tableau de bord. Gardez les valeurs de dimension de tag courtes ; déplacez les métadonnées verbeuses dans le titre du lien à la place.
Oublier dry_run=true lors des reprises. Si vous relancez un upload CSV contre une campagne qui a déjà des liens, on_conflict=skip est sûr mais on_conflict=replace va mettre à jour les URL de destination sur tout slug qui apparaît à la fois dans l'ancien et le nouveau CSV. Sur une campagne où les URL de destination n'ont pas changé, c'est inoffensif. Sur une campagne où vous avez mis à jour les URL de landing pages en vol, c'est ce que vous voulez. Sachez dans quel mode vous êtes avant de committer.
Le résumé configuration-à-lancement#
La version la plus complète de ce workflow : construisez la feuille une fois avec des noms de colonnes stables, définissez un template UTM de workspace pour que les colonnes UTM vides héritent de défauts sensés (couvert dans setup-branded-short-links), lancez le dry-import pour attraper les conflits et avertissements, committez, et écrivez le déclencheur Apps Script pour que la prochaine campagne nécessite zéro étape manuelle.
Pour la couche d'attribution qui ferme la boucle après le clic, le suivi de conversion côté serveur couvre comment câbler le click_id depuis la réponse de redirection d'Elido jusqu'à Meta CAPI et GA4, la pièce côté serveur qui survit à Safari ITP et à l'interférence des ad-blockers. Cet article-là et celui-ci ensemble vous donnent une image complète du workflow de campagne solutions/marketers, de la feuille au lien court à la conversion attribuée.
La surface complète de gestion d'URL de campagne - templates, import en masse, regroupement de campagne, transfert de conversion - est sur la page features/campaigns.
Essayer Elido
Collez une URL, obtenez un lien court
Sans inscription. Lien actif 30 jours. Inscrivez-vous pour le garder pour toujours.
Gratuit, sans inscription · 2 par jour