You do not need weeks of experience to build a useful Chrome extension. With modern AI APIs and a free afternoon, you can create a browser tool that summarizes pages, rewrites text, or answers questions about any website you visit.
This tutorial walks you through building a Chrome extension that extracts page content and sends it to an AI model for summarization. By the end, you will have a working extension you can customize for your own workflows.
What You Will Build
A Chrome extension with a popup interface that:
- Extracts text content from the current tab
- Sends it to the OpenAI API (compatible with ChatGPT models)
- Returns a concise summary displayed in the popup
The same architecture works with any LLM API, including Claude or local models.
Prerequisites
- Basic knowledge of HTML, CSS, and JavaScript
- A code editor (VS Code recommended)
- Chrome browser
- An OpenAI API key (or any compatible API key)
Step 1: Set Up the Project Structure
Create a new folder and add these files:
ai-summarizer-extension/
manifest.json
popup.html
popup.js
content.js
styles.css
Step 2: Write the Manifest File
The manifest tells Chrome how your extension works. Create manifest.json:
{
"manifest_version": 3,
"name": "AI Page Summarizer",
"version": "1.0",
"description": "Summarize any web page using AI",
"permissions": ["activeTab", "scripting"],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}Key details: We use Manifest V3 (required for new extensions), request only activeTab and scripting permissions to keep the extension lightweight, and register a content script that runs on all pages.
Step 3: Build the Popup Interface
Create popup.html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h1>AI Summarizer</h1>
<div id="status">Ready to summarize</div>
<button id="summarize-btn">Summarize This Page</button>
<div id="result" class="hidden"></div>
</div>
<script src="popup.js"></script>
</body>
</html>Add basic styling in styles.css:
body {
width: 360px;
padding: 16px;
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
}
.container {
display: flex;
flex-direction: column;
gap: 12px;
}
h1 {
font-size: 18px;
margin: 0;
}
button {
padding: 10px 16px;
background: #2563eb;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
}
button:hover {
background: #1d4ed8;
}
button:disabled {
background: #94a3b8;
cursor: not-allowed;
}
#result {
max-height: 300px;
overflow-y: auto;
padding: 12px;
background: #f8fafc;
border-radius: 6px;
font-size: 13px;
line-height: 1.5;
}
.hidden {
display: none;
}Step 4: Extract Page Content
The content script (content.js) runs inside web pages and extracts readable text:
// content.js - extracts main text content from the page
function extractPageContent() {
const selectors = ['article', 'main', '[role="main"]', '.post-content'];
let content = '';
for (const selector of selectors) {
const element = document.querySelector(selector);
if (element) {
content = element.innerText;
break;
}
}
if (!content) {
content = document.body.innerText;
}
// Truncate to avoid hitting token limits
return content.substring(0, 8000);
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'extractContent') {
sendResponse({ content: extractPageContent() });
}
});Step 5: Connect to the AI API
This is the core logic in popup.js:
const API_KEY = 'your-api-key-here'; // Store securely in production
const API_URL = 'https://api.openai.com/v1/chat/completions';
document.getElementById('summarize-btn').addEventListener('click', async () => {
const btn = document.getElementById('summarize-btn');
const status = document.getElementById('status');
const result = document.getElementById('result');
btn.disabled = true;
status.textContent = 'Extracting page content...';
try {
// Get content from the active tab
const [tab] = await chrome.tabs.query({
active: true,
currentWindow: true
});
const response = await chrome.tabs.sendMessage(tab.id, {
action: 'extractContent'
});
status.textContent = 'Sending to AI...';
// Call the AI API
const aiResponse = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content: 'Summarize the following web page content in 3-5 bullet points. Be concise and focus on key information.'
},
{
role: 'user',
content: response.content
}
],
max_tokens: 500
})
});
const data = await aiResponse.json();
const summary = data.choices[0].message.content;
result.textContent = summary;
result.classList.remove('hidden');
status.textContent = 'Summary complete';
} catch (error) {
status.textContent = `Error: ${error.message}`;
} finally {
btn.disabled = false;
}
});Step 6: Load and Test Your Extension
- Open Chrome and navigate to
chrome://extensions/ - Enable "Developer mode" in the top right
- Click "Load unpacked" and select your project folder
- Navigate to any article or blog post
- Click the extension icon and hit "Summarize This Page"
You should see bullet points appear within a few seconds.
Step 7: Improve and Customize
Once the basic version works, consider these enhancements:
Add multiple AI actions: Instead of just summarization, offer translation, key takeaways, or question answering. Add a dropdown in the popup to select the action, then swap the system prompt accordingly.
Store the API key securely: Use chrome.storage.sync to let users enter their own API key through an options page rather than hardcoding it.
Support streaming responses: For longer outputs, use the streaming API endpoint to display text as it generates, giving users faster feedback.
Switch models: The same code works with Claude by changing the API endpoint and adjusting the request format slightly. You can also use ChatGPT Plus for higher rate limits.
Practical Tips
- Token management: Always truncate page content before sending. Most articles fit within 4000-8000 characters. Going beyond wastes tokens without improving summary quality.
- Error handling: Network requests fail. Always wrap API calls in try/catch and show meaningful error messages to users.
- Cost control: Use
gpt-4o-minifor summarization tasks. It is fast, cheap, and more than capable for this use case. - Testing: Test on different types of pages (news articles, documentation, social media) since content extraction behaves differently on each.
- Publishing: When ready, submit to the Chrome Web Store. The review process takes 1-3 days. Remove hardcoded API keys before submission.
Going Further
This basic architecture supports many practical extensions:
- A writing assistant that rewrites selected text
- A research tool that finds related sources
- A coding helper that explains error messages on Stack Overflow pages
- A shopping assistant that compares prices across tabs
The pattern is always the same: extract context from the page, send it to an AI model with the right prompt, and display the result.
Need a More Powerful AI?
Claude excels at longer context and nuanced reasoning. ChatGPT is great for fast general-purpose tasks.
Try Claude