SERP Position Tracker

SERP Position Tracker

Monitor your keyword rankings on search engine results pages.

Keyword Performance

Keyword Current Position Change Best Position Last Checked

Position History

Current Keyword Positions

${top3Count}

Biggest Gainer

${biggestMover.name} (+${biggestMover.stats.change})

Biggest Drop

${biggestLoser.name} (${biggestLoser.stats.change})

`; // Main Table const dashboardTableBody = document.getElementById('dashboard-table-body'); dashboardTableBody.innerHTML = processedKeywords.map(k => { const changeHtml = k.stats.change === 0 ? `0` : k.stats.change > 0 ? `↑ ${k.stats.change}` : `↓ ${Math.abs(k.stats.change)}`; return ` ${k.name} ${k.stats.currentPos} ${changeHtml} ${k.stats.bestPos} ${k.stats.lastChecked} `; }).join(''); // Charts const historySelect = document.getElementById('history-keyword-select'); historySelect.innerHTML = keywords.map(k => ``).join(''); renderHistoryChart(parseInt(historySelect.value)); historySelect.onchange = (e) => renderHistoryChart(parseInt(e.target.value)); const sortedByPos = [...processedKeywords].sort((a,b) => a.stats.currentPos - b.stats.currentPos); if (positionsChart) positionsChart.destroy(); positionsChart = new Chart(document.getElementById('positions-chart').getContext('2d'), { type: 'bar', data: { labels: sortedByPos.map(k => k.name), datasets: [{ label: 'Position', data: sortedByPos.map(k => k.stats.currentPos), backgroundColor: '#a78bfa' }] }, options: { indexAxis: 'y', reversed: true, plugins: { legend: { display: false } }, scales: { x: { reverse: true, beginAtZero: true } } } }); }; const renderHistoryChart = (keywordId) => { const keyword = keywords.find(k => k.id === keywordId); if (!keyword) return; if (historyChart) historyChart.destroy(); historyChart = new Chart(document.getElementById('history-chart').getContext('2d'), { type: 'line', data: { datasets: [{ label: 'Position', data: keyword.history.map(h => ({ x: h.date, y: h.pos })), borderColor: '#3b82f6', tension: 0.1 }] }, options: { scales: { y: { reverse: true, beginAtZero: true }, x: { type: 'time', time: { unit: 'day' } } }, plugins: { legend: { display: false } } } }); }; const renderConfigTable = () => { const configTableBody = document.getElementById('config-table-body'); configTableBody.innerHTML = keywords.map(k => ` ${k.name} `).join(''); }; // --- EVENT HANDLERS --- const handleAddUpdate = () => { const nameInput = document.getElementById('new-keyword-name'); const posInput = document.getElementById('new-keyword-position'); const name = nameInput.value.trim().toLowerCase(); const position = parseInt(posInput.value); if (!name || !position) { alert('Please enter both keyword and position.'); return; } const existingKeyword = keywords.find(k => k.name === name); const today = new Date().toISOString().split('T')[0]; if (existingKeyword) { // Update existingKeyword.history.push({ date: today, pos: position }); } else { // Add new const newId = keywords.length > 0 ? Math.max(...keywords.map(k => k.id)) + 1 : 1; keywords.push({ id: newId, name, history: [{ date: today, pos: position }] }); } nameInput.value = ''; posInput.value = ''; renderConfigTable(); }; const handleDelete = (e) => { if(e.target.classList.contains('delete-btn')) { const id = parseInt(e.target.closest('tr').dataset.id); keywords = keywords.filter(k => k.id !== id); renderConfigTable(); } }; const generatePDF = () => { const pdfContent = document.getElementById('pdf-content'); html2canvas(pdfContent, { scale: 2, useCORS: true }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'l', unit: 'mm', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const imgWidth = pdfWidth - 20; const imgHeight = (canvas.height * imgWidth) / canvas.width; pdf.setFontSize(22).setFont('helvetica', 'bold').text('SERP Position Report', pdfWidth / 2, 15, { align: 'center' }); pdf.addImage(imgData, 'PNG', 10, 25, imgWidth, imgHeight); pdf.save('serp-position-report.pdf'); }); }; // --- ATTACH LISTENERS --- prevBtn.addEventListener('click', () => showTab('dashboard')); nextBtn.addEventListener('click', () => showTab('config')); tabButtons.dashboard.addEventListener('click', () => showTab('dashboard')); tabButtons.config.addEventListener('click', () => showTab('config')); document.getElementById('add-update-btn').addEventListener('click', handleAddUpdate); document.getElementById('config-table-body').addEventListener('click', handleDelete); document.getElementById('download-pdf-btn').addEventListener('click', generatePDF); // --- INITIAL SETUP --- showTab('dashboard'); });
Scroll to Top