Create desktop notifications with the Chrome Notifications API. Learn how to build engaging notification experiences. This tutorial walks you through creating a Chrome extension that monitors GitHub notifications.
notifications scopegithub-notifier/
├── manifest.json
├── popup/popup.html, popup.js
├── background/background.js
├── options/options.html, options.js
{
"manifest_version": 3,
"name": "GitHub Notifier",
"permissions": ["alarms", "notifications", "storage"],
"host_permissions": ["https://api.github.com/"],
"action": { "default_popup": "popup/popup.html" },
"background": { "service_worker": "background/background.js" },
"options_page": "options/options.html"
}
<!-- popup/popup.html -->
<!DOCTYPE html><html><body>
<h3>GitHub Notifications</h3><p id="count">Loading...</p>
<button id="openSettings">Settings</button>
<script src="popup.js"></script></body></html>
Set up periodic polling using the Alarms API:
// background/background.js
chrome.alarms.create('pollNotifications', { periodInMinutes: 5 });
chrome.alarms.onAlarm.addListener((a) => { if (a.name === 'pollNotifications') check(); });
async function check() {
const { token } = await chrome.storage.local.get('token');
if (!token) return;
const r = await fetch('https://api.github.com/notifications', {
headers: { 'Authorization': `Bearer ${token}`, 'Accept': 'application/vnd.github+json' }
});
if (r.status === 401) { await chrome.storage.local.remove('token'); return; }
if (r.status === 403) return;
const n = await r.json();
const u = n.filter(x => x.unread);
await badge(u.length);
const lc = await chrome.storage.local.get('lastCheck');
if (lc.lastCheck && n.some(x => new Date(x.updated_at) > new Date(lc.lastCheck))) notify(u);
await chrome.storage.local.set({ lastCheck: new Date().toISOString() });
}
Store token in local storage. For production, implement OAuth.
async function badge(count) {
await chrome.action.setBadgeText({ text: count > 0 ? String(count) : '' });
await chrome.action.setBadgeBackgroundColor({ color: '#ff4500' });
}
Implement using the Notifications API:
async function notify(list) {
const l = list[0];
await chrome.notifications.create({
type: 'basic', iconUrl: 'icons/icon48.png',
title: l.repository.full_name, message: l.subject.title, priority: 1
});
}
chrome.notifications.onClicked.addListener((id) => {
chrome.tabs.create({ url: 'https://github.com/notifications' });
chrome.notifications.clear(id);
});
<!-- options/options.html -->
<!DOCTYPE html><html><body>
<h2>Settings</h2>
<input type="password" id="token" placeholder="Personal Access Token">
<button id="save">Save</button>
<script src="options.js"></script></body></html>
// options/options.js
document.getElementById('save').addEventListener('click', async () => {
await chrome.storage.local.set({ token: document.getElementById('token').value });
});
chrome.action.onClicked.addListener(async () => {
const { token } = await chrome.storage.local.get('token');
await fetch('https://api.github.com/notifications', {
method: 'PUT', headers: { 'Authorization': `Bearer ${token}` },
body: JSON.stringify({ read: true })
});
await badge(0);
});
| Error | Handling | |——-|———-| | 401 Unauthorized | Clear token, prompt re-auth | | 403 Rate Limited | Increase poll interval | | Network Error | Retry with backoff |
You’ve built a GitHub notifications extension with alarm-based polling, badge updates, desktop notifications, and token configuration. For production, upgrade to OAuth as documented in Identity and OAuth. -e —
Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.