Mark Ku's Blog
在 ChatGPT 開啟在 Claude 開啟

歡迎來到 Mark 的 Tech Insights,我是主持人璦廷。你是否想過,瀏覽器擴充功能不只是實用工具,還能成為絕佳的產品導流神器?今天,我們將帶您從零開始,探索如何開發一款內容合規檢查的 Chrome 擴充功能。 讓我們來看看實際的應用場景。想像一下,行銷人員在發布貼文前,只要選取網頁文字按右鍵,就能快速檢查文案是否觸犯法規,甚至支援圖片識別與截圖檢查,能大幅降低違規風險。 在技術層面,這個重點值得注意。專案全面採用最新的 Manifest V3 架構,以 Service Worker 提升執行效率與安全性。此外,為了實現單一登入,系統整合了開源的 Keycloak,並搭配專屬的安全機制,確保登入過程滴水不漏。 開發工具的同時,我們也融入了產品導流策略。透過解鎖完整建議的行動呼籲設計,使用者能獲得有價值的分析報告,團隊也能藉此收集潛在客戶名單,創造雙贏的價值交換。 總結來說,擴充功能不僅能建立品牌認知,更能有效降低獲客成本。如果您正在思考如何為產品開創新的曝光管道,不妨評估看看,您的核心服務是否也能化身為使用者瀏覽器上的得力助手呢?

Podcast 對話本文 AI 對話朗讀版
本文音訊由 VoAI 提供技術支援VoAI 絕好聲創

前言

今年我們團隊打算在 Chrome 瀏覽器推出一款「網頁內容檢核」的擴充功能,主要目的是增加產品曝光機會,同時也能為使用者提供實用的工具。

這篇文章+將完整分享:

  1. Chrome Extension 開發重點 - 架構設計與必備知識
  2. 整合 Keycloak 登入 - 如何在擴充功能中實現 SSO 單一登入
  3. 產品導流策略 - 如何將免費工具轉換為付費客戶
  4. 上架 Chrome 商店 - 從打包到審核的完整流程

產品定位與目標用戶

這款擴充功能的主要目標用戶是行銷小編與社群經營者。他們在發文前,常常需要確認內容是否符合相關法規要求,避免廣告文案觸犯法規而遭到處罰。

使用情境

想像一下這個場景:

小編準備在 Facebook 發布一則保健食品的促銷貼文,在正式發布前,她想確認文案中是否有違規用詞。這時候,她只需要選取文字,右鍵點擊,就能快速檢查內容是否合規。

合規檢查操作示範
合規檢查操作示範

核心功能設計

右鍵選單功能

使用者在網頁上選取文字後,可透過右鍵選單快速進行檢查:

Loading diagram…

四種檢查模式

  1. 📝 檢查選取文字 - 直接檢查選取的文字內容
  2. 🔗 檢查連結內容 - 抓取網頁內容進行分析
  3. 🖼️ 檢查圖片文字 - 透過 OCR 識別圖片中的文字
  4. ✂️ 截圖檢查 - 截取畫面區域進行文字識別與檢查

技術架構

這個專案採用 Manifest V3 架構開發,主要技術組成如下:

chrome-extension/
├── manifest.json          # 插件配置檔(Manifest V3)
├── background.js          # Service Worker
├── content.js             # 內容腳本
├── config.js              # 集中設定檔
│
├── auth/                  # 認證模組(Keycloak 整合)
│   ├── auth-config.js     # 認證設定
│   ├── auth-service.js    # 登入邏輯
│   ├── auth.html          # 登入頁面
│   └── auth.js            # 登入 UI 控制
│
├── core/                  # 核心模組
│   ├── utils.js           # 共用工具
│   ├── risk-levels.js     # 風險等級定義
│   └── api-client.js      # API 呼叫封裝
│
├── handlers/              # 功能處理器
│   ├── text-handler.js    # 文字檢查
│   ├── link-handler.js    # 連結檢查
│   ├── image-handler.js   # 圖片 OCR
│   └── screenshot-handler.js # 截圖檢查
│
├── ui/                    # UI 元件
│   ├── loading.js         # 載入動畫
│   ├── dialog.js          # 對話框
│   ├── result-panel.js    # 結果面板
│   └── styles.css         # 樣式
│
├── popup/                 # Popup 頁面
│   ├── popup.html
│   ├── popup.css
│   └── popup.js
│
└── options/               # 設定頁面
    ├── options.html
    ├── options.css
    └── options.js

Chrome Extension 開發重點

如果你是第一次開發 Chrome 擴充功能,以下是幾個必須了解的核心概念:

什麼是 Chrome Extension?

簡單來說,Chrome Extension 就是一個跑在瀏覽器裡的小程式,可以:

  • 在網頁上加入新功能(如右鍵選單、浮動按鈕)
  • 讀取或修改網頁內容
  • 與外部 API 溝通
  • 儲存使用者設定

Manifest V3 vs V2:一定要用新版!

Chrome 已經強制要求新的擴充功能使用 Manifest V3,2024 年起 V2 將逐步淘汰。

差異Manifest V2(舊版)Manifest V3(新版)
背景執行Background Page(常駐)Service Worker(按需啟動)
權限管理較寬鬆更嚴格,需明確宣告
安全性一般更高,限制 remote code
上架已停止接受必須使用

五大核心檔案

開發 Chrome Extension 一定會用到這些檔案:

Loading diagram…

manifest.json 設定範例

這是擴充功能最重要的檔案,告訴 Chrome 這個擴充功能需要什麼權限:

{
  "manifest_version": 3,
  "name": "快合規快篩",
  "version": "1.1.0",
  "description": "圈選任何文字,快速檢查是否符合廣告法規",
  
  "permissions": [
    "contextMenus",    // 右鍵選單
    "activeTab",       // 存取當前分頁
    "storage",         // 儲存資料
    "notifications",   // 顯示通知
    "scripting",       // 動態注入腳本
    "identity"         // OAuth 登入
  ],
  
  "host_permissions": [
    "https://api.textcomply.com/*",  // API 網址
    "https://sso.example.com/*"       // SSO 登入網址
  ],
  
  "background": {
    "service_worker": "background.js"
  },
  
  "action": {
    "default_popup": "popup/popup.html",
    "default_icon": "logo/icon128.png"
  }
}

各元件如何溝通?

Chrome Extension 的各個部分是「隔離」的,需要透過 Message Passing 溝通:

Loading diagram…

程式碼範例:

// content.js - 發送訊息給 background
chrome.runtime.sendMessage(
  { action: 'checkText', text: '選取的文字內容' },
  (response) => {
    console.log('檢查結果:', response);
  }
);

// background.js - 接收並處理訊息
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.action === 'checkText') {
    // 呼叫 API 檢查文字
    checkTextApi(message.text).then(result => {
      sendResponse(result);
    });
    return true; // 表示會非同步回應
  }
});

整合 Keycloak SSO 登入

如果你的產品需要使用者登入,可以整合 Keycloak(或其他 OAuth2 / OIDC 提供者)來實現單一登入。

擴充功能登入頁面 Login

為什麼選 Keycloak?

  • 開源免費 - 不用付授權費
  • 支援多種登入方式 - 帳密、Google、GitHub、Facebook...
  • 標準協定 - 使用 OAuth2 / OpenID Connect
  • 企業級功能 - 角色管理、多租戶、MFA 等

整合流程概覽

Loading diagram…

設定 Keycloak Client

在 Keycloak 管理後台建立 Client:

Client ID: chrome-extension
Client Protocol: openid-connect
Access Type: public (擴充功能無法保密 client_secret)
Valid Redirect URIs: https://<extension-id>.chromiumapp.org/*
Web Origins: *

PKCE 安全機制(重要!)

因為 Chrome Extension 是「公開客戶端」(無法安全儲存 client_secret),必須使用 PKCE 來增加安全性:

// 1. 產生隨機的 code_verifier
function generateRandomString(length = 64) {
  const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
  const array = new Uint8Array(length);
  crypto.getRandomValues(array);
  return Array.from(array, (byte) => charset[byte % charset.length]).join('');
}

// 2. 用 code_verifier 產生 code_challenge
async function generateCodeChallenge(codeVerifier) {
  const encoder = new TextEncoder();
  const data = encoder.encode(codeVerifier);
  const hash = await crypto.subtle.digest('SHA-256', data);
  
  // Base64 URL 編碼
  const bytes = new Uint8Array(hash);
  let binary = '';
  bytes.forEach(byte => binary += String.fromCharCode(byte));
  return btoa(binary)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
}

發起登入請求

async function loginWithKeycloak() {
  // 1. 產生 PKCE 參數
  const codeVerifier = generateRandomString(64);
  const codeChallenge = await generateCodeChallenge(codeVerifier);
  const state = generateRandomString(32);
  
  // 2. 儲存 verifier(稍後換 token 時需要)
  await chrome.storage.local.set({ codeVerifier, state });
  
  // 3. 組合登入 URL
  const authUrl = new URL('https://sso.example.com/realms/myrealm/protocol/openid-connect/auth');
  authUrl.searchParams.set('client_id', 'chrome-extension');
  authUrl.searchParams.set('redirect_uri', chrome.identity.getRedirectURL());
  authUrl.searchParams.set('response_type', 'code');
  authUrl.searchParams.set('scope', 'openid profile email');
  authUrl.searchParams.set('code_challenge', codeChallenge);
  authUrl.searchParams.set('code_challenge_method', 'S256');
  authUrl.searchParams.set('state', state);
  
  // 4. 開啟登入視窗
  chrome.identity.launchWebAuthFlow(
    { url: authUrl.toString(), interactive: true },
    handleAuthCallback
  );
}

換取 Access Token

async function exchangeCodeForToken(code) {
  const { codeVerifier } = await chrome.storage.local.get('codeVerifier');
  
  const response = await fetch(
    'https://sso.example.com/realms/myrealm/protocol/openid-connect/token',
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        client_id: 'chrome-extension',
        code: code,
        redirect_uri: chrome.identity.getRedirectURL(),
        code_verifier: codeVerifier  // PKCE 驗證
      })
    }
  );
  
  const tokens = await response.json();
  
  // 儲存 token
  await chrome.storage.local.set({
    accessToken: tokens.access_token,
    refreshToken: tokens.refresh_token,
    expiresAt: Date.now() + (tokens.expires_in * 1000)
  });
  
  return tokens;
}

Token 自動刷新

Access Token 通常幾分鐘就會過期,需要自動刷新:

async function getValidToken() {
  const { accessToken, refreshToken, expiresAt } = 
    await chrome.storage.local.get(['accessToken', 'refreshToken', 'expiresAt']);
  
  // Token 還沒過期,直接使用
  if (expiresAt && Date.now() < expiresAt - 60000) {
    return accessToken;
  }
  
  // Token 即將過期,用 refresh_token 換新的
  if (refreshToken) {
    const newTokens = await refreshAccessToken(refreshToken);
    return newTokens.access_token;
  }
  
  // 沒有 token,需要重新登入
  return null;
}

導流策略設計

這才是這個專案最精華的部分 - 如何將免費工具的使用者轉換為潛在客戶

漏斗設計流程

Loading diagram…

等待時間的價值

當使用者發起檢查請求後,因為需要等待 AI 模型回應(通常 3-5 秒),這段時間就是絕佳的廣告曝光時機!

// config.js - 輪播設定
CAROUSEL_IMAGES: [
  'images/banner_square-1.png',
  'images/banner_square-2.png'
],
CAROUSEL_INTERVAL_MS: 3000,

我們在 Loading 畫面中嵌入圖片輪播,投放產品廣告或促銷訊息。

結果頁面的導流設計

檢查結果會顯示:

  • ✅ 是否合規
  • ⚠️ 違規項目數量
  • 🔒 部分資訊以模糊方式呈現

關鍵設計:違規說明和調整建議會顯示前 15 個字,其餘以「...」遮蔽,引導使用者點擊解鎖。

// 說明(違規原因)- 鎖定狀態
if (violation.explanations && violation.explanations.length > 0) {
  const expPreview = escapeHtml(violation.explanations[0]).substring(0, 15) + '...';
  html += `
    <a href="${ctaLink}" target="_blank" class="compliance-result__locked-block">
      <div class="compliance-result__locked-header">
        <p class="compliance-result__locked-label">📋 違規說明</p>
        <span class="compliance-result__locked-icon">🔒</span>
      </div>
      <p class="compliance-result__locked-text compliance-result__locked-text--blur">${expPreview}</p>
      <p class="compliance-result__locked-cta">立即體驗完整功能</p>
    </a>
  `;
}

CTA 按鈕設計

在結果面板底部,我們放置了醒目的行動呼籲按鈕:

// CTA 按鈕
html += `
  <div class="compliance-result__footer">
    <a href="${ctaLink}" target="_blank" class="compliance-result__cta-btn">
      🚀 使用產品取得完整建議
    </a>
  </div>
`;

Lead Generation 機制

當使用者點擊「取得完整建議」按鈕,會被導向解鎖頁面:

解鎖流程

  1. 使用者填寫 Email
  2. 驗證 Email 有效性
  3. 解鎖完整報告
  4. 每組 Email 只能解鎖一篇報告

這個設計的巧妙之處:

  • ✅ 使用者獲得有價值的完整分析報告
  • ✅ 我們獲得有效的潛在客戶名單
  • ✅ 業務團隊可以後續進行接觸與轉化

安裝與使用

從 Chrome 線上應用程式商店安裝

使用者可以直接在 Chrome 線上應用程式商店搜尋並安裝這個擴充功能。

開發者模式安裝

如果你想自己部署類似的專案:

  1. 開啟 Chrome → chrome://extensions/
  2. 開啟「開發人員模式」
  3. 點擊「載入未封裝項目」
  4. 選取 chrome-extension 資料夾

使用方式

  1. 在任何網頁上選取文字
  2. 按下右鍵
  3. 選擇「🛡️ 廣告合規檢查」
  4. 選擇檢查類型
  5. 等待結果顯示

開發心得與建議

Manifest V3 的挑戰

Chrome 已經強制要求新的擴充功能使用 Manifest V3,這帶來了一些開發上的改變:

  • Service Worker 取代了 Background Page
  • 需要更明確地宣告權限
  • Content Script 的注入方式有所改變

模組化設計

建議將功能拆分成獨立模組:

  • core/ - 核心邏輯
  • handlers/ - 各種檢查處理器
  • ui/ - UI 元件

這樣的設計讓程式碼更易於維護和擴展。

API 設計考量

// 集中設定檔
const CONFIG = {
  DEFAULT_API_ENDPOINT: 'https://your-api-endpoint.com',
  IMAGE_OCR_PATH: '/api/image/ocr',
  CREATE_AND_CHECK_PATH: '/api/TextContent/CreateAndCheck',
  MAX_RETRIES: 3,
  RETRY_DELAY: 1000,
};

建議將 API 端點設計為可配置,方便未來切換環境或更新服務。

成效預期

目前擴充功能尚未正式上架,以下為規劃階段的初期目標,待上架後將依實際數據持續調整:

指標初期目標
擴充功能安裝數500+ 次(上架後追蹤)
每月活躍用戶200 人以上
Lead 轉換率5–10%
有效名單數每月 10–50 筆

總結

Chrome Extension 不只是一個工具,更是一個絕佳的產品導流渠道。透過提供免費且實用的功能,我們能夠:

  1. 建立品牌認知 - 使用者每天使用,自然記住產品
  2. 收集潛在客戶 - 透過解鎖機制獲取有效名單
  3. 降低獲客成本 - 相較於廣告投放,擴充功能的 CAC 更低
  4. 提供價值交換 - 使用者獲得工具,我們獲得 Lead

如果你也在思考如何為產品創造新的曝光管道,Chrome Extension 絕對值得一試!


參考資源

作者

Mark Ku

擁有 10+ 年經驗的資深軟體工程師,現為 AI 應用 Builder,專注於大型平台架構與簡化複雜系統設計,從電商系統到訂閱與收費平台,結合 AI Agent、AI 整合與自動化開發,打造高效率且可持續演進的產品技術基礎。閱讀更多

覺得這篇有幫助?

作者做的免費工具、每日 Podcast 與電子報,都在這裡。

Mark Ku · 本文採用 CC BY 4.0 授權,轉載請註明作者並附上原文連結。

留言

訂閱電子報

訂閱後即時收到新文章通知,不錯過任何技術分享。

提交即表示同意接收電子報,隨時可

熱門文章

View all
Mark Ku
··621

Oracle Cloud 永久免費方案 Linux 主機及固定 IP :0 元打造雲端解決方案

Oracle Cloud 永久免費方案 Linux 主機及固定 IP :0 元打造雲端解決方案
Mark Ku
··489

告別 Postman 收費陷阱!開源 Git 原生 API 測試神器 Bruno 實戰指南

告別 Postman 收費陷阱!開源 Git 原生 API 測試神器 Bruno 實戰指南
Mark Ku
··337

一款免費開源類似於 Notion 類知識庫系統 — Outline Wiki 佈署與備份全攻略

一款免費開源類似於 Notion 類知識庫系統 — Outline Wiki 佈署與備份全攻略
Mark Ku
··261

訓練自己的 AI 語音:硬體門檻、開源模型比較與 LoRA 微調

訓練自己的 AI 語音:硬體門檻、開源模型比較與 LoRA 微調
Mark Ku
··234

打造高效 API 管理平台:從 0 開始部署 Kong Gateway - Part 1

打造高效 API 管理平台:從 0 開始部署 Kong Gateway - Part 1
Mark Ku
··214

在 Ubuntu 上設置 Samba 來共享資料夾,讓 Windows 11 用戶可以存取

在 Ubuntu 上設置 Samba 來共享資料夾,讓 Windows 11 用戶可以存取