### Setup local development environment Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/CONTRIBUTING.md Commands to clone a fork and install necessary project dependencies. ```sh # clone your fork to your local machine git clone https://github.com/your-fork/chrome-extensions-samples.git cd chrome-extensions-samples # install dependencies npm install ``` -------------------------------- ### Run the demo chat application Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/ai.gemini-on-device-audio-scribe/README.md Starts a local server to host the demo chat application for testing the extension. ```bash npx serve demo-chat-app ``` -------------------------------- ### Install Gemini API Client Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/ai.gemini-in-the-cloud/README.md Run this command in your project's root directory to install the necessary Gemini API client library. ```sh npm install ``` -------------------------------- ### Install wasm-pack Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/cookbook.wasm-helloworld-print-nomodule/README.md Use cargo to install the wasm-pack tool required for building WASM modules. ```bash cargo install wasm-pack ``` -------------------------------- ### Handle Extension Lifecycle Events Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt The service-worker.js demonstrates how to use chrome.runtime.onInstalled and chrome.runtime.onStartup listeners to manage the extension's lifecycle, such as opening a welcome page on installation or logging on browser startup. ```javascript // service-worker.js // Extension lifecycle events chrome.runtime.onInstalled.addListener(({ reason, previousVersion }) => { switch (reason) { case chrome.runtime.OnInstalledReason.INSTALL: console.log('Extension installed'); chrome.tabs.create({ url: 'welcome.html' }); break; case chrome.runtime.OnInstalledReason.UPDATE: console.log(`Updated from ${previousVersion}`); break; case chrome.runtime.OnInstalledReason.CHROME_UPDATE: console.log('Chrome was updated'); break; } }); // Handle extension startup chrome.runtime.onStartup.addListener(() => { console.log('Browser started, extension loaded'); }); ``` -------------------------------- ### Stylizr CSS Example Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/api-samples/storage/stylizr/options.html This is an example of CSS that can be used with the Stylizr extension. It defines styles for the body, labels, textareas, and a message class. ```css body { font-family: sans-serif; } label { display: block; } textarea { font-family: monospace; } .message { height: 20px; background: #eee; padding: 5px; } ``` -------------------------------- ### Manage Bookmarks with chrome.bookmarks API Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Use the chrome.bookmarks API to interact with Chrome's bookmark system. Requires the 'bookmarks' permission in manifest.json. Examples cover getting the bookmark tree, creating, searching, removing, updating, and moving bookmarks and folders. ```javascript // manifest.json: permissions: ["bookmarks"] // Get the entire bookmark tree chrome.bookmarks.getTree((tree) => { displayBookmarks(tree[0].children); }); // Recursively display bookmarks function displayBookmarks(nodes, indent = 0) { for (const node of nodes) { if (node.url) { console.log(' '.repeat(indent) + `📄 ${node.title}: ${node.url}`); } else { console.log(' '.repeat(indent) + `📁 ${node.title}`); } if (node.children) { displayBookmarks(node.children, indent + 2); } } } ``` ```javascript // Create a new bookmark chrome.bookmarks.create({ title: 'Google', url: 'https://www.google.com', parentId: '1' // '1' is typically the Bookmarks Bar }, (newBookmark) => { console.log('Bookmark created with ID:', newBookmark.id); }); // Search for bookmarks chrome.bookmarks.search({ url: 'https://www.google.com/' }, (results) => { console.log(`Found ${results.length} matching bookmarks`); }); // Remove a bookmark by ID chrome.bookmarks.remove(bookmarkId, () => { console.log('Bookmark removed'); }); // Update a bookmark chrome.bookmarks.update(bookmarkId, { title: 'New Title', url: 'https://newurl.com' }); // Create a bookmark folder chrome.bookmarks.create({ title: 'My Folder', parentId: '1' }); // Move a bookmark to a different folder chrome.bookmarks.move(bookmarkId, { parentId: folderId }); ``` -------------------------------- ### Get Extension URL at Runtime Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/api-samples/web-accessible-resources/index.html Use chrome.runtime.getURL() to construct the URL for web accessible resources dynamically. This is useful when the resource path is not known at manifest declaration time or needs to be generated. ```javascript const imageUrl = chrome.runtime.getURL("test2.png"); console.log(imageUrl); ``` -------------------------------- ### Query, Create, Update, and Manage Browser Tabs Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Use the chrome.tabs API to query tabs by URL, get the active tab, create new tabs, update existing tabs, focus windows, and group tabs. Ensure proper error handling for asynchronous operations. ```javascript const tabs = await chrome.tabs.query({ url: [ 'https://developer.chrome.com/docs/webstore/*', 'https://developer.chrome.com/docs/extensions/*' ] }); ``` ```javascript const collator = new Intl.Collator(); tabs.sort((a, b) => collator.compare(a.title, b.title)); ``` ```javascript const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true }); ``` ```javascript const newTab = await chrome.tabs.create({ url: 'https://example.com', active: true, pinned: false }); ``` ```javascript await chrome.tabs.update(tab.id, { active: true, url: 'https://newurl.com' }); ``` ```javascript await chrome.windows.update(tab.windowId, { focused: true }); ``` ```javascript const tabIds = tabs.map(({ id }) => id); if (tabIds.length) { const groupId = await chrome.tabs.group({ tabIds }); await chrome.tabGroups.update(groupId, { title: 'DOCS', color: 'blue' }); } ``` ```javascript chrome.action.onClicked.addListener(async function () { const screenshotUrl = await chrome.tabs.captureVisibleTab(); // screenshotUrl is a data URL of the screenshot chrome.tabs.create({ url: 'screenshot.html' }); }); ``` ```javascript chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { if (changeInfo.status === 'complete') { console.log('Tab finished loading:', tab.url); } }); ``` -------------------------------- ### Create and Handle Context Menus Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Demonstrates creating various context menu types including parent-child hierarchies, radio buttons, and checkboxes, along with handling click events. ```javascript // service-worker.js - Create context menu items on install chrome.runtime.onInstalled.addListener(() => { // Create items for different contexts const contexts = ['page', 'selection', 'link', 'editable', 'image', 'video', 'audio']; for (const context of contexts) { chrome.contextMenus.create({ id: context, title: `Action for "${context}"`, contexts: [context] }); } // Create a parent item with children chrome.contextMenus.create({ id: 'parent', title: 'Parent Menu' }); chrome.contextMenus.create({ id: 'child1', parentId: 'parent', title: 'Child Item 1' }); chrome.contextMenus.create({ id: 'child2', parentId: 'parent', title: 'Child Item 2' }); // Create radio and checkbox items chrome.contextMenus.create({ id: 'radio', title: 'Radio Option', type: 'radio' }); chrome.contextMenus.create({ id: 'checkbox', title: 'Enable Feature', type: 'checkbox', checked: false }); }); // Handle menu item clicks chrome.contextMenus.onClicked.addListener((info, tab) => { switch (info.menuItemId) { case 'selection': console.log('Selected text:', info.selectionText); break; case 'link': console.log('Link URL:', info.linkUrl); break; case 'checkbox': console.log('Checkbox state:', info.checked); break; case 'radio': console.log('Radio selected'); break; } }); ``` -------------------------------- ### Basic Open Props Styling Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/ai.gemini-on-device-audio-scribe/sidepanel.html Demonstrates basic styling using Open Props custom properties for font size, padding, margins, borders, and shadows. Includes a hover effect and fade-in animation. ```css :root { --font-size-00: 0.6rem; } body { margin: auto; padding: var(--size-2); } ul { padding: var(--size-2); } li { background: var(--surface-3); border: 1px solid var(--surface-1); padding: var(--size-4); margin-bottom: var(--size-3); border-radius: var(--radius-3); box-shadow: var(--shadow-2); list-style: none; border-radius: var(--radius-2); padding: var(--size-fluid-3); box-shadow: var(--shadow-2); &:hover { box-shadow: var(--shadow-3); } @media (--motionOK) { animation: var(--animation-fade-in); } } ``` -------------------------------- ### Integrate Side Panel with Context Menu Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Creates a context menu item to define selected text and opens the side panel to display the definition. Stores the selected word in session storage. ```javascript // sidepanel.js - Dictionary side panel with context menu integration chrome.runtime.onInstalled.addListener(() => { chrome.contextMenus.create({ id: 'define-word', title: 'Define', contexts: ['selection'] }); }); chrome.contextMenus.onClicked.addListener((data, tab) => { // Store selected word in session storage chrome.storage.session.set({ lastWord: data.selectionText }); // Open the side panel chrome.sidePanel.open({ tabId: tab.id }); }); ``` -------------------------------- ### Build WASM locally Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/cookbook.wasm-helloworld-print/README.md Commands to navigate to the WASM directory and build the project for the web target. ```bash cd wasm wasm-pack build --target web ``` -------------------------------- ### Build WASM module Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/cookbook.wasm-helloworld-print-nomodule/README.md Navigate to the wasm directory and compile the project into a WASM module using the no-modules target. ```bash cd wasm wasm-pack build --target no-modules ``` -------------------------------- ### Build Sidepanel JavaScript Bundle Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/ai.gemini-in-the-cloud/README.md Execute this command to compile the JavaScript code for the extension's sidepanel functionality. ```sh npm run build ``` -------------------------------- ### Import Open Props CSS Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/ai.gemini-on-device-audio-scribe/sidepanel.html Import Open Props CSS and its utility modules. Ensure these imports are placed at the beginning of your CSS file. ```css @import 'https://unpkg.com/open-props'; @import 'https://unpkg.com/open-props/normalize.min.css'; @import 'https://unpkg.com/open-props/buttons.min.css'; @import 'https://unpkg.com/open-props/theme.light.switch.min.css'; @import 'https://unpkg.com/open-props/theme.dark.switch.min.css'; ``` -------------------------------- ### Configure Side Panel in Manifest Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Defines the side panel's default HTML file and enables the sidePanel permission in the extension's manifest. ```json { "manifest_version": 3, "name": "Side Panel Extension", "permissions": ["sidePanel"], "side_panel": { "default_path": "sidepanel.html" }, "background": { "service_worker": "service-worker.js" } } ``` -------------------------------- ### Import Open Props CSS for Styling Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/ai.gemini-on-device-alt-texter/popup.html This CSS code imports various Open Props stylesheets for styling the extension's UI. It sets up basic styles for the body, headings, textareas, and buttons, including responsive font sizes and layout. ```css @import 'https://unpkg.com/open-props'; @import 'https://unpkg.com/open-props/normalize.min.css'; @import 'https://unpkg.com/open-props/buttons.min.css'; @import 'https://unpkg.com/open-props/theme.light.switch.min.css'; @import 'https://unpkg.com/open-props/theme.dark.switch.min.css'; :root { --font-size-00: 0.6rem; } body { margin: auto; padding: var(--size-2); width: 500px; padding: 10px; } h4 { margin-bottom: var(--size-2); } textarea { width: 100%; height: 100px; } button { margin-right: 5px; } #loading, textarea { margin: 16px 0; height: 200px; } ``` -------------------------------- ### Communicate with native hosts via JavaScript Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Methods for establishing persistent ports or sending one-time messages to native applications. ```javascript // popup.js - Connect and communicate with native host let port = null; function connect() { const hostName = 'com.google.chrome.example.echo'; // Establish persistent connection port = chrome.runtime.connectNative(hostName); // Listen for messages from native app port.onMessage.addListener((message) => { console.log('Received from native app:', message); }); // Handle disconnection port.onDisconnect.addListener(() => { console.log('Disconnected:', chrome.runtime.lastError?.message); port = null; }); } // Send message to native app function sendMessage(text) { if (port) { port.postMessage({ text: text }); } } // Alternative: One-time message (no persistent connection) function sendOneTimeMessage() { chrome.runtime.sendNativeMessage( 'com.google.chrome.example.echo', { text: 'Hello from extension!' }, (response) => { if (chrome.runtime.lastError) { console.error(chrome.runtime.lastError.message); } else { console.log('Response:', response); } } ); } ``` -------------------------------- ### Define Keyboard Shortcuts with chrome.commands API Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Configure keyboard shortcuts for extension actions using the Commands API. Define commands and their suggested keys in manifest.json. The service worker can listen for these commands and execute corresponding logic. ```json { "manifest_version": 3, "name": "Commands Demo", "commands": { "run-action": { "suggested_key": { "default": "Ctrl+Shift+Y", "mac": "Command+Shift+Y" }, "description": "Run the main action" }, "toggle-feature": { "suggested_key": { "default": "Ctrl+Shift+U", "mac": "Command+Shift+U" }, "description": "Toggle feature on/off" }, "_execute_action": { "suggested_key": { "default": "Ctrl+B", "mac": "Command+B" } } } } ``` ```javascript // service-worker.js let featureEnabled = false; chrome.commands.onCommand.addListener(async (command) => { if (command === 'run-action') { chrome.notifications.create({ type: 'basic', iconUrl: 'images/icon-128.png', title: 'Commands API Demo', message: 'The "run-action" command was triggered.' }); } if (command === 'toggle-feature') { featureEnabled = !featureEnabled; chrome.action.setBadgeText({ text: featureEnabled ? 'ON' : '' }); chrome.action.setBadgeBackgroundColor({ color: '#4688F1' }); chrome.notifications.create({ type: 'basic', iconUrl: 'images/icon-128.png', title: 'Feature Toggled', message: `The feature is now ${featureEnabled ? 'ON' : 'OFF'}.` }); } }); // Get all registered commands and their shortcuts chrome.commands.getAll((commands) => { for (const {name, shortcut, description} of commands) { console.log(`Command: ${name}, Shortcut: ${shortcut || 'Not set'}`); } }); ``` -------------------------------- ### Manage Cookies with Cookies API Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Demonstrates querying, deleting, and setting cookies, as well as listening for changes. Requires 'cookies' permission and host permissions. ```javascript // manifest.json: permissions: ["cookies"], host_permissions: [""] // Get all cookies for a domain async function getCookiesForDomain(domain) { const cookies = await chrome.cookies.getAll({ domain }); console.log(`Found ${cookies.length} cookies for ${domain}`); return cookies; } // Delete all cookies for a domain async function deleteDomainCookies(domain) { const cookies = await chrome.cookies.getAll({ domain }); if (cookies.length === 0) { return 'No cookies found'; } for (const cookie of cookies) { // Determine correct protocol for deletion const protocol = cookie.secure ? 'https:' : 'http:'; const cookieUrl = `${protocol}//${cookie.domain}${cookie.path}`; await chrome.cookies.remove({ url: cookieUrl, name: cookie.name, storeId: cookie.storeId }); } return `Deleted ${cookies.length} cookie(s)`; } // Set a cookie chrome.cookies.set({ url: 'https://example.com', name: 'myCookie', value: 'myValue', expirationDate: (Date.now() / 1000) + 3600 // 1 hour from now }); // Listen for cookie changes chrome.cookies.onChanged.addListener(({ removed, cookie, cause }) => { console.log(`Cookie ${removed ? 'removed' : 'set'}: ${cookie.name}`); console.log(`Cause: ${cause}`); // 'explicit', 'expired', 'overwrite', etc. }); ``` -------------------------------- ### Schedule Tasks with Alarms API Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Shows how to create periodic and one-time alarms, listen for alarm events, and manage existing alarms. Requires the 'alarms' permission in manifest.json. ```javascript // manifest.json permissions: ["alarms"] // Create alarms on extension install chrome.runtime.onInstalled.addListener(({ reason }) => { if (reason !== chrome.runtime.OnInstalledReason.INSTALL) return; // Create a repeating alarm (minimum period is 1 minute) chrome.alarms.create('periodic-alarm', { delayInMinutes: 1, // First trigger after 1 minute periodInMinutes: 1 // Repeat every minute }); // Create a one-time alarm using absolute time chrome.alarms.create('one-time-alarm', { when: Date.now() + 60000 // Trigger after 60 seconds }); }); // Listen for alarm events chrome.alarms.onAlarm.addListener((alarm) => { console.log(`Alarm "${alarm.name}" fired at ${alarm.scheduledTime}`); if (alarm.name === 'periodic-alarm') { // Perform periodic task checkForUpdates(); } }); // Get all registered alarms chrome.alarms.getAll((alarms) => { for (const alarm of alarms) { console.log(`Alarm: ${alarm.name}, Next: ${new Date(alarm.scheduledTime)}`); } }); // Clear a specific alarm chrome.alarms.clear('one-time-alarm', (wasCleared) => { console.log(wasCleared ? 'Alarm cleared' : 'Alarm not found'); }); // Clear all alarms chrome.alarms.clearAll((wasCleared) => { console.log('All alarms cleared:', wasCleared); }); ``` -------------------------------- ### Configure Declarative Net Request in Manifest Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Enables the declarativeNetRequest and declarativeNetRequestFeedback permissions and specifies the path to the rules JSON file in the extension's manifest. ```json { "manifest_version": 3, "name": "URL Blocker", "permissions": ["declarativeNetRequest", "declarativeNetRequestFeedback"], "declarative_net_request": { "rule_resources": [{ "id": "ruleset_1", "enabled": true, "path": "rules.json" }] } } ``` -------------------------------- ### Define Blocking and Redirect Rules Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt A JSON file defining rules for blocking specific domains and redirecting others. Includes conditions based on URL filters and resource types. ```json // rules.json - Declarative blocking rules [ { "id": 1, "priority": 1, "action": { "type": "block" }, "condition": { "urlFilter": "||example.com", "resourceTypes": ["main_frame"] } }, { "id": 2, "priority": 1, "action": { "type": "block" }, "condition": { "urlFilter": "*://*.ads.com/*", "resourceTypes": ["script", "image"] } }, { "id": 3, "priority": 2, "action": { "type": "redirect", "redirect": { "url": "https://safe-site.com" } }, "condition": { "urlFilter": "||dangerous-site.com", "resourceTypes": ["main_frame"] } } ] ``` -------------------------------- ### Configure Native Messaging in manifest.json Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Required manifest configuration to enable native messaging capabilities. ```json { "manifest_version": 3, "name": "Native Messaging Example", "permissions": ["nativeMessaging"], "action": { "default_popup": "popup.html" } } ``` -------------------------------- ### Configure Identity API in manifest.json Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Required manifest configuration to enable identity permissions and define OAuth2 client settings. ```json { "manifest_version": 3, "name": "Identity Example", "permissions": ["identity", "identity.email"], "oauth2": { "client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com", "scopes": ["https://www.googleapis.com/auth/userinfo.profile"] } } ``` -------------------------------- ### Manifest V3 Basic Structure Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Defines the metadata, permissions, and components for a Chrome Extension. This is the fundamental configuration file. ```json { "manifest_version": 3, "name": "My Extension", "version": "1.0", "description": "A description of my extension", "icons": { "16": "images/icon-16.png", "32": "images/icon-32.png", "48": "images/icon-48.png", "128": "images/icon-128.png" }, "action": { "default_popup": "popup.html", "default_icon": { "16": "images/icon-16.png", "32": "images/icon-32.png" }, "default_title": "Click to open" }, "background": { "service_worker": "service-worker.js" }, "permissions": ["storage", "activeTab"], "host_permissions": ["https://example.com/*"] } ``` -------------------------------- ### Manifest V3 Configuration for Offscreen Clipboard Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt This manifest.json file declares the necessary permissions for using the Offscreen API and clipboardWrite. It specifies the service worker responsible for background tasks. ```json { "manifest_version": 3, "name": "Offscreen Clipboard", "permissions": ["offscreen", "clipboardWrite"], "background": { "service_worker": "background.js" } } ``` -------------------------------- ### Filter Navigation Events by URL Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Use the options object in addListener to filter webNavigation events for specific URLs, such as those containing 'example.com'. ```javascript // Filter events for specific URLs chrome.webNavigation.onCompleted.addListener( (details) => { console.log('Target site loaded:', details.url); }, { url: [{ hostContains: 'example.com' }] } ); ``` -------------------------------- ### Define Web Accessible Resources in manifest.json Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/api-samples/web-accessible-resources/index.html Specify which extension assets are accessible to external websites. This configuration is crucial for controlling access to images, scripts, or other files. ```json { "manifest_version": 3, "name": "Web Accessible Resources Demo", "version": "1.0", "web_accessible_resources": [ { "resources": [ "test1.png", "test2.png" ], "matches": [ "https://web-accessible-resources-1.glitch.me/*" ] }, { "resources": [ "test3.png", "test4.png" ], "matches": [ "https://web-accessible-resources-2.glitch.me/*" ] }, { "resources": [ "test3.png", "test4.png" ], "matches": [ "https://web-accessible-resources-3.glitch.me/*" ], "use_dynamic_url": true } ] } ``` -------------------------------- ### Declare Content Scripts in Manifest Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Configure content scripts in the manifest.json file to automatically inject JavaScript and CSS into web pages matching specified patterns. Use 'run_at' to control injection timing. ```json { "manifest_version": 3, "name": "Reading Time", "content_scripts": [ { "js": ["scripts/content.js"], "css": ["styles/content.css"], "matches": [ "https://developer.chrome.com/docs/extensions/*", "https://developer.chrome.com/docs/webstore/*" ], "run_at": "document_idle" } ] } ``` -------------------------------- ### Define Native Messaging host manifest Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Configuration file required by the native host to authorize communication with specific extension IDs. ```json // Native host manifest (com.google.chrome.example.echo.json) // Location: // Windows: HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\ // macOS: ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/ // Linux: ~/.config/google-chrome/NativeMessagingHosts/ { "name": "com.google.chrome.example.echo", "description": "Chrome Native Messaging Echo Host", "path": "/path/to/native-messaging-host", "type": "stdio", "allowed_origins": [ "chrome-extension://YOUR_EXTENSION_ID/" ] } ``` -------------------------------- ### Implement Message Passing Between Extension Components Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt This snippet shows how to set up a listener for messages using chrome.runtime.onMessage and send messages using chrome.runtime.sendMessage. It includes handling asynchronous responses and sending messages to specific tabs. ```javascript // Message passing between components chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { console.log('Message from:', sender.tab ? `Tab ${sender.tab.id}` : 'Extension'); if (message.type === 'getData') { // Async response fetchData().then(data => sendResponse({ data })); return true; // Keep message channel open for async response } if (message.type === 'log') { console.log(message.text); sendResponse({ success: true }); } }); // Send message from content script to service worker // content-script.js chrome.runtime.sendMessage( { type: 'getData', query: 'user' }, (response) => { console.log('Received:', response.data); } ); // Send message to specific tab chrome.tabs.sendMessage(tabId, { type: 'highlight' }, (response) => { console.log('Tab response:', response); }); // Get extension URL const optionsUrl = chrome.runtime.getURL('options.html'); // Get extension manifest const manifest = chrome.runtime.getManifest(); console.log(`${manifest.name} v${manifest.version}`); ``` -------------------------------- ### Handle postMessage Events for Template Rendering Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/api-samples/sandbox/sandbox/sandbox.html This event listener processes messages received from other frames. It identifies the requested template by name, checks if it exists, and then renders it using the provided context. If the template is unknown or the command is not 'render', it returns an appropriate message. ```javascript // Set up message event handler: window.addEventListener('message', function (event) { const command = event.data.command; const template = templates[event.data.templateName]; let result = 'invalid request'; // if we don't know the templateName requested, return an error message if (template) { switch (command) { case 'render': result = template(event.data.context); break; // you could even do dynamic compilation, by accepting a command // to compile a new template instead of using static ones, for example: // case 'new': // template = Handlebars.compile(event.data.templateSource); // result = template(event.data.context); // break; } } else { result = 'Unknown template: ' + event.data.templateName; } event.source.postMessage({ result: result }, event.origin); }); ``` -------------------------------- ### Create Offscreen Document for Clipboard Operations Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt The background.js script uses the chrome.offscreen.createDocument method to set up an offscreen document for clipboard operations. It then sends a message to this document to perform the copy action. ```javascript // background.js - Use offscreen document to write to clipboard async function copyToClipboard(text) { // Create offscreen document await chrome.offscreen.createDocument({ url: 'offscreen.html', reasons: [chrome.offscreen.Reason.CLIPBOARD], justification: 'Write text to the clipboard' }); // Send data to offscreen document chrome.runtime.sendMessage({ type: 'copy-to-clipboard', target: 'offscreen-doc', data: text }); } chrome.action.onClicked.addListener(async () => { await copyToClipboard('Hello from extension!'); }); ``` -------------------------------- ### Omnibox Manifest Configuration Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Configure the omnibox keyword in the manifest.json file for your Chrome extension. ```json { "manifest_version": 3, "name": "Omnibox Example", "omnibox": { "keyword": "search" }, "background": { "service_worker": "service-worker.js" } } ``` -------------------------------- ### Track Navigation Lifecycle Events Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Monitor the navigation process using onBeforeNavigate, onCommitted, and onDOMContentLoaded events to log navigation details and inject scripts. ```javascript // Track navigation lifecycle chrome.webNavigation.onBeforeNavigate.addListener((details) => { console.log('Navigation starting to:', details.url); }); chrome.webNavigation.onCommitted.addListener((details) => { console.log('Navigation committed:', details.transitionType); }); chrome.webNavigation.onDOMContentLoaded.addListener(async ({ tabId, url }) => { // Inject script when DOM is ready if (url.includes('target-site.com')) { await chrome.scripting.executeScript({ target: { tabId }, files: ['content-script.js'] }); } }); ``` -------------------------------- ### Offscreen HTML Structure Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt A minimal HTML file is required to host the offscreen JavaScript. This file links to the offscreen.js script. ```html ``` -------------------------------- ### Implement Identity API authentication flows Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Functions for retrieving user profile info, managing OAuth2 tokens, and revoking access. ```javascript // Get user's email without OAuth async function getEmail() { const profileInfo = await chrome.identity.getProfileUserInfo({ accountStatus: chrome.identity.AccountStatus.ANY }); console.log('User email:', profileInfo.email); return profileInfo; } // Interactive sign-in flow async function signIn() { try { const token = await chrome.identity.getAuthToken({ interactive: true }); console.log('Access token acquired:', token.token); return token; } catch (error) { console.error('Sign-in failed:', error.message); } } // Silent sign-in (non-interactive) async function silentSignIn() { try { const token = await chrome.identity.getAuthToken({ interactive: false }); return token; } catch (error) { // User needs to sign in interactively return null; } } // Fetch user info with token async function getUserInfo(interactive) { const token = await chrome.identity.getAuthToken({ interactive }); const response = await fetch( 'https://openidconnect.googleapis.com/v1/userinfo', { headers: { Authorization: `Bearer ${token.token}` } } ); if (response.status === 401) { // Token expired, remove and retry await chrome.identity.removeCachedAuthToken({ token: token.token }); return getUserInfo(interactive); } return response.json(); } // Revoke token and sign out async function revokeToken() { const token = await chrome.identity.getAuthToken({ interactive: false }); // Remove from Chrome's cache await chrome.identity.removeCachedAuthToken({ token: token.token }); // Revoke on Google's server await fetch( `https://oauth2.googleapis.com/revoke?token=${token.token}`, { method: 'POST' } ); console.log('Token revoked'); } ``` -------------------------------- ### Apply CSS styles to extension body Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/api-samples/idle/history.html Defines layout and typography for the extension popup or options page. ```css body { width: 100%; margin: 0; padding: 0 1em; box-sizing: border-box; font: 13px Arial; } ``` -------------------------------- ### Precompile Handlebars Templates Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/api-samples/sandbox/sandbox/sandbox.html This code iterates through script tags with type 'text/x-handlebars-template', extracts their content, and precompiles them using Handlebars. This is useful for preparing templates before they are needed for rendering. ```javascript const templatesElements = document.querySelectorAll( "script[type='text/x-handlebars-template']" ); let templates = {}, source, name; // precompile all templates in this page for (let i = 0; i < templatesElements.length; i++) { source = templatesElements[i].innerHTML; name = templatesElements[i].id; templates[name] = Handlebars.compile(source); } ``` -------------------------------- ### Listen for Page Load Completion Source: https://context7.com/googlechrome/chrome-extensions-samples/llms.txt Use chrome.webNavigation.onCompleted to trigger actions when a page finishes loading. Requires 'webNavigation' and 'notifications' permissions. ```javascript // manifest.json: permissions: ["webNavigation", "notifications"] // Notify when any page finishes loading chrome.webNavigation.onCompleted.addListener((details) => { chrome.notifications.create({ type: 'basic', iconUrl: 'icon.png', title: 'Page Loaded', message: `Completed loading: ${details.url}` }); }); ``` -------------------------------- ### Set Extension Action Options for Badge Text Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/sample.dnr-rule-manager/README.md Sets the extension's badge text to the number of requests modified by the extension. Requires the 'declarativeNetRequestFeedback' permission. ```javascript chrome.declarativeNetRequest.setExtensionActionOptions({ badge: { text: String(count) } }); ``` -------------------------------- ### Import and Shim XHR in Service Worker Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/functional-samples/libraries-xhr-in-sw/README.md Import a shim for XMLHttpRequest and set the global XMLHttpRequest to it to enable XHR usage in service workers. This is typically done in the background script. ```javascript import "./third_party/xhr-shim/xhr-shim.js"; // Set the global XMLHttpRequest to the shim self.XMLHttpRequest = self.XMLHttpRequest; ``` -------------------------------- ### CSS Styling for Action API Popup Source: https://github.com/googlechrome/chrome-extensions-samples/blob/main/api-samples/action/popups/popup.html Defines the layout and visual properties for the extension popup container and text elements. ```css .center { min-height: 100px; min-width: 200px; display: grid; flex-direction: column; align-items: center; justify-content: center; gap: 1ch; background-color: lightseagreen; } .text { font-size: 2rem; font-weight: bold; color: white; } ```