YouTube User Activity Recorder

Records all user interactions including clicks, inputs, navigation, and scrolling

Size

11.1 KB

Version

1.0.1

Created

Oct 23, 2025

Updated

about 7 hours ago

1// ==UserScript==
2// @name		YouTube User Activity Recorder
3// @description		Records all user interactions including clicks, inputs, navigation, and scrolling
4// @version		1.0.1
5// @match		https://*.youtube.com/*
6// @icon		https://www.youtube.com/s/desktop/83278897/img/favicon_32x32.png
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    // Initialize activity log storage
12    async function init() {
13        console.log('YouTube User Activity Recorder initialized');
14        
15        // Load existing activity log
16        let activityLog = await GM.getValue('activityLog', []);
17        
18        // Helper function to save activity
19        async function logActivity(activityType, details) {
20            const timestamp = new Date().toISOString();
21            const activity = {
22                timestamp,
23                type: activityType,
24                url: window.location.href,
25                ...details
26            };
27            
28            activityLog.push(activity);
29            
30            // Keep only last 1000 activities to prevent storage overflow
31            if (activityLog.length > 1000) {
32                activityLog = activityLog.slice(-1000);
33            }
34            
35            await GM.setValue('activityLog', activityLog);
36            console.log('Activity logged:', activity);
37        }
38        
39        // Track all clicks
40        document.addEventListener('click', async (event) => {
41            const target = event.target;
42            const details = {
43                tagName: target.tagName,
44                id: target.id || null,
45                className: target.className || null,
46                text: target.textContent?.substring(0, 100) || null,
47                href: target.href || null,
48                coordinates: {
49                    x: event.clientX,
50                    y: event.clientY
51                }
52            };
53            
54            await logActivity('click', details);
55        }, true);
56        
57        // Track all input changes
58        document.addEventListener('input', async (event) => {
59            const target = event.target;
60            const details = {
61                tagName: target.tagName,
62                id: target.id || null,
63                name: target.name || null,
64                type: target.type || null,
65                value: target.value?.substring(0, 100) || null,
66                placeholder: target.placeholder || null
67            };
68            
69            await logActivity('input', details);
70        }, true);
71        
72        // Track form submissions
73        document.addEventListener('submit', async (event) => {
74            const target = event.target;
75            const details = {
76                formId: target.id || null,
77                formAction: target.action || null,
78                formMethod: target.method || null
79            };
80            
81            await logActivity('form_submit', details);
82        }, true);
83        
84        // Track scrolling with debounce
85        let scrollTimeout;
86        let lastScrollPosition = { x: window.scrollX, y: window.scrollY };
87        
88        window.addEventListener('scroll', () => {
89            clearTimeout(scrollTimeout);
90            scrollTimeout = setTimeout(async () => {
91                const details = {
92                    scrollX: window.scrollX,
93                    scrollY: window.scrollY,
94                    scrollHeight: document.documentElement.scrollHeight,
95                    clientHeight: document.documentElement.clientHeight,
96                    scrollPercentage: Math.round((window.scrollY / (document.documentElement.scrollHeight - document.documentElement.clientHeight)) * 100)
97                };
98                
99                // Only log if scroll position changed significantly (more than 50px)
100                if (Math.abs(window.scrollY - lastScrollPosition.y) > 50 || 
101                    Math.abs(window.scrollX - lastScrollPosition.x) > 50) {
102                    await logActivity('scroll', details);
103                    lastScrollPosition = { x: window.scrollX, y: window.scrollY };
104                }
105            }, 500);
106        }, true);
107        
108        // Track navigation (URL changes)
109        let lastUrl = window.location.href;
110        
111        const navigationObserver = new MutationObserver(async () => {
112            if (window.location.href !== lastUrl) {
113                const details = {
114                    from: lastUrl,
115                    to: window.location.href,
116                    title: document.title
117                };
118                
119                await logActivity('navigation', details);
120                lastUrl = window.location.href;
121            }
122        });
123        
124        navigationObserver.observe(document.body, {
125            childList: true,
126            subtree: true
127        });
128        
129        // Track page load
130        await logActivity('page_load', {
131            title: document.title,
132            referrer: document.referrer || null
133        });
134        
135        // Track page unload
136        window.addEventListener('beforeunload', async () => {
137            await logActivity('page_unload', {
138                title: document.title,
139                timeOnPage: Date.now() - performance.timing.navigationStart
140            });
141        });
142        
143        // Add UI to view and export logs
144        createLogViewerUI();
145    }
146    
147    // Create UI for viewing and exporting logs
148    function createLogViewerUI() {
149        const button = document.createElement('button');
150        button.textContent = '📊 Activity Log';
151        button.style.cssText = `
152            position: fixed;
153            bottom: 20px;
154            right: 20px;
155            z-index: 10000;
156            background: #ff0000;
157            color: white;
158            border: none;
159            border-radius: 50%;
160            width: 60px;
161            height: 60px;
162            font-size: 24px;
163            cursor: pointer;
164            box-shadow: 0 4px 8px rgba(0,0,0,0.3);
165            transition: transform 0.2s;
166        `;
167        
168        button.addEventListener('mouseenter', () => {
169            button.style.transform = 'scale(1.1)';
170        });
171        
172        button.addEventListener('mouseleave', () => {
173            button.style.transform = 'scale(1)';
174        });
175        
176        button.addEventListener('click', async () => {
177            const activityLog = await GM.getValue('activityLog', []);
178            showLogViewer(activityLog);
179        });
180        
181        document.body.appendChild(button);
182    }
183    
184    // Show log viewer modal
185    function showLogViewer(activityLog) {
186        const modal = document.createElement('div');
187        modal.style.cssText = `
188            position: fixed;
189            top: 0;
190            left: 0;
191            width: 100%;
192            height: 100%;
193            background: rgba(0,0,0,0.8);
194            z-index: 10001;
195            display: flex;
196            justify-content: center;
197            align-items: center;
198        `;
199        
200        const content = document.createElement('div');
201        content.style.cssText = `
202            background: white;
203            color: black;
204            padding: 30px;
205            border-radius: 10px;
206            max-width: 90%;
207            max-height: 90%;
208            overflow: auto;
209            box-shadow: 0 8px 16px rgba(0,0,0,0.5);
210        `;
211        
212        const title = document.createElement('h2');
213        title.textContent = 'Activity Log';
214        title.style.cssText = 'margin-top: 0; color: #ff0000;';
215        
216        const stats = document.createElement('div');
217        stats.style.cssText = 'margin: 20px 0; padding: 15px; background: #f5f5f5; border-radius: 5px;';
218        stats.innerHTML = `
219            <strong>Total Activities:</strong> ${activityLog.length}<br>
220            <strong>Clicks:</strong> ${activityLog.filter(a => a.type === 'click').length}<br>
221            <strong>Inputs:</strong> ${activityLog.filter(a => a.type === 'input').length}<br>
222            <strong>Scrolls:</strong> ${activityLog.filter(a => a.type === 'scroll').length}<br>
223            <strong>Navigations:</strong> ${activityLog.filter(a => a.type === 'navigation').length}
224        `;
225        
226        const logContainer = document.createElement('pre');
227        logContainer.style.cssText = `
228            background: #f5f5f5;
229            padding: 15px;
230            border-radius: 5px;
231            max-height: 400px;
232            overflow: auto;
233            font-size: 12px;
234            white-space: pre-wrap;
235            word-wrap: break-word;
236        `;
237        logContainer.textContent = JSON.stringify(activityLog, null, 2);
238        
239        const buttonContainer = document.createElement('div');
240        buttonContainer.style.cssText = 'margin-top: 20px; display: flex; gap: 10px;';
241        
242        const exportButton = document.createElement('button');
243        exportButton.textContent = 'Export as JSON';
244        exportButton.style.cssText = `
245            background: #ff0000;
246            color: white;
247            border: none;
248            padding: 10px 20px;
249            border-radius: 5px;
250            cursor: pointer;
251            font-size: 14px;
252        `;
253        exportButton.addEventListener('click', () => {
254            const dataStr = JSON.stringify(activityLog, null, 2);
255            const dataBlob = new Blob([dataStr], { type: 'application/json' });
256            const url = URL.createObjectURL(dataBlob);
257            const link = document.createElement('a');
258            link.href = url;
259            link.download = `youtube-activity-log-${new Date().toISOString()}.json`;
260            link.click();
261            URL.revokeObjectURL(url);
262        });
263        
264        const clearButton = document.createElement('button');
265        clearButton.textContent = 'Clear Log';
266        clearButton.style.cssText = `
267            background: #666;
268            color: white;
269            border: none;
270            padding: 10px 20px;
271            border-radius: 5px;
272            cursor: pointer;
273            font-size: 14px;
274        `;
275        clearButton.addEventListener('click', async () => {
276            if (confirm('Are you sure you want to clear all activity logs?')) {
277                await GM.setValue('activityLog', []);
278                modal.remove();
279                alert('Activity log cleared!');
280            }
281        });
282        
283        const closeButton = document.createElement('button');
284        closeButton.textContent = 'Close';
285        closeButton.style.cssText = `
286            background: #333;
287            color: white;
288            border: none;
289            padding: 10px 20px;
290            border-radius: 5px;
291            cursor: pointer;
292            font-size: 14px;
293        `;
294        closeButton.addEventListener('click', () => {
295            modal.remove();
296        });
297        
298        buttonContainer.appendChild(exportButton);
299        buttonContainer.appendChild(clearButton);
300        buttonContainer.appendChild(closeButton);
301        
302        content.appendChild(title);
303        content.appendChild(stats);
304        content.appendChild(logContainer);
305        content.appendChild(buttonContainer);
306        modal.appendChild(content);
307        document.body.appendChild(modal);
308        
309        modal.addEventListener('click', (e) => {
310            if (e.target === modal) {
311                modal.remove();
312            }
313        });
314    }
315    
316    // Start the extension
317    init();
318})();
YouTube User Activity Recorder | Robomonkey