リサーチ
1つの検索クエリをSEOコンテンツブリーフに変える
いまそのクエリに答えているページを確認し、Markdown で読み、答えている問いと抜けている問いを整理し、ライターがそのまま構成に使えるブリーフを書きます。
プロンプトをコピー
角括弧の項目を置き換えて、Claude Code、Codex、ターミナルにアクセスできる AI に貼り付けてください。Felo スキルをインストールし、クレジットを使う前に確認し、ワークフローを実行します。
[製品またはサイト] のための、クエリ [対象クエリ] の SEO コンテンツブリーフを書いてください。 読者: [読者]。市場と言語: [地域]、[言語]。切り口: [ガイド / 比較 / 製品ページ]。この分析が支える意思決定: [新規記事 / リフレッシュ / ギャップ埋め]。 アウトラインを作る前に、現在このクエリに答えているページを読んでください。Markdown のブリーフに以下を含めてください。 1. 対象クエリと、あなたが推測した検索意図。その読みの根拠も添えてください。 2. 現在のページが扱っている内容: タイトル、URL、冒頭のセクション。 3. 現在のページが答えている質問と、見落としている質問。 4. 提案するアウトライン。各セクションが何を証明すべきかを1行で書いてください。 5. 出典からの証拠と例(リンク付き)。 6. 出典の完全な一覧。 ルール: - 検索ボリューム、キーワード難易度、順位、トラフィックを主張しないでください。このワークフローはそれらを測定しません。数値の代わりに「ここでは未測定」と書いてください。 - 統計、引用、競合コンテンツに関する主張を捏造しないでください。 - 検索意図はページを読んだ解釈として説明し、測定された事実としては書かないでください。 - 引用は短くし、出典とリンクを付けてください。 - 地域と言語を明示的な値に解決してください。 - クレジットを消費する前に、実行予定の API 呼び出しを示して私の承認を待ってください。 - 公開、予約、送信はしないでください。 - 結果を ./seo-brief.md に書き、チャットで要約してください。
コピー内容にはインストール手順と安全ルールも含まれます。
完成するもの
実行時の出力例です。リアルタイム生成ではありません。
SEO ブリーフ — 「サポートトリアージを自動化する方法」
対象クエリと意図
クエリ:「サポートトリアージを自動化する方法」。返ってきたページは製品ページではなく実装手順で始まるため、意図はハウツーと読める。これはページの読みであり、測定された意図ラベルではない。
現在のページのカバー範囲
| ページ | URL | 冒頭 |
|---|---|---|
| サポートトリアージの自動化: 実践ガイド | https://example.com/guide | ルーティングルール、次にタグ |
| トリアージ自動化チェックリスト | https://example.com/checklist | チェックリスト自体 |
ページが答える質問
- トリアージ自動化で何が変わるか
- どのルーティングルールから始めるか
ページが見落とす質問
- トリアージが実際に改善したかをどう測るか
- 分類器が間違えたときどうするか
提案する構成
- トリアージ自動化で何が変わるか — 人数ではなくキューの話だと証明する。
- 最初に自動化する価値のある3つのルーティングルール — それぞれ実例で証明する。
- 最初の1か月でどう測るか — 運用責任者が取得できる指標で証明する。
- 自動化が間違えるとき — 人間のフォールバック経路を証明する。
証拠
- ルーティングルールの例。https://example.com/guide から引用(2026-10-30 確認)
ここでは測定していない
検索ボリューム、キーワード難易度、順位。このワークフローは公開ページを読むだけで、検索インデックスや順位トラッカーには問い合わせない。
出典
- https://example.com/guide
- https://example.com/checklist
実際の呼び出し
開発者向け:同じワークフローを実行順に並べたコピー可能なコード。
実際の API 呼び出しを表示
いま誰が答えているかを見る
Chat でクエリを聞き、回答と引用ページを取得します。そのページが現在の競合コンテンツです。
seo-brief.ts const BASE = "https://openapi.felo.ai"; const headers = { Authorization: `Bearer ${process.env.FELO_API_KEY}`, "Content-Type": "application/json", }; async function felo<T>(path: string, body?: unknown): Promise<T> { const res = await fetch(`${BASE}${path}`, { method: body ? "POST" : "GET", headers, body: body ? JSON.stringify(body) : undefined, }); if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`); return res.json() as Promise<T>; } type ChatData = { data: { answer: string; resources: { link: string; title: string; snippet: string }[]; }; }; const query = "how to automate support triage"; const ourSite = "example.com"; const coverage = await felo<ChatData>("/v2/chat", { query: `What pages currently answer the search query "${query}"? List the pages and what each one covers.`, }); const candidates = coverage.data.resources .filter((resource) => !resource.link.includes(ourSite)) .slice(0, 5) .map((resource) => ({ url: resource.link, title: resource.title }));出力例
{ "answer": "Readers searching this usually want a step-by-step …", "sources": [ { "link": "https://example.com/guide", "title": "…", "snippet": "…" } ] }ページを Markdown で読む
上位3〜5ページを Web Fetch で Markdown にし、見出しと問いを残します。
seo-brief.ts type ExtractData = { data: { content: string } }; const pages = await Promise.all( candidates.map(async (page) => { const res = await felo<ExtractData>("/v2/web/extract", { url: page.url, output_format: "markdown", with_readability: true, with_cache: true, }); const checkedAt = new Date().toISOString().slice(0, 10); return { ...page, checkedAt, content: res.data.content }; }), );出力例
{ "url": "https://example.com/guide", "checkedAt": "2026-10-30", "content": "# Automating support triage\n\n## Routing rules\n…" }カバレッジと抜けを整理する
各ページの H2/H3 と FAQ の問いを抽出し、答えている問いと抜けている問いの表を作ります。
seo-brief.ts type Heading = { page: string; heading: string }; const headings: Heading[] = pages.flatMap((page) => page.content .split("\n") .filter((line) => line.startsWith("## ")) .map((line) => ({ page: page.title, heading: line.replace(/^##\s+/, ""), })), ); const questions = headings.filter((item) => item.heading.includes("?")); const byTopic = new Map<string, string[]>(); for (const item of headings) { byTopic.set(item.heading, [...(byTopic.get(item.heading) ?? []), item.page]); }出力例
// questions [ { "page": "…", "heading": "What routes should you automate first?" } ]ブリーフを書く
対象クエリ、意図、カバレッジ比較、抜けている問い、提案構成、出典リストを書きます。
seo-brief.ts const today = new Date().toISOString().slice(0, 10); const brief = [ `# SEO brief — "${query}"`, `Checked ${today}. Site: ${ourSite}.`, "", "## Intent read", "The pages returned for this query lead with: " + headings.slice(0, 6).map((item) => item.heading).join("; ") + ". This is a reading of their structure, not a measured intent label.", "", "## What the pages cover", "| Page | URL | Checked |", "| --- | --- | --- |", ...pages.map((page) => `| ${page.title} | ${page.url} | ${page.checkedAt} |`), "", "## Questions the pages answer", ...questions.map((item) => `- ${item.heading} (${item.page})`), "", "## Topics more than one page covers", ...[byTopic.entries()] .filter(([, pageTitles]) => pageTitles.length > 1) .map(([heading, pageTitles]) => `- ${heading} (${pageTitles.length} pages)`), "", "## Proposed outline", ...questions.slice(0, 5).map((item, index) => `${index + 1}. ${item.heading}`), "", "## Questions they miss", "<!-- Only questions none of the fetched pages answer. Delete this comment when filled. -->", "", "## Not measured here", "Search volume, keyword difficulty, and ranking position. This workflow reads public pages; it does not query a search index or a rank tracker.", "", "## Sources", ...pages.map((page) => `- ${page.title}: ${page.url}`), ].join("\n"); console.log(brief);出力例
# SEO brief — "how to automate support triage"
LiveDoc に保存する
ブリーフとページリンクを LiveDoc に保存し、次回は変わった部分だけ取得します。
seo-brief.ts type LiveDocData = { data: { short_id: string } }; const briefDoc = await felo<LiveDocData>("/v2/livedocs", { name: `SEO briefs: ${ourSite}`, description: "One document resource per target query", }); await felo(`/v2/livedocs/${briefDoc.data.short_id}/resources/urls`, { urls: pages.map((page) => ({ url: page.url, title: page.title })), }); await felo(`/v2/livedocs/${briefDoc.data.short_id}/resources/doc`, { title: `SEO brief — ${query}`, content: brief, }); console.log(briefDoc.data.short_id); // the next query adds to this archive出力例
{ "short_id": "PvyKouzJirXjFdst4uKRK3" }
含まれるもの
- Chat の出典付きページ一覧と回答の根拠リンク
- 現在上位のページを Markdown に
- それらのページが扱う見出しと問い
- そのまま構成に使えるブリーフ
- 次回更新で再利用できる LiveDoc
やらないこと
- 検索順位、検索ボリューム、キーワード難易度、トラフィックは測定しない
- 公開ページのみ。ログインやペイウォールは失敗することがある
- 記事の公開や全面リライトはしない
- 1クエリにつき1回実行。複数クエリは自分でループする
- 順位を保証しない
よくある質問
検索ボリュームや順位を測りますか?
測りません。公開ページを読み、いまそのクエリに答えているコンテンツを判断するだけです。順位と検索ボリュームは既存のSEOツールを使ってください。
データはどこから来ますか?
Chat が出典付きページを返し、Web Fetch が Markdown に変換します。ブリーフの各判断は具体的なページと日付を指します。
複数のクエリを扱えますか?
できますが、1回に1クエリです。複数の場合は各クエリで同じ手順を繰り返し、それぞれブリーフを保存します。
どんなクエリに向いていますか?
情報型、比較型、「方法」系のクエリです。公開ページから十分なシグナルが得られます。取引型は自社の製品・コンバージョンデータも必要です。
記事も書きますか?
いいえ。ブリーフと構成を出力し、執筆は編集者か執筆 agent が行います。
1回の費用は?
Chat とページ抽出は従量制クレジットを使います。現在の料金は料金ページにあります。プロンプトは使う前に承認を求めます。
関連ワークフロー
1つの問いを、出典付きリサーチブリーフに変える
Web に問いを投げ、回答の根拠ページを Markdown で取得し、X の実務者の声を加え、最後に証拠をあとから検索できる LiveDoc に残します。
ワークフローを開くコンテンツ読者が実際に聞いている質問で1か月分のコンテンツを埋める
Chat でテーマを整理し、読者が X で聞いている質問を見つけ、参考動画の文字起こしからリアルな切り口を取り、すべての行に根拠を書いた4週間のコンテンツカレンダーを作ります。
ワークフローを開くコンテンツチームが本当に読む日次AIニュースダイジェストを作る
出典付きのニュースまとめを取り、X の実務者の議論を加え、動画の文字起こしを1本取得し、Markdown で号を構成して LiveDoc に保存します。
ワークフローを開く自分の形に変える
同じレシピを、実際の進め方に合わせて調整します。
比較クエリだけに絞る
「X vs Y」「最高の X」に範囲を絞ると、差別化の角度が見えやすくなります。
自社製品ページを加える
製品ページを追加ソースとして入れ、構成が自社の機能と価格に着地するようにします。
四半期ごとに更新する
同じ LiveDoc で再実行し、競合ページと構成提案の変化を見ます。
さらに進む
このレシピの背景にあるリファレンスと、次に見るべきページ。