Microsoft Rewards Auto-Complete

Automatically completes Microsoft Rewards activities to earn points

Size

12.5 KB

Version

1.0.1

Created

Jan 11, 2026

Updated

24 days ago

1// ==UserScript==
2// @name		Microsoft Rewards Auto-Complete
3// @description		Automatically completes Microsoft Rewards activities to earn points
4// @version		1.0.1
5// @match		https://*.rewards.bing.com/*
6// @icon		https://rewards.bing.com/rewards.png
7// @grant		GM.getValue
8// @grant		GM.setValue
9// @grant		GM.openInTab
10// ==/UserScript==
11(function() {
12    'use strict';
13
14    console.log('Microsoft Rewards Auto-Complete extension loaded');
15
16    // Debounce function to prevent excessive calls
17    function debounce(func, wait) {
18        let timeout;
19        return function executedFunction(...args) {
20            const later = () => {
21                clearTimeout(timeout);
22                func(...args);
23            };
24            clearTimeout(timeout);
25            timeout = setTimeout(later, wait);
26        };
27    }
28
29    // Main initialization function
30    async function init() {
31        console.log('Initializing Microsoft Rewards Auto-Complete...');
32
33        // Check if we're on the main dashboard
34        if (window.location.pathname === '/' || window.location.pathname.includes('dashboard')) {
35            await handleDashboard();
36        } else if (window.location.href.includes('bing.com/search')) {
37            // If we're on a Bing search page (activity completion)
38            await handleActivityCompletion();
39        }
40    }
41
42    // Handle the main dashboard - find and complete activities
43    async function handleDashboard() {
44        console.log('On Microsoft Rewards dashboard');
45
46        // Wait for the page to fully load
47        await waitForElement('mee-card');
48
49        // Add a control panel to the page
50        addControlPanel();
51
52        // Get all available activities
53        const activities = await getAvailableActivities();
54        console.log(`Found ${activities.length} activities`);
55
56        // Store activities for later use
57        await GM.setValue('pendingActivities', JSON.stringify(activities));
58    }
59
60    // Get all available activities from the page
61    async function getAvailableActivities() {
62        const activityCards = document.querySelectorAll('mee-card a.ds-card-sec');
63        const activities = [];
64
65        activityCards.forEach((card, index) => {
66            const title = card.querySelector('.c-heading')?.textContent?.trim() || '';
67            const description = card.querySelector('.c-paragraph-4')?.textContent?.trim() || '';
68            const pointsText = card.querySelector('.pointLink')?.textContent?.trim() || '';
69            const href = card.getAttribute('href') || '';
70            
71            // Skip if already completed or if it's not a valid activity
72            const isCompleted = card.closest('mee-card')?.classList.contains('completed');
73            const isDisabled = card.getAttribute('aria-disabled') === 'true';
74            
75            // Only include activities that link to Bing searches or rewards pages
76            if (!isCompleted && !isDisabled && href && 
77                (href.includes('bing.com/search') || href.includes('rewards.bing.com'))) {
78                activities.push({
79                    index,
80                    title,
81                    description,
82                    pointsText,
83                    href
84                });
85            }
86        });
87
88        return activities;
89    }
90
91    // Add control panel to the page
92    function addControlPanel() {
93        // Check if panel already exists
94        if (document.getElementById('rewards-auto-complete-panel')) {
95            return;
96        }
97
98        const panel = document.createElement('div');
99        panel.id = 'rewards-auto-complete-panel';
100        panel.style.cssText = `
101            position: fixed;
102            top: 20px;
103            right: 20px;
104            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
105            color: white;
106            padding: 20px;
107            border-radius: 12px;
108            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
109            z-index: 10000;
110            min-width: 280px;
111            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
112        `;
113
114        panel.innerHTML = `
115            <div style="margin-bottom: 15px;">
116                <h3 style="margin: 0 0 10px 0; font-size: 18px; font-weight: 600;">🎯 Auto-Complete</h3>
117                <p style="margin: 0; font-size: 13px; opacity: 0.9;">Automatically complete activities</p>
118            </div>
119            <div style="margin-bottom: 15px;">
120                <div id="activity-status" style="font-size: 14px; margin-bottom: 10px;">
121                    Ready to start
122                </div>
123                <div id="activity-progress" style="background: rgba(255,255,255,0.2); height: 6px; border-radius: 3px; overflow: hidden;">
124                    <div id="progress-bar" style="width: 0%; height: 100%; background: #4ade80; transition: width 0.3s;"></div>
125                </div>
126            </div>
127            <button id="start-auto-complete" style="
128                width: 100%;
129                padding: 12px;
130                background: white;
131                color: #667eea;
132                border: none;
133                border-radius: 8px;
134                font-size: 14px;
135                font-weight: 600;
136                cursor: pointer;
137                transition: all 0.2s;
138                margin-bottom: 8px;
139            ">Start Auto-Complete</button>
140            <button id="stop-auto-complete" style="
141                width: 100%;
142                padding: 12px;
143                background: rgba(255,255,255,0.2);
144                color: white;
145                border: none;
146                border-radius: 8px;
147                font-size: 14px;
148                font-weight: 600;
149                cursor: pointer;
150                transition: all 0.2s;
151                display: none;
152            ">Stop</button>
153        `;
154
155        document.body.appendChild(panel);
156
157        // Add hover effects
158        const startBtn = document.getElementById('start-auto-complete');
159        const stopBtn = document.getElementById('stop-auto-complete');
160
161        startBtn.addEventListener('mouseenter', () => {
162            startBtn.style.transform = 'translateY(-2px)';
163            startBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.2)';
164        });
165        startBtn.addEventListener('mouseleave', () => {
166            startBtn.style.transform = 'translateY(0)';
167            startBtn.style.boxShadow = 'none';
168        });
169
170        // Add click handlers
171        startBtn.addEventListener('click', startAutoComplete);
172        stopBtn.addEventListener('click', stopAutoComplete);
173    }
174
175    // Start auto-completing activities
176    async function startAutoComplete() {
177        console.log('Starting auto-complete...');
178        
179        const startBtn = document.getElementById('start-auto-complete');
180        const stopBtn = document.getElementById('stop-auto-complete');
181        const statusDiv = document.getElementById('activity-status');
182
183        startBtn.style.display = 'none';
184        stopBtn.style.display = 'block';
185
186        // Set running flag
187        await GM.setValue('autoCompleteRunning', true);
188        await GM.setValue('currentActivityIndex', 0);
189
190        // Get activities
191        const activitiesJson = await GM.getValue('pendingActivities', '[]');
192        const activities = JSON.parse(activitiesJson);
193
194        if (activities.length === 0) {
195            statusDiv.textContent = 'No activities found';
196            startBtn.style.display = 'block';
197            stopBtn.style.display = 'none';
198            return;
199        }
200
201        statusDiv.textContent = `Starting... (${activities.length} activities)`;
202
203        // Start completing activities one by one
204        await completeNextActivity();
205    }
206
207    // Stop auto-completing
208    async function stopAutoComplete() {
209        console.log('Stopping auto-complete...');
210        await GM.setValue('autoCompleteRunning', false);
211        
212        const startBtn = document.getElementById('start-auto-complete');
213        const stopBtn = document.getElementById('stop-auto-complete');
214        const statusDiv = document.getElementById('activity-status');
215
216        startBtn.style.display = 'block';
217        stopBtn.style.display = 'none';
218        statusDiv.textContent = 'Stopped';
219    }
220
221    // Complete the next activity in the queue
222    async function completeNextActivity() {
223        const isRunning = await GM.getValue('autoCompleteRunning', false);
224        if (!isRunning) {
225            console.log('Auto-complete stopped');
226            return;
227        }
228
229        const activitiesJson = await GM.getValue('pendingActivities', '[]');
230        const activities = JSON.parse(activitiesJson);
231        const currentIndex = await GM.getValue('currentActivityIndex', 0);
232
233        if (currentIndex >= activities.length) {
234            console.log('All activities completed!');
235            await completeAllActivities();
236            return;
237        }
238
239        const activity = activities[currentIndex];
240        console.log(`Completing activity ${currentIndex + 1}/${activities.length}: ${activity.title}`);
241
242        // Update UI
243        updateProgress(currentIndex, activities.length, activity.title);
244
245        // Open the activity in a new tab
246        await GM.setValue('completingActivity', true);
247        await GM.setValue('activityStartTime', Date.now());
248        
249        // Open in background
250        GM.openInTab(activity.href, true);
251
252        // Wait a bit before moving to next activity
253        setTimeout(async () => {
254            await GM.setValue('currentActivityIndex', currentIndex + 1);
255            await completeNextActivity();
256        }, 8000); // Wait 8 seconds between activities
257    }
258
259    // Update progress UI
260    function updateProgress(current, total, activityTitle) {
261        const statusDiv = document.getElementById('activity-status');
262        const progressBar = document.getElementById('progress-bar');
263
264        if (statusDiv && progressBar) {
265            const percentage = ((current + 1) / total) * 100;
266            statusDiv.textContent = `Completing ${current + 1}/${total}: ${activityTitle.substring(0, 30)}...`;
267            progressBar.style.width = `${percentage}%`;
268        }
269    }
270
271    // All activities completed
272    async function completeAllActivities() {
273        const statusDiv = document.getElementById('activity-status');
274        const progressBar = document.getElementById('progress-bar');
275        const startBtn = document.getElementById('start-auto-complete');
276        const stopBtn = document.getElementById('stop-auto-complete');
277
278        if (statusDiv) {
279            statusDiv.textContent = '✅ All activities completed!';
280        }
281        if (progressBar) {
282            progressBar.style.width = '100%';
283        }
284        if (startBtn) {
285            startBtn.style.display = 'block';
286        }
287        if (stopBtn) {
288            stopBtn.style.display = 'none';
289        }
290
291        await GM.setValue('autoCompleteRunning', false);
292        await GM.setValue('currentActivityIndex', 0);
293
294        console.log('All activities completed successfully!');
295    }
296
297    // Handle activity completion on Bing search pages
298    async function handleActivityCompletion() {
299        const isCompleting = await GM.getValue('completingActivity', false);
300        
301        if (isCompleting) {
302            console.log('Activity page loaded, waiting for completion...');
303            
304            // Wait for the page to load
305            await new Promise(resolve => setTimeout(resolve, 3000));
306            
307            // Mark as completed
308            await GM.setValue('completingActivity', false);
309            
310            // Close this tab by navigating back (we can't actually close tabs)
311            console.log('Activity completed, you can close this tab');
312        }
313    }
314
315    // Wait for an element to appear
316    function waitForElement(selector, timeout = 10000) {
317        return new Promise((resolve, reject) => {
318            if (document.querySelector(selector)) {
319                return resolve(document.querySelector(selector));
320            }
321
322            const observer = new MutationObserver(debounce(() => {
323                if (document.querySelector(selector)) {
324                    observer.disconnect();
325                    resolve(document.querySelector(selector));
326                }
327            }, 100));
328
329            observer.observe(document.body, {
330                childList: true,
331                subtree: true
332            });
333
334            setTimeout(() => {
335                observer.disconnect();
336                reject(new Error(`Timeout waiting for element: ${selector}`));
337            }, timeout);
338        });
339    }
340
341    // Start the extension when the page is ready
342    if (document.readyState === 'loading') {
343        document.addEventListener('DOMContentLoaded', init);
344    } else {
345        init();
346    }
347
348})();
Microsoft Rewards Auto-Complete | Robomonkey