<?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>Forem: Joel</title>
    <description>The latest articles on Forem by Joel (@candle-dojo).</description>
    <link>https://forem.com/candle-dojo</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3845154%2F62b7f12d-40de-48a6-94ef-3f10a10a152c.png</url>
      <title>Forem: Joel</title>
      <link>https://forem.com/candle-dojo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/candle-dojo"/>
    <language>en</language>
    <item>
      <title>I'm losing my own brand SERP to 3rd-party articles. Here's the JSON-LD stack I'm shipping to claw it back.</title>
      <dc:creator>Joel</dc:creator>
      <pubDate>Wed, 22 Apr 2026 06:52:27 +0000</pubDate>
      <link>https://forem.com/candle-dojo/im-losing-my-own-brand-serp-to-3rd-party-articles-heres-the-json-ld-stack-im-shipping-to-claw-2bf1</link>
      <guid>https://forem.com/candle-dojo/im-losing-my-own-brand-serp-to-3rd-party-articles-heres-the-json-ld-stack-im-shipping-to-claw-2bf1</guid>
      <description>&lt;h2&gt;
  
  
  The problem I'm still losing at
&lt;/h2&gt;

&lt;p&gt;Search my app's name on Google and the first results aren't my site. They're other people's articles &lt;em&gt;about&lt;/em&gt; it. Directories, aggregators, a Reddit thread, a Medium post. The actual product, &lt;a href="https://candledojo.app" rel="noopener noreferrer"&gt;CandleDojo&lt;/a&gt;, sits somewhere below the fold.&lt;/p&gt;

&lt;p&gt;This is normal for a young domain. Google doesn't have enough signal that "candledojo" the query = "candledojo.app" the entity. Every 3rd-party write-up outranks the site itself because those domains are older, have more backlinks, and carry more topical weight than a six-month-old app.&lt;/p&gt;

&lt;p&gt;I'm not done fixing this, but one of the levers I'm pulling is structured data. Specifically JSON-LD. And not just the basics that SEO checklists tell you to ship. There's a specific stack that matters when you're trying to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Resolve as a clean entity in Google's Knowledge Graph&lt;/li&gt;
&lt;li&gt;Win rich result eligibility on your own content pages&lt;/li&gt;
&lt;li&gt;Get cited by AI tools (Perplexity, ChatGPT search, Claude) when they answer questions in your niche&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the stack I ship on every page of &lt;a href="https://candledojo.app" rel="noopener noreferrer"&gt;CandleDojo&lt;/a&gt;, what each schema actually does, and what I'd skip if I were starting from scratch.&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%2Fjnbwtr9g9d8ruld32ch5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnbwtr9g9d8ruld32ch5.png" alt="Google SERP for " width="800" height="969"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model: one helper, many schemas
&lt;/h2&gt;

&lt;p&gt;All my JSON-LD lives in &lt;code&gt;src/lib/structured-data.ts&lt;/code&gt;. It's one file of pure TypeScript helpers that return plain objects. Each helper is a schema builder. I inject them via &lt;code&gt;&amp;lt;script type="application/ld+json"&amp;gt;&lt;/code&gt; tags from either the root layout (site-wide schemas) or page components (page-specific schemas).&lt;/p&gt;

&lt;p&gt;No CMS, no plugin, no markup hacked into &lt;code&gt;&amp;lt;Head&amp;gt;&lt;/code&gt;. Just typed functions.&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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildBreadcrumbJsonLd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BreadcrumbItem&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="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="s1"&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="s1"&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="s1"&gt;BreadcrumbList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;itemListElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;items&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;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="s1"&gt;ListItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;index&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&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="p"&gt;...(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&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="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;That shape repeats for every schema. Helper in, object out, inject once. Below is what I inject where.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schema 1: Organization + WebSite in the root layout (the entity anchor)
&lt;/h2&gt;

&lt;p&gt;This is the single most important one for branded search. If you do nothing else, do this.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;src/app/layout.tsx&lt;/code&gt;, I run &lt;code&gt;buildOrganizationJsonLd()&lt;/code&gt; once per request. It emits:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="s1"&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="s1"&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="s1"&gt;Organization&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CandleDojo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;alternateName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Candle Dojo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;url&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://candledojo.app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;logo&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://candledojo.app/favicon.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;description&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="nx"&gt;contactPoint&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;@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;ContactPoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;contactType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customer support&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="nx"&gt;sameAs&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;https://x.com/candledojo&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;https://discord.gg/...&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;https://www.youtube.com/@candledojo&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;https://www.reddit.com/user/CandleDojo/&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things matter here more than anything else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;sameAs&lt;/code&gt;&lt;/strong&gt;. Every owned profile, listed. X, YouTube, Discord, Reddit, GitHub if public, dev.to author page. This is how Google connects your brand name to a set of identities it can cross-verify. The more consistent profiles you list, the faster "candledojo" becomes a resolved entity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;alternateName&lt;/code&gt;&lt;/strong&gt;. Search users type "candle dojo" as two words too. Telling Google both variants point at the same entity saves you a ranking split.&lt;/p&gt;

&lt;p&gt;I pair Organization with a separate &lt;code&gt;WebSite&lt;/code&gt; schema on the homepage. Same idea, narrower scope: here's the site, here's its name, here's the canonical URL. Two entity anchors reinforce each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schema 2: WebApplication on the homepage
&lt;/h2&gt;

&lt;p&gt;If you're an app, not a blog, tell Google. A content-only schema stack is why so many SaaS tools get treated as articles.&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="s1"&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="s1"&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="s1"&gt;WebApplication&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CandleDojo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;applicationCategory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EducationalApplication&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;operatingSystem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;offers&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;@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;Offer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;priceCurrency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USD&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;p&gt;&lt;code&gt;applicationCategory&lt;/code&gt; and &lt;code&gt;operatingSystem&lt;/code&gt; unlock app-style rich results eligibility. &lt;code&gt;offers&lt;/code&gt; is where you declare freemium or paid tiers. If you have honest review volume, add &lt;code&gt;aggregateRating&lt;/code&gt;. I don't yet, so I leave it off. Stuffing fake ratings is the fastest way to earn a manual action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schema 3: BreadcrumbList on every nested route
&lt;/h2&gt;

&lt;p&gt;The laziest high-leverage schema. Takes 10 lines per route, gives you rich breadcrumb links in SERPs, and tells Google exactly how your site is structured.&lt;/p&gt;

&lt;p&gt;On an insights page, I inject:&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="nf"&gt;buildBreadcrumbJsonLd&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;item&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://candledojo.app&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Insights&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;item&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://candledojo.app/insights&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;canonicalUrl&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;Every nested route on &lt;a href="https://candledojo.app/patterns" rel="noopener noreferrer"&gt;CandleDojo&lt;/a&gt; does this: /patterns, /guides, /insights, /vs, /tools. The App Router makes it trivial because each route file already knows its own URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schema 4: Article + HowTo on guide pages (the combo)
&lt;/h2&gt;

&lt;p&gt;For long-form pages that explain something, Article plus HowTo is the pairing.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Article&lt;/code&gt; gets you eligibility for the Top Stories carousel, date-surfaced results, and author byline display. &lt;code&gt;HowTo&lt;/code&gt; gets you steppable rich results (though Google has narrowed the visual treatment, the entity signal still matters).&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;buildArticleJsonLd()&lt;/code&gt; helper spits out:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="s1"&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="s1"&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="s1"&gt;Article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;headline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&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;mainEntityOfPage&lt;/span&gt;&lt;span class="p"&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;inLanguage&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;author&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;@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;Organization&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CandleDojo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&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="nx"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;buildPublisher&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nx"&gt;datePublished&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;dateModified&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;about&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;about&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;name&lt;/span&gt; &lt;span class="o"&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="s1"&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="s1"&gt;Thing&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;articleSection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;section&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;Two details people mess up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mainEntityOfPage&lt;/code&gt; must equal the canonical URL. Not a tracking param version, not a trailing-slash mismatch. Google will silently ignore mismatched entities.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dateModified&lt;/code&gt; should update when the page actually changes. Don't set it equal to &lt;code&gt;datePublished&lt;/code&gt; forever. Freshness signals help.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the HowTo pair, I only emit it when the page genuinely has steps. Don't synthesize steps just to qualify. Google's Rich Results Test will accept it, then Google Search itself will quietly not surface it and you'll have wasted markup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schema 5: DefinedTerm on glossary and pattern pages
&lt;/h2&gt;

&lt;p&gt;This one is underused and it's my favorite.&lt;/p&gt;

&lt;p&gt;I have 12 candlestick pattern pages on &lt;a href="https://candledojo.app/patterns" rel="noopener noreferrer"&gt;CandleDojo&lt;/a&gt; (hammer, doji, engulfing, etc.). Each page is essentially a definition plus a guide. &lt;code&gt;DefinedTerm&lt;/code&gt; is the schema built for exactly this:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="s1"&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="s1"&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="s1"&gt;DefinedTerm&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;@id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;url&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bullish Engulfing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;description&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="nx"&gt;inDefinedTermSet&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://candledojo.app/patterns&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;about&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;@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;Thing&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;candlestick patterns&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;p&gt;Why I like it for AI citations specifically: LLMs building answers for "what is a bullish engulfing pattern" prefer to cite sources that expose structured definitions. &lt;code&gt;DefinedTerm&lt;/code&gt; is cleaner than Article for single-concept pages and reduces the chance of the crawler pulling the wrong paragraph.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;inDefinedTermSet&lt;/code&gt; groups all your terms under one glossary URL. It's the schema equivalent of saying "this term is part of my taxonomy, here's the index."&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate and measure
&lt;/h2&gt;

&lt;p&gt;The boring but critical part.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://search.google.com/test/rich-results" rel="noopener noreferrer"&gt;Google Rich Results Test&lt;/a&gt;.&lt;/strong&gt; Run every page type through it after shipping. It will tell you what it parsed and what it rejected. Screenshot the detected schemas list for your own records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GSC Enhancements.&lt;/strong&gt; After ~2 weeks, Google Search Console will populate Enhancement reports for each schema it found (Breadcrumbs, Sitelinks, Logo, etc.). If a schema doesn't show up, it wasn't parsed at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brand query panel.&lt;/strong&gt; GSC Performance, filter query = your brand name. Watch impressions and average position for the branded term specifically. That's your scoreboard.&lt;/li&gt;
&lt;/ul&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%2Fluarzfdz6msr8qhkaan7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fluarzfdz6msr8qhkaan7.png" alt="Google Search Console performance panel filtered to the " width="800" height="333"&gt;&lt;/a&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%2Fc6y373rsmst523s2gjna.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6y373rsmst523s2gjna.png" alt="Google Rich Results Test showing the detected JSON-LD schemas for candledojo.app" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For AI citations, there's no dashboard. I just periodically run two queries in Perplexity and compare.&lt;/p&gt;

&lt;p&gt;The first is a &lt;strong&gt;branded query&lt;/strong&gt;: "what is candledojo". This tells me whether LLMs have resolved my brand as a distinct entity yet. Ideally the top answer cites candledojo.app directly.&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%2Fmy4wtfs0krg5w7obblwd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmy4wtfs0krg5w7obblwd.png" alt="Perplexity answering " width="800" height="753"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second is a &lt;strong&gt;category query&lt;/strong&gt;: "best candlestick pattern trainer" or "best trainer app for reading price action". This tells me whether my pages show up when someone is &lt;em&gt;not&lt;/em&gt; already looking for me by name. That's the harder win and the one that drives new traffic.&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%2Fhddgcyhxlcfkgy0f149e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhddgcyhxlcfkgy0f149e.png" alt="Perplexity answering the category query " width="800" height="857"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Branded citation means entity resolution is working. Category citation means topical authority is starting to stick. Both matter. Right now I get intermittent branded citations and almost zero category citations. The goal of stacking &lt;code&gt;DefinedTerm&lt;/code&gt;, &lt;code&gt;Article&lt;/code&gt;, and &lt;code&gt;HowTo&lt;/code&gt; across my content pages is to move that second needle.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd skip
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FAQPage schema for non-support pages.&lt;/strong&gt; Google nerfed it in 2023. It's still parseable but only surfaces on government and health sites now. Waste of markup on a product page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product schema for SaaS.&lt;/strong&gt; Use WebApplication or SoftwareApplication instead. Product is for physical goods and triggers price-snippet rules that don't map cleanly to software.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Over-nesting.&lt;/strong&gt; Don't inline your Organization inside every Article's &lt;code&gt;publisher&lt;/code&gt;. Reference it by &lt;code&gt;@id&lt;/code&gt; where you can, otherwise you balloon the JSON-LD weight and Google starts dropping payloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review schema you don't control.&lt;/strong&gt; If testimonials aren't from a verifiable source, leave them out. The risk of a manual action outweighs the rich result.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Structured data isn't going to single-handedly beat an aggregator that's been indexed since 2019. What it does is stack entity signals so that every page on your site tells the same story: this brand, this URL, these topics, this category.&lt;/p&gt;

&lt;p&gt;I'm still losing my brand SERP today. Every week I check GSC, and every week the gap is a bit smaller. The JSON-LD stack above is one of the levers I'm pulling. The other is just shipping more content that gets linked with my brand name as anchor text. That's partly why I'm writing this post.&lt;/p&gt;

&lt;p&gt;If you want to see the full schema stack live, pull up &lt;a href="https://candledojo.app" rel="noopener noreferrer"&gt;CandleDojo&lt;/a&gt; and view source. Everything in &lt;code&gt;&amp;lt;script type="application/ld+json"&amp;gt;&lt;/code&gt; is the output of one of the helpers above. Copy what's useful.&lt;/p&gt;

&lt;p&gt;And if you're fighting the same branded-SERP problem, drop the schemas that worked for you in the comments. I want more data points.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>seo</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How I’m Building SEO + GEO for CandleDojo, a Chart-Reading Trainer</title>
      <dc:creator>Joel</dc:creator>
      <pubDate>Tue, 31 Mar 2026 17:09:15 +0000</pubDate>
      <link>https://forem.com/candle-dojo/how-im-building-seo-geo-for-candledojo-a-chart-reading-trainer-1kfk</link>
      <guid>https://forem.com/candle-dojo/how-im-building-seo-geo-for-candledojo-a-chart-reading-trainer-1kfk</guid>
      <description>&lt;p&gt;Hi there!&lt;/p&gt;

&lt;p&gt;I’ve been working on &lt;a href="https://candledojo.app" rel="noopener noreferrer"&gt;CandleDojo&lt;/a&gt;, a browser-based chart-reading trainer for traders.&lt;/p&gt;

&lt;p&gt;The product idea was always pretty clear in my head:&lt;br&gt;
help traders get structured reps reading historical charts, recognizing candlestick patterns in context, and improving chart-reading skill without turning practice into random screen time.&lt;/p&gt;

&lt;p&gt;But I realized something uncomfortable:&lt;/p&gt;

&lt;p&gt;the product made much more sense when &lt;em&gt;I&lt;/em&gt; explained it than when the website explained it.&lt;/p&gt;

&lt;p&gt;That is a problem for normal SEO, and it is also a problem for GEO.&lt;/p&gt;

&lt;p&gt;If someone searches Google for a &lt;strong&gt;candlestick practice tool&lt;/strong&gt;, a &lt;strong&gt;chart-reading trainer&lt;/strong&gt;, or a &lt;strong&gt;way to practice price action&lt;/strong&gt;, the site needs to make that obvious.&lt;/p&gt;

&lt;p&gt;And if someone asks ChatGPT, Claude, Perplexity, or Google AI something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;what’s a good tool for practicing chart reading?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;then CandleDojo needs to be understandable enough to be suggested as an answer.&lt;/p&gt;

&lt;p&gt;So I started rebuilding the public side of CandleDojo around those goals.&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%2Fxywo5uamrdgsn6a9c57x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxywo5uamrdgsn6a9c57x.png" alt="CandleDojo tools hub with chart-reading assessments and practice diagnostics" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I cared about SEO and GEO
&lt;/h2&gt;

&lt;p&gt;At first, most of the discoverability was basically brand-driven.&lt;/p&gt;

&lt;p&gt;That means if someone already knew &lt;code&gt;CandleDojo&lt;/code&gt; or typed &lt;code&gt;Candle Dojo&lt;/code&gt;, they could probably find it.&lt;/p&gt;

&lt;p&gt;But that is not the real challenge.&lt;/p&gt;

&lt;p&gt;The real challenge is showing up for the kind of searches people use when they do &lt;strong&gt;not&lt;/strong&gt; know your product yet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;candlestick practice tool&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chart reading trainer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;how to practice price action&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trading replay simulator&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bar replay vs paper trading&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;best way to practice chart reading&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the SEO side.&lt;/p&gt;

&lt;p&gt;The GEO side is slightly different.&lt;/p&gt;

&lt;p&gt;For me, GEO is not about stuffing “AI” everywhere.&lt;br&gt;
It is about making the site easier for generative systems to classify, summarize, and recommend.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what is this product?&lt;/li&gt;
&lt;li&gt;who is it for?&lt;/li&gt;
&lt;li&gt;what problem does it solve?&lt;/li&gt;
&lt;li&gt;when should it be recommended instead of something else?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted CandleDojo to answer those questions much more clearly.&lt;/p&gt;




&lt;h2&gt;
  
  
  What CandleDojo actually is
&lt;/h2&gt;

&lt;p&gt;This was the first thing I had to fix.&lt;/p&gt;

&lt;p&gt;I stopped assuming the branding alone was enough.&lt;/p&gt;

&lt;p&gt;So instead of leaving the product too abstract, I started being much more explicit about the language on public pages.&lt;/p&gt;

&lt;p&gt;CandleDojo is now described more clearly as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;chart-reading trainer&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;candlestick practice tool&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;a product for &lt;strong&gt;price action practice&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;a way to train with &lt;strong&gt;historical charts and structured reps&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That sounds simple, but I think it matters a lot.&lt;/p&gt;

&lt;p&gt;Search engines do better when the product category is clear.&lt;br&gt;
LLMs also do better when the product can be placed into a clean mental bucket.&lt;/p&gt;

&lt;p&gt;If the site only sounds clever or branded, it is harder to rank and harder to recommend.&lt;/p&gt;

&lt;p&gt;If the site clearly says what it is, the odds get much better.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I changed on the site
&lt;/h2&gt;

&lt;p&gt;The biggest shift was structural.&lt;/p&gt;

&lt;p&gt;I stopped treating public pages like isolated marketing pages and started treating them like a real content system.&lt;/p&gt;

&lt;p&gt;I split the public surface into clearer sections:&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%2Fbmptldfvukbiwi8dnm4t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmptldfvukbiwi8dnm4t.png" alt="A CandleDojo guide page targeting chart-reading practice intent" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/guides&lt;/code&gt; for educational and problem-aware content&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/patterns&lt;/code&gt; for glossary-style candlestick pattern pages&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/vs&lt;/code&gt; for comparison intent&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/tools&lt;/code&gt; for interactive assessments&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/insights&lt;/code&gt; for first-party research and reporting&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/newsletter&lt;/code&gt; for owned audience growth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gave each page type a more specific job.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;guide&lt;/strong&gt; can target questions like “how to practice price action”&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;comparison page&lt;/strong&gt; can target high-intent searches like “CandleDojo vs TradingView Replay”&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;tool page&lt;/strong&gt; can capture people looking for a chart-reading assessment or candlestick quiz&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;insight page&lt;/strong&gt; can build trust and give the product something more citeable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point matters more than I expected.&lt;/p&gt;

&lt;p&gt;A lot of GEO-friendly content is not just “content.”&lt;br&gt;
It is content that is easy to quote, summarize, or reference.&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%2F8uuyk5sub339rtpq939y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8uuyk5sub339rtpq939y.png" alt="A CandleDojo insights page built to make first-party research easier to cite and understand" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I changed specifically for GEO
&lt;/h2&gt;

&lt;p&gt;For GEO, I tried to focus on clarity over gimmicks.&lt;/p&gt;

&lt;p&gt;A few things seemed especially important:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Clear product classification
&lt;/h3&gt;

&lt;p&gt;I made sure the pages say what CandleDojo is in plain English.&lt;/p&gt;

&lt;p&gt;Not just “train your chart reading.”&lt;br&gt;
More like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CandleDojo is a chart-reading trainer&lt;/li&gt;
&lt;li&gt;CandleDojo is a candlestick practice tool&lt;/li&gt;
&lt;li&gt;CandleDojo helps traders practice reading price action on historical charts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gives LLMs much better raw material.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Pages that match recommendation intent
&lt;/h3&gt;

&lt;p&gt;A lot of AI questions are recommendation-shaped.&lt;/p&gt;

&lt;p&gt;So I leaned into content that naturally answers those kinds of prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;best way to practice chart reading&lt;/li&gt;
&lt;li&gt;what makes a good chart-reading trainer&lt;/li&gt;
&lt;li&gt;bar replay vs paper trading&lt;/li&gt;
&lt;li&gt;candlestick pattern practice tool&lt;/li&gt;
&lt;li&gt;trading replay simulator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are not giant vanity keywords, but they are much closer to actual product discovery.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Better internal linking
&lt;/h3&gt;

&lt;p&gt;I wanted the public content to feel like a connected graph instead of scattered pages.&lt;/p&gt;

&lt;p&gt;So pattern pages can point to related tools or guides.&lt;br&gt;
Guides can point to assessments.&lt;br&gt;
Insight pages can point back into the product.&lt;br&gt;
Comparison pages can link to deeper educational content.&lt;/p&gt;

&lt;p&gt;That helps both users and machines understand how the topics connect.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Crawl accessibility for public pages
&lt;/h3&gt;

&lt;p&gt;I also updated the crawl policy so public content can be accessed more broadly, while private app routes stay blocked.&lt;/p&gt;

&lt;p&gt;That means pages like guides, tools, comparisons, and insights are part of the public surface, while routes like &lt;code&gt;/play&lt;/code&gt;, &lt;code&gt;/profile&lt;/code&gt;, &lt;code&gt;/auth&lt;/code&gt;, and &lt;code&gt;/api&lt;/code&gt; stay out of that layer.&lt;/p&gt;

&lt;p&gt;For me, that is the right split:&lt;br&gt;
make the public knowledge surface accessible, and keep the actual app internals private.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I changed for measurement
&lt;/h2&gt;

&lt;p&gt;One thing I really did not want was to spend weeks “doing SEO” and then only know whether pageviews went up.&lt;/p&gt;

&lt;p&gt;That is not enough.&lt;/p&gt;

&lt;p&gt;So I added more attribution and event tracking around the public funnel.&lt;/p&gt;

&lt;p&gt;I started tracking things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;page views&lt;/li&gt;
&lt;li&gt;CTA clicks&lt;/li&gt;
&lt;li&gt;tool starts&lt;/li&gt;
&lt;li&gt;tool completions&lt;/li&gt;
&lt;li&gt;newsletter signups&lt;/li&gt;
&lt;li&gt;signup starts&lt;/li&gt;
&lt;li&gt;signup completions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also added first-touch attribution on signup.&lt;/p&gt;

&lt;p&gt;That matters because I want to know which content types actually help create users.&lt;/p&gt;

&lt;p&gt;Not just:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which page got traffic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which page led to a newsletter signup&lt;/li&gt;
&lt;li&gt;which page led to a tool completion&lt;/li&gt;
&lt;li&gt;which page helped start an account signup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That feels much closer to the real job.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I changed for scale
&lt;/h2&gt;

&lt;p&gt;I also built a weekly content pack workflow around CandleDojo.&lt;/p&gt;

&lt;p&gt;Instead of thinking about SEO posts, videos, newsletter content, and directory snippets as separate workflows, I wanted one source topic to create a full pack.&lt;/p&gt;

&lt;p&gt;So one topic can produce:&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%2Fmq40k3dtc7onh5pp6yhr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmq40k3dtc7onh5pp6yhr.png" alt="CandleDojo newsletter page for the weekly drill digest" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one primary content asset&lt;/li&gt;
&lt;li&gt;one YouTube script&lt;/li&gt;
&lt;li&gt;a few short-form hooks&lt;/li&gt;
&lt;li&gt;one newsletter block&lt;/li&gt;
&lt;li&gt;one directory/profile snippet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes the system much more scalable.&lt;/p&gt;

&lt;p&gt;It also fits how I think about search now.&lt;/p&gt;

&lt;p&gt;The same core idea should be able to show up across:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google Search&lt;/li&gt;
&lt;li&gt;AI-generated recommendations&lt;/li&gt;
&lt;li&gt;YouTube&lt;/li&gt;
&lt;li&gt;newsletter&lt;/li&gt;
&lt;li&gt;directory/referral traffic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Different channels, same underlying intent.&lt;/p&gt;

&lt;p&gt;That feels much more durable than creating random one-off content.&lt;/p&gt;




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

&lt;p&gt;A few things became clearer while doing this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Broad keywords are not the point
&lt;/h3&gt;

&lt;p&gt;Trying to rank for something like &lt;code&gt;candle&lt;/code&gt;, &lt;code&gt;dojo&lt;/code&gt;, or even &lt;code&gt;trading&lt;/code&gt; is not the right game.&lt;/p&gt;

&lt;p&gt;The better targets are narrower and more product-shaped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;chart-reading trainer&lt;/li&gt;
&lt;li&gt;candlestick practice tool&lt;/li&gt;
&lt;li&gt;best way to practice chart reading&lt;/li&gt;
&lt;li&gt;trading replay simulator&lt;/li&gt;
&lt;li&gt;bar replay vs paper trading&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are much more realistic and much more useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  GEO is not magic
&lt;/h3&gt;

&lt;p&gt;Just letting AI crawlers access your site does not automatically make your product recommendable.&lt;/p&gt;

&lt;p&gt;If the pages are vague, thin, or hard to classify, LLMs still will not have much to work with.&lt;/p&gt;

&lt;p&gt;The real work is still:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clarity&lt;/li&gt;
&lt;li&gt;structure&lt;/li&gt;
&lt;li&gt;useful page types&lt;/li&gt;
&lt;li&gt;internal linking&lt;/li&gt;
&lt;li&gt;recommendation-friendly language&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tools and comparisons are strong assets
&lt;/h3&gt;

&lt;p&gt;I think interactive tools and comparison pages are underrated.&lt;/p&gt;

&lt;p&gt;A generic blog post can be useful, but a good tool page or a strong comparison page often does a much better job of matching high-intent discovery.&lt;/p&gt;

&lt;h3&gt;
  
  
  The content system matters as much as the writing
&lt;/h3&gt;

&lt;p&gt;The more I worked on this, the more it felt like an information architecture problem, not just a writing problem.&lt;/p&gt;

&lt;p&gt;You are not only writing articles.&lt;br&gt;
You are teaching search engines and LLMs how your product should be understood.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where I am now
&lt;/h2&gt;

&lt;p&gt;I do not think SEO or GEO is something you “finish.”&lt;/p&gt;

&lt;p&gt;It feels more like building a long-lived public knowledge layer around the product.&lt;/p&gt;

&lt;p&gt;For CandleDojo, that layer now has a much clearer shape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;educational guides&lt;/li&gt;
&lt;li&gt;pattern pages&lt;/li&gt;
&lt;li&gt;comparison pages&lt;/li&gt;
&lt;li&gt;interactive tools&lt;/li&gt;
&lt;li&gt;insight pages&lt;/li&gt;
&lt;li&gt;newsletter capture&lt;/li&gt;
&lt;li&gt;attribution so I can measure what actually works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is still early, but this already feels much better than hoping the homepage alone will do all the work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;My current takeaway is pretty simple:&lt;/p&gt;

&lt;p&gt;if you want your product to show up in both search and AI recommendations, do not just publish more content.&lt;/p&gt;

&lt;p&gt;Make your site easier to understand.&lt;/p&gt;

&lt;p&gt;Make it obvious what the product is, who it is for, and when it should be recommended.&lt;/p&gt;

&lt;p&gt;That has been the real shift for me with CandleDojo.&lt;/p&gt;

&lt;p&gt;If you want to check it out, it’s here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://candledojo.app" rel="noopener noreferrer"&gt;https://candledojo.app&lt;/a&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>ai</category>
      <category>nextjs</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>I Built "Duolingo for Chart Reading" as a Solo Dev - Here's What I Learned</title>
      <dc:creator>Joel</dc:creator>
      <pubDate>Thu, 26 Mar 2026 19:00:38 +0000</pubDate>
      <link>https://forem.com/candle-dojo/i-built-duolingo-for-chart-reading-as-a-solo-dev-heres-what-i-learned-3770</link>
      <guid>https://forem.com/candle-dojo/i-built-duolingo-for-chart-reading-as-a-solo-dev-heres-what-i-learned-3770</guid>
      <description>&lt;p&gt;There are thousands of resources that teach you what a hammer candlestick looks like. Almost none of them make you actually practice spotting one in a real chart.&lt;/p&gt;

&lt;p&gt;Reading price action is a visual skill. You can't learn it from flashcards. You learn it the same way you learn to read sheet music or spot patterns in an X-ray - through repetition with real data.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://candledojo.app" rel="noopener noreferrer"&gt;CandleDojo&lt;/a&gt;. It gives you a real historical chart, you call the direction, and then the chart replays forward so you see what actually happened.&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%2Fkhqio9aareca12guzwdm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhqio9aareca12guzwdm.png" alt="CandleDojo gameplay" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;You see a frozen moment from a real BTC, ETH, or SOL chart&lt;/li&gt;
&lt;li&gt;You read the candles and call bullish or bearish&lt;/li&gt;
&lt;li&gt;The chart replays forward - instant feedback&lt;/li&gt;
&lt;li&gt;A belt system (white to black) tracks your progression across 3,700+ scenarios&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No sign-up required. You can start practicing immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&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;Framework&lt;/td&gt;
&lt;td&gt;Next.js 15 (App Router)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth + DB&lt;/td&gt;
&lt;td&gt;Supabase (Postgres + RPC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling&lt;/td&gt;
&lt;td&gt;TailwindCSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Charts&lt;/td&gt;
&lt;td&gt;Hand-rolled HTML Canvas&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I didn't use a charting library. The replay animation needed frame-level control over candle rendering, so the entire chart component is built directly on the Canvas API.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually hard
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The scenarios, not the code.&lt;/strong&gt; A random slice of price data is usually flat and boring. I had to build a generation pipeline that filters for interesting price action - clear trends, reversals at key levels, recognizable patterns - and tags each scenario by difficulty level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Difficulty balance broke retention.&lt;/strong&gt; The first version had 87% hard scenarios. New users went on losing streaks and bounced. After rebalancing to 14% easy, 18% medium, 67% hard, session lengths went up immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round saves had race conditions.&lt;/strong&gt; A single round completion touches XP, belt unlocks, streaks, weekly challenges, and profile stats. The first implementation was 13+ sequential database calls and took 3-5 seconds. I collapsed it into one atomic Postgres RPC function. Save time dropped to under a second.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons from building solo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ship the core loop first.&lt;/strong&gt; I built belts, weekly challenges, streak tracking, and an admin dashboard before anyone had used the app. The only thing that mattered early was: show chart, get input, replay result. Everything else could have waited.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distribution is a separate problem from building.&lt;/strong&gt; I had zero audience when I launched. The product could have been ready months earlier if I'd started building in public from day one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Talk to users before you assume.&lt;/strong&gt; I built difficulty balancing based on gut feel. Five minutes of watching someone use the app would have shown me the problem immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I'm working on adding SPY and ES/NQ futures (the trading community asked for these), a badge system, and figuring out monetization. Right now it's completely free.&lt;/p&gt;

&lt;p&gt;If you trade, or you're curious about how the chart rendering or scenario generation works, I'm happy to go deeper on any of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://candledojo.app/play" rel="noopener noreferrer"&gt;Try it here - no sign-up needed&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>ai</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
