Elido
13 min di letturaTutorial

Importa in massa link brevi da un Google Sheet (il vero flusso di lavoro di campagna)

Copia-incolla 200 URL di campagna in un foglio, importali in massa in Elido, ottieni link brevi con tagging UTM in un solo passaggio. La forma del foglio e l'automazione Apps Script

Ana Kowalska
Marketing solutions engineering
Google Sheet grid with eight rows of campaign URLs and UTM columns arrowed into Elido's bulk-import interface producing eight short links

I lanci di campagne non iniziano in una dashboard. Iniziano in un foglio di calcolo che qualcuno ha condiviso su Slack. Gli URL vivono nella colonna A, i metadati UTM riempiono le colonne B-G, gli slug sono nella colonna H e il brief dice che il lancio è domani. La parte più lenta dell'intero processo è copiare ogni riga in una UI di accorciatore un link alla volta - non perché qualcosa sia tecnicamente difficile, ma perché non c'è motivo di farlo in quel modo.

Questo post è il flusso di lavoro diretto: come appare il foglio, come si mappa all'endpoint di import in massa di Elido, tre percorsi di import a seconda del numero di righe, il passo dry-run che cattura gli errori prima che siano in produzione e uno snippet di Apps Script che automatizza tutto su un trigger. Per il contesto più ampio sull'igiene UTM end-to-end, il cornerstone sul tracciamento UTM copre i template del workspace e l'inoltro server-side delle conversioni in profondità. Questo post è la fetta da foglio a link brevi di quella pipeline.

TL;DR#

  • Tieni un foglio per campagna: target_url, slug, utm_source, utm_medium, utm_campaign, tags come colonne nominate. Le colonne UTM lasciate vuote vengono riempite dal template del tuo workspace.
  • Tre percorsi di import: incolla righe nella UI (fino a 1.000 righe), upload CSV (fino a 10.000 righe), o l'API tramite script (illimitato, ripetibile).
  • Esegui sempre con dry_run=true prima. L'anteprima mostra il link breve risolto e la stringa di query UTM completamente renderizzata senza fare il commit.
  • Anteponi un prefisso agli slug di campagna (q2-, jun-) per dare loro un namespace. Le collisioni emergono nel dry run, non a metà import.

Forma del foglio#

Le colonne richieste sono target_url e uno tra slug o auto_slug. Tutto il resto è opzionale ma ha un'interpretazione definita quando presente.

ColonnaRichiestaNote
target_urlURL di destinazione completo incluso schema
sluguna delle duePreferita - ti dà URL brevi prevedibili
auto_sluguna delle dueImposta su true e Elido genera uno slug
utm_sourceopzionaleSovrascrive il valore del template del workspace
utm_mediumopzionaleSovrascrive il valore del template del workspace
utm_campaignopzionaleSovrascrive il valore del template del workspace
utm_contentopzionaleSolitamente la variante creativa
utm_termopzionaleKeyword a pagamento o segmento di audience
tagsopzionaleSeparati da virgola, applicati al link
titleopzionaleMostrato nella lista dei link nella dashboard

La regola UTM è semplice: se target_url contiene già un parametro di query ?utm_source= (o qualsiasi utm_*), quei valori vengono passati invariati. Nessuna sovrascrittura, nessuna fusione. Se l'URL di destinazione non ha parametri UTM, Elido li costruisce dalle colonne UTM, ricadendo sul template del tuo workspace per qualsiasi colonna vuota. Questo è importante in pratica - alcuni team mantengono URL di destinazione pre-taggati per il loro provider di email service, e uno strumento di import in massa che li ri-tagga silenziosamente produce analytics rotti. Elido avvisa sulle righe in modalità mista (alcune UTM presenti, altre mancanti) e ti chiede di confermare.

La colonna dei tag merita una nota a sé. I valori sono stringhe separate da virgola: campaign:q2-spring, channel:paid-social, variant:hero-a. Quella forma a tre parti (dimensione:valore) ti dà assi filtrabili nella dashboard senza necessitare di una configurazione di tassonomia separata. Maggiori dettagli nella sezione tassonomia tag qui sotto.

I tre percorsi di import#

Matrice decisionale che confronta: incolla (fino a 1.000 righe, senza strumenti), upload CSV (fino a 10.000 righe, asincrono) e script API (oltre 10.000 in batch, automatizzato e idempotente) per l'import in massa di Elido

Incolla righe nella UI di import in massa (fino a 1.000 righe)#

Per qualsiasi cosa sotto le 1.000 righe, il percorso più veloce è copiare l'intervallo del foglio e incollarlo nell'area di testo di import in massa. La UI di Elido rileva automaticamente i valori separati da tab da un incolla da foglio di calcolo e mappa le colonne per intestazione. Non esporti un CSV; lo incolli e basta.

Questo funziona bene per il caso più comune: un brief di campagna che già vive in Sheets, una scadenza di lancio a un'ora di distanza e nessuna voglia di scripting. La UI mostra un'anteprima di tutte le righe prima del commit (lo stesso dry-run che otterresti dall'API) e ti permette di correggere eventuali righe fallite in linea prima di procedere.

Un gotcha: se il tuo foglio ha celle unite o formattazione complessa, l'incolla può produrre output confuso. La mossa sicura per qualsiasi foglio con una struttura non banale è copiare prima in un foglio pulito (incolla-come-valori), poi incollare l'intervallo pulito nella UI di import.

Upload CSV (fino a 10.000 righe)#

Per lanci con più di 1.000 righe (grandi campagne di catalogo, codici evento, link personalizzati), il percorso di upload CSV gestisce fino a 10.000 righe. Esporta il foglio come CSV (File > Scarica > CSV) e caricalo nella finestra di dialogo di import. La mappatura delle intestazioni di colonna è la stessa; la differenza è che gli upload grandi vengono elaborati in modo asincrono e riportano il loro stato tramite un webhook o un endpoint di poll.

L'esportazione CSV di Google Sheets tramite l'API (consultato il 2026-05-12) supporta l'esportazione di un intervallo nominato piuttosto che dell'intero foglio, che è utile quando il tuo foglio di campagna ha più tab o righe di intestazione che non vuoi pulire manualmente.

Chiamata API da uno script (più di 10.000 righe, o esecuzioni ripetute)#

Per cataloghi grandi, o per campagne che vengono eseguite settimanalmente e necessitano lo stesso processo automatizzato, il percorso API è quello giusto. Due implementazioni comuni: Apps Script (nessun tooling locale richiesto, gira nel browser) e Python (migliore per team con pipeline di dati esistenti). L'endpoint è lo stesso in entrambi i casi.

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"

Il parametro on_conflict controlla cosa succede quando uno slug esiste già: skip lascia il link esistente al suo posto e registra un avviso, fail interrompe l'intero import alla prima collisione, e replace aggiorna la destinazione del link esistente. Per la maggior parte degli import di campagna, skip è il default giusto: una ri-esecuzione dello stesso CSV non sovrascriverà i link che hai già creato.

L'API accetta fino a 10.000 righe per chiamata. Per cataloghi più grandi, fai batch in pezzi di 5.000 righe; ogni chiamata è indipendente e idempotente se usi slug stabili.

Dry run pre-import#

Esegui ogni import con dry_run=true prima del commit. La risposta è identica all'import live (ogni riga mostra il suo link breve risolto, la stringa di query UTM analizzata, la lista di tag e qualsiasi avviso) ma nulla viene scritto nel database.

Le cose che dry-run cattura che non catturerai in nessun altro modo prima del lancio:

  • Uno slug nella riga 14 che collide con un link esistente nel tuo workspace (mostrato come avviso di conflitto)
  • Una colonna UTM che è stata accidentalmente lasciata vuota (Elido segnala utm_medium mancante come avviso, non come errore fatale, ma uno che vuoi conoscere prima del lancio)
  • Un target_url con uno spazio finale che è sopravvissuto alla copia dal foglio di calcolo (l'URL risolto sembra a posto nel CSV ma la destinazione effettiva ha %20 aggiunto)
  • Valori di tag che superano i 32 caratteri (silenziosamente troncati; il dry run rende visibile il valore memorizzato)

La risposta dry-run è paginata nello stesso formato di un risultato di import reale. Apri la prima pagina, controlla a campione la riga 2 (la prima riga di dati dopo la tua probabilmente perfetta riga 1) e l'ultima riga. Poi guarda eventuali righe che segnalano un avviso. Due minuti di revisione catturano gli errori che altrimenti emergerebbero come "perché questo link di campagna sta dando 404?" la mattina dopo il lancio.

Diagramma di flusso: i dati del Google Sheet passano attraverso l'anteprima dry-run che mostra UTM risolti e conflitti di slug, poi vengono committati per produrre link brevi visualizzati nella dashboard di Elido

Conflitti di slug#

I conflitti di slug accadono quando uno slug che stai cercando di importare esiste già nel tuo workspace o sul tuo dominio personalizzato. L'import li fa emergere nella risposta dry-run con il tipo di conflitto (same_workspace, same_domain, reserved) e l'URL di destinazione del link esistente.

La soluzione pratica è il namespacing. Anteponi agli slug di campagna un breve identificatore: q2-, jun26-, sm- (per social media), em- (per email). Uno slug come q2-spring-hero-a è improbabile che collida con qualcosa di una campagna precedente. I prefissi rendono anche ovvio il filtro della dashboard - tutti i link taggati q2-* appartengono a un trimestre di campagna.

Un caso che vale la pena evidenziare: se stai migrando da un altro accorciatore e vuoi preservare gli slug legacy, importali prima senza un prefisso, poi usa slug con prefisso per contenuti di nuova campagna. L'import in massa di Elido ti dirà nel dry run se uno qualsiasi degli slug legacy entra in conflitto con quelli già nel workspace.

Tassonomia dei tag#

I tag applicati al momento dell'import ottengono la stessa struttura a tre parti delle colonne del foglio che li hanno guidati: campaign:q2-spring, channel:email, variant:hero-a. Quando apri la dashboard più tardi e filtri per channel:email, non stai setacciando stringhe di testo libero - stai interrogando una tassonomia coerente.

I nomi delle dimensioni (campaign, channel, variant) vengono dalla convenzione del tuo team, non da uno schema imposto da Elido. Il vincolo è il formato: un separatore due punti, nessuno spazio nella chiave, valori sotto i 32 caratteri. I team che applicano questo nel foglio (una colonna tags che una formula costruisce come "campaign:"&E2&", channel:"&F2) non hanno mai tag malformati nella dashboard. I team che lasciano la colonna tag come testo libero hanno un problema di pulizia entro tre campagne.

Prima e dopo: i tag in testo libero producono tre varianti non corrispondibili di un'idea, mentre il formato dimensione:valore con separatore due punti filtra correttamente per canale nella dashboard

Per la panoramica della funzionalità campagne, il raggruppamento basato sui tag è il modo principale in cui Elido raggruppa i click per dimensione di campagna nel pannello di analytics - quindi la tassonomia che definisci nel foglio è la tassonomia per cui filtrerai quando fai report.

Automazione Apps Script#

Per team che eseguono la stessa struttura di campagna settimanalmente (link newsletter, link social a pagamento, varianti email), la mossa giusta è automatizzare completamente l'import. Google Apps Script gira nel browser, ha accesso ai dati del foglio e può attivarsi su un cron basato sul tempo o sull'invio di un modulo.

Il pattern: un trigger si attiva, lo script legge qualsiasi riga del foglio che non ha un valore short_link nella colonna I, fa POST all'API di import in massa e scrive i link brevi creati di nuovo nella colonna I. Sul prossimo trigger, le righe già importate vengono saltate perché la colonna I è popolata.

// 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);
  });
}

Alcune note di implementazione:

Memorizza il token API in PropertiesService.getScriptProperties(), non hardcodato nello script. La documentazione dei trigger di Apps Script (consultato il 2026-05-12) copre sia il setup di trigger time-driven che event-driven. Per un foglio di campagna che un team compila in modo collaborativo, un trigger onEdit si attiva quando la colonna A è popolata; il link breve appare nella colonna I entro secondi dalla digitazione dell'URL di destinazione.

Il flag muteHttpExceptions: true è importante. Senza di esso, un 422 dall'API lancia un'eccezione a livello di script e il trigger smette di tentare di nuovo. Con esso, ottieni il corpo dell'errore e puoi loggarlo invece.

Per un'integrazione più pesante (uno script Python, un passo CI che legge un foglio tramite l'API Sheets, o un job pianificato nella tua pipeline di dati esistente), l'endpoint spreadsheets.values.get dell'API Sheets (consultato il 2026-05-12) ti dà JSON direttamente. Da lì la forma della chiamata di import in massa è identica all'esempio curl sopra.

Errori comuni#

Spazio bianco finale negli slug. Uno slug copiato da una cella del foglio di calcolo può avere uno spazio finale invisibile nella UI. Elido lo permette (lo slug è tecnicamente valido), ma go.example.com/q2-promo con uno spazio finale è un URL brutto e la copia da clipboard da una barra di indirizzo del browser solitamente lo elimina, quindi la persona che incolla il link breve più tardi ottiene un 404. La soluzione è una formula =TRIM(H2) sulla colonna slug prima dell'esportazione.

utm_medium mancante. Elido avvisa ma non blocca su un utm_medium mancante perché alcune campagne lo saltano intenzionalmente. Ma un medium mancante è quasi sempre un errore: GA4 instrada qualsiasi cosa senza uno al canale (none), che rende l'attribuzione del canale inutile. Il riferimento canonico del costruttore URL GA4 (consultato il 2026-05-12) elenca utm_medium come richiesto perché l'attribuzione di campagna funzioni correttamente. Se il template del tuo workspace ha un default utm_medium, le celle vuote nella colonna lo ereditano; altrimenti, l'avviso dry-run è la tua ultima possibilità di catturarlo.

Valori di tag oltre i 32 caratteri. Elido tronca silenziosamente i valori di tag che superano i 32 caratteri. Il troncamento è invisibile negli avvisi dry-run a meno che non lo cerchi (la risposta mostra il valore memorizzato, non l'originale). I valori di tag lunghi solitamente vengono dall'incollare nomi di campagna UTM nella colonna tag: spring-2026-dach-email-reactivation-week3 è 42 caratteri e diventerà spring-2026-dach-email-reactivation-we nella dashboard. Mantieni brevi i valori di dimensione del tag; sposta i metadati prolissi nel titolo del link invece.

Dimenticare dry_run=true sulle ri-esecuzioni. Se ri-esegui un upload CSV contro una campagna che ha già link, on_conflict=skip è sicuro ma on_conflict=replace aggiornerà gli URL di destinazione su qualsiasi slug che appare sia nel vecchio che nel nuovo CSV. Su una campagna in cui gli URL di destinazione non sono cambiati, questo è innocuo. Su una campagna in cui hai aggiornato gli URL della landing page in corsa, è quello che vuoi. Sappi in che modalità sei prima di fare il commit.

Il riepilogo setup-to-launch#

La versione più completa di questo flusso di lavoro: costruisci il foglio una volta con nomi di colonne stabili, definisci un template UTM del workspace così le colonne UTM vuote ereditano default sensati (coperto in setup-branded-short-links), esegui l'import dry per catturare conflitti e avvisi, fai il commit e scrivi il trigger Apps Script così la prossima campagna richieda zero passi manuali.

Per il layer di attribuzione che chiude il loop dopo il click, il tracciamento server-side delle conversioni copre come cablare il click_id dalla risposta di redirect di Elido fino a Meta CAPI e GA4, il pezzo server-side che sopravvive all'ITP di Safari e all'interferenza degli ad blocker. Quel post e questo insieme ti danno un'immagine completa del flusso di lavoro di campagna solutions/marketers, dal foglio al link breve alla conversione attribuita.

L'intera superficie di gestione URL di campagna - template, import in massa, raggruppamento di campagna, inoltro delle conversioni - è sulla pagina features/campaigns.

Prova Elido

Incolla un URL, ottieni un link breve

Senza registrazione. Il link vive 30 giorni. Iscriviti per conservarlo.

Gratis, nessuna registrazione richiesta · 2 al giorno

Prova Elido

Accorciatore di URL ospitato nell'UE: domini personalizzati, analisi approfondite e API aperta. Piano gratuito - senza carta di credito.

Tag
bulk url shortener
csv import short links
sheets to short links
bulk link creation
campaign url shortener
google sheets automation

Continua a leggere