Analyze Competitive Narratives

See how AI search engines describe your competitors vs your brand

Enter up to 5 competitors
Analyzing... this may take up to 90 seconds.

Executive Summary

Competitor Narratives

fetch('/api/stats').then(function(r){return r.json()}).then(function(d){var ns=document.getElementById('nav-stars');if(ns&&d.github_stars)ns.textContent='★ '+d.github_stars}).catch(function(){}); const $=id=>document.getElementById(id); const $in=$tag=>$('input[type="text"]')&&$.prototype.addEventListener.call(document.querySelector($tag),arguments[1],arguments[2]); $('btn').addEventListener('click',run); $('competitorUrls').addEventListener('keypress',e=>{if(e.key==='Enter')run()}); function isValidUrl(str){ if(/^https?:\/\/.+\..+/.test(str))return true; if(/^[^\s]+\.[a-z]{2,}(\/.*)?$/i.test(str))return true; return false; } async function run(){ const targetUrl=$('targetUrl').value.trim(); const competitorText=$('competitorUrls').value.trim(); if(!targetUrl)return; if(!competitorText)return; if(!isValidUrl(targetUrl)){$('error').textContent='Please enter a valid URL for your website';$('error').style.display='block';return} if(!/^https?:\/\//i.test(targetUrl)){$('targetUrl').value='https://'+targetUrl;targetUrl=$('targetUrl').value} const competitors=competitorText.split(',').map(u=>u.trim()).filter(u=>u&&isValidUrl(u)); if(competitors.length===0){$('error').textContent='Please enter at least one valid competitor URL';$('error').style.display='block';return} $('btn').disabled=true;$('spinner').classList.add('active');$('error').style.display='none';$('results').style.display='none'; try{ const response=await fetch('/api/analyze-competitors',{ method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({target_url:targetUrl,competitor_urls:competitors}) }); if(!response.ok){throw new Error('Analysis failed: '+response.statusText);} const data=await response.json(); render(data); $('results').style.display='block'; if(data.summary){$('summaryText').textContent=data.summary;} }catch(e){$('error').textContent=e.message;$('error').style.display='block'} finally{$('btn').disabled=false;$('spinner').classList.remove('active')} } function render(data){ const competitorList=$('competitorList'); competitorList.textContent=''; data.competitors.forEach(function(c){ const card=document.createElement('div'); card.className='narrative-card'; const header=document.createElement('div'); header.className='narrative-header'; const brandSpan=document.createElement('span'); brandSpan.className='narrative-brand'; brandSpan.textContent=(c.brand_name||c.url); const badgeSpan=document.createElement('span'); badgeSpan.className='badge'; badgeSpan.textContent='Score '+(c.score||'N/A'); brandSpan.appendChild(badgeSpan); header.appendChild(brandSpan); card.appendChild(header); if(c.dominant_adjectives&&c.dominant_adjectives.length>0){ const adjDiv=document.createElement('div'); adjDiv.className='adjectives'; const adjLabel=document.createElement('span'); adjLabel.className='adjective-label'; adjLabel.textContent='Adjectives:'; adjDiv.appendChild(adjLabel); c.dominant_adjectives.forEach(function(a){ const span=document.createElement('span'); span.className='adjective'; span.textContent=a; adjDiv.appendChild(span); }); card.appendChild(adjDiv); } if(c.key_frames&&c.key_frames.length>0){ const frameDiv=document.createElement('div'); frameDiv.className='frames'; const frameLabel=document.createElement('span'); frameLabel.className='frame-label'; frameLabel.textContent='Frames:'; frameDiv.appendChild(frameLabel); c.key_frames.forEach(function(f){ const span=document.createElement('span'); span.className='frame'; span.textContent=f; frameDiv.appendChild(span); }); card.appendChild(frameDiv); } if(c.positioning){ const posDiv=document.createElement('div'); posDiv.className='positioning'; posDiv.setAttribute('dir','ltr'); posDiv.textContent='"'+c.positioning+'"'; card.appendChild(posDiv); } if(c.credibility_signals&&c.credibility_signals.length>0){ const credDiv=document.createElement('div'); credDiv.className='credibility'; const credH4=document.createElement('h4'); credH4.textContent='Credibility Signals'; credDiv.appendChild(credH4); const credUl=document.createElement('ul'); c.credibility_signals.forEach(function(s){ const li=document.createElement('li'); li.textContent=s; credUl.appendChild(li); }); credDiv.appendChild(credUl); card.appendChild(credDiv); } if(c.content_gaps&&c.content_gaps.length>0){ const gapDiv=document.createElement('div'); gapDiv.className='gaps'; const gapH4=document.createElement('h4'); gapH4.textContent='Content Gaps'; gapDiv.appendChild(gapH4); const gapUl=document.createElement('ul'); c.content_gaps.forEach(function(g){ const li=document.createElement('li'); li.textContent=g; gapUl.appendChild(li); }); gapDiv.appendChild(gapUl); card.appendChild(gapDiv); } competitorList.appendChild(card); }); // Render gaps table if available if(data.competitive_gaps&&data.competitive_gaps.length>0){ const gapTableBody=$('gapTableBody'); gapTableBody.textContent=''; $('gapSection').style.display='block'; data.competitive_gaps.forEach(function(g){ const tr=document.createElement('tr'); const tdCat=document.createElement('td'); tdCat.textContent=g.category; tr.appendChild(tdCat); const tdUrl=document.createElement('td'); const aUrl=document.createElement('a'); try{ aUrl.href=new URL(g.competitor_url).href; aUrl.textContent=new URL(g.competitor_url).hostname; }catch{ aUrl.href='#'; aUrl.textContent=g.competitor_url||''; } aUrl.target='_blank'; aUrl.rel='noopener'; tdUrl.appendChild(aUrl); tr.appendChild(tdUrl); const tdType=document.createElement('td'); const spanType=document.createElement('span'); spanType.className='gap-type gap-'+g.gap_type; spanType.textContent=g.gap_type; tdType.appendChild(spanType); tr.appendChild(tdType); const tdMissing=document.createElement('td'); tdMissing.textContent=g.target_missing; tr.appendChild(tdMissing); const tdSuggest=document.createElement('td'); tdSuggest.className='suggestion'; tdSuggest.textContent=g.suggested_content; tr.appendChild(tdSuggest); gapTableBody.appendChild(tr); }); } } document.getElementById('nav-ham').addEventListener('click',function(){ document.querySelector('.nav-links').classList.toggle('open'); this.textContent=this.textContent==='☰'?'✕':'☰'; }); document.querySelectorAll('.nav-dropdown-toggle').forEach(function(btn){ btn.addEventListener('click',function(e){ e.stopPropagation(); var dd=this.closest('.nav-dropdown'); dd.classList.toggle('open'); this.setAttribute('aria-expanded',dd.classList.contains('open')); }); }); document.addEventListener('click',function(){ document.querySelectorAll('.nav-dropdown.open').forEach(function(dd){ dd.classList.remove('open'); dd.querySelector('.nav-dropdown-toggle').setAttribute('aria-expanded','false'); }); });