研究
做一份業務團隊能直接用的競品拆解
收集競品自己的頁面、圍繞它的報導,以及買家在 X 上的說法,再拼成一份拆解:每條主張都有來源、日期和狀態。
複製 prompt
把方括號裡的欄位替換掉,然後貼到 Claude Code、Codex 或任何能存取終端機的 AI。它會安裝 Felo skill、在花額度前詢問,並執行這套工作流程。
為[我們的產品]製作一份針對[競品名稱]的競品拆解。 範圍:[細分市場]、[地區]、[語言]。時間範圍:[過去 90 天 / 過去 12 個月]。它支援的決策:[調價 / 發布定位 / 異議處理]。 起始來源:[競品網域]、[定價頁 URL]、[更新日誌 URL]。 輸出一份 Markdown 拆解,包含: 1. 他們如何定位自己,用他們自己的話。 2. 證據表:主張、來源標題、URL、日期、狀態(Verified / Vendor claim / Third-party / Signal / Inference / Not verified)。 3. 定價:頁面寫了什麼,附連結和核對日期。沒有頁面和日期,絕不把價格寫進正文。 4. 買家在哪些地方反彈,附 X 帳號和日期,並標示為訊號。 5. 我們下一步該做什麼,標示為建議。 6. 完整來源清單。 規則: - 引用他們的定位,不要改寫成更強的說法。 - 區分廠商主張、第三方報導和你自己的推論,每一列都加標籤。 - 不要編造價格、指標、客戶名稱或基準。資料缺失時寫「暫無資料」。 - 把時間範圍和地區落實為明確值。 - 消耗額度前,先展示預計執行的 API 呼叫並等待我批准。 - 不要發布、傳送、排程,或寫入任何 CRM。 - 將結果寫入 ./competitor-teardown.md,並在對話中總結。
複製的內容也包含安裝步驟和安全規則。
你會得到什麼
一次執行的範例輸出,不是即時生成。
競品拆解 — [競品],2026-10-30 核對
他們如何定位自己
首頁標題:「為成長中的支援團隊打造的平台。」分類頁:「支援團隊需要的一切。」兩者都是廠商主張,依原文引用。
證據表
| 主張 | 來源 | 日期 | 狀態 |
|---|---|---|---|
| 定位為平台而非單點工具 | https://example.com/competitor/home | 2026-10-30 | Verified |
| 每週發布變更 | https://example.com/competitor/changelog | 2026-10-28 | Verified |
| 被獨立評測收錄 | https://example.com/roundup | 2026-10-27 | Third-party |
| 買家提到上手慢 | 下文引用的 X 貼文 | 2026-10-14 | Signal |
| 企業是他們最大的細分 | 暫無資料 | — | Not verified |
定價
定價頁列出分層方案與按量方案。這裡不重複費率;查看即時頁面與日期:https://example.com/competitor/pricing(2026-10-30)。
買家反彈的地方
@example_dev,2026-10-14:「安裝比示範說的更久。」一條有日期的貼文,是投訴,不是普遍性估計。
建議
在比較頁上突出「到第一個結果的時間」。這是我們的推論,不是競品主張。
來源
- https://example.com/competitor/home
- https://example.com/competitor/pricing
- https://example.com/competitor/changelog
實際呼叫
給開發者:同一套工作流程的可複製程式碼,依執行順序排列。
展開實際 API 呼叫
從有來源的基線開始
Chat 會回傳答案和它用過的頁面,等於給你一張「競品在哪裡被討論」的地圖。把答案當成線索而不是來源:真正要保留的是連結,它們提供證據表裡的第三方列。下方的 helper 只送出一次 Key,非 2xx 回應會拋錯。
competitor.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 competitor = "Example Competitor"; const segment = "mid-market support teams"; const baseline = await felo<ChatData>("/v2/chat", { query: `How does ${competitor} position itself for ${segment}? Include pricing and recent launches.`, }); const seedSources = baseline.data.resources.slice(0, 5);範例輸出
{ "answer": "The competitor positions itself as …", "sources": [ { "link": "https://example.com/competitor", "title": "…", "snippet": "…" } ] }抓取他們自己控制的頁面
第三方報導告訴你別人怎麼想,競品自己的頁面告訴你他們怎麼宣稱。用 readability 把首頁、定價頁和 changelog 抽成 Markdown,並給每個頁面蓋上抓取日期——沒有日期的定價頁是個陷阱。
competitor.ts type ExtractData = { data: { content: string } }; const ownedPages = [ { url: "https://example.com/competitor/home", title: "Homepage" }, { url: "https://example.com/competitor/pricing", title: "Pricing" }, { url: "https://example.com/competitor/changelog", title: "Changelog" }, ]; const fetched = await Promise.all( ownedPages.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/competitor/pricing", "checkedAt": "2026-10-30", "content": "# Pricing\n\nExtracted page text…" }看看買家在 X 上怎麼說
在 X 搜尋人們對競品的異議和繞行方案。保留每個貼文的帳號和日期;一則帶日期的引語只是「有人抱怨過」的證據,不是「有多普遍」的證據,所以拆解把它標為訊號,絕不把幾則貼文變成百分比。
competitor.ts type XData = { data: { tweets: { content: string; author: { username: string }; created_at: string; metrics: { retweet_count: number; favorite_count: number }; }[]; }; }; const since = Math.floor((Date.now() - 90 * 24 * 60 * 60 * 1000) / 1000); const buyerSignal = await felo<XData>("/v2/x/tweet/search", { query: `"${competitor}" (pricing OR onboarding OR migration)`, limit: 25, since_time: since, }); const objections = buyerSignal.data.tweets.slice(0, 5);範例輸出
{ "data": { "tweets": [ { "content": "setup took longer than the demo suggested", "author": { "username": "example_dev" }, "created_at": "2026-10-14T09:20:00Z", "metrics": { "retweet_count": 3, "favorite_count": 24 } } ] } }用證據表組裝拆解
這是編輯步驟:把抓到的頁面和 X 貼文變成一條條主張,再給每條主張配來源、日期和狀態。狀態欄讓文件保持誠實——頁面原文是
Verified,廠商行銷是Vendor claim,外部報導是Third-party,帶日期貼文是Signal,你的解讀是Inference,缺證據是Not verified。competitor.ts const today = new Date().toISOString().slice(0, 10); const row = (claim: string, source: string, date: string, status: string) => `| ${claim} | ${source} | ${date} | ${status} |`; const teardown = [ `# Competitor teardown — ${competitor}`, `Scope: ${segment}. Checked ${today}.`, "", "| Claim | Source | Date | Status |", "| --- | --- | --- | --- |", row("Free tier listed on the pricing page", ownedPages[1].url, fetched[1].checkedAt, "Verified"), row("Positions as a platform, not a point tool", ownedPages[0].url, fetched[0].checkedAt, "Vendor claim"), row("Discussed in independent coverage", seedSources[0]?.link ?? "Not available", today, "Third-party"), row("Buyers report onboarding friction", "X post, quoted below", today, "Signal"), row("Most revenue comes from enterprise", "Not available", "—", "Not verified"), "", "## Recommendation", "Lead with time-to-first-result on the comparison page. Inference, not a competitor claim.", ].join("\n"); console.log(teardown);範例輸出
| Free tier listed on the pricing page | https://example.com/competitor/pricing | 2026-10-30 | Verified |
存進 LiveDoc,供下次更新
每個競品建一個 LiveDoc,把抓到的頁面作為 URL 資源加進去,再把拆解本身作為文件資源加進去。重複加入 URL 會自動去重,下一季只需要抓變化的部分,上一季的拆解仍和新內容放在同一個歸檔裡。
competitor.ts type LiveDocData = { data: { short_id: string } }; const teardownDoc = await felo<LiveDocData>("/v2/livedocs", { name: `Teardown: ${competitor}`, description: `Sources and teardown checked ${today}`, }); await felo(`/v2/livedocs/${teardownDoc.data.short_id}/resources/urls`, { urls: fetched.map((page) => ({ url: page.url, title: page.title })), }); await felo(`/v2/livedocs/${teardownDoc.data.short_id}/resources/doc`, { title: `Teardown ${today}`, content: teardown, }); console.log(teardownDoc.data.short_id); // the next refresh reuses this LiveDoc範例輸出
{ "short_id": "PvyKouzJirXjFdst4uKRK3" }
包含什麼
- 來自 Chat API 的有來源基線,以及答案背後的頁面
- 競品首頁、定價頁和 changelog 的 Markdown 擷取
- X 上帶日期的買家評論,標記為訊號而不是證據
- 把已驗證事實、廠商說法和推論分開的證據表
- 保存來源的 LiveDoc,下一次更新不用從零開始
不做什麼
- 只涵蓋公開來源;不做贏單/輸單訪談、CRM 備註或私有看板
- 價格只做連結和日期,不把費率凍結進沒有檢查日期的表格
- X 覆蓋不完整,不代表買家的有代表性樣本
- 它不會替你決定定位;建議會明確標為推論
- 它不會發佈拆解,也不會寫進 battlecard 工具
常見問題
證據從哪裡來?
Chat API 回傳有來源的基線及其用過的頁面,Web Fetch 把競品自己的頁面轉成 Markdown,X Search 補充帶日期的買家貼文。每一列都保留來源和日期,推論單獨有狀態。
可以同時涵蓋多個競品嗎?
可以。每個競品跑一次同樣的 prompt,並為每家公司保留一個 LiveDoc。做對比頁時只拼接標記為「已驗證」的列,不要把兩次執行的證據混在一起。
可以直接引用競品價格嗎?
工作流程會記錄定價頁上寫了什麼,並附上連結和檢查日期。它不會把費率寫死成文字,因為廠商價格會變,過時的數字比沒有數字更糟。
我們自己的贏單/輸單筆記能用嗎?
它只讀公開來源。把內部筆記作為獨立的文件資源加進 LiveDoc,並標記為內部;這些內容不會出現在面向客戶的材料裡。
應該多久更新一次?
依觸發條件更新,而不是依日曆:價格變化、產品發佈或業務週期開始時。對同一個 LiveDoc 重跑工作流程,讓上一季的拆解留在新拆解旁邊方便對比。
一份拆解要花多少?
每次 chat、擷取和 X 搜尋都會消耗按用量計費的額度;目前費率在價格頁面。prompt 會在花額度之前請求確認。
相關工作流程
改成你的版本
同一套配方,依你實際的交付方式調整。
依觸發條件更新,而不是依日曆
競品改價、發佈重要版本或大型業務週期開始前,重跑同一套工作流程。每份拆解都作為帶日期的文件資源留在同一個 LiveDoc 裡,下一季和上一季並排,而不是覆蓋。
把拆解變成 battlecard
用同一張證據表,依角色各寫一頁——經濟買家、擁護者和技術審查——只使用 `Verified` 列,並保留連結。任何面向客戶的材料都不要放 `Inference`。
把兩個競品並排比較
每個競品各跑一次,使用獨立的 LiveDoc;然後做一張只拼接兩次執行都標記為 `Verified` 的對比頁。沒有狀態欄時,絕不把兩次執行合併成一張證據表。
繼續深入
這套配方背後的參考頁面,以及下一步可以看什麼。