Audit
Compare
Roadmap
Research
Docs
...
GEO Optimizer
Audit your website's visibility to ChatGPT, Perplexity, Claude & Gemini
★
—
stars
📦
—
/mo
🔍
—
audits
Run Audit
Connecting...
0
/ 100
—
—
Citability Score
▶
Recommendations
/* ─── Constants ─── */ const BANDS = {excellent:'#22c55e',good:'#06b6d4',foundation:'#eab308',critical:'#ef4444'}; const CATEGORIES = [ {key:'robots',label:'Robots.txt',max:18}, {key:'llms',label:'llms.txt',max:18}, {key:'schema',label:'Schema JSON-LD',max:22}, {key:'meta',label:'Meta Tags',max:14}, {key:'content',label:'Content',max:14}, {key:'signals',label:'Signals',max:8}, {key:'ai_discovery',label:'AI Discovery',max:6}, ]; const SPIN_MSGS = ['Checking robots.txt...','Analyzing llms.txt...','Parsing schema...','Evaluating content...','Scoring citability...','Compiling results...']; /* ─── Version + Stats ─── */ (async function init(){ try{ const h = await fetch('/health'); if(h.ok){const d=await h.json();document.getElementById('ver-badge').textContent='v'+d.version} }catch(e){} try{ const s = await fetch('/api/stats'); if(s.ok){ const d=await s.json(); const fmt=n=>n>=1000?(n/1000).toFixed(1)+'k':String(n); document.getElementById('stars').textContent=fmt(d.github_stars); document.getElementById('downloads').textContent=fmt(d.pypi_downloads_month); document.getElementById('audits').textContent=fmt(d.audits_run); } }catch(e){} })(); /* ─── Audit ─── */ const $=id=>document.getElementById(id); let spinInterval; function startSpin(){ $('spinner').classList.add('active'); let i=0; $('spin-text').textContent=SPIN_MSGS[0]; spinInterval=setInterval(()=>{i=(i+1)%SPIN_MSGS.length;$('spin-text').textContent=SPIN_MSGS[i]},2200); } function stopSpin(){$('spinner').classList.remove('active');clearInterval(spinInterval)} async function runAudit(){ const url=$('url-input').value;if(!url)return; $('btn').disabled=true;$('error').style.display='none';$('result').style.display='none'; startSpin(); try{ const res=await fetch('/api/audit?url='+encodeURIComponent(url)); const data=await res.json(); if(!res.ok)throw new Error(data.detail||'Audit failed'); renderResult(data,url); }catch(e){ $('error').textContent=e.message;$('error').style.display='block'; }finally{stopSpin();$('btn').disabled=false} } function renderResult(data,url){ const color=BANDS[data.band]||'#888'; const score=data.score||0; /* Gauge */ const circ=314.16; const offset=circ-(score/100*circ); const fill=$('gauge-fill'); fill.style.stroke=color; fill.style.strokeDashoffset=String(offset); $('gauge-score').textContent=score; $('gauge-score').style.fill=color; const tag=$('band-tag'); tag.textContent=data.band?data.band.toUpperCase():'—'; tag.style.background=color+'1a';tag.style.color=color; /* Breakdown */ const bd=$('breakdown');bd.textContent=''; const br=data.score_breakdown||{}; for(const cat of CATEGORIES){ const val=br[cat.key]||0; const pct=Math.min(val/cat.max*100,100); const row=document.createElement('div');row.className='bar-row'; const lbl=document.createElement('span');lbl.className='bar-label';lbl.textContent=cat.label; const track=document.createElement('div');track.className='bar-track'; const barFill=document.createElement('div');barFill.className='bar-fill'; barFill.style.width='0%';barFill.style.background=color; track.appendChild(barFill); const valSpan=document.createElement('span');valSpan.className='bar-val'; valSpan.textContent=val+'/'+cat.max; row.appendChild(lbl);row.appendChild(track);row.appendChild(valSpan); bd.appendChild(row); requestAnimationFrame(()=>{requestAnimationFrame(()=>{barFill.style.width=pct+'%'})}); } /* Citability */ const cit=data.citability; if(cit&&cit.total_score!==undefined){ $('cit-wrap').style.display='flex'; const cs=$('cit-score');cs.textContent=cit.total_score+'/100'; const cc=cit.total_score>=86?BANDS.excellent:cit.total_score>=68?BANDS.good:cit.total_score>=36?BANDS.foundation:BANDS.critical; cs.style.color=cc; $('cit-grade').textContent=cit.grade?cit.grade.toUpperCase():''; $('cit-grade').style.color=cc; }else{$('cit-wrap').style.display='none'} /* Recommendations */ const recs=data.recommendations||[]; $('recs-count').textContent='('+recs.length+')'; const rl=$('recs-list');rl.textContent='';rl.classList.remove('open'); $('recs-toggle').classList.remove('open'); for(const r of recs){const li=document.createElement('li');li.textContent=r;rl.appendChild(li)} /* Actions */ const acts=$('actions');acts.textContent=''; if(data.report_url){ const a=document.createElement('a');a.className='action-link';a.href=data.report_url; a.target='_blank';a.rel='noopener';a.textContent='HTML Report';acts.appendChild(a); } const pdf=document.createElement('a');pdf.className='action-link'; pdf.href='/api/audit/pdf?url='+encodeURIComponent(url); pdf.textContent='Download PDF';acts.appendChild(pdf); $('result').style.display='block'; } /* ─── Event listeners ─── */ $('btn').addEventListener('click',runAudit); $('url-input').addEventListener('keypress',e=>{if(e.key==='Enter')runAudit()}); $('recs-toggle').addEventListener('click',function(){ this.classList.toggle('open');$('recs-list').classList.toggle('open'); }); $('copy-btn').addEventListener('click',function(){ navigator.clipboard.writeText('pip install geo-optimizer-skill').then(()=>{this.textContent='Done!'}); setTimeout(()=>{this.textContent='\u{1F4CB}'},1500); });