ChatGPT Query Fanout Analyzer (Bookmarklet)

This Bookmarklet will help you parse the conversations data from your ChatGPT prompts including the fan-out queries, which URLs rank and what entities are found on the page. It allows you to view the conversation as a Markdown file too.

This was inspired, derived from and adapted from the works of Mike Friedman (TheSEOPUB) and Geeksta.

Parsing Query Fanouts

Whenever you look into your Chrome Devtools Console you see that ChatGPT gives you a ton of informations such as the queries that it sent for each of your prompt via the search_model_queries.

I’ve created this bookmarklet to help you get to that data easily.

Adding the Bookmarklet

To add a bookmarklet, right-click on the bookmark bar.

Click on “Add Page…”

Add a name and copy this code in the URL section of the bookmark bar.

Don’t worry, this is simple, I didn’t add any bad tracking of your stuff in there, simple thing I built for myself and sharing with you.

javascript:void(async()=>{const w=window.open("","_blank");if(!w)return alert("Popup blocked!");const ft="<link rel='preconnect' href='https://fonts.googleapis.com'><link rel='preconnect' href='https://fonts.gstatic.com' crossorigin><link href='https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap' rel='stylesheet'>";const st="<style>*{box-sizing:border-box}body{background:#000;color:#FFF;font-family:'Poppins',sans-serif;margin:0;padding:20px}#c{width:100%;max-width:1600px;margin:0 auto}h1{text-align:center;font-weight:700;display:flex;align-items:center;justify-content:center;margin-bottom:10px}.logo{height:28px;margin-right:15px;filter:broadness(0) invert(1)}h2{text-align:center;color:#eee;font-weight:400;font-size:20px;margin-bottom:20px;margin-top:5px}.cred{text-align:center;font-size:11px;color:#666;margin-bottom:15px;font-family:monospace}.cred a{color:#00EB5B;text-decoration:none}.cred a:hover{text-decoration:underline}.ctrl{background:#121212;padding:15px;border-radius:8px;border:1px solid #333;margin-bottom:20px;display:flex;flex-wrap:wrap;justify-content:center;gap:10px;align-items:center;position:relative}.btn{background:#000;color:#00EB5B;border:1px solid #00EB5B;padding:8px 16px;cursor:pointer;border-radius:4px;font-weight:700;font-size:13px;transition:0.2s}.btn:hover{background:#00EB5B;color:#000}.tn{background:#121212;border-radius:8px;margin-bottom:20px;border:1px solid #333;overflow:hidden}.th{background:#000;padding:15px 20px;color:#00EB5B;font-weight:700;cursor:pointer;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid #333;font-size:15px}.th:hover{background:#1a1a1a}.ar{transition:transform .2s}.cl .ar{transform:rotate(-90deg)}.cols{padding:15px;display:grid;grid-template-columns:repeat(auto-fit, minmax(250px, 1fr));gap:15px}.col{background:#000;border:1px solid #333;border-radius:6px;display:flex;flex-direction:column}.ch{padding:10px;border-bottom:1px solid #333;font-weight:700;color:#888;font-size:12px;text-transform:uppercase;background:#0a0a0a;display:flex;justify-content:space-between}.it{background:#1a1a1a;padding:12px;margin:10px;border-radius:4px;font-size:13px;border:1px solid #333;word-break:break-word}.ih{border-left:3px solid #00EB5B}.sm{display:flex;justify-content:space-between;margin-bottom:6px;font-size:11px;color:#aaa}.sb{padding:2px 6px;border-radius:3px;font-weight:700;color:#000;font-size:10px}.type-Primary{background:#00EB5B}.type-Grouped{background:#FFFF59}.type-Sidebar{background:#5FEAFF}.type-Footnote{background:#C197FF}.type-Supporting{background:#9Bf2FF}.type-Business{background:#FF9626}.type-Tool{background:#FFED0E}.type-Image{background:#FF4E51}.type-Attachment{background:#D1FF73}.type-Entity{background:#FFA0E9}.type-ImgGroup{background:#FFA500}.type-Decision{background:#FF00FF}.type-Model{background:#FF4500}.sti{font-weight:700;color:#00EB5B;margin-bottom:4px;font-family:monospace}.ri{font-size:10px;background:#000;color:#00EB5B;padding:2px 5px;border:1px solid #00EB5B;vertical-align:middle;margin-left:8px}.su{font-size:12px;color:#888;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block;margin-bottom:4px;text-decoration:none}.ssn{font-size:11px;color:#ccc;background:#000;padding:8px;border-radius:4px;margin-top:6px;border:1px solid #222;white-space:pre-wrap;font-family:monospace}.cp{background:transparent;border:1px solid #555;color:#aaa;font-size:10px;cursor:pointer}.cp:hover{color:#00EB5B;border-color:#00EB5B}.ms-con{position:relative;display:inline-block}.ms-btn{min-width:180px;text-align:left;display:flex;justify-content:space-between}.ms-drop{display:none;position:absolute;top:100%;left:0;background:#222;border:1px solid #444;border-radius:4px;z-index:1000;width:100%;padding:8px;box-shadow:0 10px 20px rgba(0,0,0,0.5)}.ms-row{display:flex;align-items:center;padding:4px 0;cursor:pointer;font-size:13px;color:#ddd}.ms-row:hover{color:#fff}.ms-chk{margin-right:10px;accent-color:#00EB5B}#md{display:none;width:100%;margin-top:20px}#mt{width:100%;height:70vh;background:#121212;color:#00EB5B;border:1px solid #333;padding:20px;font-family:monospace;border-radius:8px}.av{font-size:10px;color:#888;font-weight:400;text-transform:uppercase;margin-top:4px}</style>";w.document.write("<!DOCTYPE html><html><head><title>ChatGPT Analyzer</title>"+ft+st+"</head><body><p style='font-weight:700;margin-top:20px'>Fetching...</p></body></html>");try{const cid=location.pathname.match(/\/c\/([^/]+)/)?.[1];if(!cid)throw new Error("Open a chat first.");const s=await fetch("/api/auth/session").then(r=>r.json());const r=await fetch(`/backend-api/conversation/${cid}`,{headers:{Authorization:"Bearer "+s.accessToken,"Content-Type":"application/json"}});if(!r.ok)throw new Error("Fetch error");const d=await r.json();const gm=new Map();const fd=t=>typeof t==="number"?new Date(t*1000).toLocaleDateString():t||"";for(const id in d.mapping){const n=d.mapping[id],m=n.message?.metadata,c=n.message?.content;let q=[],st=[],fn=[],l=[],sw=[],en=[],ig=[],dc=[],fbq=[];const ss=new Set(),sl=new Set(),sfn=new Set(),ssw=new Set(),sen=new Set(),sig=new Set(),sfbq=new Set();const al=(arr,set,o,ty,rk=null,fri=null,dom=null)=>{if(!o.url&&!o.title)return false;const cl=(o.url||o.title).trim().replace(/\/$/,"");if(set.has(cl))return false;set.add(cl);let ri=fri??(o.ref_id?.ref_index??o.refs?.[0]?.ref_index);arr.push({u:o.url||"",t:ty,ti:o.title||"No Title",sn:o.snippet||"",at:o.attribution||"",dt:fd(o.pub_date),r:rk,ri:ri,dm:dom||o.attribution||""});return true};if(m?.search_model_queries?.queries)m.search_model_queries.queries.forEach(x=>q.push({t:x,h:true}));if(m?.search_queries)m.search_queries.forEach(x=>q.push({t:x.q,h:false}));if(n.message?.recipient==="web.run"&&c?.content_type==="code"&&typeof c.text==="string"){c.text.split("\n").forEach(line=>{line=line.trim();if(!line)return;const parts=line.split("|");const query=parts[1]?.trim();if(!query)return;const key=query.toLowerCase();if(sfbq.has(key))return;sfbq.add(key);fbq.push({t:query,h:true,fb:true})})}if(m?.search_result_groups)m.search_result_groups.forEach(g=>{g.entries?.forEach(e=>al(st,ss,e,"Grouped Citation",null,null,g.domain))});if(m?.content_references)m.content_references.forEach(x=>{if(x.cite_map)Object.values(x.cite_map).forEach(v=>al(st,ss,v,"Sidebar Citation"));if(x.type==="businesses_map"&&x.businesses)x.businesses.forEach(b=>al(st,ss,{url:b.website_url,title:b.name,snippet:b.address,attribution:"Map Result"},"Business Map"));if((x.type==="sources_footnote"||x.type==="sources_footnotes")&&x.sources)x.sources.forEach(src=>al(fn,sfn,src,"Footnote Source"))});let pr=1;if(m?.content_references)m.content_references.forEach(x=>{if(x.type==="grouped_webpages"&&x.items)x.items.forEach(i=>{const pri=(i.refs?.[0]?.ref_index);if(al(l,sl,i,"Primary Citation",pr))pr++;if(i.supporting_websites)i.supporting_websites.forEach(s=>al(sw,ssw,s,"Supporting Web",null,pri))})});if(m?.image_results)m.image_results.forEach(i=>al(l,sl,{url:i.url||i.content_url,title:i.title},"Image"));if(m?.attachments)m.attachments.forEach(a=>al(l,sl,{url:a.url,title:a.name},"Attachment"));let txt="";if(c?.parts){txt=c.parts.join("\n");const rig=/\uE200image_group\uE202(.*?)\uE201/g;let mig;while((mig=rig.exec(txt))!==null){try{const j=JSON.parse(mig[1]);const t=JSON.stringify(j);if(!sig.has(t)){sig.add(t);ig.push({t:"ImgGroup",ti:t,sn:"",u:""})}}catch(e){}}const ren=/\uE200entity\uE202(.*?)\uE201/g;let men;while((men=ren.exec(txt))!==null){try{const j=JSON.parse(men[1]);const t=j[1],ty=j[0],det=j[3]?JSON.stringify(j[3]):"";if(!sen.has(t)){sen.add(t);en.push({t:"Entity",ti:t,sn:ty+(det?" | "+det:""),u:""})}}catch(e){}}}if(q.length||st.length||fn.length||l.length||sw.length||en.length||ig.length||dc.length||fbq.length||(txt&&n.message.author.role==="assistant")){let pt=n.parent,pm="[Start]";for(let i=0;i<25;i++){const p=d.mapping[pt];if(!p)break;if(p.message?.author?.role==="user"){const px=p.message.content.parts;pm=Array.isArray(px)?px.join(" "):px;break}pt=p.parent}if(!gm.has(pm))gm.set(pm,{p:pm,q:[],st:[],fn:[],l:[],sw:[],en:[],ig:[],dc:[],fbq:[],txt:"",models:new Set(),uniqDec:new Set()});const g=gm.get(pm);g.q.push(...q);g.st.push(...st);g.fn.push(...fn);g.l.push(...l);g.sw.push(...sw);g.en.push(...en);g.ig.push(...ig);g.fbq.push(...fbq);if(n.message?.author?.role==="assistant"&&m?.model_slug)g.models.add(m.model_slug);if(txt&&n.message.author.role==="assistant")g.txt+=txt+"\n\n"}}gm.forEach(g=>{if(g.models.size){g.dc.unshift({t:"Model",ti:Array.from(g.models).join(", "),sn:"Generative Models",u:""})}if(g.fbq.length){const seen=new Set(g.q.map(x=>(x.t||"").trim().toLowerCase()));g.fbq.forEach(x=>{const key=x.t.trim().toLowerCase();if(!seen.has(key)){seen.add(key);g.q.push(x)}})}});const grps=Array.from(gm.values());const doc=w.document;doc.open();doc.write("<!DOCTYPE html><html><head><title>ChatGPT Analyzer</title>"+ft+st+"</head><body></body></html>");doc.close();const ct=doc.createElement("div");ct.id="c";ct.innerHTML=`<h1>ChatGPT Conversations Analyzer</h1><div class="cred">Created by: <a href="https://www.jcchouinard.com/" target="_blank">Jean-Christophe Chouinard</a></div><h2>Conversation Title: ${d.title}</h2>`;const cb=doc.createElement("div");cb.className="ctrl";const msCon=doc.createElement("div");msCon.className="ms-con";const msBtn=doc.createElement("button");msBtn.className="btn ms-btn";msBtn.innerHTML="Visible Columns <span>▲</span>";const msDrop=doc.createElement("div");msDrop.className="ms-drop";const colsState={"Model Info":true,"Queries":true,"Entities":true,"Footnotes":true,"Steps":false,"Links":false,"Supporting":false,"Image Groups":false};Object.keys(colsState).forEach(k=>{const row=doc.createElement("div");row.className="ms-row";const chk=doc.createElement("input");chk.type="checkbox";chk.className="ms-chk";chk.checked=colsState[k];chk.onclick=(e)=>{e.stopPropagation();colsState[k]=e.target.checked;rdr()};row.onclick=(e)=>{if(e.target!==chk){chk.checked=!chk.checked;colsState[k]=chk.checked;rdr()}};const lbl=doc.createElement("span");lbl.textContent=k;row.append(chk,lbl);msDrop.appendChild(row)});msBtn.onclick=(e)=>{e.stopPropagation();msDrop.style.display=msDrop.style.display==="block"?"none":"block"};doc.onclick=()=>msDrop.style.display="none";msCon.append(msBtn,msDrop);cb.appendChild(msCon);const mkBtn=(txt,fn)=>{const b=doc.createElement("button");b.className="btn";b.textContent=txt;b.onclick=fn;cb.appendChild(b)};mkBtn("Expand All",()=>{doc.querySelectorAll(".cols").forEach(el=>el.style.display="grid");doc.querySelectorAll(".th").forEach(el=>el.classList.remove("cl"))});mkBtn("Collapse All",()=>{doc.querySelectorAll(".cols").forEach(el=>el.style.display="none");doc.querySelectorAll(".th").forEach(el=>el.classList.add("cl"))});const dld=(c,n)=>{const b=new Blob([c],{type:'text/csv;charset=utf-8;'});const l=doc.createElement("a");l.href=URL.createObjectURL(b);l.download=n;l.click()};const esc=t=>(t===null||t===undefined)?'""':'"'+String(t).replace(/"/g,'""')+'"';mkBtn("Export Selected",async()=>{const km={"Model Info":"dc","Queries":"q","Steps":"st","Footnotes":"fn","Links":"l","Supporting":"sw","Image Groups":"ig","Entities":"en"};const act=Object.keys(colsState).filter(k=>colsState[k]);if(!act.length)return alert("Select columns first");for(const k of act){let c="",h=false;if(k==="Queries")c="User Query,Search Queries\n";else if(k==="Entities")c="User Query,Entities\n";else if(k==="Image Groups")c="User Query,Image Group\n";else if(k==="Model Info")c="User Query,Info Type,Value\n";else c="User Query,Type,Domain,Title,URL,Snippet\n";grps.forEach(g=>{const ar=g[km[k]];if(ar&&ar.length){h=true;ar.forEach(x=>{if(k==="Queries")c+=`${esc(g.p)},${esc(x.t)}\n`;else if(k==="Entities"||k==="Image Groups")c+=`${esc(g.p)},${esc(x.ti)}\n`;else if(k==="Model Info")c+=`${esc(g.p)},${esc(x.ti)},${esc(x.sn)}\n`;else c+=`${esc(g.p)},${k},${esc(x.dm)},${esc(x.ti)},${esc(x.u)},${esc(x.sn)}\n`})}});if(h){dld(c,k.replace(/\s+/g,"_")+"_Report.csv");await new Promise(r=>setTimeout(r,750))}}});mkBtn("View Markdown",(e)=>{const m=doc.getElementById("md"),da=doc.getElementById("display-area");const s=m.style.display==="none";m.style.display=s?"block":"none";da.style.display=s?"none":"block";e.target.textContent=s?"View Report":"View Markdown"});ct.appendChild(cb);const da=doc.createElement("div");da.id="display-area";ct.appendChild(da);let mdt=`# ${doc.title}\n\n`;grps.forEach((g,i)=>{mdt+=`### PROMPT ${i+1}\n\n${g.p}\n\n### RESPONSE ${i+1}\n\n${g.txt}\n\n---\n\n`});const md=doc.createElement("div");md.id="md";md.innerHTML=`<textarea id="mt" readonly>${mdt}</textarea>`;ct.appendChild(md);const rc=(ti,it,dst)=>{if(!it||!it.length)return;const cl=doc.createElement("div");cl.className="col";const hd=doc.createElement("div");hd.className="ch";hd.innerHTML=`<span>${ti} (${it.length})</span>`;const cpb=doc.createElement("button");cpb.className="cp";cpb.textContent="Copy";cpb.onclick=()=>{navigator.clipboard.writeText(it.map(x=>x.u||x.t||x.ti).join("\n")).then(()=>alert("Copied!"))};hd.appendChild(cpb);cl.appendChild(hd);it.forEach(x=>{if(x.t&&!x.u&&!x.ti){cl.innerHTML+=`<div class="it ${x.h?'ih':''}">${x.t}</div>`}else{let rk=x.r?`<span style="background:#00EB5B;color:#000;padding:1px 5px;border-radius:3px;margin-right:5px">#${x.r}</span>`:"";let ri=(x.ri!=null)?`<span class="ri">Ref: ${x.ri}</span>`:"";cl.innerHTML+=`<div class="it"><div class="sm"><span class="sb type-${x.t.split(" ")[0]}">${x.t}</span><span>${x.at} ${x.dt?'• '+x.dt:''}</span></div><div class="sti">${rk}${x.ti}${ri}</div>${x.u?`<a class="su" href="${x.u}" target="_blank">${x.u}</a>`:""}${x.sn?`<div class="ssn">${x.sn}</div>`:""}</div>`}});dst.appendChild(cl)};const rdr=()=>{da.innerHTML="";grps.forEach(g=>{const tn=doc.createElement("div");tn.className="tn";const th=doc.createElement("div");th.className="th";let av=[];if(g.dc.length)av.push("Model Info");if(g.q.length)av.push("Queries");if(g.en.length)av.push("Entities");if(g.fn.length)av.push("Footnotes");if(g.l.length)av.push("Links");if(g.ig.length)av.push("Image Groups");th.innerHTML=`<div style="display:flex;flex-direction:column;gap:4px"><span>${g.p}</span>${av.length?`<div class="av">Available: ${av.join(", ")}</div>`:""}</div><span class="ar">▲</span>`;th.onclick=function(){const n=this.nextElementSibling;const h=n.style.display==="none";n.style.display=h?"grid":"none";if(h)this.classList.remove("cl");else this.classList.add("cl")};tn.appendChild(th);const cls=doc.createElement("div");cls.className="cols";if(colsState["Model Info"])rc("Model Info",g.dc,cls);if(colsState["Queries"])rc("Queries",g.q,cls);if(colsState["Steps"])rc("Steps",g.st,cls);if(colsState["Footnotes"])rc("Footnotes",g.fn,cls);if(colsState["Links"])rc("Links",g.l,cls);if(colsState["Supporting"])rc("Supporting",g.sw,cls);if(colsState["Image Groups"])rc("Image Groups",g.ig,cls);if(colsState["Entities"])rc("Entities",g.en,cls);tn.appendChild(cls);da.appendChild(tn)})};rdr();doc.body.appendChild(ct)}catch(e){w.document.body.innerHTML=`<h2 style='color:red;text-align:center;font-family:Poppins,sans-serif'>${e.message}</h2>`}})();
3.8/5 - (20 votes)