Slackはすでにチームのチャット画面を占領しているので、リンクの短縮も任せてしまいましょう。Elido Slack アプリは2つのことをします。全メンバーに /shorten スラッシュコマンドを提供し、リンクイベントアラートを指定したチャンネルにルーティングします。インストールは約90秒。webhookハンドラーのコードも、Bolt SDKも、ngrokトンネルも不要です。
この記事では3つの構成要素を説明します。スラッシュコマンドのフロー、アラートルーティングマトリクス、そしてランダムなPOSTリクエストがSlackを詐称するのを防ぐHMAC署名の仕組みです。これらのアラートを動かすwebhookの全体像を理解したい場合は、リンクイベント向けwebhookの記事でElidoが送出する各ペイロードを確認できます。Slack アプリはそれらのイベントを自動で処理するプリビルドインテグレーションの1つです。
/shorten スラッシュコマンド
任意のチャンネルでユーザーがこれを入力します。
/shorten https://blog.elido.app/post/launch-2026?utm_source=announce
Slackは署名済みPOSTを https://api.elido.app/integrations/slack/commands に送信します。ボディは application/x-www-form-urlencoded 形式です(Slackはスラッシュコマンドにはまだフォームエンコーディングを使用しており、JSONではありません。これは初めての人を必ず驚かせます)。関連するフィールドは次のとおりです。
team_id=T01ABCD2EF
channel_id=C01234ABCDE
user_id=U01HJKLMNOP
command=/shorten
text=https://blog.elido.app/post/launch-2026?utm_source=announce
response_url=https://hooks.slack.com/commands/T01ABCD2EF/...
Elidoは team_id でOAuth行を検索し、インストール先のワークスペースIDを特定し、そのワークスペースのデフォルトドメインにショートリンクを生成して、p95で200ms以内にエフェメラルメッセージを返します。デフォルトでエフェメラル応答なので、会議中に誰かがURLを短縮するたびにチャンネルがスパム状態になることはありません。
公開メッセージが必要な場合は、最後のトークンとして --public を渡します。
/shorten --public https://launch.elido.app
インストール時に必要なOAuth scopeは3つです。commands(スラッシュコマンドを呼び出せるようにする)、chat:write(コピーボタン付きのフォローアップメッセージを投稿できるようにする)、そして incoming-webhook(インストール者が選んだチャンネルにアラートを送信できるようにする)。Slackのスラッシュコマンドリファレンスに全scopeが記載されていますが、この3つでElidoが行うすべてをカバーしています。カスタムドメインも尊重されます。ワークスペースにカスタムドメイン経由で go.acme.com が設定されている場合、/shorten はそのホスト上でショートリンクを生成します。
レイテンシーバジェットについて。Slackはスラッシュコマンドに3000msの応答時間を与えます。Elidoはスラッシュコマンドハンドラーがエッジリダイレクトと同じホットパスキャッシュを使用するため、EUおよびUS edgeのPOPで180-220ms p95で応答します。チームがAPACにあり350msを超える値が見られる場合は、/docs/guides/observabilityでリージョンPOPルーティングを確認してください。
イベントトリガーによるチャンネルアラート
Slack アプリのもう一方の機能はアラートルーティングです。イベントタイプを選び、チャンネルを選ぶと通知が届きます。現在利用できる4つのイベントタイプは次のとおりです。
- broken-link: リンクスキャナーが最後にクロールした際、ターゲットが4xxまたは5xxを返した
- click-threshold: クリック数が保存済みの閾値を超えた(デフォルト:5分間のローリングウィンドウで100回)
- scan-failure: URLスキャナーがターゲットをフィッシング、マルウェア、または公開ブロックリスト掲載として判定した
- new-conversion: トラッキングされたコンバージョンが発火した(コンバージョントラッキングが必要)
ElidoがSlackに転送するアラートペイロードはBlock Kitを使用します。賑やかなチャンネルではプレーンテキストは無視されるためです。ElidoがSlackのincoming-webhook URLにPOSTする際の click-threshold アラートは次のようになります。
{
"text": "click-threshold crossed on go.acme.com/launch",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":chart_with_upwards_trend: Click threshold crossed"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Link:*\n<https://go.acme.com/launch|go.acme.com/launch>"
},
{ "type": "mrkdwn", "text": "*Window:*\n5m" },
{ "type": "mrkdwn", "text": "*Clicks:*\n412" },
{ "type": "mrkdwn", "text": "*Threshold:*\n100" }
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": { "type": "plain_text", "text": "Open dashboard" },
"url": "https://app.elido.app/links/abc123"
}
]
}
]
}
scan-failure アラートは同様の形式ですが :rotating_light: を使用し、スキャナーからの脅威カテゴリ(phishing、malware、spam、または blocklist)を含みます。broken-link アラートにはHTTPステータスコードと最後に正常だったときのタイムスタンプが含まれており、オンコール担当者が最初に確認することです。
ルーティングはワークスペースとイベントごとに設定します。30人規模のグロースチームの典型的な設定例です。
| イベント | チャンネル | 絵文字 | Ping |
|---|---|---|---|
| broken-link | #ops-alerts | :rotating_light: | @oncall |
| click-threshold | #growth | :chart_with_upwards_trend: | (なし) |
| scan-failure | #security | :rotating_light: | @sec-oncall |
| new-conversion | #wins | :tada: | (なし) |
これはSlackインテグレーションの設定パネルで構成します。各ルートはPostgresの1行です。YAMLもJSONの設定ファイルも、再デプロイも不要です。同じルーティングエンジンがLinearとPipedriveのインテグレーションも動かしているため、両方を使う場合にも同じ考え方が通用します。
アラートを複数の宛先に届けたい場合は、同じイベントを汎用のwebhookサブスクリプションにミラーして、必要な場所にJSONをルーティングします。このパターンはノーコード向けにZapier URL短縮自動化で解説しています。
HMAC検証と再インストールの落とし穴
Slackはスラッシュコマンドエンドポイントへのすべての受信リクエストに署名します。署名はSlackがバージョン、タイムスタンプ、生のリクエストボディから構成する文字列に対するHMAC SHA256です。手順はSlackのリクエスト検証ガイドに記載されています。ElidoのGoでの検証器は概ね次のようになります。
func verifySlackSignature(secret, ts, body, sig string) error {
// Reject anything older than 5 minutes to block replays.
age := time.Since(parseTs(ts))
if age > 5*time.Minute || age < -1*time.Minute {
return errReplay
}
base := fmt.Sprintf("v0:%s:%s", ts, body)
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(base))
expected := "v0=" + hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(expected), []byte(sig)) {
return errBadSig
}
return nil
}
ここでは3つの問題が起きやすく、頻度の高い順に列挙します。
1. 署名前にボディがパースされる。 HTTPフレームワークが生のボディを読む前に r.ParseForm() を呼び出すと、ボディが消えてしまい、署名が一致しなくなります。まず r.Body を読み込み、その後パースします。Elidoのスラッシュコマンドハンドラーはボディをバッファに読み込んで再パースします。これで1回のアロケーションが増えますが、1週間のデバッグを節約できます。
2. タイムスタンプの時刻ずれ。 Slackが推奨するリプレイウィンドウは5分です。サーバーの時刻がそれ以上ずれている場合(chronyなしのベアメタルでよく起こる)、すべての署名済みリクエストがリプレイに見えます。サーバーで chronyc tracking を実行して Leap status: Normal を確認してください。
3. signing secretをローテーションした状態での再インストール。 これが夜中に叩き起こされる原因です。Slackアプリのダッシュボード(Basic Information > Signing Secret > Regenerate)でsigning secretをローテーションすると、すべてのワークスペースの既存OAuth インストールが即座に署名検証に失敗し始めます。ワークスペース管理者は新しいhandshakeを得るためにアプリを再インストールしなければなりません。サイレントローテーションはありません。Slackは既存のインストールに新しいシークレットをプッシュしません。
影響範囲はディストリビューションモデルによって異なります。Slackアプリが単一ワークスペース(社内用アプリ)であれば、ローテーションは1人の管理者が90秒で行える再インストールです。アプリがSlackの公開ディレクトリに登録されており4000のワークスペースがインストールしている場合は、全員を道連れにしたことになります。ローテーションウィンドウを適切に選択し、少なくとも48時間前にchangelogで告知してください。
関連する障害パターン:同じブラウザセッションで同じSlackアプリを別のワークスペースにインストールする場合。Cookieが残っていると、Slackが誤ったチームに紐付いたトークンを返すことがあります。対処法はプライベートウィンドウを使うか、インストールURLに ?ignore_session=1 を付けることです。Elidoのインストールフロー(/dashboard/integrations/slack)は早期ベータで痛い目を見たため、すでにそのフラグを付けています。
Slackボットが適切でないケース
Slackは人間が介在するアラートに最適です。高ボリュームのプログラマティックイベントには向いていません。1分あたり約20件以上のイベントが発生すると、Slackがincoming-webhookエンドポイントをチャンネルあたり約1メッセージ/秒にレート制限し、アラートが失われます。そういったイベントはDatadogのメトリクスや生のwebhookコンシューマーにルーティングし、閾値超過のサマリーだけをSlackに転送しましょう。
Slackが不適切なもう1つのケース:コンプライアンス監査証跡です。Slackメッセージは可変で(編集・削除できる)、保持ポリシーはワークスペースが管理します。監査人が誰がいつどのリンクを短縮したかの不変ログを必要とする場合は、スラッシュコマンドイベントをClickHouseエクスポートでデータウェアハウスに送り、Slackは通知レイヤーとしてのみ扱ってください。
キャンペーンのクリックアラートをルーティングするグロースチームにとって、Slackボットは/solutions/marketersで求められることの95%をカバーします。API + SDKを活用するプラットフォームチームにとっては、fan-outできる複数の出力先の1つです。
料金と制限
Slackインテグレーションは無料プランを含む全プランで利用できます。メッセージごとの課金はありません。制限はショートリンクとクリック数自体にあり、料金ページで確認できます。各ワークスペースは最大32のルーティングルール(イベントタイプとチャンネルの組み合わせ)を設定できます。これは私が話したどのチームも実際には使い切っていない数です。
セルフホストのElido環境でも動作します。SlackアプリのリクエストURLを自社ドメインに向け、api-coreの環境変数にsigning secretを設定すれば、他はすべて同じです。セルフホストドキュメントが環境変数を説明しており、可観測性ガイドがメトリクス名を説明しているため、GrafanaやDatadogでスラッシュコマンドのレイテンシーとアラート配信成功率をグラフ化できます。
次にすること
Elidoをすでに使っている場合は、/dashboard/integrations/slack を開き、「接続」をクリックして、各イベントタイプのデフォルトチャンネルを選んで始めましょう。インストールは本当に90秒で完了します。評価中の場合は、インテグレーションカタログで各コネクタと対応するプランを確認でき、Bitlyとの比較でSlackの機能が既存サービスとどう違うかを確認できます(ネタバレ:Bitlyにはスラッシュコマンドがありません)。
独自のボットを構築している場合は、上記のHMACパターンをコピーし、3000msの時計制限を守ってください。Slackのスラッシュコマンドのユーザー体験は遅いものを容赦なく罰します。速く感じるボットこそが、人々がインストールする理由の半分です。
よくある質問
Elido Slack URL短縮ボットのインストール方法を教えてください。
ElodoのSlackアプリをインストールし、/shortenスラッシュコマンドを使って、webhookハンドラーを書かずに任意のチャンネルへ閾値アラートをルーティングしましょう。Elido内で /dashboard/integrations/slack を開き、「接続」をクリックします。SlackのOAuth画面にリダイレクトされるので、ワークスペースを選んでscope(commands、chat:write、incoming-webhook)を承認すると、約90秒でElidoに戻ります。インストールはteam_idをキーにしたトークン行を書き込むため、各ワークスペースは独自の認証情報を持ちます。
/shortenはプライベートチャンネルやDMでも機能しますか?
はい。スラッシュコマンドはユーザーが入力したチャンネル(プライベートチャンネルやDMを含む)で実行されます。これはSlackが署名済みペイロード内にchannel_idを渡すためです。Elidoは呼び出し元にのみ見えるエフェメラルメッセージで応答するため、一時的な短縮作業でチャンネルが騒がしくなりません。
SlackのアラートペイロードはどのようにSINGされますか?
ElidoからSlackへの送信アラートはSlackのincoming-webhook URLを使用します。このURLはチャンネルに紐付いたbearerスタイルのシークレットです。SlackからElidoへの受信スラッシュコマンドは、Slackのsigning-secretの手順に従い、生のリクエストボディとX-Slack-Request-Timestampヘッダーに対してHMAC SHA256で検証されます。
OAuthアプリを再インストールするとSlackボットはどうなりますか?
再インストールすると新しいボットトークンが発行され、古いトークンは無効になります。signing secretはSlackアプリのダッシュボードで再生成した場合にのみローテーションされます。その場合、配布先の全ワークスペースが再インストールする必要があります。ローテーションはトラフィックの少ない時間帯に計画し、#opsで事前に告知してください。
Slackチャンネルにルーティングできるアラートの種類は何ですか?
現在、4種類のイベントタイプが提供されています。broken-link(ショートリンク先で4xxまたは5xxが検出された)、click-threshold(5分間のウィンドウで保存済みの閾値を超えた)、scan-failure(URLスキャナーが対象をフィッシングまたはマルウェアと判定した)、new-conversion(トラッキングされたコンバージョンが発火した)です。各アラートは異なるチャンネルをターゲットにできます。
Elidoを試す
URLを貼り付けて短縮リンクを取得
登録不要。リンクは30日間有効。永久に保存するには登録してください。
Free、登録不要 · 1日あたり2件