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

  1. Open Chrome and navigate to chrome://extensions/
  2. Enable "Developer mode" in the top right
  3. Click "Load unpacked" and select your project folder
  4. Navigate to any article or blog post
  5. 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-mini for 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