キャンペーンのローンチはダッシュボードから始まりません。Slackで共有されたスプレッドシートから始まります。URLはA列にあり、UTMメタデータはB列からG列を埋め、スラッグはH列にあり、ブリーフには明日がローンチだと書いてあります。プロセス全体で最も遅い部分は、各行をショートナーのUIに1リンクずつコピーすることです - 技術的に難しいことは何もないのですが、そのようにする理由がないにも関わらずです。
この記事はダイレクトなワークフローです:シートの見た目、ElidoのAPIの一括インポートエンドポイントへのマッピング、行数によって異なる3つのインポートパス、本番環境に入る前にミスを捕捉するドライランステップ、そして全体をトリガーで自動化するApps Scriptスニペット。エンドツーエンドのUTM管理の広いコンテキストについては、UTMトラッキングのコーナーストーンでワークスペーステンプレートとサーバーサイドコンバージョン転送を詳しく説明しています。この記事はそのパイプラインのシートからショートリンクへの部分を扱います。
まとめ#
- キャンペーンごとに1つのシートを保持します:
target_url、slug、utm_source、utm_medium、utm_campaign、tagsを名前付き列として使用。空白のUTM列はワークスペーステンプレートから補完されます。 - 3つのインポートパス:UIに行を貼り付け(最大1,000行)、CSVアップロード(最大10,000行)、またはスクリプト経由でAPI(無制限、繰り返し実行可能)。
- 常に最初に
dry_run=trueで実行してください。プレビューには、何もコミットせずに解決済みのショートリンクと完全にレンダリングされたUTMクエリ文字列が表示されます。 - キャンペーンスラッグにプレフィックスを付けます(
q2-、jun-)。衝突はドライランで表面化されます。インポートの途中ではありません。
シートの構成#
必須の列はtarget_urlとslugまたはauto_slugのいずれかです。それ以外はすべてオプションですが、存在する場合に定義された解釈があります。
| 列 | 必須 | 備考 |
|---|---|---|
target_url | はい | スキームを含む完全な遷移先URL |
slug | 2つのうち1つ | 推奨 - 予測可能なショートURLが得られます |
auto_slug | 2つのうち1つ | trueに設定するとElidoがスラッグを生成 |
utm_source | オプション | ワークスペーステンプレートの値を上書き |
utm_medium | オプション | ワークスペーステンプレートの値を上書き |
utm_campaign | オプション | ワークスペーステンプレートの値を上書き |
utm_content | オプション | 通常はクリエイティブバリアント |
utm_term | オプション | 有料キーワードまたはオーディエンスセグメント |
tags | オプション | カンマ区切り、リンクに適用 |
title | オプション | ダッシュボードのリンクリストに表示 |
UTMルールはシンプルです:target_urlにすでに?utm_source=(または任意のutm_*)クエリパラメータが含まれている場合、それらの値はそのまま渡されます。上書きも、マージもありません。遷移先URLにUTMパラメータがない場合、ElidoはUTM列からそれらを構築し、空白の列に対してはワークスペーステンプレートにフォールバックします。これは実際には重要です - 一部のチームはメールサービスプロバイダー向けの事前タグ付き遷移先URLを保持しており、それらをサイレントに再タグする一括インポートツールは壊れたアナリティクスを生成します。Elidoは混合モードの行(一部のUTMが存在し、一部が欠落している)に警告を出し、確認を求めます。
タグ列には独自のメモが必要です。値はカンマ区切りの文字列です:campaign:q2-spring, channel:paid-social, variant:hero-a。この3パートの形式(次元:値)は、別途タクソノミー設定なしにダッシュボードでフィルタリング可能な軸を提供します。これについては下のタグタクソノミーセクションで詳しく説明します。
3つのインポートパス#
UIにデータを貼り付け(最大1,000行)#
1,000行未満の場合、最速のパスはシートの範囲をコピーして一括インポートテキストエリアに貼り付けることです。ElidoのUIはスプレッドシートの貼り付けからタブ区切り値を自動検出し、ヘッダーで列をマッピングします。CSVをエクスポートする必要はありません。貼り付けるだけです。
これは最も一般的なケースに適しています:Sheetsにすでに存在するキャンペーンブリーフ、1時間後のローンチ期限、そしてスクリプトへの熱意がない場合。UIはコミット前にすべての行のプレビューを表示し(APIから取得するのと同じドライラン)、続行前に失敗した行をインラインで修正できます。
1つの注意点:シートに結合セルや複雑な書式がある場合、貼り付けで文字化けが発生することがあります。非自明な構造のシートのための安全策は、まずクリーンなシートにコピーし(値として貼り付け)、その後クリーンな範囲をインポートUIに貼り付けることです。
CSVアップロード(最大10,000行)#
1,000行を超えるローンチ(大規模なカタログキャンペーン、イベントコード、パーソナライズされたリンク)の場合、CSVアップロードパスは最大10,000行を処理します。シートをCSVとしてエクスポートし(ファイル > ダウンロード > CSV)、インポートダイアログでアップロードします。列ヘッダーのマッピングは同じです。大きなアップロードは非同期で処理され、Webhookまたはポーリングエンドポイントでステータスを報告します。
Google SheetsのAPI経由のCSVエクスポート(2026-05-12参照)はシート全体ではなく名前付き範囲のエクスポートをサポートしており、キャンペーンシートに複数のタブや手動でクリーンアップしたくないヘッダー行がある場合に便利です。
スクリプトからのAPI呼び出し(10,000行超、または繰り返し実行の場合)#
大規模なカタログや、毎週同じプロセスを自動化する必要があるキャンペーンには、APIパスが正しい選択です。2つの一般的な実装:Apps Script(ローカルツール不要、ブラウザで動作)とPython(既存のデータパイプラインがあるチームに適しています)。エンドポイントはどちらでも同じです。
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"
on_conflictパラメータは、スラッグがすでに存在する場合に何が起きるかを制御します:skipは既存のリンクをそのままにして警告を記録し、failは最初の衝突でインポート全体を中止し、replaceは既存のリンクの遷移先を更新します。ほとんどのキャンペーンインポートでは、skipが正しいデフォルトです。同じCSVを再実行してもすでに作成したリンクを上書きしません。
APIは呼び出しごとに最大10,000行を受け付けます。大規模なカタログの場合は5,000行のチャンクでバッチ処理してください。安定したスラッグを使用すれば各呼び出しは独立してべき等です。
インポート前のドライラン#
コミット前に必ずdry_run=trueでインポートを実行してください。レスポンスはライブインポートと同一です(すべての行に解決済みのショートリンク、解析されたUTMクエリ文字列、タグリスト、および警告が表示されます)が、データベースには何も書き込まれません。
ドライランがローンチ前に他の方法では捕捉できないものを発見します:
- ワークスペースの既存のリンクと衝突する14行目のスラッグ(衝突警告として表面化)
- 誤って空白のままになったUTM列(Elidoは
utm_mediumが欠落していることをハードエラーではなく警告としてフラグしますが、ローンチ前に知りたいことです) - スプレッドシートのコピーで生き残った末尾にスペースがある
target_url(CSVでは解決済みのURLが問題なく見えますが、実際の遷移先には%20が追加されています) - 32文字を超えるタグ値(サイレントに切り捨てられます。ドライランで保存済みの値が表示されます)
ドライランのレスポンスは実際のインポート結果と同じ形式でページネーションされます。最初のページを開き、2行目(おそらく完璧な1行目の後の最初のデータ行)と最後の行をスポットチェックします。次に警告をフラグした行を確認します。2分間のレビューで、「このキャンペーンリンクがローンチ翌朝に404になっているのはなぜか?」として表面化するミスを捕捉できます。
スラッグの衝突#
スラッグの衝突は、インポートしようとしているスラッグがワークスペースまたはカスタムドメインにすでに存在している場合に発生します。インポートはドライランのレスポンスで衝突タイプ(same_workspace、same_domain、reserved)と既存リンクの遷移先URLと共にそれらを表面化します。
実用的な修正は名前空間です。キャンペーンスラッグに短い識別子をプレフィックスとして付けます:q2-、jun26-、sm-(ソーシャルメディア用)、em-(メール用)。q2-spring-hero-aのようなスラッグは以前のキャンペーンのものと衝突する可能性は低いです。プレフィックスはダッシュボードのフィルターも明確にします - q2-*とタグ付けされたすべてのリンクは1つのキャンペーン四半期に属します。
特筆する価値のある1つのケース:別のショートナーから移行して旧来のスラッグを保持したい場合は、まずプレフィックスなしでそれらをインポートし、その後新しいキャンペーンコンテンツにはプレフィックス付きのスラッグを使用します。Elidoの一括インポートはドライランで旧来のスラッグがワークスペースにすでに存在するものと衝突するかどうかを教えてくれます。
タグタクソノミー#
インポート時に適用されたタグは、それらを駆動したシート列と同じ3パートの構造を持ちます:campaign:q2-spring、channel:email、variant:hero-a。後でダッシュボードを開いてchannel:emailでフィルタリングするとき、フリーテキスト文字列を仕分けているのではなく、一貫したタクソノミーをクエリしています。
次元名(campaign、channel、variant)は、Elidoが強制するスキーマではなく、チームの規約から来ます。制約は形式です:コロンセパレータ、キーにスペースなし、32文字未満の値。シートでこれを強制するチーム(列tagsでフォーミュラが"campaign:"&E2&", channel:"&F2として構築)のダッシュボードには不正なタグが発生しません。タグ列をフリーテキストにするチームは3つのキャンペーン以内にクリーンアップの問題を抱えます。
キャンペーン機能の概要では、タグベースのグループ化がElidoがアナリティクスパネルでキャンペーン次元でクリックをグループ化する主な方法です - シートで定義するタクソノミーはレポート時にフィルタリングするタクソノミーです。
Apps Scriptの自動化#
毎週同じキャンペーン構造(ニュースレターリンク、有料ソーシャルリンク、メールバリアント)を実行するチームにとって、正しいアプローチはインポートを完全に自動化することです。Google Apps Scriptはブラウザーで動作し、シートデータにアクセスでき、時間ベースまたはフォーム送信のcronでトリガーできます。
パターン:トリガーが起動し、スクリプトはI列にshort_linkの値がないシート行を読み取り、一括インポートAPIにPOSTし、作成されたショートリンクをI列に書き戻します。次のトリガーでは、I列が入力されているため、すでにインポートされた行はスキップされます。
// Google Apps Script - Elido APIを通じて新しい行を一括インポート
// トリガー:時間駆動、毎時(またはフォーム送信時)
// Docs: https://developers.google.com/apps-script/guides/triggers (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"); // ここに書き戻す
const newRows = [];
const rowIndexes = [];
for (let i = 1; i < data.length; i++) {
const row = data[i];
if (!row[urlCol] || row[doneCol]) continue; // 空またはすでにインポートされた行をスキップ
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 || [];
// ショートリンクを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);
});
}
いくつかの実装上の注意事項:
APIトークンをスクリプトにハードコードするのではなく、PropertiesService.getScriptProperties()に保存してください。Apps Scriptトリガーのドキュメント(2026-05-12参照)では、時間駆動とイベント駆動の両方のトリガー設定が説明されています。チームが共同で入力するキャンペーンシートの場合、A列が入力されたときにonEditトリガーが起動します。遷移先URLを入力して数秒以内にI列にショートリンクが表示されます。
muteHttpExceptions: trueフラグは重要です。これがなければ、APIからの422がスクリプトレベルの例外をスローし、トリガーがリトライを停止します。これがあれば、エラー本文を取得して代わりにログに記録できます。
より重い統合(Pythonスクリプト、Sheets APIを通じてシートを読み取るCIステップ、または既存のデータパイプラインのスケジュールされたジョブ)の場合、Sheets APIのspreadsheets.values.getエンドポイント(2026-05-12参照)はJSONを直接提供します。そこから一括インポート呼び出しの形式は上記のcurlの例と同じです。
よくあるミス#
スラッグの末尾の空白。 スプレッドシートのセルからコピーされたスラッグには末尾のスペースがあり、UIでは見えないことがあります。Elidoは技術的には有効なスラッグとして許可しますが、go.example.com/q2-promo という末尾にスペースがあるURLは見た目が悪く、ブラウザのアドレスバーからのクリップボードコピーは通常それを取り除くため、後でショートリンクを貼り付けた人は404を受け取ります。修正はエクスポート前にスラッグ列に=TRIM(H2)フォーミュラを使うことです。
utm_mediumの欠落。 Elidoはutm_mediumが欠落している場合に警告しますが、一部のキャンペーンが意図的にそれをスキップするためブロックはしません。しかし欠落したmediumはほぼ常にミスです:GA4はそれがないものを(none)チャネルにルーティングし、チャネルアトリビューションが役に立たなくなります。GA4 URLビルダーの標準的な参照(2026-05-12参照)ではutm_mediumがキャンペーンアトリビューションが正しく機能するための必須として記載されています。ワークスペーステンプレートにデフォルトのutm_mediumがある場合、列の空白セルはそれを継承します。ない場合、ドライランの警告が最後のチャンスです。
32文字を超えるタグ値。 Elidoは32文字を超えるタグ値をサイレントに切り捨てます。切り捨ては、元の値ではなく保存された値を表示するため、注意して確認しないとドライランの警告には表示されません。長いタグ値は通常、UTMキャンペーン名をタグ列に貼り付けることで発生します:spring-2026-dach-email-reactivation-week3は42文字で、ダッシュボードではspring-2026-dach-email-reactivation-weになります。タグの次元値は短く保ってください。詳細なメタデータはリンクのタイトルに移してください。
再実行時にdry_run=trueを忘れる。 すでにリンクがあるキャンペーンに対してCSVアップロードを再実行する場合、on_conflict=skipは安全ですがon_conflict=replaceは古いCSVと新しいCSVの両方に現れるスラッグの遷移先URLを更新します。遷移先URLが変更されていないキャンペーンでは無害です。フライト中にランディングページのURLを更新したキャンペーンでは、それが望む動作です。コミット前にどのモードにいるかを把握してください。
セットアップからローンチまでのまとめ#
このワークフローの最も完全なバージョン:安定した列名で一度シートを構築し、空白のUTM列が適切なデフォルトを継承するようにワークスペースのUTMテンプレートを定義し(setup-branded-short-linksで説明)、ドライインポートを実行して衝突と警告を捕捉し、コミットし、次のキャンペーンでは手動のステップがゼロになるようApps Scriptトリガーを設定します。
クリック後にループを閉じるアトリビューション層については、サーバーサイドコンバージョントラッキングでElidoのリダイレクトレスポンスのclick_idをMeta CAPIとGA4に接続する方法、Safari ITPと広告ブロッカーの干渉を乗り越えるサーバーサイドの部分を説明しています。その記事とこの記事を合わせると、solutions/marketersのキャンペーンワークフロー - シートからショートリンク、そしてアトリビュートされたコンバージョンまで - の完全な全体像が得られます。
テンプレート、一括インポート、キャンペーングループ化、コンバージョン転送を含む完全なキャンペーンURL管理サーフェスは、features/campaignsページにあります。
Elidoを試す
URLを貼り付けて短縮リンクを取得
登録不要。リンクは30日間有効。永久に保存するには登録してください。
Free、登録不要 · 1日あたり2件