Skip to content

Cách dev browser AI assistant extension — tóm tắt web 1 click

Cập nhật 2026

  • Chrome 138+ có built-in AI (Gemini Nano) — Summarizer, Translator, Writer API local, không cần API key
  • Manifest V3 mandatory — V2 deprecated từ 2025
  • Side Panel API (Chrome 114+) thay thế Popup cho UX tốt hơn
  • Edge cũng có built-in AI (Phi-3 model, Q1/2026)
  • Cross-browser: Manifest V3 work với Edge, Brave, Opera. Firefox vẫn hơi khác
  • VN context: dùng extension cho tóm tắt báo VN, dịch tin tức global, AI assistant cho công việc

Chương 1: browser extension và Chrome extension là gì

Trong tutorial này, ta đi đầy đủ closed loop: từ 0 dev 1 Chrome extension AI-driven, đọc nội dung page bạn đang xem, dùng AI tóm tắt 1 click. Bạn sẽ tự tay dev, debug, học cách publish lên Chrome Web Store.

Bạn ít nhất cần:

  • Chrome browser (khuyến nghị 138+ nếu dùng built-in AI)
  • 1 code editor (VS Code / Cursor / Trae)
  • (Tuỳ chọn) OpenAI hoặc Claude API key

1.1 Browser extension là gì?

Bạn chắc đã dùng extension — Adblock, translate tool, password manager... Chúng như "exoskeleton" cho browser, cho bạn super power khi browse web.

Tưởng tượng: mở 1 blog tech 5000 từ, click 1 button extension, vài giây sau, 1 tóm tắt tinh gọn tiếng Việt hiện ở side panel. Đây là cái ta sẽ build.

1.2 Kiến trúc cơ bản Chrome extension

Chrome extension (dựa Manifest V3) gồm các thành phần core, mỗi cái 1 việc:

  • Manifest file (manifest.json): "ID card" của extension, declare tên, permission, entry file
  • Service Worker (background script): "não" extension, xử lý event background, call API. Không chạy luôn, mà start theo nhu cầu
  • Content Script: "mắt" extension, inject vào page, đọc DOM page được
  • Side Panel: "mặt" extension, hiện UI ở right side browser, user xem kết quả AI
  • Options Page: cho user config API Key và param

Flow phối hợp:

User click icon extension
    → Side panel mở
    → User click button "Tóm tắt"
    → Side panel notify Service Worker
    → Service Worker bảo Content Script đọc text page
    → Content Script return content
    → Service Worker gửi content cho AI API
    → AI return summary
    → Service Worker gửi summary về side panel display

1.3 2 phương án AI: cloud API vs Chrome built-in AI

Extension ta có 2 cách lấy năng lực AI:

Phương án A: call cloud AI API (OpenAI / Claude)

  • Lợi: model mạnh, support mọi device
  • Nhược: cần API Key, cần online, có cost
  • Phù hợp: cần summary chất lượng cao, content phức tạp

Phương án B: Chrome built-in AI (Summarizer API)

Từ Chrome 138, Google built-in AI dựa Gemini Nano vào browser, gồm Summarizer API — chạy hoàn toàn local, không cần API Key, không cần online, free hoàn toàn.

  • Lợi: free, privacy secure, không cần API Key
  • Nhược: cần Chrome 138+, cần hardware tốt (4GB+ VRAM hoặc 16GB+ RAM), năng lực model kém cloud
  • Phù hợp: quan tâm privacy, không muốn tốn tiền, hardware OK

Tutorial này implement cả 2 phương án, bạn chọn theo trường hợp.

1.4 Roadmap tutorial này

Ta sẽ build extension "AI Page Summarizer" từ 0 theo các bước:

  1. Dựng khung extension: tạo structure project Manifest V3, load vào Chrome
  2. Implement function core: Content Script đọc page + Service Worker call AI API + side panel hiện kết quả
  3. Tích hợp Chrome built-in AI: dùng Summarizer API cho local summary free
  4. Test và debug: nắm kỹ thuật debug Chrome extension
  5. Publish lên Chrome Web Store: package và submit review

Chương 2: dựng khung extension

2.1 Tạo structure project

Mở AI coding assistant (Cursor / Trae / Claude Code), tạo folder mới ai-page-summarizer, rồi prompt:

Tạo cho tôi 1 Chrome extension project, dùng Manifest V3.
Tên project: ai-page-summarizer, function: dùng AI tóm tắt nội dung web.
Tạo file structure:

ai-page-summarizer/
├── manifest.json          # MV3 manifest
├── background.js          # Service Worker
├── content.js             # Content Script (đọc text page)
├── sidepanel.html         # Side Panel HTML
├── sidepanel.js           # Side Panel logic
├── sidepanel.css          # Side Panel style
├── options.html           # Settings page
├── options.js             # Settings logic
└── icons/                 # Icon folder

Yêu cầu manifest.json:
1. manifest_version: 3
2. Permission: storage, activeTab, scripting, sidePanel
3. Background dùng service_worker: "background.js"
4. Config side_panel, default path sidepanel.html
5. Action config default icon và title

AI sẽ gen full khung project.

2.2 manifest.json — "ID card" extension

json
{
  "manifest_version": 3,
  "name": "AI Page Summarizer",
  "version": "1.0",
  "description": "Tóm tắt mọi web 1 click bằng AI",
  "permissions": ["storage", "activeTab", "scripting", "sidePanel"],
  "host_permissions": ["<all_urls>"],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "AI Summarizer",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "side_panel": {
    "default_path": "sidepanel.html"
  },
  "options_page": "options.html",
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  }
}

2.3 Load extension vào Chrome

  1. Mở chrome://extensions/
  2. Bật "Developer mode" (góc trên phải)
  3. Click "Load unpacked"
  4. Chọn folder ai-page-summarizer
  5. Extension xuất hiện trong list

2.4 Test khung cơ bản

Click icon extension → side panel mở. Nếu chưa thấy → check console error.

Chương 3: implement function core

3.1 Content Script: đọc text page

content.js:

javascript
// Listen message từ Service Worker
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === "getPageContent") {
    // Lấy text chính của page (ưu tiên article tag, fallback body)
    const article = document.querySelector('article') || document.body;
    const content = article.innerText;
    sendResponse({ content: content.substring(0, 8000) }); // Giới hạn 8000 chars
  }
  return true; // Async response
});

3.2 Side Panel UI

sidepanel.html:

html
<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="sidepanel.css">
</head>
<body>
  <div class="container">
    <h2>📝 AI Page Summarizer</h2>
    <button id="summarizeBtn">Tóm tắt page này</button>
    <div id="result" class="result"></div>
    <div id="loading" class="loading" style="display:none">Đang tóm tắt...</div>
  </div>
  <script src="sidepanel.js"></script>
</body>
</html>

sidepanel.css:

css
body { font-family: -apple-system, sans-serif; padding: 16px; }
.container { max-width: 100%; }
button { 
  width: 100%; padding: 12px; 
  background: #4F46E5; color: white; 
  border: none; border-radius: 8px; 
  cursor: pointer; font-size: 14px;
}
button:hover { background: #4338CA; }
.result { 
  margin-top: 16px; padding: 12px; 
  background: #F9FAFB; border-radius: 8px;
  line-height: 1.6; font-size: 14px;
}
.loading { color: #6B7280; margin-top: 16px; }

sidepanel.js:

javascript
document.getElementById('summarizeBtn').addEventListener('click', async () => {
  const loading = document.getElementById('loading');
  const result = document.getElementById('result');
  
  loading.style.display = 'block';
  result.textContent = '';
  
  try {
    // Gửi message tới Service Worker
    const response = await chrome.runtime.sendMessage({ action: "summarize" });
    
    if (response.error) {
      result.textContent = `❌ Lỗi: ${response.error}`;
    } else {
      result.textContent = response.summary;
    }
  } catch (err) {
    result.textContent = `❌ Lỗi: ${err.message}`;
  } finally {
    loading.style.display = 'none';
  }
});

3.3 Service Worker: orchestration logic

background.js:

javascript
// Cho phép side panel mở khi click icon
chrome.sidePanel
  .setPanelBehavior({ openPanelOnActionClick: true })
  .catch((error) => console.error(error));

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === "summarize") {
    handleSummarize().then(sendResponse);
    return true; // Async
  }
});

async function handleSummarize() {
  try {
    // Lấy active tab
    const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
    
    // Inject content script và lấy text page
    const [{ result: pageContent }] = await chrome.scripting.executeScript({
      target: { tabId: tab.id },
      func: () => {
        const article = document.querySelector('article') || document.body;
        return article.innerText.substring(0, 8000);
      }
    });
    
    if (!pageContent || pageContent.length < 100) {
      return { error: "Page có quá ít text để tóm tắt" };
    }
    
    // Call AI
    const summary = await callAI(pageContent);
    return { summary };
  } catch (err) {
    return { error: err.message };
  }
}

async function callAI(content) {
  // Lấy API key từ storage
  const { apiKey, provider } = await chrome.storage.sync.get(['apiKey', 'provider']);
  
  if (provider === 'chrome-builtin') {
    return await callChromeBuiltinAI(content);
  } else {
    return await callCloudAPI(content, apiKey, provider || 'openai');
  }
}

async function callCloudAPI(content, apiKey, provider) {
  if (!apiKey) throw new Error("Chưa config API key, vào Settings để config");
  
  const endpoint = provider === 'anthropic'
    ? 'https://api.anthropic.com/v1/messages'
    : 'https://api.openai.com/v1/chat/completions';
  
  const body = provider === 'anthropic' ? {
    model: 'claude-sonnet-5',
    max_tokens: 500,
    messages: [{
      role: 'user',
      content: `Tóm tắt nội dung sau bằng tiếng Việt, 3-5 bullet point chính:\n\n${content}`
    }]
  } : {
    model: 'gpt-4o-mini',
    messages: [{
      role: 'user',
      content: `Tóm tắt nội dung sau bằng tiếng Việt, 3-5 bullet point chính:\n\n${content}`
    }]
  };
  
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...(provider === 'anthropic' 
        ? { 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' }
        : { 'Authorization': `Bearer ${apiKey}` })
    },
    body: JSON.stringify(body)
  });
  
  const data = await response.json();
  return provider === 'anthropic' 
    ? data.content[0].text 
    : data.choices[0].message.content;
}

async function callChromeBuiltinAI(content) {
  if (!('ai' in self) || !('summarizer' in self.ai)) {
    throw new Error("Chrome built-in AI chưa available. Cần Chrome 138+ và enable flag.");
  }
  
  const summarizer = await self.ai.summarizer.create({
    type: 'key-points',
    format: 'markdown',
    length: 'medium'
  });
  
  return await summarizer.summarize(content);
}

3.4 Options page

options.html:

html
<!DOCTYPE html>
<html>
<body style="font-family: -apple-system, sans-serif; padding: 20px;">
  <h2>AI Summarizer Settings</h2>
  
  <label>AI Provider:</label>
  <select id="provider">
    <option value="openai">OpenAI (GPT-4o-mini)</option>
    <option value="anthropic">Anthropic (Claude Sonnet 5)</option>
    <option value="chrome-builtin">Chrome Built-in AI (Free, local)</option>
  </select>
  
  <br><br>
  <label>API Key:</label>
  <input type="password" id="apiKey" style="width: 400px" />
  <small id="hint">Không cần với Chrome Built-in AI</small>
  
  <br><br>
  <button id="save">Save</button>
  <span id="status"></span>
</body>
<script src="options.js"></script>
</html>

options.js:

javascript
// Load saved settings
chrome.storage.sync.get(['provider', 'apiKey'], (data) => {
  if (data.provider) document.getElementById('provider').value = data.provider;
  if (data.apiKey) document.getElementById('apiKey').value = data.apiKey;
});

document.getElementById('save').addEventListener('click', () => {
  const provider = document.getElementById('provider').value;
  const apiKey = document.getElementById('apiKey').value;
  
  chrome.storage.sync.set({ provider, apiKey }, () => {
    document.getElementById('status').textContent = '✅ Saved!';
    setTimeout(() => document.getElementById('status').textContent = '', 2000);
  });
});

3.5 Test end-to-end

  1. Reload extension trong chrome://extensions/
  2. Right-click icon → Options → setup API key
  3. Mở 1 web article dài
  4. Click icon extension → side panel mở
  5. Click "Tóm tắt page này"
  6. Đợi 5-10s → kết quả hiện

Chương 4: tích hợp Chrome built-in AI (Summarizer API)

Chrome 138+ có built-in Gemini Nano. Để dùng:

4.1 Enable Chrome flag

  1. Mở chrome://flags/
  2. Search "Optimization Guide On Device Model" → set "Enabled BypassPerfRequirement"
  3. Search "Summarization API" → set "Enabled"
  4. Restart Chrome

4.2 Verify model downloaded

javascript
// Trong DevTools console
const canSummarize = await self.ai.summarizer.capabilities();
console.log(canSummarize.available); 
// "readily" = ready
// "after-download" = đang download
// "no" = không support

4.3 Code đã sẵn sàng

Code callChromeBuiltinAI ở chương 3 đã support. Trong Options chọn "Chrome Built-in AI" → free local summarization.

Chương 5: debug và test

5.1 Debug Service Worker

  1. chrome://extensions/ → click "service worker" link dưới extension
  2. DevTools mở → check Console log, Network request

5.2 Debug Content Script

  1. F12 trên page bất kỳ
  2. DevTools → Console → log từ content script hiện ở đây

5.3 Debug Side Panel

  1. Right-click trong side panel → "Inspect"
  2. DevTools mở cho side panel

5.4 Common bug

BugFix
"Service worker not registered"Check background.js path trong manifest
"Cannot read content of page"Đợi page load xong, check activeTab permission
"API key invalid"Verify key trong Options
"CORS error"Cần host_permissions: ["<all_urls>"]
"Chrome built-in AI not available"Enable flag + Chrome 138+ + đủ hardware

Chương 6: publish lên Chrome Web Store

6.1 Chuẩn bị

  • Developer account: $5 one-time fee (https://chrome.google.com/webstore/devconsole)
  • Icon: 128x128 PNG (đẹp, brand-aligned)
  • Screenshots: 1280x800, ít nhất 1 cái
  • Description: ngắn (132 chars) + detailed (16k chars)
  • Privacy policy URL: nếu collect data

6.2 Package extension

bash
# Trong folder extension
zip -r ai-page-summarizer.zip . -x "*.git*" -x "*.DS_Store"

6.3 Submit review

  1. Truy cập Developer Console
  2. Click "New Item"
  3. Upload zip file
  4. Fill thông tin:
    • Name, description
    • Category (Productivity)
    • Language (Vietnamese, English)
    • Screenshots, promo images
    • Privacy practices: declare data usage rõ
  5. Submit for review (thường 1-7 ngày)

6.4 Sau approval

  • Extension xuất hiện trong Chrome Web Store
  • Có link share (chrome.google.com/webstore/detail/xxx)
  • Track install, rating trong dashboard
  • Push update bằng cách upload zip mới (re-review 1-3 ngày)

Câu hỏi thường gặp

Q1: Cost Chrome Web Store?

$5 one-time fee cho dev account. Sau đó publish extension unlimited.

Q2: Có cách publish private không?

Có. Trong Distribution → "Private" → chia sẻ qua link riêng cho user cụ thể (cần email).

Q3: Manifest V2 vẫn dùng được không?

Không. V2 deprecated từ January 2025. Mọi extension mới phải V3.

Q4: Firefox extension khác Chrome thế nào?

Firefox dùng WebExtensions API tương tự Chrome, nhưng:

  • Không support Service Worker (dùng background scripts)
  • Side Panel API khác
  • Publish qua addons.mozilla.org (free, không $5)

Có thể share 90% code, build 2 manifest riêng.

Q5: Edge, Brave, Opera?

Tất cả đều dùng Chrome extension. Submit cùng zip lên Edge Add-ons (free), Brave/Opera tự sync từ Chrome Web Store.

Tài liệu tham khảo


Phụ lục: Browser extension 2026

A. Cross-browser strategy

StoreCostReview timeAudience
Chrome Web Store$5 one-time1-7 daysLargest (Chrome + Edge + Brave)
Edge Add-onsFree1-3 daysEdge users
Mozilla Add-onsFree1-7 daysFirefox users
Opera Add-onsFree1-7 daysOpera users

Khuyến nghị: build cho Chrome trước (covers 75% market), Firefox version sau.

B. Browser built-in AI 2026

Tất cả browser lớn đang add AI native:

BrowserAIModelAvailable
ChromeBuilt-in AIGemini Nano138+ stable
EdgePhi-3 miniMicrosoft2026 Q1
ArcNative AICloud-basedBuilt-in
BraveLeo AIMixtral / ClaudeBuilt-in
OperaAriaMulti-modelBuilt-in

Build extension dùng browser built-in AI = no API cost cho user.

C. Use case extension cho VN 2026

Extension ideaUse case VN
VN news summarizerTóm tắt VnExpress, ZNews, Tuổi Trẻ
EN-VN translatorTranslate technical article, paper
Shopee/Lazada price trackerTrack giá, notify khi giảm
VietQR generatorQuick gen VietQR cho bill split
Zalo OA helperCSKH bot integration
Form filler VNAuto-fill địa chỉ, số điện thoại VN
Tax invoice extractorLấy hoá đơn điện tử từ Sapo, KiotViet
AI search VNTích hợp Claude/Gemini cho search context

D. Best practice 2026

  1. Manifest V3 mandatory: V2 deprecated. Đừng start V2 mới.
  2. Side Panel > Popup: Side panel persistent, UX tốt hơn popup
  3. Use built-in AI khi có thể: free cho user, privacy tốt hơn
  4. Minimum permissions: chỉ request permission cần, Chrome Web Store review strict
  5. Privacy policy mandatory: nếu collect bất cứ data nào
  6. Localization: hỗ trợ tiếng Việt cho VN audience
  7. Dark mode: support cả light + dark
  8. Keyboard shortcut: power user love shortcuts

E. Monetization

  • Free + premium: free tier limited, paid tier unlock (Stripe subscription)
  • One-time purchase: Gumroad, $5-20
  • Open source + donations: GitHub Sponsors, Buy Me a Coffee
  • Affiliate: extension giúp shop comparison → affiliate fee
  • No monetization: free, build portfolio

F. Cảnh báo

Chrome Web Store review strict 2026:

  • Single purpose only — extension không sprawl scope
  • Data minimization — không collect data không cần
  • Permission justification — explain rõ tại sao cần permission X
  • No remote code — không load JS từ remote
  • No tracking pixels — privacy first

Risk: extension bị remove → user mất tool. Backup plan: tự host distribution.

Sources