Search Console SEO Analyzer

Analyzes all Search Console data to provide keyword and SEO opportunities to increase traffic, CTR and impressions

Size

35.1 KB

Version

1.0.1

Created

Mar 3, 2026

Updated

19 days ago

1// ==UserScript==
2// @name		Search Console SEO Analyzer
3// @description		Analyzes all Search Console data to provide keyword and SEO opportunities to increase traffic, CTR and impressions
4// @version		1.0.1
5// @match		https://search.google.com/search-console/*
6// @icon		https://www.gstatic.com/search-console/scfe/favicon.png
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('Search Console SEO Analyzer initialized');
12
13    // Utility function to wait for element
14    function waitForElement(selector, timeout = 10000) {
15        return new Promise((resolve, reject) => {
16            const element = document.querySelector(selector);
17            if (element) {
18                return resolve(element);
19            }
20
21            const observer = new MutationObserver((mutations, obs) => {
22                const element = document.querySelector(selector);
23                if (element) {
24                    obs.disconnect();
25                    resolve(element);
26                }
27            });
28
29            observer.observe(document.body, {
30                childList: true,
31                subtree: true
32            });
33
34            setTimeout(() => {
35                observer.disconnect();
36                reject(new Error(`Element ${selector} not found within ${timeout}ms`));
37            }, timeout);
38        });
39    }
40
41    // Debounce function for MutationObserver
42    function debounce(func, wait) {
43        let timeout;
44        return function executedFunction(...args) {
45            const later = () => {
46                clearTimeout(timeout);
47                func(...args);
48            };
49            clearTimeout(timeout);
50            timeout = setTimeout(later, wait);
51        };
52    }
53
54    // Extract data from the current Search Console page
55    async function extractSearchConsoleData() {
56        console.log('Extracting Search Console data...');
57        const data = {
58            queries: [],
59            pages: [],
60            countries: [],
61            devices: [],
62            searchAppearance: [],
63            dates: [],
64            totalClicks: 0,
65            totalImpressions: 0,
66            avgCTR: 0,
67            avgPosition: 0
68        };
69
70        try {
71            // Extract summary metrics from scorecards
72            const scorecards = document.querySelectorAll('.PCt8xf.ZzqKLb.IKe2ed');
73            scorecards.forEach(card => {
74                const label = card.getAttribute('data-label');
75                const valueElement = card.querySelector('.nnLLaf.vtZz6e');
76                if (valueElement) {
77                    const value = valueElement.textContent.trim().replace(/\s/g, '').replace(/\./g, '').replace(',', '.');
78                    const numValue = parseFloat(value);
79                    
80                    if (label === 'CLICKS') data.totalClicks = numValue;
81                    if (label === 'IMPRESSIONS') data.totalImpressions = numValue;
82                    if (label === 'CTR') data.avgCTR = numValue;
83                    if (label === 'POSITION') data.avgPosition = numValue;
84                }
85            });
86
87            console.log('Summary metrics extracted:', {
88                clicks: data.totalClicks,
89                impressions: data.totalImpressions,
90                ctr: data.avgCTR,
91                position: data.avgPosition
92            });
93
94            // Extract table data (queries, pages, etc.)
95            await extractTableData(data);
96
97        } catch (error) {
98            console.error('Error extracting Search Console data:', error);
99        }
100
101        return data;
102    }
103
104    // Extract data from the performance table
105    async function extractTableData(data) {
106        console.log('Extracting table data...');
107        
108        // Wait for table to load
109        await new Promise(resolve => setTimeout(resolve, 2000));
110
111        const tableRows = document.querySelectorAll('table tbody tr, .yMNAbc, [role="row"]');
112        console.log(`Found ${tableRows.length} table rows`);
113
114        tableRows.forEach((row, index) => {
115            try {
116                const cells = row.querySelectorAll('td, [role="cell"]');
117                if (cells.length >= 4) {
118                    const queryText = cells[0]?.textContent?.trim();
119                    const clicks = parseFloat(cells[1]?.textContent?.trim().replace(/\./g, '').replace(',', '.')) || 0;
120                    const impressions = parseFloat(cells[2]?.textContent?.trim().replace(/\./g, '').replace(',', '.')) || 0;
121                    const ctr = parseFloat(cells[3]?.textContent?.trim().replace('%', '').replace(',', '.')) || 0;
122                    const position = parseFloat(cells[4]?.textContent?.trim().replace(',', '.')) || 0;
123
124                    if (queryText && queryText.length > 0 && !queryText.includes('Consulta')) {
125                        data.queries.push({
126                            query: queryText,
127                            clicks: clicks,
128                            impressions: impressions,
129                            ctr: ctr,
130                            position: position
131                        });
132                    }
133                }
134            } catch (error) {
135                console.error(`Error parsing row ${index}:`, error);
136            }
137        });
138
139        console.log(`Extracted ${data.queries.length} queries from table`);
140    }
141
142    // Navigate through different tabs and collect data
143    async function collectAllData(progressCallback) {
144        console.log('Starting comprehensive data collection...');
145        const allData = {
146            queries: [],
147            pages: [],
148            summary: {}
149        };
150
151        try {
152            // Extract current page data
153            progressCallback('Extracting performance data...');
154            const performanceData = await extractSearchConsoleData();
155            allData.summary = {
156                totalClicks: performanceData.totalClicks,
157                totalImpressions: performanceData.totalImpressions,
158                avgCTR: performanceData.avgCTR,
159                avgPosition: performanceData.avgPosition
160            };
161            allData.queries = performanceData.queries;
162
163            // Try to load more rows if pagination exists
164            progressCallback('Loading all available data...');
165            await loadMoreRows();
166            
167            // Re-extract after loading more
168            const updatedData = await extractSearchConsoleData();
169            allData.queries = updatedData.queries;
170
171            console.log('Data collection complete:', {
172                queriesCount: allData.queries.length,
173                summary: allData.summary
174            });
175
176        } catch (error) {
177            console.error('Error collecting data:', error);
178        }
179
180        return allData;
181    }
182
183    // Try to load more rows in the table
184    async function loadMoreRows() {
185        console.log('Attempting to load more rows...');
186        
187        // Look for "Show more" or pagination buttons
188        const showMoreButtons = document.querySelectorAll('button, [role="button"]');
189        
190        for (const button of showMoreButtons) {
191            const buttonText = button.textContent.toLowerCase();
192            if (buttonText.includes('mรกs') || buttonText.includes('more') || buttonText.includes('cargar')) {
193                console.log('Found load more button, clicking...');
194                button.click();
195                await new Promise(resolve => setTimeout(resolve, 2000));
196                break;
197            }
198        }
199
200        // Try to change rows per page to maximum
201        const rowsPerPageSelects = document.querySelectorAll('select, [role="listbox"]');
202        for (const select of rowsPerPageSelects) {
203            if (select.options && select.options.length > 0) {
204                select.value = select.options[select.options.length - 1].value;
205                select.dispatchEvent(new Event('change', { bubbles: true }));
206                await new Promise(resolve => setTimeout(resolve, 2000));
207                break;
208            }
209        }
210    }
211
212    // Analyze data with AI to provide SEO opportunities
213    async function analyzeWithAI(data, progressCallback) {
214        console.log('Starting AI analysis...');
215        progressCallback('Analyzing data with AI...');
216
217        try {
218            const prompt = `You are an SEO expert analyzing Google Search Console data. 
219
220SUMMARY METRICS:
221- Total Clicks: ${data.summary.totalClicks}
222- Total Impressions: ${data.summary.totalImpressions}
223- Average CTR: ${data.summary.avgCTR}%
224- Average Position: ${data.summary.avgPosition}
225
226TOP QUERIES DATA (${data.queries.length} queries):
227${JSON.stringify(data.queries.slice(0, 50), null, 2)}
228
229Analyze this data and provide actionable SEO recommendations to increase traffic, CTR, and impressions. Focus on:
2301. High-impression, low-CTR keywords (quick wins)
2312. Keywords ranking positions 4-20 (opportunity to reach page 1)
2323. Content gaps and keyword opportunities
2334. Technical SEO recommendations
2345. Priority actions ranked by potential impact`;
235
236            const analysis = await RM.aiCall(prompt, {
237                type: "json_schema",
238                json_schema: {
239                    name: "seo_analysis",
240                    schema: {
241                        type: "object",
242                        properties: {
243                            quickWins: {
244                                type: "array",
245                                items: {
246                                    type: "object",
247                                    properties: {
248                                        keyword: { type: "string" },
249                                        currentCTR: { type: "number" },
250                                        currentPosition: { type: "number" },
251                                        impressions: { type: "number" },
252                                        recommendation: { type: "string" },
253                                        potentialImpact: { type: "string" }
254                                    },
255                                    required: ["keyword", "recommendation", "potentialImpact"]
256                                }
257                            },
258                            rankingOpportunities: {
259                                type: "array",
260                                items: {
261                                    type: "object",
262                                    properties: {
263                                        keyword: { type: "string" },
264                                        currentPosition: { type: "number" },
265                                        targetPosition: { type: "number" },
266                                        recommendation: { type: "string" },
267                                        estimatedTrafficIncrease: { type: "string" }
268                                    },
269                                    required: ["keyword", "currentPosition", "recommendation"]
270                                }
271                            },
272                            contentGaps: {
273                                type: "array",
274                                items: {
275                                    type: "object",
276                                    properties: {
277                                        topic: { type: "string" },
278                                        suggestedKeywords: { type: "array", items: { type: "string" } },
279                                        reasoning: { type: "string" }
280                                    },
281                                    required: ["topic", "reasoning"]
282                                }
283                            },
284                            technicalRecommendations: {
285                                type: "array",
286                                items: {
287                                    type: "object",
288                                    properties: {
289                                        issue: { type: "string" },
290                                        solution: { type: "string" },
291                                        priority: { type: "string", enum: ["high", "medium", "low"] }
292                                    },
293                                    required: ["issue", "solution", "priority"]
294                                }
295                            },
296                            priorityActions: {
297                                type: "array",
298                                items: {
299                                    type: "object",
300                                    properties: {
301                                        action: { type: "string" },
302                                        impact: { type: "string", enum: ["high", "medium", "low"] },
303                                        effort: { type: "string", enum: ["high", "medium", "low"] },
304                                        description: { type: "string" }
305                                    },
306                                    required: ["action", "impact", "effort", "description"]
307                                }
308                            },
309                            overallSummary: { type: "string" }
310                        },
311                        required: ["quickWins", "rankingOpportunities", "priorityActions", "overallSummary"]
312                    }
313                }
314            });
315
316            console.log('AI analysis complete:', analysis);
317            return analysis;
318
319        } catch (error) {
320            console.error('Error during AI analysis:', error);
321            throw error;
322        }
323    }
324
325    // Display results in a modal
326    function displayResults(analysis, data) {
327        console.log('Displaying results...');
328
329        // Remove existing modal if any
330        const existingModal = document.getElementById('seo-analyzer-modal');
331        if (existingModal) {
332            existingModal.remove();
333        }
334
335        // Create modal
336        const modal = document.createElement('div');
337        modal.id = 'seo-analyzer-modal';
338        modal.innerHTML = `
339            <div class="seo-modal-overlay">
340                <div class="seo-modal-content">
341                    <div class="seo-modal-header">
342                        <h2>๐Ÿš€ SEO Analysis Results</h2>
343                        <button class="seo-modal-close" id="seo-close-modal">ร—</button>
344                    </div>
345                    <div class="seo-modal-body">
346                        <div class="seo-summary-section">
347                            <h3>๐Ÿ“Š Summary</h3>
348                            <p>${analysis.overallSummary}</p>
349                            <div class="seo-metrics">
350                                <div class="seo-metric">
351                                    <span class="metric-label">Total Clicks</span>
352                                    <span class="metric-value">${data.summary.totalClicks.toLocaleString()}</span>
353                                </div>
354                                <div class="seo-metric">
355                                    <span class="metric-label">Total Impressions</span>
356                                    <span class="metric-value">${data.summary.totalImpressions.toLocaleString()}</span>
357                                </div>
358                                <div class="seo-metric">
359                                    <span class="metric-label">Avg CTR</span>
360                                    <span class="metric-value">${data.summary.avgCTR}%</span>
361                                </div>
362                                <div class="seo-metric">
363                                    <span class="metric-label">Avg Position</span>
364                                    <span class="metric-value">${data.summary.avgPosition.toFixed(1)}</span>
365                                </div>
366                            </div>
367                        </div>
368
369                        <div class="seo-section">
370                            <h3>โšก Quick Wins (${analysis.quickWins.length})</h3>
371                            <p class="section-description">High-impression keywords with low CTR - optimize these for immediate impact</p>
372                            ${analysis.quickWins.map(item => `
373                                <div class="seo-item">
374                                    <div class="seo-item-header">
375                                        <strong>${item.keyword}</strong>
376                                        <span class="impact-badge impact-${item.potentialImpact?.toLowerCase() || 'medium'}">${item.potentialImpact || 'Medium Impact'}</span>
377                                    </div>
378                                    <div class="seo-item-stats">
379                                        ${item.currentPosition ? `<span>Position: ${item.currentPosition}</span>` : ''}
380                                        ${item.currentCTR ? `<span>CTR: ${item.currentCTR}%</span>` : ''}
381                                        ${item.impressions ? `<span>Impressions: ${item.impressions.toLocaleString()}</span>` : ''}
382                                    </div>
383                                    <p>${item.recommendation}</p>
384                                </div>
385                            `).join('')}
386                        </div>
387
388                        <div class="seo-section">
389                            <h3>๐Ÿ“ˆ Ranking Opportunities (${analysis.rankingOpportunities.length})</h3>
390                            <p class="section-description">Keywords close to page 1 - push these to top positions</p>
391                            ${analysis.rankingOpportunities.map(item => `
392                                <div class="seo-item">
393                                    <div class="seo-item-header">
394                                        <strong>${item.keyword}</strong>
395                                        <span class="position-badge">Position ${item.currentPosition} โ†’ ${item.targetPosition || 'Top 3'}</span>
396                                    </div>
397                                    ${item.estimatedTrafficIncrease ? `<div class="traffic-estimate">๐Ÿ“Š ${item.estimatedTrafficIncrease}</div>` : ''}
398                                    <p>${item.recommendation}</p>
399                                </div>
400                            `).join('')}
401                        </div>
402
403                        ${analysis.contentGaps && analysis.contentGaps.length > 0 ? `
404                        <div class="seo-section">
405                            <h3>๐Ÿ“ Content Gaps</h3>
406                            <p class="section-description">Missing content opportunities based on your current performance</p>
407                            ${analysis.contentGaps.map(item => `
408                                <div class="seo-item">
409                                    <div class="seo-item-header">
410                                        <strong>${item.topic}</strong>
411                                    </div>
412                                    ${item.suggestedKeywords && item.suggestedKeywords.length > 0 ? `
413                                        <div class="keyword-tags">
414                                            ${item.suggestedKeywords.map(kw => `<span class="keyword-tag">${kw}</span>`).join('')}
415                                        </div>
416                                    ` : ''}
417                                    <p>${item.reasoning}</p>
418                                </div>
419                            `).join('')}
420                        </div>
421                        ` : ''}
422
423                        ${analysis.technicalRecommendations && analysis.technicalRecommendations.length > 0 ? `
424                        <div class="seo-section">
425                            <h3>๐Ÿ”ง Technical Recommendations</h3>
426                            ${analysis.technicalRecommendations.map(item => `
427                                <div class="seo-item">
428                                    <div class="seo-item-header">
429                                        <strong>${item.issue}</strong>
430                                        <span class="priority-badge priority-${item.priority}">${item.priority.toUpperCase()}</span>
431                                    </div>
432                                    <p>${item.solution}</p>
433                                </div>
434                            `).join('')}
435                        </div>
436                        ` : ''}
437
438                        <div class="seo-section">
439                            <h3>๐ŸŽฏ Priority Actions</h3>
440                            <p class="section-description">Recommended actions ranked by impact vs effort</p>
441                            ${analysis.priorityActions.map(item => `
442                                <div class="seo-item priority-action">
443                                    <div class="seo-item-header">
444                                        <strong>${item.action}</strong>
445                                        <div class="action-badges">
446                                            <span class="impact-badge impact-${item.impact}">Impact: ${item.impact}</span>
447                                            <span class="effort-badge effort-${item.effort}">Effort: ${item.effort}</span>
448                                        </div>
449                                    </div>
450                                    <p>${item.description}</p>
451                                </div>
452                            `).join('')}
453                        </div>
454
455                        <div class="seo-export-section">
456                            <button class="seo-export-btn" id="seo-export-results">๐Ÿ“ฅ Export Results as JSON</button>
457                            <button class="seo-copy-btn" id="seo-copy-summary">๐Ÿ“‹ Copy Summary</button>
458                        </div>
459                    </div>
460                </div>
461            </div>
462        `;
463
464        document.body.appendChild(modal);
465
466        // Add event listeners
467        document.getElementById('seo-close-modal').addEventListener('click', () => {
468            modal.remove();
469        });
470
471        document.getElementById('seo-export-results').addEventListener('click', async () => {
472            const exportData = {
473                analysis: analysis,
474                data: data,
475                exportDate: new Date().toISOString()
476            };
477            const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
478            const url = URL.createObjectURL(blob);
479            const a = document.createElement('a');
480            a.href = url;
481            a.download = `seo-analysis-${new Date().toISOString().split('T')[0]}.json`;
482            a.click();
483            URL.revokeObjectURL(url);
484        });
485
486        document.getElementById('seo-copy-summary').addEventListener('click', async () => {
487            const summary = `SEO Analysis Summary\n\n${analysis.overallSummary}\n\nQuick Wins: ${analysis.quickWins.length}\nRanking Opportunities: ${analysis.rankingOpportunities.length}\nPriority Actions: ${analysis.priorityActions.length}`;
488            await GM.setClipboard(summary);
489            alert('Summary copied to clipboard!');
490        });
491
492        // Close on overlay click
493        modal.querySelector('.seo-modal-overlay').addEventListener('click', (e) => {
494            if (e.target.classList.contains('seo-modal-overlay')) {
495                modal.remove();
496            }
497        });
498    }
499
500    // Show progress modal
501    function showProgressModal(message) {
502        let progressModal = document.getElementById('seo-progress-modal');
503        
504        if (!progressModal) {
505            progressModal = document.createElement('div');
506            progressModal.id = 'seo-progress-modal';
507            progressModal.innerHTML = `
508                <div class="seo-modal-overlay">
509                    <div class="seo-progress-content">
510                        <div class="seo-spinner"></div>
511                        <h3 id="seo-progress-message">Analyzing...</h3>
512                        <p class="seo-progress-subtitle">This may take a minute...</p>
513                    </div>
514                </div>
515            `;
516            document.body.appendChild(progressModal);
517        }
518
519        document.getElementById('seo-progress-message').textContent = message;
520        return progressModal;
521    }
522
523    function hideProgressModal() {
524        const progressModal = document.getElementById('seo-progress-modal');
525        if (progressModal) {
526            progressModal.remove();
527        }
528    }
529
530    // Main analysis function
531    async function runAnalysis() {
532        console.log('Starting SEO analysis...');
533        
534        try {
535            const progressModal = showProgressModal('Collecting Search Console data...');
536
537            // Collect all data
538            const data = await collectAllData((message) => {
539                document.getElementById('seo-progress-message').textContent = message;
540            });
541
542            if (data.queries.length === 0) {
543                hideProgressModal();
544                alert('No query data found. Please make sure you are on the Performance page with data visible.');
545                return;
546            }
547
548            // Analyze with AI
549            document.getElementById('seo-progress-message').textContent = 'Analyzing with AI...';
550            const analysis = await analyzeWithAI(data, (message) => {
551                document.getElementById('seo-progress-message').textContent = message;
552            });
553
554            hideProgressModal();
555
556            // Display results
557            displayResults(analysis, data);
558
559            // Save results
560            await GM.setValue('last_seo_analysis', JSON.stringify({
561                analysis: analysis,
562                data: data,
563                timestamp: new Date().toISOString()
564            }));
565
566        } catch (error) {
567            console.error('Error running analysis:', error);
568            hideProgressModal();
569            alert('Error running analysis: ' + error.message);
570        }
571    }
572
573    // Add styles
574    const styles = `
575        .seo-analyzer-button {
576            display: inline-flex;
577            align-items: center;
578            gap: 8px;
579            padding: 10px 20px;
580            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
581            color: white;
582            border: none;
583            border-radius: 8px;
584            font-size: 14px;
585            font-weight: 500;
586            cursor: pointer;
587            box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
588            transition: all 0.3s ease;
589            margin: 16px 0;
590        }
591
592        .seo-analyzer-button:hover {
593            transform: translateY(-2px);
594            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
595        }
596
597        .seo-analyzer-button:active {
598            transform: translateY(0);
599        }
600
601        .seo-modal-overlay {
602            position: fixed;
603            top: 0;
604            left: 0;
605            right: 0;
606            bottom: 0;
607            background: rgba(0, 0, 0, 0.7);
608            display: flex;
609            align-items: center;
610            justify-content: center;
611            z-index: 999999;
612            padding: 20px;
613        }
614
615        .seo-modal-content {
616            background: white;
617            border-radius: 12px;
618            max-width: 900px;
619            width: 100%;
620            max-height: 90vh;
621            display: flex;
622            flex-direction: column;
623            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
624        }
625
626        .seo-modal-header {
627            display: flex;
628            justify-content: space-between;
629            align-items: center;
630            padding: 24px;
631            border-bottom: 1px solid #e0e0e0;
632        }
633
634        .seo-modal-header h2 {
635            margin: 0;
636            font-size: 24px;
637            color: #333;
638        }
639
640        .seo-modal-close {
641            background: none;
642            border: none;
643            font-size: 32px;
644            color: #666;
645            cursor: pointer;
646            padding: 0;
647            width: 32px;
648            height: 32px;
649            display: flex;
650            align-items: center;
651            justify-content: center;
652            border-radius: 4px;
653            transition: all 0.2s;
654        }
655
656        .seo-modal-close:hover {
657            background: #f0f0f0;
658            color: #333;
659        }
660
661        .seo-modal-body {
662            padding: 24px;
663            overflow-y: auto;
664        }
665
666        .seo-summary-section {
667            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
668            color: white;
669            padding: 24px;
670            border-radius: 8px;
671            margin-bottom: 24px;
672        }
673
674        .seo-summary-section h3 {
675            margin: 0 0 12px 0;
676            font-size: 20px;
677        }
678
679        .seo-summary-section p {
680            margin: 0 0 16px 0;
681            line-height: 1.6;
682        }
683
684        .seo-metrics {
685            display: grid;
686            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
687            gap: 16px;
688        }
689
690        .seo-metric {
691            background: rgba(255, 255, 255, 0.2);
692            padding: 12px;
693            border-radius: 6px;
694            display: flex;
695            flex-direction: column;
696            gap: 4px;
697        }
698
699        .metric-label {
700            font-size: 12px;
701            opacity: 0.9;
702        }
703
704        .metric-value {
705            font-size: 24px;
706            font-weight: bold;
707        }
708
709        .seo-section {
710            margin-bottom: 32px;
711        }
712
713        .seo-section h3 {
714            font-size: 20px;
715            color: #333;
716            margin: 0 0 8px 0;
717        }
718
719        .section-description {
720            color: #666;
721            font-size: 14px;
722            margin: 0 0 16px 0;
723        }
724
725        .seo-item {
726            background: #f8f9fa;
727            border-left: 4px solid #667eea;
728            padding: 16px;
729            margin-bottom: 12px;
730            border-radius: 4px;
731        }
732
733        .seo-item-header {
734            display: flex;
735            justify-content: space-between;
736            align-items: center;
737            margin-bottom: 8px;
738            flex-wrap: wrap;
739            gap: 8px;
740        }
741
742        .seo-item-header strong {
743            color: #333;
744            font-size: 16px;
745        }
746
747        .seo-item-stats {
748            display: flex;
749            gap: 16px;
750            margin-bottom: 8px;
751            font-size: 13px;
752            color: #666;
753        }
754
755        .seo-item p {
756            margin: 0;
757            color: #555;
758            line-height: 1.6;
759        }
760
761        .impact-badge, .priority-badge, .position-badge {
762            padding: 4px 12px;
763            border-radius: 12px;
764            font-size: 12px;
765            font-weight: 600;
766            text-transform: uppercase;
767        }
768
769        .impact-high, .priority-high {
770            background: #ff4444;
771            color: white;
772        }
773
774        .impact-medium, .priority-medium {
775            background: #ffaa00;
776            color: white;
777        }
778
779        .impact-low, .priority-low {
780            background: #00cc66;
781            color: white;
782        }
783
784        .position-badge {
785            background: #667eea;
786            color: white;
787        }
788
789        .action-badges {
790            display: flex;
791            gap: 8px;
792        }
793
794        .effort-badge {
795            padding: 4px 12px;
796            border-radius: 12px;
797            font-size: 12px;
798            font-weight: 600;
799            text-transform: uppercase;
800        }
801
802        .effort-high {
803            background: #ff6b6b;
804            color: white;
805        }
806
807        .effort-medium {
808            background: #ffd93d;
809            color: #333;
810        }
811
812        .effort-low {
813            background: #6bcf7f;
814            color: white;
815        }
816
817        .traffic-estimate {
818            background: #e3f2fd;
819            color: #1976d2;
820            padding: 8px 12px;
821            border-radius: 4px;
822            font-size: 13px;
823            margin-bottom: 8px;
824        }
825
826        .keyword-tags {
827            display: flex;
828            flex-wrap: wrap;
829            gap: 8px;
830            margin-bottom: 8px;
831        }
832
833        .keyword-tag {
834            background: #e0e7ff;
835            color: #4c51bf;
836            padding: 4px 10px;
837            border-radius: 4px;
838            font-size: 12px;
839        }
840
841        .seo-export-section {
842            display: flex;
843            gap: 12px;
844            margin-top: 24px;
845            padding-top: 24px;
846            border-top: 1px solid #e0e0e0;
847        }
848
849        .seo-export-btn, .seo-copy-btn {
850            flex: 1;
851            padding: 12px 24px;
852            border: none;
853            border-radius: 6px;
854            font-size: 14px;
855            font-weight: 500;
856            cursor: pointer;
857            transition: all 0.2s;
858        }
859
860        .seo-export-btn {
861            background: #667eea;
862            color: white;
863        }
864
865        .seo-export-btn:hover {
866            background: #5568d3;
867        }
868
869        .seo-copy-btn {
870            background: #f0f0f0;
871            color: #333;
872        }
873
874        .seo-copy-btn:hover {
875            background: #e0e0e0;
876        }
877
878        .seo-progress-content {
879            background: white;
880            padding: 40px;
881            border-radius: 12px;
882            text-align: center;
883            min-width: 300px;
884        }
885
886        .seo-spinner {
887            width: 50px;
888            height: 50px;
889            border: 4px solid #f3f3f3;
890            border-top: 4px solid #667eea;
891            border-radius: 50%;
892            animation: spin 1s linear infinite;
893            margin: 0 auto 20px;
894        }
895
896        @keyframes spin {
897            0% { transform: rotate(0deg); }
898            100% { transform: rotate(360deg); }
899        }
900
901        .seo-progress-content h3 {
902            margin: 0 0 8px 0;
903            color: #333;
904        }
905
906        .seo-progress-subtitle {
907            margin: 0;
908            color: #666;
909            font-size: 14px;
910        }
911
912        .priority-action {
913            border-left-color: #ff6b6b;
914        }
915    `;
916
917    TM_addStyle(styles);
918
919    // Initialize the button
920    async function init() {
921        console.log('Initializing SEO Analyzer button...');
922
923        try {
924            // Wait for the navigation element
925            const navElement = await waitForElement('.cp8g2d', 15000);
926            console.log('Navigation element found');
927
928            // Check if button already exists
929            if (document.getElementById('seo-analyzer-btn-container')) {
930                console.log('Button already exists');
931                return;
932            }
933
934            // Create button container
935            const buttonContainer = document.createElement('div');
936            buttonContainer.id = 'seo-analyzer-btn-container';
937            buttonContainer.style.cssText = 'padding: 0 24px;';
938
939            const button = document.createElement('button');
940            button.className = 'seo-analyzer-button';
941            button.innerHTML = '๐Ÿš€ Analyze SEO Opportunities';
942            button.addEventListener('click', runAnalysis);
943
944            buttonContainer.appendChild(button);
945
946            // Insert before the navigation element
947            navElement.parentElement.insertBefore(buttonContainer, navElement);
948            console.log('SEO Analyzer button added successfully');
949
950        } catch (error) {
951            console.error('Error initializing SEO Analyzer:', error);
952        }
953    }
954
955    // Run initialization when DOM is ready
956    if (document.readyState === 'loading') {
957        document.addEventListener('DOMContentLoaded', init);
958    } else {
959        init();
960    }
961
962    // Re-initialize on navigation changes (for SPA behavior)
963    const debouncedInit = debounce(init, 1000);
964    const observer = new MutationObserver(debouncedInit);
965    observer.observe(document.body, {
966        childList: true,
967        subtree: true
968    });
969
970})();