AIエージェントの観測
GPTBotからClaudeBot、PerplexityBotまで、AIクローラーは毎日あなたのサイトを読み取っていますが、ほとんどのサイト運営者はそれに気づいていません。観測モードはSilentShieldのAIエージェントコントロールのステージ1です: どのAIサービスがどのページを訪れたかを記録します — 何もブロックせず、サイトの動作も一切変えません。
可視化はコントロールに先立ちます。誰がコンテンツを読んでいるかを知って初めて、誰を許可し、制限し、ブロックするかを適切に判断できます。そのため、記録された訪問はすべて次の3つのカテゴリのいずれかに分類されます:
- 学習
- クローラーがあなたのコンテンツを収集し、将来のAIモデルの学習に利用します(例: GPTBot、ClaudeBot、CCBot)。
- AI検索
- サービスがユーザーの質問に答えるためにページを読み取り、その際にあなたのサイトを情報源として引用することがあります(例: OAI-SearchBot、PerplexityBot)。
- エージェント
- ボットが特定のユーザーの代理としてリアルタイムに行動します。例えば商品を調べたり、サイト上のフォームに入力したりします(例: ChatGPT-User、Claude-User)。
プラットフォーム別の設定
WordPress
組み込みオブザーバーは、SilentShieldプラグインの今後のアップデートで提供されます。それまでは、小さなmust-useプラグインで観測を有効にできます — ファイル1つ、設定不要:
wp-content/mu-plugins/silentshield-observer.php というファイルを以下の内容で作成してください(mu-pluginは自動的に読み込まれます。無効にするにはファイルを削除):
<?php
/**
* Plugin Name: SilentShield — AI Agent Observer
* Description: Reports AI crawler visits to SilentShield (fire-and-forget;
* IP/UA are hashed server-side, GDPR). Delete this file to disable.
*
* Install: save this file as wp-content/mu-plugins/silentshield-observer.php
* (mu-plugins load automatically — no activation needed). To force it off
* without deleting: define('SILENTSHIELD_OBSERVER', false) in wp-config.php.
* An upcoming SilentShield plugin update will build this in.
*/
if (!defined('ABSPATH')) exit;
if (defined('SILENTSHIELD_OBSERVER') && !SILENTSHIELD_OBSERVER) return;
const SS_OBSERVE_URL = "https://api.silentshield.io/api/v1/agent/telemetry";
const SS_API_KEY = "YOUR_API_KEY"; // publishable site key
// For the always-fresh list, cache https://api.silentshield.io/api/v1/agent/bot-directory daily.
$ss_bots = ["GPTBot","OAI-SearchBot","ChatGPT-User","ClaudeBot","Claude-User",
"PerplexityBot","Perplexity-User","Bingbot","Applebot","Amazonbot","CCBot",
"Bytespider","meta-externalagent","Google-Agent"];
register_shutdown_function(function () use ($ss_bots) {
$ua = $_SERVER["HTTP_USER_AGENT"] ?? "";
$signed = !empty($_SERVER["HTTP_SIGNATURE"]);
$isBot = $signed;
foreach ($ss_bots as $b) { if (stripos($ua, $b) !== false) { $isBot = true; break; } }
if (!$isBot) return;
if (function_exists("fastcgi_finish_request")) { fastcgi_finish_request(); }
wp_remote_post(SS_OBSERVE_URL, [
"timeout" => 3,
"blocking" => false,
"headers" => ["Content-Type" => "application/json", "x-api-key" => SS_API_KEY],
"body" => wp_json_encode(["sightings" => [[
"ua" => $ua,
"ip" => $_SERVER["REMOTE_ADDR"] ?? "",
"path" => strtok($_SERVER["REQUEST_URI"] ?? "/", "?"),
"method" => $_SERVER["REQUEST_METHOD"] ?? "GET",
]]]),
]);
});Next.js
自己完結型のミドルウェアです — SDK不要。観測はevent.waitUntil()によりレスポンス経路の外で実行されるため、ページが遅延することはありません:
// middleware.ts — self-contained observer, no SDK required.
// Sightings are reported via event.waitUntil(), off the response path,
// so your pages never wait. Best-effort and fail-open by design.
import { NextResponse, type NextRequest } from "next/server";
const OBSERVE_URL = "https://api.silentshield.io/api/v1/agent/telemetry";
const API_KEY = "YOUR_API_KEY"; // publishable site key
// Known AI-agent UA tokens. For the always-fresh list, fetch
// https://api.silentshield.io/api/v1/agent/bot-directory once a day and cache it.
const BOTS = ["GPTBot", "OAI-SearchBot", "ChatGPT-User", "ClaudeBot", "Claude-User",
"PerplexityBot", "Perplexity-User", "Bingbot", "Applebot", "Amazonbot", "CCBot",
"Bytespider", "meta-externalagent", "Google-Agent"];
export function middleware(req: NextRequest, event: { waitUntil(p: Promise<unknown>): void }) {
const ua = req.headers.get("user-agent") ?? "";
const signed = !!req.headers.get("signature");
if (signed || BOTS.some((b) => ua.toLowerCase().includes(b.toLowerCase()))) {
const sighting = {
ua,
path: req.nextUrl.pathname,
method: req.method,
ip: req.headers.get("x-forwarded-for")?.split(",")[0]?.trim(),
...(signed && {
signature: req.headers.get("signature"),
signature_input: req.headers.get("signature-input"),
signature_agent: req.headers.get("signature-agent"),
authority: req.nextUrl.host,
scheme: req.nextUrl.protocol.replace(":", ""),
}),
};
event.waitUntil(
fetch(OBSERVE_URL, {
method: "POST",
headers: { "Content-Type": "application/json", "x-api-key": API_KEY },
body: JSON.stringify({ sightings: [sighting] }),
}).catch(() => {}) // best-effort, fail-open
);
}
return NextResponse.next();
}Node.js (Express)
Express(または他のNodeサーバー)では、fire-and-forget型のミドルウェアを追加します。User-Agentが既知のAIエージェントに一致するリクエスト、またはWeb Bot Auth署名を持つリクエストのみを報告し、レスポンスをブロックすることはありません:
import express from "express";
const app = express();
const OBSERVE_URL = "https://api.silentshield.io/api/v1/agent/telemetry";
const API_KEY = "YOUR_API_KEY";
// Known AI-agent UA tokens. For the always-fresh list, fetch
// https://api.silentshield.io/api/v1/agent/bot-directory once a day and cache it.
const BOTS = ["GPTBot", "OAI-SearchBot", "ChatGPT-User", "ClaudeBot", "Claude-User",
"PerplexityBot", "Perplexity-User", "Bingbot", "Applebot", "Amazonbot", "CCBot",
"Bytespider", "meta-externalagent", "Google-Agent"];
// Fire-and-forget observer — never blocks the response.
app.use((req, res, next) => {
const ua = req.headers["user-agent"] || "";
const signed = !!req.headers["signature"];
if (signed || BOTS.some((b) => ua.toLowerCase().includes(b.toLowerCase()))) {
const sighting = {
ua, ip: req.ip, path: req.path, method: req.method,
...(signed && {
signature: req.headers["signature"],
signature_input: req.headers["signature-input"],
signature_agent: req.headers["signature-agent"],
authority: req.headers["host"], scheme: req.protocol,
}),
};
fetch(OBSERVE_URL, {
method: "POST",
headers: { "Content-Type": "application/json", "x-api-key": API_KEY },
body: JSON.stringify({ sightings: [sighting] }),
}).catch(() => {}); // best-effort, fail-open
}
next();
});PHP
素のPHPでは、フロントコントローラーの先頭にこのオブザーバーを組み込みます。レスポンスの配信後(fastcgi_finish_request)に訪問記録を送信するため、ページが遅くなることはありません:
<?php
// Drop-in observer: include at the very top of your front controller.
// It runs after the response is sent (fastcgi_finish_request) so it never
// slows down the page. Reuses the same publishable key.
const SS_OBSERVE_URL = "https://api.silentshield.io/api/v1/agent/telemetry";
const SS_API_KEY = "YOUR_API_KEY";
// For the always-fresh list, cache https://api.silentshield.io/api/v1/agent/bot-directory daily.
$ss_bots = ["GPTBot","OAI-SearchBot","ChatGPT-User","ClaudeBot","Claude-User",
"PerplexityBot","Perplexity-User","Bingbot","Applebot","Amazonbot","CCBot",
"Bytespider","meta-externalagent","Google-Agent"];
register_shutdown_function(function () use ($ss_bots) {
$ua = $_SERVER["HTTP_USER_AGENT"] ?? "";
$signed = !empty($_SERVER["HTTP_SIGNATURE"]);
$isBot = $signed;
foreach ($ss_bots as $b) { if (stripos($ua, $b) !== false) { $isBot = true; break; } }
if (!$isBot) return;
if (function_exists("fastcgi_finish_request")) { fastcgi_finish_request(); }
$sighting = [
"ua" => $ua,
"ip" => $_SERVER["REMOTE_ADDR"] ?? "",
"path" => strtok($_SERVER["REQUEST_URI"] ?? "/", "?"),
"method" => $_SERVER["REQUEST_METHOD"] ?? "GET",
];
$ch = curl_init(SS_OBSERVE_URL);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 3,
CURLOPT_HTTPHEADER => ["Content-Type: application/json", "x-api-key: " . SS_API_KEY],
CURLOPT_POSTFIELDS => json_encode(["sightings" => [$sighting]]),
]);
curl_exec($ch); // best-effort, fail-open
curl_close($ch);
});Go
数行で完結する自己完結型オブザーバーです — 標準ライブラリのみ、SDK不要。サイティングはfire-and-forgetで送信されるため、リクエストが遅くなることはありません:
// Self-contained observer — stdlib only, no SDK required.
// Reports AI-agent sightings fire-and-forget: never blocks a request,
// fail-open on any error. For the always-fresh bot list, cache
// https://api.silentshield.io/api/v1/agent/bot-directory daily.
const observeURL = "https://api.silentshield.io/api/v1/agent/telemetry"
const siteKey = "YOUR_API_KEY" // publishable — or os.Getenv("SILENTSHIELD_SITE_KEY")
var bots = []string{"GPTBot", "OAI-SearchBot", "ChatGPT-User", "ClaudeBot",
"Claude-User", "PerplexityBot", "Perplexity-User", "Bingbot", "Applebot",
"Amazonbot", "CCBot", "Bytespider", "meta-externalagent", "Google-Agent"}
func observe(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ua, signed := r.UserAgent(), r.Header.Get("Signature") != ""
hit := signed
for _, b := range bots {
if strings.Contains(strings.ToLower(ua), strings.ToLower(b)) {
hit = true
break
}
}
if hit {
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
s := map[string]any{"ua": ua, "ip": ip, "path": r.URL.Path, "method": r.Method}
if signed { // Web Bot Auth (RFC 9421) — forward for verification
s["signature"] = r.Header.Get("Signature")
s["signature_input"] = r.Header.Get("Signature-Input")
s["signature_agent"] = r.Header.Get("Signature-Agent")
s["authority"] = r.Host
}
body, _ := json.Marshal(map[string]any{"sightings": []any{s}})
go func() { // best-effort, fail-open
req, _ := http.NewRequest("POST", observeURL, bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-api-key", siteKey)
if resp, err := (&http.Client{Timeout: 3 * time.Second}).Do(req); err == nil {
resp.Body.Close()
}
}()
}
next.ServeHTTP(w, r)
})
}
// net/http: http.ListenAndServe(":8080", observe(mux))
// Gin: srv := &http.Server{Addr: ":8080", Handler: observe(r)}
// srv.ListenAndServe()接続のテスト
統合が機能しているかを確認するために、最初の本物のAIクローラーを待つ必要はありません。空のバッチを送信すれば、偽の訪問記録を書き込むことなく、キーのハートビートが登録されます:
curl -X POST https://api.silentshield.io/api/v1/agent/telemetry \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
--data '{"sightings":[]}'その後、APIキーのエージェントハブ(APIキー → キーを選択 → エージェント)が「未接続」から「接続済み — 受信待機中」に切り替わります。本物のエージェントが訪れるまでレポートは空のままです: SilentShieldがデータを捏造することはありません。
GDPR
観測は正当な利益(GDPR第6条1項f号)に基づいています。IPアドレスはサーバーサイドで、毎日ローテーションするソルトを用いてハッシュ化されます — 生のIPが保存されることはありません。訪問記録は14日間保持され、そもそも既知のAIエージェントからのリクエストのみが保存対象です: 通常の訪問者のトラフィックが記録されることはありません。
FAQ
サイトが遅くなりませんか?
いいえ。すべての統合はfire-and-forget方式です: Next.jsはevent.waitUntil()を使用し、PHPはレスポンス配信後にのみ報告し、NodeとGoはバックグラウンドで送信します。万一SilentShield APIに到達できない場合でも、サイトには影響しません — すべてフェイルオープンで動作します。
何がAIエージェントとしてカウントされますか?
SilentShieldの既知のAIクローラー・エージェントのボットディレクトリ(GPTBot、ClaudeBot、PerplexityBotなど)に一致するリクエスト、またはWeb Bot Auth署名を持つリクエストのみです。常に最新のリストはhttps://api.silentshield.io/api/v1/agent/bot-directoryで確認できます。
なぜまだデータが表示されないのですか?
AIクローラーは独自のスケジュールで訪れます。ほとんどのサイトでは最初の訪問が24〜72時間以内に記録されますが、小規模なサイトではもっと時間がかかることもあります。その間も、エージェントハブのハートビートで統合自体が機能していることを確認できます。