<?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: Tabor Bachelor</title>
    <description>The latest articles on DEV Community by Tabor Bachelor (@taborbachelor).</description>
    <link>https://dev.to/taborbachelor</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%2F4011099%2F007f08c4-6a23-4037-8f4f-4427845a824f.jpg</url>
      <title>DEV Community: Tabor Bachelor</title>
      <link>https://dev.to/taborbachelor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/taborbachelor"/>
    <language>en</language>
    <item>
      <title>The Free Scan Everyone Can Try (And Almost Nobody Can Break)</title>
      <dc:creator>Tabor Bachelor</dc:creator>
      <pubDate>Thu, 09 Jul 2026 17:14:48 +0000</pubDate>
      <link>https://dev.to/taborbachelor/the-free-scan-everyone-can-try-and-almost-nobody-can-break-5el5</link>
      <guid>https://dev.to/taborbachelor/the-free-scan-everyone-can-try-and-almost-nobody-can-break-5el5</guid>
      <description>&lt;p&gt;A free tool with no signup wall is the best acquisition lever you can build and the easiest thing on the internet to abuse, and those two facts show up at exactly the same time.&lt;/p&gt;

&lt;p&gt;Relevyn's public audit — type in a brand and a website, get a free AI-visibility check, no account required — exists specifically to remove friction. Every bit of friction we didn't add is also a door we didn't lock. Somewhere between "anyone can try this instantly" and "anyone can script a few thousand requests against our LLM bill overnight" is a line we had to actually draw, not just hope nobody would find.&lt;/p&gt;

&lt;h2&gt;
  
  
  One limit isn't enough
&lt;/h2&gt;

&lt;p&gt;The naive fix is a single cap — say, five free audits per IP address per day. That stops one visitor from hammering the endpoint. It does nothing about distributed abuse: a hundred different IPs, each politely staying under the per-IP limit, adding up to a very real bill with zero revenue behind any of it.&lt;/p&gt;

&lt;p&gt;The other naive fix is a single global ceiling — the whole system accepts, say, a few hundred free audits a day, full stop. That protects the budget, but it has a different failure mode: one aggressive actor (or one bad script) can burn through the entire day's allowance before a single genuine visitor gets a turn.&lt;/p&gt;

&lt;p&gt;Neither limit alone covers both failure modes. You need both, layered.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two layers, and what each one is actually for
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;global daily ceiling&lt;/strong&gt; is the backstop against catastrophic, system-wide abuse — a hard number the whole free tier can't exceed in a day, regardless of where the requests are coming from. It's blunt on purpose. It's not there to catch normal usage; it's there so a worst-case script kiddie or scraping run can't turn a growth lever into an unbounded bill.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;per-IP cap&lt;/strong&gt; is the finer-grained rule underneath it — a handful of free tries per address per day, generous enough that a real visitor can check their own brand and maybe a competitor's without hitting a wall, tight enough that scripting requests from one machine stops being worth the trouble.&lt;/p&gt;

&lt;p&gt;Together they cover the two shapes abuse actually takes: concentrated (one IP, many requests) and distributed (many IPs, few requests each). Either limit alone leaves the other door open.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number is a guess, and that's fine
&lt;/h2&gt;

&lt;p&gt;Here's the part that surprised me more than the architecture: there's no formula that tells you the "correct" per-IP number or the "correct" global ceiling. Five audits a day per IP is a bet about where a genuinely curious visitor stops and a script starts — informed by nothing but intuition on day one, because there's no real traffic yet to learn from.&lt;/p&gt;

&lt;p&gt;That's the actual lesson. Rate limits aren't a constant you set once during setup and forget. They're a hypothesis you write down, ship, and revisit once real usage tells you whether you guessed too tight or too loose. Anyone waiting to "figure out the right number" before shipping a free tool is waiting for information that only exists after you ship it.&lt;/p&gt;

&lt;p&gt;Try the free audit yourself, limits and all: &lt;a href="https://relevyn.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=ratelimiting" rel="noopener noreferrer"&gt;relevyn.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>startup</category>
      <category>productivity</category>
    </item>
    <item>
      <title>ChatGPT Has a Very Specific Way of Saying "I've Never Heard of You"</title>
      <dc:creator>Tabor Bachelor</dc:creator>
      <pubDate>Tue, 07 Jul 2026 15:51:33 +0000</pubDate>
      <link>https://dev.to/taborbachelor/chatgpt-has-a-very-specific-way-of-saying-ive-never-heard-of-you-4313</link>
      <guid>https://dev.to/taborbachelor/chatgpt-has-a-very-specific-way-of-saying-ive-never-heard-of-you-4313</guid>
      <description>&lt;p&gt;Ask ChatGPT about a brand it doesn't know, and something interesting happens. It doesn't hallucinate a confident answer. It doesn't go quiet. It reaches for a small, strangely consistent set of phrases — "I don't have information about," "I'm not familiar with," "I couldn't find" — and hands you a polite, hedged admission that you don't exist in its world.&lt;/p&gt;

&lt;p&gt;We noticed this by accident, building the detection logic behind Relevyn's scans, and it's stuck with me since, because it means AI invisibility isn't one problem. It's at least two, and they need completely different fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Low visibility and zero visibility are not the same failure
&lt;/h2&gt;

&lt;p&gt;Most people picture "AI doesn't know my brand" as a ranking problem — you exist, you're just buried under bigger competitors, the same mental model as page two of Google. Sometimes that's exactly right. The model knows you, mentions a rival first, and the fix looks like the fix you already understand: sharper positioning, better content, more authoritative sources talking about you.&lt;/p&gt;

&lt;p&gt;But the negative-acknowledgment pattern is a different failure entirely. It's not "ranked low." It's "absent from the space of things that exist." No amount of positioning fixes that, because positioning assumes you're already in the running. You have to get into the model's knowledge at all before you can worry about where you land in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the model hedges instead of guessing
&lt;/h2&gt;

&lt;p&gt;Give this some credit before treating it as purely bad news: the alternative behavior is worse. A model that confidently invents plausible-sounding details about a brand it's never encountered is a much bigger problem than one that admits it doesn't know. The hedge is, in a real sense, the model behaving responsibly.&lt;/p&gt;

&lt;p&gt;It just happens to be the starkest possible signal for the brand on the receiving end. "You rank fourth" is disappointing. "I don't have information about you" is a different category of finding, and it doesn't show up anywhere in a normal SEO report, because Google rankings and what a language model actually learned during training are not the same dataset. You can rank respectably on page one and still be a genuine unknown to the model that a growing number of people are asking instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that should worry established brands more than new ones
&lt;/h2&gt;

&lt;p&gt;New companies expect this. It's almost reassuring — of course a six-month-old startup hasn't been absorbed into a model's training data yet. The uncomfortable version is the established brand, the one with a decade of SEO work and a real customer base, that runs this check for the first time and hits the exact same hedge language a brand-new competitor would get. Being real and being known are supposed to be the same thing. Increasingly, they're a testable, sometimes surprising gap.&lt;/p&gt;

&lt;p&gt;If you're curious which side of that gap you're on: &lt;a href="https://relevyn.com" rel="noopener noreferrer"&gt;relevyn.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>startup</category>
      <category>software</category>
    </item>
    <item>
      <title>The Tool We Built to Measure AI Visibility Couldn't Find Itself</title>
      <dc:creator>Tabor Bachelor</dc:creator>
      <pubDate>Fri, 03 Jul 2026 23:54:12 +0000</pubDate>
      <link>https://dev.to/taborbachelor/the-tool-we-built-to-measure-ai-visibility-couldnt-find-itself-4d28</link>
      <guid>https://dev.to/taborbachelor/the-tool-we-built-to-measure-ai-visibility-couldnt-find-itself-4d28</guid>
      <description>&lt;p&gt;Two weeks before we launched Relevyn, I opened ChatGPT and asked it a question I already thought I knew the answer to.&lt;/p&gt;

&lt;p&gt;We'd spent months building a tool that scores how visible a brand is across ChatGPT, Claude, Perplexity, and Gemini — whether AI recommends you when someone asks for the best option in your category. So naturally, I asked it about us. Not expecting much; we were two people, pre-launch, with no reputation yet. A footnote, maybe, buried under a few established competitors.&lt;/p&gt;

&lt;p&gt;There was no footnote. There was nothing. Across every engine I tried, the same absence.&lt;/p&gt;

&lt;p&gt;I want to be honest about what that felt like, because it wasn't just "oh, expected, we're new." It was closer to vertigo — the specific, disorienting kind that comes from building the exact instrument that measures a problem and then discovering the needle points at you. We weren't checking a hypothetical. We were staring at our own blind spot, using the tool built to find other people's.&lt;/p&gt;

&lt;p&gt;Here's the part that actually matters, past the irony: every brand that's run a scan on Relevyn since has described some version of that same jolt. Not usually a flat zero — most established companies show up somewhere. But "somewhere" is often thinner, later, or less favorably framed than they assumed, and there's a specific kind of quiet dread in seeing that in black and white after years of assuming "we rank fine on Google" meant "we exist everywhere that matters now." Those used to be the same sentence. They aren't anymore, and almost nobody has actually checked.&lt;/p&gt;

&lt;p&gt;I've gone back and forth on whether admitting our own invisibility undercuts the pitch. Part of me wants to only ever show the after — the version where a scan nails the problem, hands over a clear fix list, and everyone looks great. But the before is the more honest reason to trust any of this. We're not selling a fear we invented in order to sell the fix. We felt the specific, small panic of asking an AI model who the best option was and hearing silence where our name should have been. Then we built the thing that tells you whether that's happening to you, before a customer finds out for you.&lt;/p&gt;

&lt;p&gt;The uncomfortable truth underneath all of this: AI-generated answers are quietly becoming the first, sometimes only, place people evaluate a brand before ever visiting its website. Nobody sees when they lose that evaluation. There's no bounce you can track, no abandoned cart, no failed pageview — just a customer who asked a question, got an answer that didn't include you, and moved on to whoever it did include. You don't get a notification. You just don't get the customer.&lt;/p&gt;

&lt;p&gt;We're still closing that gap for ourselves, same as anyone else running a scan for the first time today. If you want to see where you actually stand: &lt;a href="https://relevyn.com" rel="noopener noreferrer"&gt;relevyn.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>analytics</category>
      <category>seo</category>
      <category>startup</category>
    </item>
    <item>
      <title>A Score Nobody Can Act On Is Just Anxiety: Building Relevyn's "What To Fix" Engine</title>
      <dc:creator>Tabor Bachelor</dc:creator>
      <pubDate>Thu, 02 Jul 2026 19:40:23 +0000</pubDate>
      <link>https://dev.to/taborbachelor/a-score-nobody-can-act-on-is-just-anxiety-building-relevyns-what-to-fix-engine-5gk3</link>
      <guid>https://dev.to/taborbachelor/a-score-nobody-can-act-on-is-just-anxiety-building-relevyns-what-to-fix-engine-5gk3</guid>
      <description>&lt;p&gt;Last time I wrote about querying four different LLMs to measure whether a brand shows up when someone asks AI for a recommendation. That's the easy half of the problem. The harder half: once you know you're invisible, what do you actually do about it?&lt;/p&gt;

&lt;p&gt;A score with no next step is just a source of dread. So the engine underneath Relevyn's "Fix This Week" panel turned out to be more interesting to build than the scanner — and it broke in more interesting ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model selection is a latency problem before it's a quality problem
&lt;/h2&gt;

&lt;p&gt;The obvious move: throw the same big model at everything. We started generating each of the three "Fix This Week" content briefs with a larger reasoning model, since it writes better structured recommendations than a smaller one. It also routinely blew past our serverless function's timeout window generating three of them back to back.&lt;/p&gt;

&lt;p&gt;Swapping the brief-generation step to a faster, cheaper model fixed the timeouts immediately, and the quality difference didn't actually matter at that stage — a brief is a short, structured recommendation, not the finished asset. We kept the larger model for the one place quality is load-bearing: the actual 700–900 word draft a user downloads and publishes. Not every step in a pipeline deserves the same model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Truncated JSON doesn't look like an error. It looks like a crash.
&lt;/h2&gt;

&lt;p&gt;Content briefs come back as structured JSON so the frontend can render them into cards. Early on we set a conservative token limit to keep costs down — and started seeing intermittent parsing failures that looked like backend bugs. They weren't. The model was running out of tokens mid-object, so the JSON just stopped, unparseable — closer to a hallucinated syntax error than an honest failure message.&lt;/p&gt;

&lt;p&gt;Two fixes: raise the ceiling enough that a full brief never gets cut off, and strip markdown code fences before parsing — because even when a prompt explicitly says "return raw JSON only," the model still wraps it in triple backticks a meaningful fraction of the time anyway. Defensive stripping is now the first line of every parser downstream of an LLM call in this codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-generate before anyone asks
&lt;/h2&gt;

&lt;p&gt;Waiting on three LLM calls the moment a user clicks "view plan" is a bad experience even when nothing goes wrong. So all three content briefs generate during the scan itself and get cached — by the time someone opens the panel, they're reading a stored result, not waiting on one. If the cache is somehow empty, on-demand generation is the fallback, not the default path.&lt;/p&gt;

&lt;p&gt;The pattern generalizes past this one feature: if you know a user is going to want something 90% of the time, generate it before they ask instead of after.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual point
&lt;/h2&gt;

&lt;p&gt;None of this is about AI writing your content for you. It's that "you're invisible to ChatGPT" is a useless sentence on its own. The only version of this worth building is one that ends in a specific paragraph you could publish this afternoon.&lt;/p&gt;

&lt;p&gt;Free to check where you stand: &lt;a href="https://relevyn.com" rel="noopener noreferrer"&gt;relevyn.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>seo</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>ChatGPT Might Be Recommending Your Competitor, Not You — Here's How We Built a Tool to Check</title>
      <dc:creator>Tabor Bachelor</dc:creator>
      <pubDate>Wed, 01 Jul 2026 15:36:43 +0000</pubDate>
      <link>https://dev.to/taborbachelor/chatgpt-might-be-recommending-your-competitor-not-you-heres-how-we-built-a-tool-to-check-5bd</link>
      <guid>https://dev.to/taborbachelor/chatgpt-might-be-recommending-your-competitor-not-you-heres-how-we-built-a-tool-to-check-5bd</guid>
      <description>&lt;p&gt;Ask ChatGPT who the best project management tool is. Or the best CRM for startups. Or the best anything-in-your-category. It'll give you an answer — a specific one, with a specific brand in it. If yours isn't in that answer, you've lost a customer you never knew was in play.&lt;/p&gt;

&lt;p&gt;That's the problem I set out to measure with Relevyn: how visible is a brand across the AI engines that are quietly becoming the new front page of the internet — ChatGPT, Claude, Perplexity, and Gemini. Turns out, actually measuring that is a more interesting engineering problem than it sounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four APIs, four different ways to fail
&lt;/h2&gt;

&lt;p&gt;The obvious approach: send the same prompt to all four engines, see who gets mentioned. The reality is each provider fails differently, on its own schedule.&lt;/p&gt;

&lt;p&gt;Early versions ran everything in parallel with &lt;code&gt;Promise.all&lt;/code&gt; — which meant one slow or erroring engine took the entire scan down with it. Swapping to &lt;code&gt;Promise.allSettled&lt;/code&gt; fixed that: if Perplexity times out, you still get results from the other three instead of nothing.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allSettled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;engines&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;engine&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;callEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;engine&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each engine call also gets its own retry logic (3 attempts, short backoff on a 503) and its own timeout, raced against the clock so one hung request doesn't stall the whole scan. Even with that, we had to drop from 6 prompts per scan down to 3, run sequentially instead of one big parallel burst — the combined latency of 4 engines × 6 prompts kept tripping serverless function timeouts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scoring text without paying another LLM to judge it
&lt;/h2&gt;

&lt;p&gt;The tempting move here is to hand each response to an LLM and ask "was the brand mentioned, and was it positive?" We deliberately didn't do that for the core detection — it's slower, non-deterministic, and adds cost to something that needs to run thousands of times a day.&lt;/p&gt;

&lt;p&gt;Instead: plain detection logic on the raw text. Is the brand name present. Where in the response does it first appear. Which sentences mention it, and do those sentences skew toward positive or negative language. Are competitor names present in the same response. It's less elegant than "ask an AI to grade the AI," but it's fast, free, and gives the same input the same score every time — which matters when you're about to tell someone their score changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a scan actually costs
&lt;/h2&gt;

&lt;p&gt;Running real queries against four commercial LLM APIs at scale isn't free, but it's cheaper than you'd think if you're deliberate about it: a full multi-engine scan costs somewhere in the $0.06–0.09 range, mixing cheaper models for high-volume detection work against pricier ones only where reasoning quality actually matters for the output. The expensive mistake we made early on was leaving prompt caching headers on for a low-volume beta — they added latency and occasional 503s with no caching benefit at that traffic level. Removing them fixed more reliability issues than any retry logic did.&lt;/p&gt;

&lt;h2&gt;
  
  
  The finding that changed how we think about this
&lt;/h2&gt;

&lt;p&gt;Run the exact same query against the exact same brand two weeks apart and you will not get the exact same answer. These models aren't static lookups — they're generating an answer fresh each time, shaped by whatever's changed in their training and retrieval since the last time you asked.&lt;/p&gt;

&lt;p&gt;Which means a one-time "AI visibility audit" tells you almost nothing. It's a photograph of a moving target. The only thing that's actually useful is watching the trend — which is the entire reason Relevyn runs as a monitor, not a single report.&lt;/p&gt;

&lt;p&gt;If you want to see where your own brand lands, the scan's free: &lt;a href="https://relevyn.com" rel="noopener noreferrer"&gt;relevyn.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>saas</category>
      <category>webdev</category>
      <category>buildinpublic</category>
    </item>
  </channel>
</rss>
