<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Juan Camilo Auriti</title>
    <description>The latest articles on DEV Community by Juan Camilo Auriti (@juanauriti).</description>
    <link>https://dev.to/juanauriti</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3279930%2F4faa1f38-8049-4b7d-a93f-a217cf7eaefa.jpg</url>
      <title>DEV Community: Juan Camilo Auriti</title>
      <link>https://dev.to/juanauriti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/juanauriti"/>
    <language>en</language>
    <item>
      <title>7 open-source AI visibility trackers launched on HN this year. Here's what each one actually does.</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Sun, 01 Nov 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/7-open-source-ai-visibility-trackers-launched-on-hn-this-year-heres-what-each-one-actually-does-1bic</link>
      <guid>https://dev.to/juanauriti/7-open-source-ai-visibility-trackers-launched-on-hn-this-year-heres-what-each-one-actually-does-1bic</guid>
      <description>&lt;p&gt;The AI visibility space has a paid side and an open-source side. The paid side is crowded: Otterly ($29/mo), Peec AI ($95/mo), Scrunch ($250/mo), Profound (enterprise), AthenaHQ ($295/mo), Semrush AI Visibility ($99/mo), and a dozen more. The open-source side is smaller but growing fast. Seven projects launched on Hacker News in 2026, each taking a different angle on the same problem: can you check your AI search visibility without paying a subscription?&lt;/p&gt;

&lt;p&gt;Here is what each one does, what it costs to run, and what it leaves out.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Elmo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://elmohq.com/" rel="noopener noreferrer"&gt;Elmo&lt;/a&gt; is a self-hosted AEO platform, MIT licensed. It tracks how your brand appears across ChatGPT, Claude, Gemini, Grok, Perplexity, Copilot, DeepSeek, Mistral, and Google's AI Mode and AI Overviews. You supply your own LLM API keys, so the cost is whatever the API providers charge per query. No per-prompt subscription.&lt;/p&gt;

&lt;p&gt;What it does: brand mention tracking, citation tracking, competitor benchmarking, sentiment. Coverage is unusually wide for open source (9+ engines).&lt;/p&gt;

&lt;p&gt;What it leaves out: site audit. Elmo tracks whether you appear in AI answers. It does not check whether your site is crawlable or parseable. You need a separate tool for that.&lt;/p&gt;

&lt;p&gt;Cost to run: API costs only. If you run 50 prompts across 9 engines weekly, expect $5-15/week in API fees depending on which models you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Canonry
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ainyc" rel="noopener noreferrer"&gt;Canonry&lt;/a&gt; is a CLI that tracks how ChatGPT, Gemini, and Claude cite your site. Self-hosted on SQLite, config-as-code in YAML, CLI and API are first-class.&lt;/p&gt;

&lt;p&gt;What it does: visibility scores, citation-readiness checks, brand accuracy across providers over time. Cross-references with Google Search Console and Google Analytics for a combined view.&lt;/p&gt;

&lt;p&gt;What it leaves out: no site audit, no fix recommendations. It tells you what is happening, not what to do about it.&lt;/p&gt;

&lt;p&gt;Cost to run: API costs for the LLM queries. SQLite is free.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Auto-geo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/shadowresearch" rel="noopener noreferrer"&gt;Auto-geo&lt;/a&gt; is a file-based GEO CLI from Shadow Inc, an AI PR lab. npm install or brew install.&lt;/p&gt;

&lt;p&gt;What it does: prompt tracking (&lt;code&gt;prompts discover&lt;/code&gt; reads your homepage and proposes queries), citation checking across ChatGPT, Claude, Gemini, Perplexity, and Grok, history diffs (which prompts you won or lost since last run), and a doctor command that audits pages for AI-citation readiness.&lt;/p&gt;

&lt;p&gt;What it leaves out: the doctor audit is lighter than a full site audit. It checks structure and "chunkability" but does not check 27 AI crawlers or run a full scoring rubric.&lt;/p&gt;

&lt;p&gt;Cost to run: API costs for the LLM queries. npm package is free.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Lettertrace
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://lettertrace.com" rel="noopener noreferrer"&gt;Lettertrace&lt;/a&gt; is a BYOK (bring your own key) library for tracking AI search, MIT licensed. It is a library, not a full platform. You embed it in your own codebase.&lt;/p&gt;

&lt;p&gt;What it does: tracks how your brand appears in AI answers using your own LLM harness. Designed for developers who want to build visibility tracking into existing systems.&lt;/p&gt;

&lt;p&gt;What it leaves out: no UI, no dashboard. It is a library. You build the interface.&lt;/p&gt;

&lt;p&gt;Cost to run: API costs only.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. CiteLadder
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/abhij1306" rel="noopener noreferrer"&gt;CiteLadder&lt;/a&gt; is an open-source AI search visibility tracker, recently launched on HN.&lt;/p&gt;

&lt;p&gt;What it does: tracks whether your site gets cited by AI search engines. Details are sparse since the project is new.&lt;/p&gt;

&lt;p&gt;What it leaves out: too early to assess. The repo is fresh.&lt;/p&gt;

&lt;p&gt;Cost to run: not specified.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. GetCito
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://getcito.com/" rel="noopener noreferrer"&gt;GetCito&lt;/a&gt; is an open-source AEO tool, MIT licensed, run by a marketing agency.&lt;/p&gt;

&lt;p&gt;What it does: AI Crawlability Clinic that checks how well AI bots can reach and parse your content.&lt;/p&gt;

&lt;p&gt;What it leaves out: maintenance. The public repo has had a single substantive code commit since it launched in late 2025. It is run by an agency, not a dedicated product team. Do not expect ongoing fixes or new engine support.&lt;/p&gt;

&lt;p&gt;Cost to run: free, but you get what you pay for in terms of maintenance.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Ansvisor
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.ansvisor.com/" rel="noopener noreferrer"&gt;Ansvisor&lt;/a&gt; is an open-source, cloud-ready AI visibility platform. It tracks mentions, citations, competitors, and Share of Voice across ChatGPT, Gemini, Perplexity, Claude, Copilot, Google AI Overviews, and Google AI Mode.&lt;/p&gt;

&lt;p&gt;What it does: separates owned citations, competitor citations, and third-party sources. Cross-platform monitoring with historical trends.&lt;/p&gt;

&lt;p&gt;What it leaves out: no site audit. Like Elmo, it tracks visibility, not crawlability.&lt;/p&gt;

&lt;p&gt;Cost to run: open source for self-hosting. Managed cloud option listed as coming soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where geo-optimizer fits
&lt;/h2&gt;

&lt;p&gt;GEO Optimizer is the only open-source tool in this list that does a deterministic site audit rather than citation tracking. The 16 CLI commands, 47 content checks, 27 AI crawlers, and 9 scoring categories check whether your page is reachable, parseable, and quotable. It does not track whether you appear in AI answers over time. That is what the monitoring layer on geoready.dev is for.&lt;/p&gt;

&lt;p&gt;The distinction matters. Citation trackers (Elmo, Canonry, Ansvisor, Auto-geo, Lettertrace, CiteLadder) tell you whether you appear in AI answers. Site auditors (geo-optimizer, GetCito) tell you whether AI crawlers can read your page in the first place. You need both: audit to fix the foundation, monitor to track whether the fixes worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Audit or track&lt;/th&gt;
&lt;th&gt;Engines&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;Maintained&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Elmo&lt;/td&gt;
&lt;td&gt;Brand tracking, citations, competitors&lt;/td&gt;
&lt;td&gt;Track&lt;/td&gt;
&lt;td&gt;9+&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonry&lt;/td&gt;
&lt;td&gt;Citation tracking, GSC integration&lt;/td&gt;
&lt;td&gt;Track&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-geo&lt;/td&gt;
&lt;td&gt;Prompt tracking, doctor audit&lt;/td&gt;
&lt;td&gt;Both&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lettertrace&lt;/td&gt;
&lt;td&gt;BYOK tracking library&lt;/td&gt;
&lt;td&gt;Track&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CiteLadder&lt;/td&gt;
&lt;td&gt;Visibility tracking&lt;/td&gt;
&lt;td&gt;Track&lt;/td&gt;
&lt;td&gt;TBD&lt;/td&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;New&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GetCito&lt;/td&gt;
&lt;td&gt;Crawlability clinic&lt;/td&gt;
&lt;td&gt;Audit&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Stale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ansvisor&lt;/td&gt;
&lt;td&gt;Citations, competitors, SoV&lt;/td&gt;
&lt;td&gt;Track&lt;/td&gt;
&lt;td&gt;7+&lt;/td&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GEO Optimizer&lt;/td&gt;
&lt;td&gt;Site audit, scoring, fixes&lt;/td&gt;
&lt;td&gt;Audit&lt;/td&gt;
&lt;td&gt;27 crawlers&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Active (v4.19.5)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What none of them have done
&lt;/h2&gt;

&lt;p&gt;None of these tools, including mine, has published a calibration study testing whether their scores or metrics predict actual citations. I did, and the result was null. That study is at &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill/tree/main/research/calibration-2026-10" rel="noopener noreferrer"&gt;github.com/Auriti-Labs/geo-optimizer-skill/tree/main/research/calibration-2026-10&lt;/a&gt;, with pre-registration hash and raw data.&lt;/p&gt;

&lt;p&gt;If you use any of these tools, ask the maintainers to do the same. A score that has not been tested against reality is a number, not a metric.&lt;/p&gt;

&lt;p&gt;If you want to run a free site audit, it is on &lt;a href="https://geoready.dev" rel="noopener noreferrer"&gt;geoready.dev&lt;/a&gt;. The CLI is on &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, 1,137 stars, MIT licensed, 2,000+ tests.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Google moved to inline citations in August. CTR quadrupled. Here's what to optimize for now.</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Sat, 31 Oct 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/google-moved-to-inline-citations-in-august-ctr-quadrupled-heres-what-to-optimize-for-now-218n</link>
      <guid>https://dev.to/juanauriti/google-moved-to-inline-citations-in-august-ctr-quadrupled-heres-what-to-optimize-for-now-218n</guid>
      <description>&lt;p&gt;In August 2026, Google changed how AI Overviews display citations. Instead of a source list at the bottom of the card, citations now appear inline, as numbered links embedded directly in the AI-generated text, next to the claim they support. Early data from publishers who shared Search Console numbers shows click-through rates roughly quadrupled compared to the old bottom-only format.&lt;/p&gt;

&lt;p&gt;If you were optimizing for the old citation format, the target moved.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;p&gt;Before August 2026, AI Overviews displayed a text summary with a carousel or list of source links at the bottom. Users had to scroll past the AI text to find the sources. The &lt;a href="https://www.nngroup.com/" rel="noopener noreferrer"&gt;Nielsen Norman Group&lt;/a&gt; had previously found that users exhibit "satisficing" behavior in search: they stop scanning once they find an acceptable answer. When all citations lived at the bottom, source pages received minimal traffic.&lt;/p&gt;

&lt;p&gt;The new format places clickable references directly in the text. When the AI Overview makes a specific claim, a numbered link appears adjacent to that statement. Bottom citations still exist but serve as supplementary "additional sources" rather than the primary attribution mechanism.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://firstpagesage.com/reports/google-click-through-rates-ctrs-by-ranking-position/" rel="noopener noreferrer"&gt;First Page Sage's CTR data&lt;/a&gt; confirmed the shift: citation CTR roughly quadrupled between December 2025 and August 2026, coinciding with the inline format rollout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://whatsmygeoscore.com/inline-source-links-ai-overviews-citation-format-august-2026" rel="noopener noreferrer"&gt;study of 6,200 AI Overviews&lt;/a&gt; captured between August 12 and 28, 2026 measured citation placement patterns and early CTR data from 23 publishers who shared anonymized Search Console data:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Inline citations&lt;/th&gt;
&lt;th&gt;Bottom-only citations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Median CTR&lt;/td&gt;
&lt;td&gt;3.1%&lt;/td&gt;
&lt;td&gt;1.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CTR range&lt;/td&gt;
&lt;td&gt;2.4% to 3.8%&lt;/td&gt;
&lt;td&gt;0.8% to 1.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lift&lt;/td&gt;
&lt;td&gt;2.8x&lt;/td&gt;
&lt;td&gt;baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For comparison, traditional blue links in positions 1-3 below the AI Overview still get 4.2% to 8.7% median CTR. Inline citations in AI Overviews are now closer to that range than to the old bottom-only format.&lt;/p&gt;

&lt;h2&gt;
  
  
  What content gets inline placement
&lt;/h2&gt;

&lt;p&gt;The study also broke down CTR by content type:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Content type cited&lt;/th&gt;
&lt;th&gt;Inline CTR&lt;/th&gt;
&lt;th&gt;Bottom-only CTR&lt;/th&gt;
&lt;th&gt;CTR lift&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Statistical data and research&lt;/td&gt;
&lt;td&gt;4.3%&lt;/td&gt;
&lt;td&gt;1.4%&lt;/td&gt;
&lt;td&gt;207%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How-to instructions&lt;/td&gt;
&lt;td&gt;3.8%&lt;/td&gt;
&lt;td&gt;1.3%&lt;/td&gt;
&lt;td&gt;192%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product comparisons&lt;/td&gt;
&lt;td&gt;3.2%&lt;/td&gt;
&lt;td&gt;1.0%&lt;/td&gt;
&lt;td&gt;220%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Definitions and explanations&lt;/td&gt;
&lt;td&gt;2.1%&lt;/td&gt;
&lt;td&gt;0.9%&lt;/td&gt;
&lt;td&gt;133%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;News and current events&lt;/td&gt;
&lt;td&gt;2.9%&lt;/td&gt;
&lt;td&gt;1.1%&lt;/td&gt;
&lt;td&gt;164%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Statistical data and research content gets the highest inline CTR (4.3%) and the largest lift over bottom-only placement (207%). Pages with specific statistics, original research data, and factual claims that need sourcing are the most likely to earn inline placement and the most likely to get clicked when they do.&lt;/p&gt;

&lt;p&gt;67% of inline citations in research-oriented queries pointed to original studies rather than secondary coverage. AI Overviews preferentially cite the source of data, not articles summarizing that data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for your content
&lt;/h2&gt;

&lt;p&gt;Three concrete changes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Put statistics and factual claims near the top of your content.&lt;/strong&gt; The Babel42 study (October 2026) found that 67% of AI Overview quoted passages come from the first 30% of the page. If your key statistics are buried in the conclusion, they are less likely to be extracted. If they are in the first two sections, they are more likely to become an inline citation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Cite your own sources inline.&lt;/strong&gt; Pages that link to primary sources (studies, official documentation, government data) are more likely to be positioned as the "source of data" rather than a secondary summary. AI Overviews cite the source, not the article about the source. If you are the page that links to the original study, you become the intermediary. If you are the original study, you are the citation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Structure factual claims as self-contained sentences.&lt;/strong&gt; Inline citations attach to specific claims. A sentence like "78% of AI Overviews cite pages outside the top 10 organic results" is easy to attach a source link to. A paragraph of context without a discrete factual claim is harder to cite inline.&lt;/p&gt;

&lt;h2&gt;
  
  
  The limitation
&lt;/h2&gt;

&lt;p&gt;The CTR data comes from 23 publishers who shared anonymized Search Console data. That is a small sample, and publishers who share data may skew toward those with better-than-average performance. The 2.8x lift is a median, not a guarantee. Individual results will vary by industry, query type, and position within the AI Overview.&lt;/p&gt;

&lt;p&gt;The format change is also still rolling out. Some queries may still show the old bottom-only format. Google does not publish which queries use which format.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to check
&lt;/h2&gt;

&lt;p&gt;If you want to see how your pages score on the signals that correlate with AI Overview citation, run a free audit on &lt;a href="https://geoready.dev" rel="noopener noreferrer"&gt;geoready.dev&lt;/a&gt;. The audit checks content structure, schema markup, published dates, named authors, and canonical URLs, all signals the WashU study found associated with AI Overview citation. The same engine is available as a CLI on &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, open source, MIT licensed.&lt;/p&gt;

&lt;p&gt;The audit tells you if your pages are structured for citation. It does not tell you if Google will cite them inline. But if your pages are missing the structural signals, inline placement is not even in play.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>datascience</category>
      <category>showdev</category>
    </item>
    <item>
      <title>ChatGPT's Reddit citations dropped 88% in six months. The 'get mentioned on Reddit' advice is already obsolete.</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Fri, 30 Oct 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/chatgpts-reddit-citations-dropped-88-in-six-months-the-get-mentioned-on-reddit-advice-is-1mg</link>
      <guid>https://dev.to/juanauriti/chatgpts-reddit-citations-dropped-88-in-six-months-the-get-mentioned-on-reddit-advice-is-1mg</guid>
      <description>&lt;p&gt;Every GEO guide published in the last 18 months says the same thing: get mentioned on Reddit because LLMs pull from it. The advice was correct in early 2025. It is now wrong for ChatGPT, and the data proving it has been public since October 12, 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number
&lt;/h2&gt;

&lt;p&gt;Ahrefs' &lt;a href="https://ahrefs.com/blog/query-fan-out-chatgpt/" rel="noopener noreferrer"&gt;citation tracking data&lt;/a&gt;, published October 12, 2026, shows ChatGPT's Reddit citations dropped 88% over six months, from March to September 2026. The data comes from their Brand Radar product, which tracked 2.4 to 3.8 million US ChatGPT answers per month across that period.&lt;/p&gt;

&lt;p&gt;Reddit is still cited by ChatGPT, but at a fraction of what it was. The trajectory is downward, and it is steep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it happened
&lt;/h2&gt;

&lt;p&gt;The Ahrefs fan-out data explains why. ChatGPT's query behavior is shifting away from forums and aggregators toward primary sources. In August and September 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Official" appeared in 13.1% of English fan-out queries, up from 10.1% in August&lt;/li&gt;
&lt;li&gt;"Price" rose 47% in relative terms (6.0% to 8.9%)&lt;/li&gt;
&lt;li&gt;"Best" stayed flat at 5.3%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ChatGPT is increasingly searching for official brand sites, pricing pages, and specifications. It is searching less for Reddit threads, listicles, and aggregator content. The &lt;code&gt;site:&lt;/code&gt; operator data confirms this: 75.9% of ChatGPT's site-specific searches target brand websites, not retailers, forums, or review sites. Reddit and Facebook together account for 1.9% of site: searches.&lt;/p&gt;

&lt;p&gt;Of the 17 publishers with OpenAI licensing deals, only Reddit appears in the top 150 most site: searched domains. ChatGPT rarely looks it up directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perplexity is the opposite
&lt;/h2&gt;

&lt;p&gt;While ChatGPT's Reddit citations dropped 88%, Perplexity still cites Reddit in roughly 20% of its answers, according to &lt;a href="https://www.evertune.ai/resources/ai-search-statistics-for-generative-engine-optimization" rel="noopener noreferrer"&gt;Evertune's data&lt;/a&gt;. Reddit accounts for about 1 in 5 Perplexity citations. Wikipedia, ChatGPT's most-cited domain, tops out at about 5% on Perplexity.&lt;/p&gt;

&lt;p&gt;The two engines are diverging. ChatGPT leans on training data and official brand sites. Perplexity leans on live web retrieval and community discussions. A Reddit strategy that is useless on ChatGPT may still work on Perplexity, and a brand-site strategy that works on ChatGPT may be less effective on Perplexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the GEO guides missed
&lt;/h2&gt;

&lt;p&gt;The "get mentioned on Reddit" advice was based on 2024 and early 2025 data, when ChatGPT was citing Reddit heavily. The advice spread because it was true at the time and because it was actionable: you can post on Reddit, you cannot easily get into an LLM's training data.&lt;/p&gt;

&lt;p&gt;But the advice treated AI search as a static system. It is not. ChatGPT's retrieval behavior changed substantially between March and September 2026. The fan-out queries shifted toward "official" and "price." The Reddit citations dropped. The model is being tuned to prefer primary sources over community discussion, and the citation data shows it happening in real time.&lt;/p&gt;

&lt;p&gt;This is the problem with tactics-based GEO advice. A tactic that works today may not work in six months because the underlying retrieval model changed. The data does not wait for the blog posts to catch up.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do instead
&lt;/h2&gt;

&lt;p&gt;Three things that are more durable than "get mentioned on Reddit":&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Be the primary source for something specific.&lt;/strong&gt; ChatGPT's fan-outs increasingly look for official documentation, pricing, and specifications. If your page is the canonical source for your own product's features, pricing, or documentation, it is more likely to be retrieved than a Reddit thread discussing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Test on each platform separately.&lt;/strong&gt; ChatGPT and Perplexity cite different sources from different retrieval mechanisms. Run your target queries on both. If you appear on Perplexity but not ChatGPT, your gap is in the training data or the brand-site retrieval path. If you appear on neither, your gap is in crawlability and content structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Monitor, do not assume.&lt;/strong&gt; The Reddit citation drop happened in six months. If you built a strategy around Reddit mentions in March 2026, it was already eroding by June. Citation patterns are volatile. The Babel42 study found only 11% of Google AI Overviews cite the same sites two days in a row. A one-shot audit tells you where you are today. It does not tell you if that changed since yesterday.&lt;/p&gt;

&lt;p&gt;If you want to check whether AI crawlers can reach your site, run a free audit on &lt;a href="https://geoready.dev" rel="noopener noreferrer"&gt;geoready.dev&lt;/a&gt;. The same engine is available as a CLI on &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, open source, MIT licensed.&lt;/p&gt;

&lt;p&gt;The audit checks if you are reachable. It does not check if you are in the training data. Nothing checks that, except asking the model. And the model's answer changes every six months.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>datascience</category>
      <category>showdev</category>
    </item>
    <item>
      <title>ChatGPT mentions 3.2x more brands than it cites. Google cites 2.4x more than it mentions. They disagree 62% of the time.</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Thu, 29 Oct 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/chatgpt-mentions-32x-more-brands-than-it-cites-google-cites-24x-more-than-it-mentions-they-3dia</link>
      <guid>https://dev.to/juanauriti/chatgpt-mentions-32x-more-brands-than-it-cites-google-cites-24x-more-than-it-mentions-they-3dia</guid>
      <description>&lt;p&gt;BrightEdge ran identical prompts across ChatGPT, Google AI Overviews, and Google AI Mode. The three platforms disagreed on which brands to recommend 62% of the time. Only 17% of queries produced the same brand recommendations across all three.&lt;/p&gt;

&lt;p&gt;If you are optimizing for "AI search" as if it is one thing, this data says it is at least three different things, and they contradict each other more often than they agree.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.brightedge.com/resources/weekly-ai-search-insights/chatgpt-vs-google-ai-62-brand-recommendation-disagreement" rel="noopener noreferrer"&gt;BrightEdge published the study&lt;/a&gt; analyzing tens of thousands of identical prompts across the three platforms using their AI Catalyst tool. The key numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;61.9% of queries get different brand recommendations&lt;/strong&gt; across platforms&lt;/li&gt;
&lt;li&gt;Only &lt;strong&gt;17% of queries result in the same brands&lt;/strong&gt; across all three&lt;/li&gt;
&lt;li&gt;Only &lt;strong&gt;33.5% of queries trigger brands from all three platforms&lt;/strong&gt; at all&lt;/li&gt;
&lt;li&gt;ChatGPT is silent on &lt;strong&gt;43.4% of queries&lt;/strong&gt; (no brand mentioned)&lt;/li&gt;
&lt;li&gt;Google AI Overviews is silent on only &lt;strong&gt;9.1%&lt;/strong&gt; (it almost always mentions something)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The citation paradox
&lt;/h2&gt;

&lt;p&gt;The most counterintuitive finding is how mentions and citations work on each platform:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Mentions per query&lt;/th&gt;
&lt;th&gt;Citations per query&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ChatGPT&lt;/td&gt;
&lt;td&gt;2.37&lt;/td&gt;
&lt;td&gt;0.73&lt;/td&gt;
&lt;td&gt;Mentions 3.2x more than cites&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google AI Overviews&lt;/td&gt;
&lt;td&gt;6.02&lt;/td&gt;
&lt;td&gt;14.30&lt;/td&gt;
&lt;td&gt;Cites 2.4x more than mentions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google AI Mode&lt;/td&gt;
&lt;td&gt;1.59&lt;/td&gt;
&lt;td&gt;9.49&lt;/td&gt;
&lt;td&gt;Cites 6x more than mentions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ChatGPT names brands 3.2 times more often than it links to them. It says "you should look at Notion" without linking to notion.com. Google AI Overviews does the opposite: it links to 14.30 sources per query but only names 6.02 brands. Google cites more pages than it recommends.&lt;/p&gt;

&lt;p&gt;This means two different things are happening. ChatGPT operates as a brand recommender that relies on training data and trust patterns. It knows what Notion is and says so, but does not always retrieve a source page. Google AI Overviews operates as a citation engine that retrieves pages and links them, but the pages it links are not always the brands it would recommend.&lt;/p&gt;

&lt;p&gt;If your strategy is "get cited by AI," you need to know which game you are playing. On ChatGPT, the game is being in the model's knowledge. On Google AI Overviews, the game is being in the retrieved source pool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the platforms agree
&lt;/h2&gt;

&lt;p&gt;The disagreement is not uniform across query types. BrightEdge broke down alignment by query intent:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Query type&lt;/th&gt;
&lt;th&gt;Same-brand agreement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Compare" queries&lt;/td&gt;
&lt;td&gt;80%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Buy" queries&lt;/td&gt;
&lt;td&gt;62%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Where" queries&lt;/td&gt;
&lt;td&gt;38%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Best" queries&lt;/td&gt;
&lt;td&gt;23%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Comparison queries produce the most agreement. When someone asks "X vs Y," all three platforms tend to name the same competitors. "Best" queries produce the least agreement. When someone asks "best tool for X," the three platforms recommend different brands 77% of the time.&lt;/p&gt;

&lt;p&gt;This makes sense. Comparison queries have a finite answer set (the two things being compared). "Best" queries are open-ended, and each platform's ranking model fills the blank differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Industry breakdown
&lt;/h2&gt;

&lt;p&gt;Disagreement rates vary by industry:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Industry&lt;/th&gt;
&lt;th&gt;Disagreement rate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Healthcare&lt;/td&gt;
&lt;td&gt;68.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Education&lt;/td&gt;
&lt;td&gt;62.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B2B Tech&lt;/td&gt;
&lt;td&gt;61.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finance&lt;/td&gt;
&lt;td&gt;57.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E-Commerce&lt;/td&gt;
&lt;td&gt;57.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Healthcare has the highest disagreement. E-Commerce the lowest. If you are in health or education, assuming your visibility on one platform transfers to another is wrong 60-68% of the time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for your audit
&lt;/h2&gt;

&lt;p&gt;If you run a single audit and call it "AI visibility," you are measuring one surface. The calibration study I published last week tested one engine (Perplexity) and found no relationship between the GEO score and citation. That result might be different on Google AI Overviews, where citation behavior is structurally different.&lt;/p&gt;

&lt;p&gt;The practical implication: test your visibility on each platform separately. Ask ChatGPT "what are the best tools for [your category]" and see if you are mentioned. Ask Google the same thing and check the AI Overview sources. Ask Perplexity and look at the citations. They will give you different answers 62% of the time, and that 62% is where your gap lives.&lt;/p&gt;

&lt;p&gt;If you want to check whether AI crawlers can even reach your site, run a free audit on &lt;a href="https://geoready.dev" rel="noopener noreferrer"&gt;geoready.dev&lt;/a&gt;. It checks 27 AI crawlers and tells you which ones can access your content. The same engine is available as a CLI on &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, open source, MIT licensed.&lt;/p&gt;

&lt;p&gt;The audit tells you if you are reachable. It does not tell you if you are recommended. These are three different platforms, and being reachable on all three does not mean being recommended on any of them.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>datascience</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I pre-registered a study, got a null result, and published it anyway. Here's why</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Wed, 28 Oct 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/i-pre-registered-a-study-got-a-null-result-and-published-it-anyway-heres-why-2kn5</link>
      <guid>https://dev.to/juanauriti/i-pre-registered-a-study-got-a-null-result-and-published-it-anyway-heres-why-2kn5</guid>
      <description>&lt;p&gt;Last week I published a calibration study showing that my tool's GEO score does not predict whether Perplexity cites a page. The odds ratio was 0.9625, p = 0.7172. Nothing.&lt;/p&gt;

&lt;p&gt;The study was pre-registered. I wrote the analysis plan before collecting the data, committed its hash to the repo, and ran the exact analysis I said I would run. No cherry-picking, no p-hacking, no "let me try a different model and see if it becomes significant."&lt;/p&gt;

&lt;p&gt;This is how that worked and why I think every tool that sells a score should do the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  What pre-registration means
&lt;/h2&gt;

&lt;p&gt;Pre-registration is a commitment device. You write down what you are going to measure, how you are going to measure it, and what counts as a result, before you have any data. Then you collect the data and run the analysis you said you would. If the result is null, you publish a null.&lt;/p&gt;

&lt;p&gt;In my case, the pre-registration was a markdown file in the repo. It specified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The sample: pages from sites that publish a sitemap, reachable, English-language&lt;/li&gt;
&lt;li&gt;The outcome: whether the page's domain appeared in Perplexity Sonar's sources for two question templates&lt;/li&gt;
&lt;li&gt;The primary analysis: logistic regression of domain citation on score/10, log rank, and log words&lt;/li&gt;
&lt;li&gt;The secondary analyses: each scoring category individually, with Holm correction&lt;/li&gt;
&lt;li&gt;The sensitivity analysis: excluding pages on sites that block AI bots&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The file's SHA-256 hash is &lt;code&gt;441fcbb422964fdf2bf2b63eb02181ccbea9e7c5590d3e770399d567cd373ff8&lt;/code&gt;. You can verify it yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sha256sum &lt;/span&gt;PREREGISTRATION.md
&lt;span class="c"&gt;# should output: 441fcbb422964fdf2bf2b63eb02181ccbea9e7c5590d3e770399d567cd373ff8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hash proves the plan existed before the data. I committed it to the repo on the same day I started collecting data. The analysis results were generated on October 17, 2026, on the exact rank values, to four decimal places.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I did not pivot
&lt;/h2&gt;

&lt;p&gt;When the primary result came back null, I had options. I could have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tried different outcome variables (page citation instead of domain citation)&lt;/li&gt;
&lt;li&gt;Tried different regression specifications&lt;/li&gt;
&lt;li&gt;Looked for subgroups where the score did predict something&lt;/li&gt;
&lt;li&gt;Run it on a different engine and hoped for a better result&lt;/li&gt;
&lt;li&gt;Not published it at all&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I did run the secondary analyses, because they were pre-registered. None of them were significant either. Every Holm-corrected p-value was 1.0000.&lt;/p&gt;

&lt;p&gt;I did run the sensitivity analysis, because it was pre-registered. Excluding blocked pages did not change anything (OR 1.0408, p = 0.7288).&lt;/p&gt;

&lt;p&gt;The page-level analyses (whether the exact page, not just the domain, was cited) were also pre-registered as secondary outcomes. Those odds ratios were above 1.0 (1.0568 and 1.0478) but still not significant (p = 0.6434 and p = 0.6933).&lt;/p&gt;

&lt;p&gt;None of these were the primary outcome. The primary outcome was domain citation on template A. It was null. That is the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why publish a null
&lt;/h2&gt;

&lt;p&gt;Three reasons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The tool is open source.&lt;/strong&gt; People can check the code. If I published a study that only showed positive results, someone would eventually run their own and find nothing. Better to publish the null myself and explain what it means than have someone else discover it and conclude I was hiding it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Null results are informative.&lt;/strong&gt; The null tells you that a 0-to-100 score based on technical readability does not predict citation. That is useful. It means the score measures what it measures (citability) and not what it does not measure (citation). Users of the tool should know that distinction. Agencies selling GEO services based on readability scores should know it too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Every other tool should do this.&lt;/strong&gt; There are at least 15 paid AI visibility tools on the market. Peec AI ($95/mo), Otterly ($29/mo), Scrunch ($250/mo), Profound (enterprise), Semrush AI Visibility ($99/mo), AthenaHQ ($295/mo), LLM Pulse (EUR 49/mo), and others. None of them have published a calibration study. None of them have tested whether their scores predict citations. They sell visibility scores and share-of-voice metrics without showing the validation data.&lt;/p&gt;

&lt;p&gt;I am not saying their scores are wrong. I am saying I do not know if they are right, because they have not shown the work. The work is: pre-register the analysis, collect the data, publish the result, whatever it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned from the process
&lt;/h2&gt;

&lt;p&gt;The pre-registration forced me to think through the analysis before I had data. That is harder than it sounds. I had to decide what the primary outcome would be, what controls to use, what counts as a secondary analysis, and what sensitivity checks to run. All before seeing a single citation.&lt;/p&gt;

&lt;p&gt;It also made the writing easier. When the result came back null, I did not have to decide how to frame it. The analysis was pre-committed. I ran it, reported it, and wrote up what it said. No decisions about what to include or exclude. The pre-registration made those decisions for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The limitation I acknowledge
&lt;/h2&gt;

&lt;p&gt;The study has one engine (Perplexity Sonar), one date (October 17, 2026), and one model version. The question is built from each page's own headline, so it tests whether a page is cited when the question is literally about that page's topic. That is a generous test. A more realistic test would use generic queries about the topic, not the page's own headline.&lt;/p&gt;

&lt;p&gt;The sample also favours reachable, English-language sites that publish a sitemap. That is not the full web. It is the part of the web that AI crawlers can easily find.&lt;/p&gt;

&lt;p&gt;I plan to run the study again with ChatGPT and Google AI Overviews, and with generic queries instead of headline-based ones. If the score predicts citation in those settings, I will publish that. If it does not, I will publish that too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The files
&lt;/h2&gt;

&lt;p&gt;Everything is at &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill/tree/main/research/calibration-2026-10" rel="noopener noreferrer"&gt;github.com/Auriti-Labs/geo-optimizer-skill/tree/main/research/calibration-2026-10&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PREREGISTRATION.md&lt;/code&gt;: the analysis plan, with the SHA-256 to verify it existed before the data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;results.csv&lt;/code&gt;: 341 rows, one per page, no domain or headline, shuffled&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;analysis-results.txt&lt;/code&gt;: the output of the pre-registered analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can reproduce the primary result from the CSV. If you find something I missed, open an issue.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>datascience</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>ChatGPT searched the web only 14.4% of the time across 66.6 million responses</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Wed, 28 Oct 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/chatgpt-searched-the-web-only-144-of-the-time-across-666-million-responses-2p6l</link>
      <guid>https://dev.to/juanauriti/chatgpt-searched-the-web-only-144-of-the-time-across-666-million-responses-2p6l</guid>
      <description>&lt;p&gt;Ahrefs analyzed 66.6 million free, logged-out ChatGPT responses from August and September 2026. Only 14.4% triggered a web search. The other 85.6% were answered from training data alone.&lt;/p&gt;

&lt;p&gt;If your content strategy assumes ChatGPT will crawl your site and cite you in real time, this number should change how you think about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The study
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ahrefs.com/blog/query-fan-out-chatgpt/" rel="noopener noreferrer"&gt;Ahrefs published the analysis on October 12, 2026&lt;/a&gt;. They collected 66.6 million responses from free, logged-out sessions on the GPT-5.6 Luna model, across all countries, along with the 15 million fan-out queries those responses produced. A separate citation dataset from their Brand Radar product tracked which domains ChatGPT cited in US answers from March to September 2026, covering 2.4 to 3.8 million answers per month.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the numbers say
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;14.4% of responses involved a web search.&lt;/strong&gt; Six in seven prompts were answered without looking anything up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When ChatGPT did search, it ran about 1.6 fan-out queries per searching response.&lt;/strong&gt; Not a broad crawl. A targeted lookup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6.8% of fan-out queries used the &lt;code&gt;site:&lt;/code&gt; operator to search a single website.&lt;/strong&gt; That is 6.8% of 14.4%, so about 1% of all responses involved a site-specific search.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;75.9% of those site-specific searches targeted brand websites&lt;/strong&gt;, not retailers, forums, or review sites. ChatGPT looks for apple.com, ikea.com, the official source. It does not look for your blog post about apple.com.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The shift toward primary sources
&lt;/h2&gt;

&lt;p&gt;The words inside the fan-out queries are changing fast. Between August and September 2026:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Word in fan-out query&lt;/th&gt;
&lt;th&gt;August&lt;/th&gt;
&lt;th&gt;September&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2026&lt;/td&gt;
&lt;td&gt;17.6%&lt;/td&gt;
&lt;td&gt;22.9%&lt;/td&gt;
&lt;td&gt;+5.2 pts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;official&lt;/td&gt;
&lt;td&gt;10.1%&lt;/td&gt;
&lt;td&gt;13.1%&lt;/td&gt;
&lt;td&gt;+3.0 pts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;price&lt;/td&gt;
&lt;td&gt;6.0%&lt;/td&gt;
&lt;td&gt;8.9%&lt;/td&gt;
&lt;td&gt;+2.8 pts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;india&lt;/td&gt;
&lt;td&gt;3.0%&lt;/td&gt;
&lt;td&gt;6.2%&lt;/td&gt;
&lt;td&gt;+3.2 pts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;best&lt;/td&gt;
&lt;td&gt;5.0%&lt;/td&gt;
&lt;td&gt;5.3%&lt;/td&gt;
&lt;td&gt;+0.3 pts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;"Official" grew by 3 percentage points in one month. "Price" grew by 47% in relative terms. "Best" barely moved. ChatGPT is moving away from listicle-style queries ("best CRM for startups") toward primary-source queries ("apple.com official pricing 2026").&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened to Reddit
&lt;/h2&gt;

&lt;p&gt;ChatGPT's Reddit citations dropped 88% over six months (March to September 2026), according to Ahrefs' citation data. The common advice in the GEO community is "get mentioned on Reddit because LLMs pull from it." That advice is already outdated for ChatGPT. Reddit is still cited, but at a fraction of what it was.&lt;/p&gt;

&lt;p&gt;Perplexity is a different story. Reddit accounts for about 1 in 5 Perplexity citations, roughly 20%, according to Evertune's data. The two engines are diverging. What works on one does not work on the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for your content
&lt;/h2&gt;

&lt;p&gt;If 85.6% of ChatGPT responses come from training data, the content that matters is content that was already in the training set. If your site was crawlable and well-linked when the model was trained, you are in there. If you launched after the training cutoff, or if you were blocked by robots.txt during training, live retrieval is your only way in, and it only fires 14.4% of the time.&lt;/p&gt;

&lt;p&gt;Three things follow from this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Being crawlable during training matters more than being crawlable now.&lt;/strong&gt; If GPTBot crawled your site before the training cutoff, your content is in the model's parametric memory. No live search needed. If it did not, you are fighting for a spot in the 14.4%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Primary-source content wins over summaries.&lt;/strong&gt; ChatGPT's fan-outs increasingly look for "official," "price," and specific brand domains. If your page is the primary source for something (official documentation, pricing, specs), it is more likely to be retrieved than a blog post summarizing someone else's data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Multi-platform strategy is not optional.&lt;/strong&gt; ChatGPT and Perplexity cite different sources, at different rates, from different retrieval mechanisms. ChatGPT leans on training data and brand sites. Perplexity leans on live web and Reddit. Google AI Overviews lean on YouTube and their own index. A strategy that works on one engine may be invisible on another.&lt;/p&gt;

&lt;h2&gt;
  
  
  The limitation
&lt;/h2&gt;

&lt;p&gt;The Ahrefs data covers free, logged-out ChatGPT. Logged-in users on paid plans may trigger more web searches, since OpenAI can afford more API calls per response for paying users. The 14.4% figure is a floor, not a ceiling, for how often ChatGPT searches. But the free tier is where most users are, so it is the number that matters for visibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to check
&lt;/h2&gt;

&lt;p&gt;If you want to know whether your site is reachable by AI crawlers, run a free audit on &lt;a href="https://geoready.dev" rel="noopener noreferrer"&gt;geoready.dev&lt;/a&gt;. It checks 27 AI crawlers, robots.txt access, and whether your content is in the HTML or hidden behind JavaScript. The same engine is available as a CLI on &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, open source, MIT licensed.&lt;/p&gt;

&lt;p&gt;An audit tells you if AI crawlers can read your page. It does not tell you if you are in the training data. Nothing can tell you that, except asking the model itself.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>datascience</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I broke my own tool's scoring model and rebuilt it. Here's what changed in rubric v2</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Tue, 27 Oct 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/i-broke-my-own-tools-scoring-model-and-rebuilt-it-heres-what-changed-in-rubric-v2-1129</link>
      <guid>https://dev.to/juanauriti/i-broke-my-own-tools-scoring-model-and-rebuilt-it-heres-what-changed-in-rubric-v2-1129</guid>
      <description>&lt;p&gt;When I published the calibration study showing the GEO score does not predict citations, one question came up immediately: if the score does not predict citations, why did you just rebuild it?&lt;/p&gt;

&lt;p&gt;The answer is that the score was never meant to predict citations. It measures citability, whether an AI crawler can reach, parse, and understand a page. The rebuild makes it better at that, and more honest about what it does not measure. Here is what changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old rubric (v1)
&lt;/h2&gt;

&lt;p&gt;The original rubric had 9 categories adding up to 100 points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;robots.txt and AI crawler access (10 pts)&lt;/li&gt;
&lt;li&gt;llms.txt presence and validity (18 pts)&lt;/li&gt;
&lt;li&gt;schema markup and structured data (10 pts)&lt;/li&gt;
&lt;li&gt;metadata and Open Graph (8 pts)&lt;/li&gt;
&lt;li&gt;content structure and readability (15 pts)&lt;/li&gt;
&lt;li&gt;citation signals (quotable passages, statistics, quotes) (12 pts)&lt;/li&gt;
&lt;li&gt;brand entity clarity (8 pts)&lt;/li&gt;
&lt;li&gt;AI discovery signals (6 pts)&lt;/li&gt;
&lt;li&gt;negative penalty for blocking, JS-only content, injection surfaces (13 pts deduction)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem was the weights. llms.txt carried 18 points, almost a fifth of the total. But Google's own guide, published in May 2026, says llms.txt does nothing for AI Overviews. The &lt;a href="https://babel42.io/research/ai-overviews-2026" rel="noopener noreferrer"&gt;Babel42 study&lt;/a&gt; confirmed it: only 0.2% of sites have a valid llms.txt file, and AI Overviews cite those sites at the same rate as everyone else. The signal was over-weighted relative to its actual importance.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed in v2
&lt;/h2&gt;

&lt;p&gt;Rubric v2 shipped in v4.19.0 (October 2026). Three structural changes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. llms.txt dropped from 18 to 6 points.&lt;/strong&gt; The file is still checked. Some AI crawlers do read it, and 0.2% of sites use it. But it is not a top-3 signal for citability. Six points reflects that: present and valid gets you something, missing does not tank your score.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. AI discovery dropped from 6 to 3 points.&lt;/strong&gt; This category checked things like RSS feeds and sitemap references to AI-specific content. Useful but minor. Three points is honest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. New category: Google AI readiness (20 points).&lt;/strong&gt; This is the biggest addition. It checks 8 signals specific to how Google's AI Overviews select and display sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;G-INDEX: is the page indexed and canonicalized correctly&lt;/li&gt;
&lt;li&gt;G-SNIPPET: does the page have a meta description and structured snippets&lt;/li&gt;
&lt;li&gt;G-CANONICAL: is there a canonical URL and does it match&lt;/li&gt;
&lt;li&gt;G-DATES: are there published and updated dates&lt;/li&gt;
&lt;li&gt;G-BYLINE: is there a named author&lt;/li&gt;
&lt;li&gt;G-LINKS: are internal links present and crawlable&lt;/li&gt;
&lt;li&gt;G-VIEWPORT: is the viewport meta tag set (mobile readiness)&lt;/li&gt;
&lt;li&gt;G-SITEMAP: is the page in a sitemap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the signals the &lt;a href="https://arxiv.org/abs/2605.14021" rel="noopener noreferrer"&gt;WashU study&lt;/a&gt; (October 2026, 55,393 queries) found correlate with AI Overview citation: credible sources with clear authorship, dates, and canonical URLs. The category does not guarantee citation. It checks whether the technical prerequisites are in place.&lt;/p&gt;

&lt;h2&gt;
  
  
  The full v2 category list
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;v1 points&lt;/th&gt;
&lt;th&gt;v2 points&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;robots.txt access&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;llms.txt&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;-12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;schema markup&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;metadata&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;content structure&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;citation signals&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;brand entity&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI discovery&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;-3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google AI readiness&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;new&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;negative penalty&lt;/td&gt;
&lt;td&gt;-13&lt;/td&gt;
&lt;td&gt;-13&lt;/td&gt;
&lt;td&gt;unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Total: still 100 points. The 15 points removed from llms.txt and AI discovery went into the new Google AI readiness category.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can still use v1
&lt;/h2&gt;

&lt;p&gt;If you have historical data on v1 scores, you do not need to re-audit everything. The CLI supports &lt;code&gt;--score-version 1&lt;/code&gt; for legacy comparisons. Drift and diff comparisons are gated to the same score version, so you cannot accidentally compare a v1 score with a v2 score and get a meaningless delta.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the calibration study changed
&lt;/h2&gt;

&lt;p&gt;The calibration study did not directly inform v2. The rubric was already designed and shipped in v4.19.0 (October 9). The study ran on October 17. But the study confirms the design philosophy: the score measures citability, not citation. The 9 categories check whether a page is reachable and parseable. They do not claim to predict whether it will be cited.&lt;/p&gt;

&lt;p&gt;The null result is actually useful for the rubric. It means I should not inflate the score's claims. A 90/100 does not mean "you will be cited by ChatGPT." It means "your page is technically reachable and parseable by AI crawlers." That is a narrower, more honest claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is next
&lt;/h2&gt;

&lt;p&gt;The rubric will keep evolving. The Google AI readiness category is new and its 20-point weight is a starting estimate, not a final answer. As more calibration data comes in (I plan to run the study again with ChatGPT and Google AI Overviews, not just Perplexity), the weights may shift again.&lt;/p&gt;

&lt;p&gt;If you want to see the full scoring rubric, it is in &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill/blob/main/SCORING_RUBRIC.md" rel="noopener noreferrer"&gt;SCORING_RUBRIC.md&lt;/a&gt; on GitHub. The tool is free and open source. You can also run a &lt;a href="https://geoready.dev" rel="noopener noreferrer"&gt;free web audit on geoready.dev&lt;/a&gt; without installing anything.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I built a tool that checks whether AI cites your site. It had never cited mine</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Tue, 27 Oct 2026 09:20:37 +0000</pubDate>
      <link>https://dev.to/juanauriti/i-built-a-tool-that-checks-whether-ai-cites-your-site-it-had-never-cited-mine-5hbh</link>
      <guid>https://dev.to/juanauriti/i-built-a-tool-that-checks-whether-ai-cites-your-site-it-had-never-cited-mine-5hbh</guid>
      <description>&lt;p&gt;I maintain &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill" rel="noopener noreferrer"&gt;GEO Optimizer&lt;/a&gt;, an open-source CLI that audits whether ChatGPT, Perplexity, Claude and Google AI Overviews can crawl, understand and cite a website. The hosted version runs at &lt;a href="https://geoready.dev" rel="noopener noreferrer"&gt;geoready.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I pointed it at itself, the way a customer would: ask the engines the questions a buyer asks, and count who gets cited.&lt;/p&gt;

&lt;h2&gt;
  
  
  The measurement
&lt;/h2&gt;

&lt;p&gt;108 calls to Claude with web search on, across Haiku and Sonnet, three runs per prompt. Prompts like &lt;em&gt;"best GEO optimization tool"&lt;/em&gt; and &lt;em&gt;"What are the best GEO and AI visibility optimization tools?"&lt;/em&gt;. The same prompts had already gone through Perplexity.&lt;/p&gt;

&lt;p&gt;geoready.dev: &lt;strong&gt;0 citations, 0 mentions.&lt;/strong&gt; On both engines.&lt;/p&gt;

&lt;p&gt;Otterly, Peec and Profound came up again and again. Fair enough, they're good products. But zero for a tool whose whole job is this number deserved a postmortem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it wasn't
&lt;/h2&gt;

&lt;p&gt;The site itself passed. robots.txt allows every Anthropic, OpenAI and Perplexity crawler. llms.txt and llms-full.txt both return 200. The JSON-LD declares a &lt;code&gt;Brand&lt;/code&gt; with &lt;code&gt;alternateName&lt;/code&gt; and &lt;code&gt;sameAs&lt;/code&gt; pointing to the GitHub repo and PyPI.&lt;/p&gt;

&lt;p&gt;None of it mattered, because the engines never got to the site.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it was
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Retrieval.&lt;/strong&gt; In 108 answers, geoready.dev never appeared among the search results Claude &lt;em&gt;read&lt;/em&gt;, let alone the ones it cited. On Google it sits around positions 25–50 for "geo tools". The engines read roughly the first page. A page that isn't in the retrieved set can't be cited, however good its schema is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9zoehlhpddc0ix642sub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9zoehlhpddc0ix642sub.png" alt="A giant funnel of light made of glowing search-result cards, wide at the top and narrowing to a small bright answer panel at the bottom, while one lone card sits far to the side, lost in dark fog." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The answer is someone else's listicle.&lt;/strong&gt; The citations went to third-party "best GEO tools" articles. In my own tally of the 18 most cited pages, Otterly appears in 14 and my tool in none.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The awesome lists.&lt;/strong&gt; On 26 October 2026 I checked eight GitHub lists on GEO, llms.txt and AI SEO. Otterly is in three of them. My repo, at 1.1k stars, is in none. I had submitted it to two of them and left it there: one pull request has been open since March, the other since last week, neither merged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. The name is taken, four times.&lt;/strong&gt; At least four other GEO products are called GeoReady, on four other domains. Even when an engine saw "GeoReady", it had no way to know which one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The two halves of the brand never met.&lt;/strong&gt; This one surprised me most. "GEO Optimizer" &lt;em&gt;was&lt;/em&gt; being named, in 10 answers out of 108, and the repo was cited 4 times. But the repo description, the PyPI summary and the README never said "GeoReady". And in this series I kept writing "the CLI I maintain" without naming it: one link to geoready.dev, in one post. The engines met two unrelated entities and credited neither.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu5r6p8zx2tgws91fiykk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu5r6p8zx2tgws91fiykk.png" alt="Two doors of light, one teal and one amber, standing apart in a dark misty hall, with thin glowing threads reaching from each door but stopping just short of touching." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Bing.&lt;/strong&gt; I had never set up Bing Webmaster Tools for the site. Copilot retrieves from Bing, and so do other AI search products, so a site Bing doesn't index is missing from their results.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fixes
&lt;/h2&gt;

&lt;p&gt;In the order I'm doing them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The repo description now says &lt;em&gt;"GEO Optimizer, the open-source engine behind GeoReady (geoready.dev)"&lt;/em&gt;. The README says it too, since the change was merged on 26 October. The PyPI summary changed with release 4.19.8, published the same day. This post exists partly for the same reason.&lt;/li&gt;
&lt;li&gt;Pull requests to five awesome lists (GEO, llms.txt and AI SEO), one line each, in each list's own format. Two were already open, three are new. None is merged yet.&lt;/li&gt;
&lt;li&gt;Outreach to the editorial listicles that the engines actually cite. On 27 October I sent three short suggestions to the authors of "best GEO tools" guides. No replies yet. I'm skipping the competitors' own listicles: they're not going to list me, and that's fine.&lt;/li&gt;
&lt;li&gt;Never writing "GeoReady" on its own outside the site. Always "GeoReady (geoready.dev)", or next to the repo.&lt;/li&gt;
&lt;li&gt;Bing Webmaster Tools: the site is verified and the sitemap has been submitted. IndexNow is still to do.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The lesson
&lt;/h2&gt;

&lt;p&gt;On-site GEO is the floor. Everything I audit for (crawler access, schema, llms.txt, passage structure) decides whether you &lt;em&gt;can&lt;/em&gt; be cited once you're retrieved. Whether you get retrieved is decided mostly by other people's pages: listicles, lists, forums, posts that name you next to the category.&lt;/p&gt;

&lt;p&gt;The audit I'd run on a client now starts with one question: which pages do the engines read for your category, and are you on them?&lt;/p&gt;

&lt;p&gt;I'll rerun the same 108 calls in a few weeks and post the numbers, zero or not.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;GEO Optimizer is MIT-licensed: &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill" rel="noopener noreferrer"&gt;github.com/Auriti-Labs/geo-optimizer-skill&lt;/a&gt;. The hosted version, GeoReady (geoready.dev), is at &lt;a href="https://geoready.dev" rel="noopener noreferrer"&gt;geoready.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Method note: the 108 calls, the 10 mentions of GEO Optimizer, the 4 repo citations, the 18-page tally and the Google positions are my own measurements, written up on 26 October 2026. The count of eight lists was re-checked on that date.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>product</category>
    </item>
    <item>
      <title>My calibration study found the GEO score doesn't predict AI citations. Here's the data</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Tue, 27 Oct 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/my-calibration-study-found-the-geo-score-doesnt-predict-ai-citations-heres-the-data-56ep</link>
      <guid>https://dev.to/juanauriti/my-calibration-study-found-the-geo-score-doesnt-predict-ai-citations-heres-the-data-56ep</guid>
      <description>&lt;p&gt;I built a tool that scores websites 0 to 100 on how visible they are to AI answer engines. Then I ran a study to check whether the score predicts anything real. It does not.&lt;/p&gt;

&lt;p&gt;The result: an odds ratio of 0.9625 with a p-value of 0.7172. No significant relationship between the GEO score and whether Perplexity cites a page. I pre-registered the analysis plan before running it, and I am publishing the data anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I tested
&lt;/h2&gt;

&lt;p&gt;I took 341 pages from sites that publish a sitemap, ran a GEO audit on each one (rubric v2, GEO Optimizer 4.19.3), and then asked Perplexity Sonar two questions built from each page's own headline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Template A: "What are the most reliable sources on: [headline]"&lt;/li&gt;
&lt;li&gt;Template B: "Explain this topic and cite your sources: [headline]"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I recorded whether the page's domain appeared among the sources Perplexity returned. Then I ran a logistic regression of citation on score, controlling for site popularity (Tranco rank) and page length (word count).&lt;/p&gt;

&lt;p&gt;The base rate was 42.23% for domain citation on template A and 44.57% on template B. So Perplexity cited the domain behind a page about 42% of the time when asked about that page's own topic. That is the baseline the score had to beat.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;The primary analysis was logistic regression of domain citation (template A) on score divided by 10, log rank, and log words.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Odds ratio per 10 score points: 0.9625 (95% CI 0.7827 to 1.1836)&lt;/li&gt;
&lt;li&gt;p-value: 0.7172&lt;/li&gt;
&lt;li&gt;n: 341&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The odds ratio is below 1.0, meaning higher scores were slightly less likely to be cited, but the confidence interval crosses 1.0 comfortably. The effect is indistinguishable from noise.&lt;/p&gt;

&lt;p&gt;The descriptive statistic tells the same story. The mean score of cited pages was 65.5. The mean score of not-cited pages was 65.5. Identical to one decimal place.&lt;/p&gt;

&lt;h2&gt;
  
  
  I tested every category too
&lt;/h2&gt;

&lt;p&gt;The audit has 9 scoring categories: robots.txt access, llms.txt, schema markup, metadata, content structure, citation signals, brand entity, AI discovery, and Google AI readiness. I ran each one individually against citation, with the same controls and a Holm correction for multiple testing.&lt;/p&gt;

&lt;p&gt;None of them were significant. Every single Holm-corrected p-value was 1.0000. The closest was the Google AI readiness category (p = 0.1220 before correction, OR = 0.8345), which trends in the wrong direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The sensitivity check
&lt;/h2&gt;

&lt;p&gt;About 26% of the pages in the sample were on sites that block at least one AI bot in robots.txt. I re-ran the primary analysis excluding those pages, leaving 253.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Odds ratio per 10 score points: 1.0408 (95% CI 0.8302 to 1.3048)&lt;/li&gt;
&lt;li&gt;p-value: 0.7288&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Still nothing. The odds ratio flipped above 1.0 but the confidence interval is wide and the p-value is unchanged.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means
&lt;/h2&gt;

&lt;p&gt;The GEO score measures whether a page is reachable, parseable, and quotable by an AI crawler. It checks robots.txt access, structured data, content structure, metadata, and AI-specific signals like llms.txt. It does a good job of that. The score correctly identifies pages that AI crawlers can read.&lt;/p&gt;

&lt;p&gt;But being readable is not the same as being cited. Perplexity's source selection depends on factors the audit does not measure: domain authority, topical authority, third-party mentions, and whatever Perplexity's ranking model does internally. A page with a perfect GEO score and no external authority will not be cited. A page with a terrible GEO score but massive domain authority might be cited anyway, if the crawler can get past the robots.txt.&lt;/p&gt;

&lt;p&gt;This is the gap between citability and citation. The first is a prerequisite. The second is an outcome that depends on more than the page itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I published a null result
&lt;/h2&gt;

&lt;p&gt;I could have not run this study. I could have run it and not published it. Most AI visibility tools have never published a calibration study, and I suspect some of them would not survive one.&lt;/p&gt;

&lt;p&gt;I published it because the alternative is worse. If I sell a score and do not test whether it predicts anything, I am doing the same thing as the agencies selling GEO tactics that the data does not support. The whole point of building this tool was to move past "trust me" and toward "check the data." That has to apply to the tool itself.&lt;/p&gt;

&lt;p&gt;The pre-registration is at &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill/tree/main/research/calibration-2026-10" rel="noopener noreferrer"&gt;github.com/Auriti-Labs/geo-optimizer-skill/tree/main/research/calibration-2026-10&lt;/a&gt;. Its SHA-256 is &lt;code&gt;441fcbb422964fdf2bf2b63eb02181ccbea9e7c5590d3e770399d567cd373ff8&lt;/code&gt;. The results CSV has 341 rows with no domain, address, or headline. You can reproduce the primary result from the published data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am doing about it
&lt;/h2&gt;

&lt;p&gt;The score still measures something useful: whether AI crawlers can reach and understand your page. That is a necessary condition for being cited. It is not a sufficient one.&lt;/p&gt;

&lt;p&gt;The problem is that a one-shot audit tells you where you are today. It does not tell you whether you are cited, and it does not tell you whether that changes. Perplexity cited the same domain about 42% of the time in this study, but other research (the &lt;a href="https://babel42.io/research/ai-overviews-2026" rel="noopener noreferrer"&gt;Babel42 AI Overviews study&lt;/a&gt;, October 2026) found that only 11% of Google AI Overviews cited the same sites two days in a row. Citation is volatile. An audit is a snapshot.&lt;/p&gt;

&lt;p&gt;That is why I am building the monitoring layer. The audit tells you if your page is readable. The monitor tells you if it is being cited, and whether that changed since yesterday. The first is a checkbox. The second is the metric that matters.&lt;/p&gt;

&lt;p&gt;If you want to run the audit on your own site, it is free and open source at &lt;a href="https://github.com/Auriti-Labs/geo-optimizer-skill" rel="noopener noreferrer"&gt;github.com/Auriti-Labs/geo-optimizer-skill&lt;/a&gt;. You can also paste a URL into the &lt;a href="https://geoready.dev" rel="noopener noreferrer"&gt;free web audit on geoready.dev&lt;/a&gt; without installing anything. Same engine, no signup.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>datascience</category>
      <category>showdev</category>
    </item>
    <item>
      <title>My VS Code setup went from 47 extensions to 6. My productivity went up.</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Mon, 26 Oct 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/my-vs-code-setup-went-from-47-extensions-to-6-my-productivity-went-up-568n</link>
      <guid>https://dev.to/juanauriti/my-vs-code-setup-went-from-47-extensions-to-6-my-productivity-went-up-568n</guid>
      <description>&lt;p&gt;I counted my VS Code extensions. There were 47. My editor took 8 seconds to start, lagged when I typed, and crashed once a week. I disabled 41 of them and kept 6. Here is what happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Extension creep is gradual. You install a formatter, then a linter, then a theme, then a snippet pack, then a language support extension for a framework you tried once and never used again. Each one seems small. Each one adds startup time, memory usage, and editor complexity.&lt;/p&gt;

&lt;p&gt;My 47 extensions included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 formatters (Prettier, ESLint, Stylelint, Beautify, Rustfmt)&lt;/li&gt;
&lt;li&gt;4 language packs (Python, Go, Rust, Java, only Python was active)&lt;/li&gt;
&lt;li&gt;3 themes (one in use, two installed "to try later")&lt;/li&gt;
&lt;li&gt;6 snippet packs (React, Vue, Python, Docker, Git, and a generic HTML one)&lt;/li&gt;
&lt;li&gt;4 Git extensions (GitLens, Git Graph, GitHub Pull Requests, Git History)&lt;/li&gt;
&lt;li&gt;3 AI extensions (GitHub Copilot, Codeium, Tabnine, all disabled in favor of Cursor)&lt;/li&gt;
&lt;li&gt;22 others (Docker, YAML, TOML, markdown preview, CSV viewer, path intellisense, import cost, indent rainbow, bracket pair colorizer, and more)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of these I had installed once and forgotten about. They were running on every startup, consuming memory, registering commands, and contributing to the status bar.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I kept
&lt;/h2&gt;

&lt;p&gt;I went through each extension and asked: "Have I used this in the last week?" If the answer was no, I disabled it. Here is what survived:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Prettier.&lt;/strong&gt; Code formatting. I use it on every file. Non-negotiable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. ESLint.&lt;/strong&gt; Linting. Same as Prettier, I use it constantly. The two work together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. GitLens.&lt;/strong&gt; I use the blame and diff features daily. The rest of GitLens (code lens, file history, commit search) I could live without, but the blame view alone justifies the extension.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Astro.&lt;/strong&gt; Language support for Astro, which is my primary framework. Without it, &lt;code&gt;.astro&lt;/code&gt; files are unstyled HTML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Tailwind CSS IntelliSense.&lt;/strong&gt; Autocomplete for Tailwind classes. I write Tailwind every day. Without this, I am guessing at class names.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Error Lens.&lt;/strong&gt; Shows errors and warnings inline instead of requiring a hover. It is a small UX improvement that saves me hundreds of micro-interactions per day.&lt;/p&gt;

&lt;p&gt;That is it. Six extensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Startup time: 8 seconds to 1.5 seconds.&lt;/strong&gt; The difference is immediately noticeable. I open and close the editor many times a day, and the 6.5 second saving compounds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory usage: 1.2 GB to 380 MB.&lt;/strong&gt; VS Code went from being the heaviest application on my machine to being lighter than my browser. The lag when typing in large files disappeared.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crashes: once a week to zero in six weeks.&lt;/strong&gt; I cannot prove causation, but the correlation is strong. Extension conflicts are a known cause of VS Code instability, and removing 41 of them eliminated a lot of potential conflicts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Productivity: up, measurably.&lt;/strong&gt; I was spending time managing extensions: updating them, configuring them, disabling ones that conflicted, and debugging issues caused by interaction between them. That time is gone. The editor does what I need and gets out of the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned about extension creep
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Extensions are not free.&lt;/strong&gt; Each one adds to startup time, memory footprint, and editor complexity. The cost is invisible until you remove them and feel the difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You do not use most of your extensions.&lt;/strong&gt; 41 out of 47 had not been used in the last week. Some had not been used in months. They were running anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The best extensions are the ones you forget you have.&lt;/strong&gt; Prettier, ESLint, Error Lens: these work silently. They do not have popups, side panels, or status bar clutter. They do their job and disappear.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI extensions are redundant when you use an AI editor.&lt;/strong&gt; I was running Copilot, Codeium, and Tabnine inside VS Code while also using Cursor (which has its own AI). The AI extensions were disabled but still loaded. Removing them freed memory and removed a source of confusion about which AI was active.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2026 editor landscape
&lt;/h2&gt;

&lt;p&gt;The choice in 2026 is not "which extensions should I install." It is "which editor should I use." The landscape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VS Code&lt;/strong&gt; remains the default. The extension ecosystem is the largest. With a minimal setup, it is fast and reliable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cursor&lt;/strong&gt; is VS Code with AI built in. If you are paying for an AI assistant, Cursor replaces the need for AI extensions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zed&lt;/strong&gt; is the performance option. Rust-native, fast startup, built-in collaboration. Smaller extension ecosystem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JetBrains&lt;/strong&gt; (WebStorm, IntelliJ) is the heavy option. Built-in tooling for everything, but higher memory footprint and per-seat licensing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My current setup is Cursor (which is VS Code under the hood) with the same 6 extensions. The AI features are built into the editor, so I do not need AI extensions. The 6 extensions I kept are the ones that do work the AI cannot do: format my code, lint it, show Astro syntax, autocomplete Tailwind classes, and display errors inline.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to try this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open your extensions tab. Sort by "installed."&lt;/li&gt;
&lt;li&gt;For each extension, ask: "Have I used this in the last week?"&lt;/li&gt;
&lt;li&gt;Disable everything where the answer is no. Do not uninstall yet, just disable.&lt;/li&gt;
&lt;li&gt;Work for a week. If you need an extension you disabled, re-enable it.&lt;/li&gt;
&lt;li&gt;After a week, uninstall everything that is still disabled.&lt;/li&gt;
&lt;li&gt;Measure your startup time before and after. The difference is your motivation to keep it lean.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The temptation to install will return. Every blog post about "10 VS Code extensions you must have" will add to your list. The discipline is not "never install." It is "install, try, and remove if you do not use it within a week."&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>devtools</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I replaced npm with pnpm in a monorepo with 14 packages. Here's what actually broke.</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Sun, 25 Oct 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/i-replaced-npm-with-pnpm-in-a-monorepo-with-14-packages-heres-what-actually-broke-56o4</link>
      <guid>https://dev.to/juanauriti/i-replaced-npm-with-pnpm-in-a-monorepo-with-14-packages-heres-what-actually-broke-56o4</guid>
      <description>&lt;p&gt;I moved a Turborepo monorepo with 14 packages from npm to pnpm. The migration took a day and a half. Three things broke. Two things improved more than I expected. Here is what happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  The monorepo
&lt;/h2&gt;

&lt;p&gt;The project is a calculator hub built with Astro 5, React, shadcn/ui, and Tailwind CSS 4. The monorepo has 14 packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2 apps (the main site and a documentation site)&lt;/li&gt;
&lt;li&gt;4 shared UI packages (components, theme, icons, utils)&lt;/li&gt;
&lt;li&gt;3 tooling packages (eslint config, tsconfig, tailwind config)&lt;/li&gt;
&lt;li&gt;5 feature packages (individual calculator modules)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total dependencies: 847 unique packages across all workspaces. With npm, the &lt;code&gt;node_modules&lt;/code&gt; directory was 2.3 GB. Install time on a clean cache: 4 minutes 12 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What broke
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Hoisting differences broke two packages.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;npm hoists all dependencies to the root &lt;code&gt;node_modules&lt;/code&gt; by default. pnpm uses a symlinked structure where each package gets its own &lt;code&gt;node_modules&lt;/code&gt; with symlinks to a shared store. This means packages can only access dependencies they explicitly declare in their &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two of my feature packages were importing a utility (&lt;code&gt;clsx&lt;/code&gt;) that was not in their &lt;code&gt;package.json&lt;/code&gt;. It worked under npm because &lt;code&gt;clsx&lt;/code&gt; was hoisted to the root and accessible from anywhere. Under pnpm, the import failed with "Cannot find module 'clsx'".&lt;/p&gt;

&lt;p&gt;The fix was to add &lt;code&gt;clsx&lt;/code&gt; to the &lt;code&gt;dependencies&lt;/code&gt; of both packages. This is the correct behavior: packages should declare what they import. But if you have been relying on npm's hoisting, pnpm will surface every undeclared dependency in your monorepo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Turborepo cache needed a reset.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After switching package managers, the Turborepo build cache was stale. Builds were passing but using cached outputs from the npm era, which meant the cache hits were masking potential failures. I had to clear the cache with &lt;code&gt;turbo clean&lt;/code&gt; and run a full rebuild to get accurate results.&lt;/p&gt;

&lt;p&gt;This is not a pnpm bug. It is a consequence of changing anything that affects the build inputs. But it is easy to miss if you assume the cache is still valid after the migration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. One postinstall script failed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A package had a &lt;code&gt;postinstall&lt;/code&gt; script that referenced &lt;code&gt;../../node_modules/.bin/something&lt;/code&gt;. Under npm, this path existed because of hoisting. Under pnpm, the binary is in the package's own &lt;code&gt;node_modules/.bin&lt;/code&gt;, not the root. The script failed.&lt;/p&gt;

&lt;p&gt;The fix was to use &lt;code&gt;npx something&lt;/code&gt; or &lt;code&gt;pnpm exec something&lt;/code&gt; instead of hardcoding the path. This is a best practice anyway, but legacy scripts that worked under npm's hoisting model needed updating.&lt;/p&gt;

&lt;h2&gt;
  
  
  What improved
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Disk usage dropped from 2.3 GB to 410 MB.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;pnpm's content-addressable store deduplicates packages across all workspaces. A package that appears in 10 workspaces is stored once on disk and symlinked. The 2.3 GB &lt;code&gt;node_modules&lt;/code&gt; became 410 MB. On a CI runner with limited disk space, this alone justified the migration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Install time dropped from 4:12 to 1:38.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On a clean cache, &lt;code&gt;pnpm install&lt;/code&gt; took 1 minute 38 seconds versus npm's 4 minutes 12 seconds. On a warm cache (with the store already populated), pnpm install took 22 seconds. The speedup comes from the hard-linking strategy: packages that are already in the global store are linked, not downloaded.&lt;/p&gt;

&lt;p&gt;In CI, where each run starts with a clean checkout but the pnpm store can be cached, the warm-cache install time is what matters. Caching &lt;code&gt;~/.local/share/pnpm/store&lt;/code&gt; in GitHub Actions reduced install time from 1:38 to 28 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. &lt;code&gt;pnpm why&lt;/code&gt; is better than &lt;code&gt;npm ls&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tracing why a dependency is installed is clearer with pnpm. &lt;code&gt;pnpm why clsx&lt;/code&gt; shows the full dependency chain from root to the package that depends on it. &lt;code&gt;npm ls clsx&lt;/code&gt; gives a tree that is harder to read in a monorepo with 14 packages.&lt;/p&gt;

&lt;h2&gt;
  
  
  The migration steps
&lt;/h2&gt;

&lt;p&gt;If you are doing the same migration, here is what worked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Delete npm artifacts&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; node_modules &lt;span class="k"&gt;**&lt;/span&gt;/node_modules package-lock.json &lt;span class="k"&gt;**&lt;/span&gt;/package-lock.json

&lt;span class="c"&gt;# 2. Enable pnpm&lt;/span&gt;
corepack &lt;span class="nb"&gt;enable
&lt;/span&gt;corepack prepare pnpm@latest &lt;span class="nt"&gt;--activate&lt;/span&gt;

&lt;span class="c"&gt;# 3. Install&lt;/span&gt;
pnpm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# 4. Fix undeclared dependencies (pnpm will tell you which imports fail)&lt;/span&gt;
&lt;span class="c"&gt;# 5. Clear Turborepo cache&lt;/span&gt;
npx turbo clean

&lt;span class="c"&gt;# 6. Full rebuild&lt;/span&gt;
pnpm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 4 is where most of the time goes. pnpm will fail on every undeclared import. Each failure is a package you need to add to a &lt;code&gt;package.json&lt;/code&gt; that should have declared it in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Run &lt;code&gt;pnpm install --shamefully-hoist&lt;/code&gt; first to get a baseline.&lt;/strong&gt; The &lt;code&gt;--shamefully-hoist&lt;/code&gt; flag mimics npm's hoisting behavior, so the install will succeed without fixing undeclared dependencies. This gives you a working baseline. Then remove the flag and fix the failures one by one, testing after each fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check postinstall scripts before migrating.&lt;/strong&gt; Any script that references &lt;code&gt;../../node_modules&lt;/code&gt; paths will break. Find them with &lt;code&gt;grep -r "node_modules" --include="*.js" packages/&lt;/code&gt; and fix them before switching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache the pnpm store in CI from day one.&lt;/strong&gt; The install time difference between cached and uncached is 28 seconds vs 1:38. Over a week of CI runs, that is hours saved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it worth it?
&lt;/h2&gt;

&lt;p&gt;For a monorepo with 14 packages, yes. The disk space and install time improvements are immediate and significant. The migration cost is a day and a half of fixing undeclared dependencies, which is work that should have been done anyway.&lt;/p&gt;

&lt;p&gt;For a single-package project, the benefit is smaller. The install time and disk improvements are proportional to the number of packages and the amount of dependency overlap. A single app with no shared dependencies will see a smaller speedup.&lt;/p&gt;

&lt;p&gt;The undeclared dependency issue is the main friction. If your monorepo has been relying on npm's hoisting for years, pnpm will surface every place where a package imports something it does not declare. That is painful in the short term and correct in the long term.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>devtools</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>git bundle without HEAD: the recovery commands I wish I'd known</title>
      <dc:creator>Juan Camilo Auriti</dc:creator>
      <pubDate>Sat, 24 Oct 2026 07:00:00 +0000</pubDate>
      <link>https://dev.to/juanauriti/git-bundle-without-head-the-recovery-commands-i-wish-id-known-2l5l</link>
      <guid>https://dev.to/juanauriti/git-bundle-without-head-the-recovery-commands-i-wish-id-known-2l5l</guid>
      <description>&lt;p&gt;A few weeks ago I wrote about a &lt;a href="https://dev.to/juanauriti"&gt;git bundle problem&lt;/a&gt;: &lt;code&gt;git bundle verify&lt;/code&gt; reported "complete history," &lt;code&gt;git clone&lt;/code&gt; exited 0, and the working tree was empty. The root cause was a missing HEAD ref in the bundle. The fix was to create the bundle with &lt;code&gt;--all HEAD&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A commenter named SystemCraftDev added the recovery side: what to do if you already have a bundle without HEAD and cannot re-create it. Their commands work, and they deserve to be in the same place as the original post. Here is the complete guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem, in one paragraph
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;git bundle create transfer.bundle main&lt;/code&gt; creates a bundle with one ref (&lt;code&gt;refs/heads/main&lt;/code&gt;) but no &lt;code&gt;HEAD&lt;/code&gt;. When you clone from it, git tries to resolve HEAD, finds it pointing at a branch that does not exist (usually &lt;code&gt;master&lt;/code&gt;), and checks out nothing. The clone succeeds with exit code 0. The working tree is empty. The objects are all there. There is simply no branch and no checkout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prevention: create the bundle with HEAD
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bundle create transfer.bundle &lt;span class="nt"&gt;--all&lt;/span&gt; HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--all&lt;/code&gt; takes every ref. &lt;code&gt;HEAD&lt;/code&gt; adds the one that makes it clonable. That bundle lists multiple heads including &lt;code&gt;HEAD&lt;/code&gt;, and the clone checks out a working tree with a branch on it.&lt;/p&gt;

&lt;p&gt;For a single branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bundle create transfer.bundle main HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Recovery: you already have a bundle without HEAD
&lt;/h2&gt;

&lt;p&gt;If you cannot re-create the bundle, you can work around the missing HEAD by naming the branch explicitly during clone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;-b&lt;/span&gt; main transfer.bundle restored
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-b main&lt;/code&gt; flag tells git which branch to check out, bypassing the HEAD resolution entirely. Git creates the local branch from the bundle's &lt;code&gt;refs/heads/main&lt;/code&gt; and checks out the files.&lt;/p&gt;

&lt;p&gt;This works because the objects and the ref are in the bundle. The only thing missing is HEAD, and &lt;code&gt;-b&lt;/code&gt; lets you specify the branch directly instead of relying on HEAD to point to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recovery: you already cloned and got an empty tree
&lt;/h2&gt;

&lt;p&gt;If you already ran &lt;code&gt;git clone transfer.bundle restored&lt;/code&gt; and ended up with an empty working tree, the objects are still there. You can recover in place:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git creates the local branch from the remote-tracking ref (&lt;code&gt;origin/main&lt;/code&gt;) and checks out the files. No need to re-clone.&lt;/p&gt;

&lt;p&gt;If you are not sure what branches are available in the broken clone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git branch &lt;span class="nt"&gt;-r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lists the remote-tracking refs. You will see &lt;code&gt;origin/main&lt;/code&gt; (or whatever branch was in the bundle). Switch to it with &lt;code&gt;git switch main&lt;/code&gt; or &lt;code&gt;git switch -c main origin/main&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to read the empty-clone symptom
&lt;/h2&gt;

&lt;p&gt;The symptom that confused me was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git &lt;span class="nt"&gt;-C&lt;/span&gt; restored symbolic-ref HEAD
refs/heads/master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HEAD points at &lt;code&gt;refs/heads/master&lt;/code&gt;, which does not exist, because the bundle carried &lt;code&gt;main&lt;/code&gt;. Git has nothing to check out. The warning on stderr (&lt;code&gt;remote HEAD refers to nonexistent ref&lt;/code&gt;) is the only signal that something is wrong. Under &lt;code&gt;set -e&lt;/code&gt;, the exit code 0 means nothing stops.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;HEAD&lt;/code&gt; ref in a bundle tells git which branch to check out after clone. Without it, git falls back to its default (usually &lt;code&gt;master&lt;/code&gt;), and if the bundle does not contain &lt;code&gt;master&lt;/code&gt;, you get an empty tree with no branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The complete decision tree
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Creating a bundle&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git bundle create transfer.bundle --all HEAD&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloning from a bundle with HEAD&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git clone transfer.bundle restored&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloning from a bundle without HEAD&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git clone -b main transfer.bundle restored&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Already cloned, empty tree, want to recover&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git switch main&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not sure which branch is in the clone&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git branch -r&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why this matters in automated workflows
&lt;/h2&gt;

&lt;p&gt;The original problem surfaced in a transfer script. The script ran &lt;code&gt;git bundle verify&lt;/code&gt; (exit 0, "complete history"), then &lt;code&gt;git clone&lt;/code&gt; (exit 0), then checked for files (none). Under &lt;code&gt;set -e&lt;/code&gt;, nothing stopped. The only evidence was a warning on stderr, which the script logged to stdout and never surfaced.&lt;/p&gt;

&lt;p&gt;If you are writing a transfer script, check for the working tree, not the exit code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone transfer.bundle restored
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; restored&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Clone succeeded but working tree is empty"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Attempting recovery with explicit branch..."&lt;/span&gt;
  git &lt;span class="nt"&gt;-C&lt;/span&gt; restored switch main 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; git &lt;span class="nt"&gt;-C&lt;/span&gt; restored switch &lt;span class="nt"&gt;-c&lt;/span&gt; main origin/main
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This catches the empty-tree case and attempts recovery in place. It is not elegant, but it handles the one failure mode that exit codes cannot detect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks to the commenter
&lt;/h2&gt;

&lt;p&gt;SystemCraftDev's comment on the original post added the recovery commands that I had not covered. The original post was about prevention (how to create the bundle correctly). The recovery side is equally important, especially for bundles you receive from someone else and cannot re-create. This article puts both sides in one place.&lt;/p&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>devtools</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
