Created
October 20, 2025 12:56
-
-
Save Trippnology/e1b0deb1c4b0dceaee92003ead1a339a to your computer and use it in GitHub Desktop.
Clear GitHub spam notifications - Mark GitHub notifications as read
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env node | |
| /** | |
| * GitHub Notification Cleaner | |
| * Clears all notifications including unreachable ones from deleted accounts | |
| * | |
| * Setup: | |
| * 1. Create a Personal Access Token at https://github.com/settings/tokens | |
| * - Required scope: notifications | |
| * 2. Set the token as an environment variable: GITHUB_TOKEN=your_token_here | |
| * 3. Run: node clear-notifications.js | |
| */ | |
| const https = require('node:https'); | |
| const GITHUB_TOKEN = process.env.GITHUB_TOKEN; | |
| const API_BASE = 'api.github.com'; | |
| if (!GITHUB_TOKEN) { | |
| console.error('Error: GITHUB_TOKEN environment variable not set'); | |
| console.error('Create a token at: https://github.com/settings/tokens'); | |
| console.error('Required scope: notifications'); | |
| process.exit(1); | |
| } | |
| function makeRequest(path, method = 'GET', data = null) { | |
| return new Promise((resolve, reject) => { | |
| const options = { | |
| hostname: API_BASE, | |
| path: path, | |
| method: method, | |
| headers: { | |
| 'User-Agent': 'GitHub-Notification-Cleaner', | |
| Authorization: `Bearer ${GITHUB_TOKEN}`, | |
| Accept: 'application/vnd.github+json', | |
| 'X-GitHub-Api-Version': '2022-11-28', | |
| }, | |
| }; | |
| if (data) { | |
| const jsonData = JSON.stringify(data); | |
| options.headers['Content-Type'] = 'application/json'; | |
| options.headers['Content-Length'] = Buffer.byteLength(jsonData); | |
| } | |
| const req = https.request(options, (res) => { | |
| let body = ''; | |
| res.on('data', (chunk) => { | |
| body += chunk; | |
| }); | |
| res.on('end', () => { | |
| if (res.statusCode >= 200 && res.statusCode < 300) { | |
| resolve({ | |
| statusCode: res.statusCode, | |
| data: body ? JSON.parse(body) : null, | |
| }); | |
| } else { | |
| reject(new Error(`HTTP ${res.statusCode}: ${body}`)); | |
| } | |
| }); | |
| }); | |
| req.on('error', reject); | |
| if (data) { | |
| req.write(JSON.stringify(data)); | |
| } | |
| req.end(); | |
| }); | |
| } | |
| async function getNotifications() { | |
| console.log('Fetching notifications...'); | |
| const response = await makeRequest('/notifications?all=true&per_page=100'); | |
| return response.data; | |
| } | |
| async function markNotificationAsRead(threadId) { | |
| await makeRequest(`/notifications/threads/${threadId}`, 'PATCH'); | |
| } | |
| async function markAllAsRead() { | |
| const lastReadAt = new Date().toISOString(); | |
| await makeRequest('/notifications', 'PUT', { last_read_at: lastReadAt }); | |
| } | |
| async function clearAllNotifications() { | |
| try { | |
| console.log('Starting notification cleanup...\n'); | |
| // Get all notifications | |
| const notifications = await getNotifications(); | |
| if (notifications.length === 0) { | |
| console.log('✓ No notifications found. Your inbox is clean!'); | |
| return; | |
| } | |
| console.log(`Found ${notifications.length} notification(s)\n`); | |
| // Try to mark each individually first (catches unreachable ones) | |
| let cleared = 0; | |
| let failed = []; | |
| for (const notif of notifications) { | |
| try { | |
| await markNotificationAsRead(notif.id); | |
| cleared++; | |
| console.log( | |
| `✓ Cleared: ${notif.subject.title.substring(0, 60)}...`, | |
| ); | |
| } catch (err) { | |
| failed.push(notif); | |
| console.log( | |
| `✗ Failed: ${notif.subject.title.substring(0, 60)}... (${err.message})`, | |
| ); | |
| } | |
| } | |
| // Mark all as read to catch any remaining | |
| console.log('\nMarking all notifications as read...'); | |
| await markAllAsRead(); | |
| console.log('\n' + '='.repeat(50)); | |
| console.log(`✓ Successfully cleared: ${cleared}`); | |
| if (failed.length > 0) { | |
| console.log(`✗ Failed to clear: ${failed.length}`); | |
| console.log(' (These should be caught by "mark all as read")'); | |
| } | |
| console.log('✓ All notifications marked as read'); | |
| console.log('='.repeat(50)); | |
| } catch (err) { | |
| console.error('\nError:', err.message); | |
| process.exit(1); | |
| } | |
| } | |
| // Run the script | |
| clearAllNotifications(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment