Felo API PlatformFelo API Platform

研究

在壓庫存之前研究一個產品細分

先拿到品類背景,在明確日期抓取競品頁面,讀買家在 X 上抱怨什麼,再把證據和備忘錄存進一個 LiveDoc,下單前還能回來看。

建置時間30 分鐘難度進階更新於2026-10-30
適合誰電商營運產品研究員DTC 創辦人

複製 prompt

把方括號裡的欄位替換掉,然後貼到 Claude Code、Codex 或任何能存取終端機的 AI。它會安裝 Felo skill、在花額度前詢問,並執行這套工作流程。

在備貨或發布之前,研究這個產品細分:[產品或品類]。

市場:[國家或地區]。通路:[電商平台 / DTC / 零售]。買家貼文時間範圍:過去 [30] 天。
可比產品或競品 URL:[URL]。預算和毛利限制:[限制]。讀者:[團隊]。

輸出一份 Markdown 備忘錄,包含:
1. 一段式結論:是否值得繼續研究,以及什麼會改變你的判斷。
2. 需求訊號:來源對興趣、季節性和替代品怎麼說。
3. 競爭產品:各自宣稱什麼、頁面上擷取到的價格、買家說它哪裡不足。
4. 價格定位:頁面上實際找到的價格點,每個都附擷取日期。
5. 買家抱怨和未被滿足的需求,附引文、帳號和日期。
6. 備貨前需要解決的風險和開放問題。
7. 來源:用到的每個頁面和貼文,附 URL 和日期。

規則:
- 只使用 API 回傳的內容。不要編造市場規模、銷量估計、評論數或競品價格。
- 依擷取到的原樣報告價格,附頁面 URL 和擷取日期。不要取平均或做正規化。
- 把 X 貼文當作軼事,不是市場資料;樣本太薄時要說明。
- 區分廠商宣稱和買家回饋。
- 消耗額度前,先展示預計執行的擷取和搜尋並等待我批准。
- 不要聯絡供應商、下訂單,或在 X 上傳訊息給任何人。
- 將結果寫入 ./product-research.md,並在對話中總結。

複製的內容也包含安裝步驟和安全規則。

你會得到什麼

一次執行的範例輸出,不是即時生成。

備忘錄範例(節錄)

產品研究 — 範例品類

結論

值得進一步研究,但公開證據不足以做庫存決策。下面的開放問題是下一步。

品類背景

買家比較的是檯面空間與清潔難度,而不是壓力。沒有公開來源支持市場規模估計。

競品頁面

  • Example A — 產品頁(2026-10-30 擷取)
  • Example B — 產品頁(2026-10-30 擷取)

買家回饋

  • @example_buyer:「一年換第三次;密封圈會壞。」 — 2026-10-19
  • @example_home:「清潔要花幾分鐘,沒人提這一點。」 — 2026-10-24

價格定位

價格於 2026-10-30 從連結頁面擷取。分為兩檔;每個頁面直接引用,沒有取平均。

風險與開放問題

  • 密封圈耐用性是最反覆出現的投訴。
  • 沒有來源涵蓋退貨率。
  • 下單前確認供應商交期與到岸成本。

來源

  • https://example.com/product-a — 2026-10-30
  • https://x.com/example_buyer/status/... — 2026-10-19

實際呼叫

給開發者:同一套工作流程的可複製程式碼,依執行順序排列。

展開實際 API 呼叫
  1. 向 Chat 要品類圖景

    從有來源的答案開始,而不是一張白紙:Chat 搜尋公開網路、給頁面排序並回傳用過的資源。一次問清需求背景、替代品和常見抱怨,然後把最相關的資源保留為證據列表。下方的 helper 只送出一次 Key,非 2xx 回應會拋錯。

    product-research.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 niche = "portable espresso maker"; // replace with the category you are judging
    
    const context = await felo<ChatData>("/v2/chat", {
      query: `Demand, price bands, and buyer complaints for ${niche} in the US`,
    });
    
    const sources = context.data.resources.slice(0, 5);

    範例輸出

    {
      "answer": "Buyers compare on counter space and cleanup …",
      "sources": [
        { "link": "https://example.com/category-guide", "title": "…", "snippet": "…" }
      ]
    }
  2. 抓取競品頁面

    用 readability 把兩三個競品商品頁抽成 Markdown。目標是頁面今天的主張和價格,而不是改寫過的規格表。把 URL 和內容放在一起,並在備忘錄裡記錄抓取日期——沒有日期的價格只是傳聞。

    product-research.ts
    const PRODUCT_PAGES = [
      { url: "https://example.com/product-a", title: "Example A — product page" },
      { url: "https://example.com/product-b", title: "Example B — product page" },
    ];
    
    type ExtractData = { data: { content: string } };
    
    const listings = await Promise.all(
      PRODUCT_PAGES.map((page) =>
        felo<ExtractData>("/v2/web/extract", {
          url: page.url,
          output_format: "markdown",
          with_readability: true,
        }).then((extracted) => ({ ...page, content: extracted.data.content })),
      ),
    );

    範例輸出

    [
      {
        "url": "https://example.com/product-a",
        "title": "Example A — product page",
        "content": "# Example A\n\nSpecs and price as displayed…"
      }
    ]
  3. 讀買家在 X 上的回饋

    廠商頁面列功能,買家描述失敗。搜尋品類加上買家遇到問題時的摩擦詞——物流、品質、退款——限定最近 30 天,並保留帳號、日期和貼文連結。這些貼文是軼事,不是需求資料,備忘錄必須說明。

    product-research.ts
    type XData = {
      data: {
        tweets: {
          content: string;
          author: { username: string };
          created_at: string;
          metrics: { retweet_count: number; favorite_count: number; reply_count: number };
          url: string;
        }[];
      };
    };
    
    const since = Math.floor((Date.now() - 30 * 24 * 60 * 60 * 1000) / 1000);
    
    const search = await felo<XData>("/v2/x/tweet/search", {
      query: `"${niche}" (shipping OR quality OR refund)`,
      limit: 50,
      since_time: since,
    });
    
    const complaints = search.data.tweets;

    範例輸出

    { "data": { "tweets": [
      {
        "content": "Third replacement in a year; the seal fails.",
        "author": { "username": "example_buyer" },
        "created_at": "2026-10-19T15:02:00Z",
        "metrics": { "retweet_count": 1, "favorite_count": 12, "reply_count": 3 },
        "url": "https://x.com/example_buyer/status/..."
      }
    ] } }
  4. 寫備忘錄

    這一步是普通程式碼:把品類答案、抓取日期、買家引語和來源列表拼成一段 Markdown。開放問題部分要誠實——備忘錄有用,正是因為它把頁面能證明的東西和還需要向供應商確認的東西分開。

    product-research.ts
    const capturedOn = new Date().toISOString().slice(0, 10);
    
    const memo = [
      `# Product research — ${niche}`,
      "",
      "## Category context",
      context.data.answer,
      "",
      "## Competitor pages",
      ...listings.map(
        (page) => `- [${page.title}](${page.url}) — captured ${capturedOn}`,
      ),
      "",
      "## What buyers report",
      ...complaints.slice(0, 10).map(
        (post) =>
          `- @${post.author.username} (${post.created_at.slice(0, 10)}): ${post.content}`,
      ),
      "",
      "## Sources",
      ...sources.map((source) => `- [${source.title}](${source.link})`),
    ].join("\n");
    
    console.log(memo);
  5. 把證據存進 LiveDoc

    每個細分跑一次:建立 LiveDoc,把 short_id 存進設定。把競品頁面和 Chat 來源作為 URL 資源加進去,歸檔會自動去重,再把備忘錄作為文件資源加進去。下單前可以檢索抓取結果,看看備忘錄寫完之後哪些價格變了。

    product-research.ts
    type LiveDocData = { data: { short_id: string } };
    
    const research = await felo<LiveDocData>("/v2/livedocs", {
      name: `Product research: ${niche}`,
      description: "Competitor pages, buyer posts, and the memo",
    });
    
    await felo(`/v2/livedocs/${research.data.short_id}/resources/urls`, {
      urls: [
        ...listings.map((page) => ({ url: page.url, title: page.title })),
        ...sources.map((source) => ({ url: source.link, title: source.title })),
      ].slice(0, 10),
    });
    
    await felo(`/v2/livedocs/${research.data.short_id}/resources/doc`, {
      title: `Product memo — ${capturedOn}`,
      content: memo,
    });

    範例輸出

    { "short_id": "PvyKouzJirXjFdst4uKRK3" }

包含什麼

  • 來自 Chat 的有來源品類圖景,以及背後的頁面
  • 在明確日期抓取的競品商品頁 Markdown
  • X 上帶帳號、日期和連結的買家抱怨
  • 由這些輸入拼成的 Markdown 備忘錄
  • 一個同時保存證據和備忘錄的 LiveDoc

不做什麼

  • 只涵蓋公開來源;付費市場報告、供應商報價和內部銷售資料不在範圍內
  • 不估算市場規模、銷量或毛利
  • 價格依抓取結果記錄,絕不做正規化或平均
  • X 貼文是軼事,不是需求資料
  • 不聯絡供應商、不下單、不改 listing

常見問題

市場背景從哪裡來?

Chat API 回傳有來源的答案及其使用的公開頁面。競品頁面來自你提供的 URL,用 Web Fetch 擷取;買家貼文來自 X Search。不涉及私有銷售資料。

它能告訴我一個產品會不會賣爆嗎?

不能。它整理公開證據——品類背景、抓取價格和買家抱怨——並寫下未知項。需求驗證仍然需要你自己的資料,例如廣告、預售或供應商溝通。

如果平台阻止抓取怎麼辦?

Web Fetch 逐個 URL 抓公開頁面,有些站點會攔截。換一個你能存取的產品或供應商頁面,讓備忘錄明確標出缺失的抓取,而不是猜價格。

怎麼避免競品價格過時?

備忘錄裡的每個價格都綁定頁面 URL 和抓取日期。下單前重新跑一次擷取;歸檔會保留更早的抓取,能看出價格動過。

它會聯絡供應商或賣家嗎?

不會。工作流程是唯讀的:抓頁面、搜公開貼文、寫本地備忘錄。它從不發訊息、下單或修改 listing。

一次研究要花多少?

每次 Chat、頁面擷取和 X 搜尋都會消耗按用量計費的額度;目前費率在價格頁面。prompt 會在這些呼叫執行前請求確認。

相關工作流程

改成你的版本

同一套配方,依你實際的交付方式調整。

加入評測影片轉錄

品類裡有評測影片時,用 YouTube Subtitling 拉轉錄,並在買家部分加兩三條帶時間戳的引語。影片評測仍然是一個人的體驗,所以沿用 X 貼文的軼事標籤。

把兩個候選並排比較

對每個候選跑同樣的步驟,把備忘錄並排看:宣稱功能、抓取價格、反覆出現的抱怨和開放問題。在拿到自己的銷售或退貨資料之前,比較保持定性,這才是誠實的排序方式。

下單前更新

下單前一天重跑頁面擷取。保留同一個 LiveDoc,新增一份備忘錄文件,這樣歸檔能看出桌面研究和真正下單之間發生了什麼——包括漲出預算的價格。

這套配方背後的參考頁面,以及下一步可以看什麼。