<?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: Devin D</title>
    <description>The latest articles on DEV Community by Devin D (@devin_daymore).</description>
    <link>https://dev.to/devin_daymore</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%2F3980721%2F2e97da6e-0a43-447a-b18a-25a49a046dc5.jpg</url>
      <title>DEV Community: Devin D</title>
      <link>https://dev.to/devin_daymore</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devin_daymore"/>
    <language>en</language>
    <item>
      <title>Show HN, Product Hunt and BetaList before launch: what each one accepts</title>
      <dc:creator>Devin D</dc:creator>
      <pubDate>Wed, 14 Oct 2026 14:52:05 +0000</pubDate>
      <link>https://dev.to/devin_daymore/show-hn-product-hunt-and-betalist-before-launch-what-each-one-accepts-1f65</link>
      <guid>https://dev.to/devin_daymore/show-hn-product-hunt-and-betalist-before-launch-what-each-one-accepts-1f65</guid>
      <description>&lt;p&gt;A common plan for launching a side project: put up a waitlist page, post it to Show HN, Product Hunt and BetaList, and let the signups come in. Two of those three have rules that get in the way before launch, and the third changed how pre-launch works in 2025.&lt;/p&gt;

&lt;p&gt;I make a waitlist tool, &lt;a href="https://waitlister.me/" rel="noopener noreferrer"&gt;Waitlister&lt;/a&gt;, and one of the rules below applies to pages built with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show HN: wait until there's something to try
&lt;/h2&gt;

&lt;p&gt;Show HN is for things people can try. The &lt;a href="https://news.ycombinator.com/showhn.html" rel="noopener noreferrer"&gt;Show HN guidelines&lt;/a&gt; list sign-up pages as off-topic, and a waitlist page is a sign-up page. Hold the post until people can use what you built.&lt;/p&gt;

&lt;h2&gt;
  
  
  Product Hunt: Coming Soon pages are gone, so schedule instead
&lt;/h2&gt;

&lt;p&gt;Product Hunt retired its "Coming Soon" pages on August 28, 2025, so older launch guides that tell you to set one up are out of date. What you can do now is schedule the launch up to 30 days ahead. People can follow the product and get notified when it goes live.&lt;/p&gt;

&lt;p&gt;Launches tend to go better with supporters who already know it's coming. So Product Hunt amplifies a list you already have, and it fits near the end of pre-launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  BetaList: your own domain, and a page that doesn't look like a template
&lt;/h2&gt;

&lt;p&gt;BetaList features startups that haven't launched yet, so it's the one of the three where a waitlist page fits. It asks for a custom-designed landing page with a signup form on your own domain, and it turns down template pages and free subdomains.&lt;/p&gt;

&lt;p&gt;This is the rule that applies to Waitlister pages. A hosted waitlist page on the tool's own domain (on Waitlister that's waitlister.me/p/your-page) won't qualify: BetaList requires your own domain, and its guidelines also turn down pages hosted by landing-page services. The route that fits is a page you design on your own domain, with the signup form embedded in it. On Waitlister, the embeddable form is on every plan, including free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before you qualify for any of them
&lt;/h2&gt;

&lt;p&gt;All three do more when people are already paying attention. Getting that attention costs time more than money, and three things work with no audience:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write to people who have the problem, one message per person.&lt;/strong&gt; Ask what they make of the problem before you bring up the waitlist. Some will join, and the replies tell you whether the problem bothers them as much as it bothers you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Answer questions where your future users ask for help&lt;/strong&gt;, often a subreddit or a forum for their trade. Read the rules first, since many communities restrict self-promotion, especially from new accounts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get featured where your users already read or listen.&lt;/strong&gt; A niche newsletter whose readers are mostly your kind of user usually does more than a big general one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your users are developers, building in public fits too, though the following grows slowly, over months. Build-in-public posts mostly reach other builders. That's the right crowd for a developer tool, and a weak one for, say, scheduling software for dentists.&lt;/p&gt;

&lt;p&gt;I wrote up twelve pre-launch strategies, sorted by how much audience each one needs, here: &lt;a href="https://waitlister.me/growth-hub/guides/pre-launch-marketing-strategies?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Pre-launch marketing strategies, sorted by audience&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>product</category>
      <category>startup</category>
    </item>
    <item>
      <title>Waitlist referral rewards: points, webhooks, and not paying self-referrers</title>
      <dc:creator>Devin D</dc:creator>
      <pubDate>Sat, 26 Sep 2026 17:55:33 +0000</pubDate>
      <link>https://dev.to/devin_daymore/waitlist-referral-rewards-points-webhooks-and-not-paying-self-referrers-9c7</link>
      <guid>https://dev.to/devin_daymore/waitlist-referral-rewards-points-webhooks-and-not-paying-self-referrers-9c7</guid>
      <description>&lt;p&gt;I make &lt;a href="https://waitlister.me/" rel="noopener noreferrer"&gt;Waitlister&lt;/a&gt;, a waitlist tool, so the examples here use it. The design carries over to most referral waitlists.&lt;/p&gt;

&lt;p&gt;A referral waitlist fits in one sentence: every subscriber gets a unique link, a signup through that link earns the referrer points, the list is ranked by points, and everyone can see their position. A waitlist tool can track all of that. The reward is where your own code usually comes in, because what you hand out, and when, is up to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why points
&lt;/h2&gt;

&lt;p&gt;A referral count measures one action. Points let you weight several. In Waitlister the defaults are 50 points for joining, 30 for a successful referral and 5 for following a social account from the thank-you page. You can change any of them, including to zero.&lt;/p&gt;

&lt;p&gt;Points also cover actions the tool can't see. On the Growth plan, the &lt;a href="https://waitlister.me/docs/api/endpoints/subscribers/update-subscriber" rel="noopener noreferrer"&gt;update subscriber endpoint&lt;/a&gt; can set a subscriber's points, so completing a survey, joining your Discord or testing a build can move someone up the list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rewards live in your backend
&lt;/h2&gt;

&lt;p&gt;The tool tracks points. Fulfillment, whether that's a discount code, beta access or a T-shirt, is yours. Two &lt;a href="https://waitlister.me/docs/webhooks" rel="noopener noreferrer"&gt;webhook events&lt;/a&gt; cover it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;waitlist.referral_completed&lt;/code&gt; fires when a referral is credited. The payload has the referrer (&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;points&lt;/code&gt;, &lt;code&gt;total_referrals&lt;/code&gt;) and &lt;code&gt;points_earned&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;waitlist.milestone_reached&lt;/code&gt; fires when a signup or a credited referral takes a subscriber's points across a threshold you configure. It carries &lt;code&gt;milestone.points&lt;/code&gt; and the subscriber's &lt;code&gt;previous_points&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Milestones are set in points. With the defaults, a reward at five referrals is a threshold of 200 points: 50 for joining plus 5 × 30, assuming the subscriber hasn't earned points any other way. Points set through the API or earned from a social follow don't trigger the milestone check, so if they carry someone past a threshold, that subscriber doesn't get the event for it. If you award points for custom actions, check thresholds in your own code too. For rewards tied to a referral count, &lt;code&gt;referral_completed&lt;/code&gt; already carries &lt;code&gt;total_referrals&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A minimal Express handler:&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;crypto&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="s1"&gt;crypto&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;express&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="s1"&gt;express&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;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Keep the raw body: the signature is computed over the exact bytes sent&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&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="na"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buf&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buf&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;isSigned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&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;secret&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;received&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Webhook-Signature&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="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;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="c1"&gt;// timingSafeEqual throws if the byte lengths differ, so check first&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;received&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;expected&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;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timingSafeEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;received&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&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="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/webhooks/waitlister&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="nf"&gt;isSigned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WAITLISTER_WEBHOOK_SECRET&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&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;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;event&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;waitlist.milestone_reached&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;// Pay each (subscriber, threshold) pair once, even if the event arrives again&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;grantRewardOnce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;milestone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&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;grantRewardOnce&lt;/code&gt; is yours to write: record each subscriber and threshold pair you pay out (a unique key on the pair stops two copies of one event from both paying), and queue anything slow, like emailing a code, so the handler responds quickly. A delivery times out after 15 seconds. Set a secret on the webhook so requests arrive signed; without one there's no signature header and this handler rejects everything. Webhooks are on the Growth plan; the referral program itself starts at Launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not paying self-referrers
&lt;/h2&gt;

&lt;p&gt;The obvious attack is one person, ten throwaway inboxes, and the top of the leaderboard. Waitlister scores each referred signup on device fingerprint, IP address, normalized email (Gmail dots and &lt;code&gt;+suffixes&lt;/code&gt; stripped) and how fast referrals arrive, and it checks against known disposable email domains. Signups you create through the API skip these checks unless you forward client signals: send the visitor's IP as &lt;code&gt;metadata.client_ip&lt;/code&gt; (it must be IPv4), plus a device &lt;code&gt;fingerprint&lt;/code&gt; if you have one. Without the visitor's IP, the IP Waitlister sees is your server's. The protection level runs from off to strict.&lt;/p&gt;

&lt;p&gt;From your code's side, a flagged referral looks like this. The new signup still joins the list. The referrer gets no points, no &lt;code&gt;referral_completed&lt;/code&gt; event fires, and no milestone gets crossed, so your reward code never sees it. Nothing tells the person gaming it why.&lt;/p&gt;

&lt;p&gt;Reward design still does more than detection. Rewards that pay out after a delay, or only to confirmed email addresses, remove most of the reason to cheat before anything has to be caught. With double opt-in on, a subscriber joins the list only after confirming their address.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which reward to run
&lt;/h2&gt;

&lt;p&gt;Pick the reward first, since everything above follows from it. A place in line needs no prize budget and works when getting in early is worth something by itself. A public leaderboard suits audiences who compete and share in public. Rewards at set thresholds work if the first one is easy to reach. A prize draw brings the most signups and the least qualified list. You can move between position and leaderboard later without resetting anything, because both run on the same points. Taking a prize away after people joined for it is the change to avoid.&lt;/p&gt;

&lt;p&gt;I wrote up the full setup, including the build order and what to put on the thank-you page, here: &lt;a href="https://waitlister.me/growth-hub/guides/how-to-build-a-viral-referral-program-for-your-waitlist?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;How to add a referral program to your waitlist&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>startup</category>
    </item>
    <item>
      <title>Adding a waitlist to your app: four ways to wire it up, and what breaks the first signup</title>
      <dc:creator>Devin D</dc:creator>
      <pubDate>Fri, 25 Sep 2026 11:51:24 +0000</pubDate>
      <link>https://dev.to/devin_daymore/adding-a-waitlist-to-your-app-four-ways-to-wire-it-up-and-what-breaks-the-first-signup-1h9k</link>
      <guid>https://dev.to/devin_daymore/adding-a-waitlist-to-your-app-four-ways-to-wire-it-up-and-what-breaks-the-first-signup-1h9k</guid>
      <description>&lt;p&gt;I make &lt;a href="https://waitlister.me/" rel="noopener noreferrer"&gt;Waitlister&lt;/a&gt;, a waitlist tool, so the examples here use it. The shape carries over to most tools.&lt;/p&gt;

&lt;p&gt;The signup part of a waitlist is small. The decision that matters is where the signup lives, because that decides how much code you write and what can go wrong on your first test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four options
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hosted page&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;no site yet, or you want something live today&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Embedded form&lt;/td&gt;
&lt;td&gt;a snippet or plugin&lt;/td&gt;
&lt;td&gt;an existing Framer, Webflow, WordPress or Shopify site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your own HTML form&lt;/td&gt;
&lt;td&gt;one form tag&lt;/td&gt;
&lt;td&gt;full control over markup and styling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API or SDK&lt;/td&gt;
&lt;td&gt;a few lines&lt;/td&gt;
&lt;td&gt;signup inside your app, or a custom flow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your site already gets traffic, put the signup there. If the site doesn't exist yet, a hosted page gets you live fastest. The last two are the ones that involve code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your own HTML form
&lt;/h2&gt;

&lt;p&gt;Any form can post straight to the waitlist:&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;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://waitlister.me/s/YOUR_WAITLIST_KEY"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"you@example.com"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Join the waitlist&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On submit, the subscriber is redirected to a hosted thank-you page with their queue position and a referral link, so you don't have to build one.&lt;/p&gt;

&lt;p&gt;Before you test it, add your site's domain to the waitlist's whitelisted domains (waitlist → Settings). Until you do, the endpoint rejects submissions from that site with a 403.&lt;/p&gt;

&lt;p&gt;Waitlister's CAPTCHA doesn't cover a form you built yourself, so bot protection on this route is yours to handle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The API or SDK
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;waitlister
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;Waitlister&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;waitlister&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Server-side only: the key must not reach the browser&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wl&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;Waitlister&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;accountKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wl_acct_…&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;waitlistKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_WAITLIST_KEY&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;result&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;wl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signUp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;email&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@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// result.position, result.referral_code, result.redirect_url&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two kinds of key, and the difference matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Account API keys&lt;/strong&gt; (&lt;code&gt;wl_acct_…&lt;/code&gt;, Settings → API keys) work on every plan, including free, with lower rate limits on the smaller plans. One key covers every waitlist you own, and it can also create waitlists (up to your plan's waitlist limit), which is handy in setup scripts and agent workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-waitlist keys&lt;/strong&gt; (passed as &lt;code&gt;apiKey&lt;/code&gt;) need the Growth plan, and so does reading or changing subscriber records over the API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a plan without access, the SDK throws a typed &lt;code&gt;PlanError&lt;/code&gt; instead of failing silently. If you'd rather not handle a key at all, &lt;code&gt;signUpViaForm&lt;/code&gt; from the same package posts to the public form endpoint and gives you the hosted thank-you page URL to redirect to. The full schema is in the &lt;a href="https://waitlister.me/openapi.json" rel="noopener noreferrer"&gt;OpenAPI spec&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What breaks the first test signup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The domain isn't whitelisted&lt;/strong&gt; (HTML form route): submissions return 403 until it is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You tested with a fake address.&lt;/strong&gt; Waitlister validates deliverability at signup, so &lt;code&gt;test@example.com&lt;/code&gt; is rejected. Use a real address you control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You re-tested with the same address.&lt;/strong&gt; Signing up again with an address that's already on the list doesn't create a new signup, so no welcome email goes out. Delete the first signup on the Submissions page, or use a different address (a &lt;code&gt;+alias&lt;/code&gt; works).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The part that isn't code
&lt;/h2&gt;

&lt;p&gt;Getting the signup, thank-you page and welcome email working fits in an afternoon. Whether the list turns into customers depends on two things no SDK handles.&lt;/p&gt;

&lt;p&gt;The first is where visitors come from. Subscribers = visitors × the share who sign up, so if you want 300 people and one visitor in five signs up, you need 1,500 visitors. (That rate is made up for the arithmetic; use your own once you have some traffic.) Plan where those visitors will come from before you polish the page.&lt;/p&gt;

&lt;p&gt;The second is what you send people while they wait. Set up the welcome email before any traffic arrives and send a short update every week or two, or the list tends to go cold before launch day.&lt;/p&gt;

&lt;p&gt;I wrote up the whole process, including the welcome email I'd use and how to protect the list from fake signups, here: &lt;a href="https://waitlister.me/growth-hub/guides/how-to-create-a-waitlist?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;How to create a waitlist, step by step&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>startup</category>
    </item>
    <item>
      <title>GEO vs SEO: what changed, what didn't, and two checks to run today</title>
      <dc:creator>Devin D</dc:creator>
      <pubDate>Fri, 25 Sep 2026 09:19:45 +0000</pubDate>
      <link>https://dev.to/devin_daymore/geo-vs-seo-what-changed-what-didnt-and-two-checks-to-run-today-3848</link>
      <guid>https://dev.to/devin_daymore/geo-vs-seo-what-changed-what-didnt-and-two-checks-to-run-today-3848</guid>
      <description>&lt;p&gt;GEO vs SEO comes down to where you show up. SEO gets your page ranked in a list of links. GEO, short for generative engine optimization, gets your brand named or your page cited inside an answer that an AI system writes, such as Google's AI Overviews or ChatGPT. GEO builds on SEO and doesn't replace it. Most of the work is shared, and a few parts are new.&lt;/p&gt;

&lt;p&gt;Search "geo vs seo" on Google and you'll likely see an AI Overview before the first link. When I checked on 18 September 2026 (US, desktop), it cited 12 pages. Six of them ranked outside the top ten, and three weren't in the top 19. That's one check on one day, and overviews vary, but it matches the larger studies below.&lt;/p&gt;

&lt;p&gt;The pages that rank for this search agree on the verdict: you need both. I agree. They skip the harder question of which GEO advice has evidence behind it, so this guide spends its time there.&lt;/p&gt;

&lt;h2&gt;
  
  
  GEO vs SEO: the differences at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;SEO&lt;/th&gt;
&lt;th&gt;GEO&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where you appear&lt;/td&gt;
&lt;td&gt;A ranked list of links&lt;/td&gt;
&lt;td&gt;Inside a written answer, as a named brand or a cited source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What gets chosen&lt;/td&gt;
&lt;td&gt;A page&lt;/td&gt;
&lt;td&gt;A passage from a page, plus brand names gathered from many pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What builds authority&lt;/td&gt;
&lt;td&gt;Links to your site&lt;/td&gt;
&lt;td&gt;Mentions of your brand across the web, linked or not. So far that's a correlation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What the query looks like&lt;/td&gt;
&lt;td&gt;A few keywords&lt;/td&gt;
&lt;td&gt;A full question, which the engine splits into several searches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who fetches your pages&lt;/td&gt;
&lt;td&gt;Googlebot, which runs JavaScript&lt;/td&gt;
&lt;td&gt;Googlebot for Google's AI features, plus AI crawlers such as OAI-SearchBot and PerplexityBot, which mostly don't&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where it searches&lt;/td&gt;
&lt;td&gt;Google's index&lt;/td&gt;
&lt;td&gt;It depends on the assistant: Google's index for AI Overviews and AI Mode, other search backends for ChatGPT, Perplexity and Claude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How you measure it&lt;/td&gt;
&lt;td&gt;A position that mostly holds between checks&lt;/td&gt;
&lt;td&gt;A rate across repeated runs, because one prompt gives different answers each time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  GEO vs SEO vs AEO: what the acronyms mean
&lt;/h2&gt;

&lt;p&gt;Four terms cover most of what you'll read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SEO&lt;/strong&gt;, search engine optimization: ranking pages in a list of results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GEO&lt;/strong&gt;, generative engine optimization: getting into answers that an AI system writes from several sources. It's the academic term, from a research paper covered below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AEO&lt;/strong&gt;, answer engine optimization: being the direct answer on any surface that gives one. It was in use by 2018, when it meant voice assistants and featured snippets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLMO&lt;/strong&gt;, large language model optimization: shaping how the model itself describes your brand, including what it absorbed in training and repeats without searching.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll also see AIO, which usually means Google's AI Overviews and sometimes means "AI optimization".&lt;/p&gt;

&lt;p&gt;The terms overlap. &lt;a href="https://en.wikipedia.org/w/index.php?title=Generative_engine_optimization&amp;amp;oldid=1372428726" rel="noopener noreferrer"&gt;Wikipedia's GEO article&lt;/a&gt; says no consensus definition distinguishing them had been established in the academic literature as of early 2026, and that they're used interchangeably in practice. Its "answer engine optimization" page now redirects to the GEO article. In this guide, GEO means the whole job: getting named and cited in AI answers.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Mentions count for more than links
&lt;/h3&gt;

&lt;p&gt;Ahrefs &lt;a href="https://ahrefs.com/blog/ai-overview-brand-correlation/" rel="noopener noreferrer"&gt;studied 75,000 brands&lt;/a&gt; in May 2025 to see what goes along with being named in AI Overviews. Branded web mentions had a correlation of 0.664 with AI Overview visibility, where 1 would be a perfect match. Backlinks had 0.218. A mention counted whether or not it carried a link.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://ahrefs.com/blog/ai-brand-visibility-correlations/" rel="noopener noreferrer"&gt;December 2025 follow-up&lt;/a&gt; added ChatGPT and AI Mode and found the same pattern: web mentions between 0.66 and 0.71, mentions on YouTube strongest at about 0.74, and link metrics "very weak".&lt;/p&gt;

&lt;p&gt;Ahrefs flags the limit itself: correlation isn't causation. Well-known brands collect both mentions and AI visibility. Still, the pattern makes sense: an AI system reads many pages and summarises them, so what those pages say about you counts for more than which of them link to you.&lt;/p&gt;

&lt;h3&gt;
  
  
  One question becomes several searches
&lt;/h3&gt;

&lt;p&gt;Google calls it &lt;a href="https://blog.google/products-and-platforms/products/search/google-search-ai-mode-update/" rel="noopener noreferrer"&gt;query fan-out&lt;/a&gt;: AI Mode breaks your question into subtopics and runs many searches at once on your behalf. Your page can be cited for a sub-question nobody typed.&lt;/p&gt;

&lt;p&gt;So ranking for the main keyword matters less than it did. In July 2025, Ahrefs found that &lt;a href="https://ahrefs.com/blog/search-rankings-ai-citations/" rel="noopener noreferrer"&gt;76% of the pages cited in AI Overviews&lt;/a&gt; ranked in Google's top 10 for the same query. Its &lt;a href="https://ahrefs.com/blog/ai-overview-citations-top-10/" rel="noopener noreferrer"&gt;March 2026 re-run&lt;/a&gt; found 38%, with 31% of cited pages ranking outside the top 100.&lt;/p&gt;

&lt;p&gt;Between the two studies, Ahrefs improved its citation tracking and AI Overviews moved to Gemini 3, so don't read the drop as exact. Ahrefs' read is that AI Overviews now lean less on the results for the query itself and more on the results for the fan-out queries. That argues for covering a topic's follow-up questions on one solid page over building one thin page per keyword.&lt;/p&gt;

&lt;h3&gt;
  
  
  Most AI crawlers don't run JavaScript
&lt;/h3&gt;

&lt;p&gt;Vercel and MERJ &lt;a href="https://vercel.com/blog/the-rise-of-the-ai-crawler" rel="noopener noreferrer"&gt;analysed crawler traffic across Vercel's network&lt;/a&gt; in December 2024. None of the major AI crawlers rendered JavaScript, and that included the crawlers from OpenAI, Anthropic, Meta, ByteDance and Perplexity. Googlebot does render pages.&lt;/p&gt;

&lt;p&gt;So if your content only appears after JavaScript runs, Google sees your page and ChatGPT may see an empty shell. Nothing errors and your Google rankings don't move, so you won't notice unless you look. The study is nearly two years old and covers one network, but I haven't seen newer data that contradicts it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Each assistant searches somewhere different
&lt;/h3&gt;

&lt;p&gt;A good Google ranking doesn't carry over to the other assistants on its own. AI Overviews and AI Mode draw on Google's index. ChatGPT search has its own crawler, OAI-SearchBot. When Seer Interactive &lt;a href="https://www.seerinteractive.com/insights/87-percent-of-searchgpt-citations-match-bings-top-results" rel="noopener noreferrer"&gt;compared ChatGPT search citations with search results&lt;/a&gt; in February 2025, 87% matched a page in Bing's top 20 for the same question, and 56% matched Google. Seer calls its 100-query sample directional. Perplexity runs its own crawler as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Answers change from run to run
&lt;/h3&gt;

&lt;p&gt;Ask an AI system the same question twice and you can get two different sets of brands. So being named in an answer is a rate: across 30 runs, you appear in some share of them. A result should read like &lt;code&gt;32% (24–41%)&lt;/code&gt;, the share plus the range the sample supports.&lt;/p&gt;

&lt;p&gt;One run of one prompt tells you close to nothing. A single "visibility score" with no range hides that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What didn't change: Google says it's still SEO
&lt;/h2&gt;

&lt;p&gt;Google publishes a guide called &lt;a href="https://developers.google.com/search/docs/fundamentals/ai-optimization-guide" rel="noopener noreferrer"&gt;Optimizing your website for generative AI features on Google Search&lt;/a&gt;. It answers the GEO question in one sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From Google Search's perspective, optimizing for generative AI search is optimizing for the search experience, and thus still SEO.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The same guide lists things you can ignore for Google Search. One is llms.txt and similar special files, because "Google Search itself doesn't use them". Another is overfocusing on schema: structured data "isn't required for generative AI search, and there's no special schema.org markup you need to add."&lt;/p&gt;

&lt;p&gt;Google is speaking for Google Search only, which covers AI Overviews and AI Mode. ChatGPT, Perplexity and Claude find their sources in other ways, and most of the differences above come from there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is GEO replacing SEO?
&lt;/h2&gt;

&lt;p&gt;No. GEO depends on SEO. AI systems answer by running searches and reading what they find, so a page that search engines can't crawl, index and retrieve has little chance of being cited. GEO adds a short list of jobs that a classic SEO plan doesn't include.&lt;/p&gt;

&lt;p&gt;The skeptics are right about a lot. Much of what gets sold as GEO is technical SEO plus clear writing: direct answers, tables, FAQ sections. Good editorial teams have done that since featured snippets arrived, and a new acronym is a convenient way to sell it again.&lt;/p&gt;

&lt;p&gt;Three jobs are new, though:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checking that AI crawlers can reach and read your pages.&lt;/li&gt;
&lt;li&gt;Earning mentions on the pages that AI answers draw from, linked or not.&lt;/li&gt;
&lt;li&gt;Measuring with repeated prompt runs and ranges, since there's no stable position to track.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of your effort still belongs to SEO.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "up to 40%" statistic comes from a lab test
&lt;/h2&gt;

&lt;p&gt;One number keeps turning up in GEO pitches: GEO methods can "boost visibility by up to 40%". It comes from &lt;a href="https://arxiv.org/abs/2311.09735" rel="noopener noreferrer"&gt;the paper that coined the term&lt;/a&gt;, by researchers at IIT Delhi and Princeton, published at the KDD conference in 2024.&lt;/p&gt;

&lt;p&gt;The authors built their own answer engine. For each of 1,000 test queries, it took the top five Google results and had GPT-3.5 write an answer that cited them. GPT-3.5 then rewrote one of the five sources using one of nine methods, the engine answered again, and the authors measured how much more of the answer drew on the rewritten source.&lt;/p&gt;

&lt;p&gt;They report gains of 30 to 40% for their best methods: adding quotations, adding statistics and citing sources. The 40% is the single best case, quotations. Keyword stuffing offered "little to no improvement".&lt;/p&gt;

&lt;p&gt;Three reasons to hold the figure loosely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The engine was the authors' own. No live AI search product produced the headline number.&lt;/li&gt;
&lt;li&gt;Five sources competed for one answer, so a gain for one is a loss for the others, and relative gains look large.&lt;/li&gt;
&lt;li&gt;GPT-3.5 wrote the rewrites, and &lt;a href="https://github.com/GEO-optim/GEO/blob/4b78a82f0a3b5b0bc239ef803a4339ed3dcef39b/src/geo_functions.py" rel="noopener noreferrer"&gt;the prompts in the authors' published code&lt;/a&gt; let it invent what it added. The statistics prompt reads "Add positive, compelling statistics (even if hypothetical)". The test shows that text shaped like evidence gets cited more. It didn't compare real evidence with invented evidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authors also ran 200 queries through Perplexity, uploading the source texts as files because Perplexity wouldn't let them choose its sources. Quotations and statistics still helped there, and citing sources gave mixed results.&lt;/p&gt;

&lt;p&gt;The direction is worth keeping: pages with concrete, attributable facts were easier for a model to cite. So publish your real numbers. The 40% describes the authors' test setup and doesn't predict what you would gain.&lt;/p&gt;

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

&lt;p&gt;In order of certainty. The first two are pass or fail, and you can check both today.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Check that AI crawlers are allowed in
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;yoursite.com/robots.txt&lt;/code&gt; and look for rules naming &lt;code&gt;OAI-SearchBot&lt;/code&gt;, &lt;code&gt;ChatGPT-User&lt;/code&gt; or &lt;code&gt;PerplexityBot&lt;/code&gt;. OpenAI &lt;a href="https://developers.openai.com/api/docs/bots" rel="noopener noreferrer"&gt;documents its crawlers separately&lt;/a&gt;: &lt;code&gt;GPTBot&lt;/code&gt; collects content that may be used for training, and &lt;code&gt;OAI-SearchBot&lt;/code&gt; surfaces sites in ChatGPT's search results. A site that blocks the second one to stay out of training data has blocked the wrong bot. If you find a block you didn't intend, remove that rule.&lt;/p&gt;

&lt;p&gt;Then check your CDN or firewall. A bot rule there can refuse AI crawlers whatever robots.txt says. Cloudflare, for one, has &lt;a href="https://developers.cloudflare.com/bots/additional-configurations/block-ai-bots/" rel="noopener noreferrer"&gt;a setting that blocks AI bots&lt;/a&gt;, and it's easy to forget who switched it on.&lt;/p&gt;

&lt;p&gt;If you use Search Console, check one more switch. Since 31 August 2026 every property has a &lt;a href="https://support.google.com/webmasters/answer/16908024" rel="noopener noreferrer"&gt;Search generative AI control&lt;/a&gt;, and a site has to be included there to appear in Google's AI features. Include is the default. Confirm nobody changed it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Check that your content is in the raw HTML
&lt;/h3&gt;

&lt;p&gt;Open a key page, view its source (Ctrl+U, or Cmd+Option+U on a Mac) and search for a sentence you can see on the page. If the sentence isn't in the source, a crawler that doesn't run JavaScript can't see it either.&lt;/p&gt;

&lt;p&gt;For a number, run this in PowerShell. It ships with Windows. On macOS or Linux, install PowerShell and start it with &lt;code&gt;pwsh&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/pricing"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Invoke-WebRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Uri&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-UseBasicParsing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Content&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-replace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'(?s)&amp;lt;script.*?&amp;lt;/script&amp;gt;|&amp;lt;style.*?&amp;lt;/style&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-replace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;[^&amp;gt;]+&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-replace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'\s+'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"{0} characters of visible text in the raw HTML"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Length&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A full page returns thousands of characters. A few hundred, on a page that looks complete in your browser, means the content arrives by JavaScript. The fix is server-side rendering or static generation, and it comes before everything else on this list.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Keep doing SEO
&lt;/h3&gt;

&lt;p&gt;AI systems find their sources by searching, so being crawlable, indexed and useful still comes first.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Find the pages that answers cite, and get onto them
&lt;/h3&gt;

&lt;p&gt;Ask ChatGPT and Google the questions your buyers ask, several times each, and note which sources keep coming back. When I checked Google for 11 buying keywords in the software category I work in, in September 2026, one search each, 49 of the 84 citations in its AI Overviews went to pages owned by vendors in the category, and YouTube videos were cited in 8 of the 11 answers. Yours will differ, so look. The sources that keep coming back are your outreach list.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Write passages that can be lifted
&lt;/h3&gt;

&lt;p&gt;Put the question in a heading and answer it in the first two or three sentences underneath. Use real numbers, names and dates. Adding statistics is the part the GEO paper tested. The rest is ordinary good editing.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Measure with repeated runs
&lt;/h3&gt;

&lt;p&gt;Pick 20 to 50 questions your buyers ask. Run each one several times on each engine. Track how often you're named, as a rate with a range, and wait for a change bigger than the run-to-run noise before you credit any fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  What can wait
&lt;/h3&gt;

&lt;p&gt;Schema markup as an AI-citation tactic, and llms.txt. Google says neither is needed for its AI features. Keep schema for rich results, where it does work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two questions that come up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is SEO dead because of AI?
&lt;/h3&gt;

&lt;p&gt;No. Clicks do drop when an AI summary is on the page: Pew Research &lt;a href="https://www.pewresearch.org/short-reads/2025/07/22/google-users-are-less-likely-to-click-on-links-when-an-ai-summary-appears-in-the-results/" rel="noopener noreferrer"&gt;tracked 900 US adults in March 2025&lt;/a&gt; and found they clicked a search result on 8% of visits when an AI summary appeared, against 15% when it didn't. But AI answers are assembled from pages that search engines can crawl, index and retrieve. Most of the work that gets you found in search also gets you into the answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does schema markup or llms.txt help with GEO?
&lt;/h3&gt;

&lt;p&gt;For Google's AI features, Google says neither is needed: structured data "isn't required for generative AI search", and Google Search doesn't use llms.txt. When Ahrefs &lt;a href="https://ahrefs.com/blog/schema-ai-citations/" rel="noopener noreferrer"&gt;tracked 1,885 already-cited pages that added schema&lt;/a&gt;, their AI citations barely moved. Schema still earns rich results in classic search, so keep it for that. llms.txt is useful for pointing coding agents at developer documentation, which is a different job from search visibility.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>ai</category>
      <category>aeo</category>
    </item>
    <item>
      <title>I checked 15 AI search guides</title>
      <dc:creator>Devin D</dc:creator>
      <pubDate>Mon, 21 Sep 2026 11:05:34 +0000</pubDate>
      <link>https://dev.to/devin_daymore/i-checked-15-ai-search-guides-3174</link>
      <guid>https://dev.to/devin_daymore/i-checked-15-ai-search-guides-3174</guid>
      <description>&lt;p&gt;I searched Google for three things people ask about AI search: "llm seo", "ai visibility" and "how to rank in chatgpt". For each search I took the first five guides.&lt;/p&gt;

&lt;p&gt;We were writing guides on the same three topics for Shruwd (&lt;a href="https://shruwd.io/" rel="noopener noreferrer"&gt;https://shruwd.io/&lt;/a&gt;), the tool we are building, so I checked the 15 on a few points our own guides would cover.&lt;/p&gt;

&lt;p&gt;Four checks came out of it that you can run on any AI search guide before you act on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Is there a source behind the number?
&lt;/h2&gt;

&lt;p&gt;Each of the five "llm seo" guides recommends schema markup at least once. Two also say schema is on close to every page ChatGPT cites.&lt;br&gt;
Neither links a source.&lt;/p&gt;

&lt;p&gt;A matched study has tested if adding schema brings more citations to pages that already get some. Ahrefs followed 1,885 such pages as their owners added schema from August 2025 to March 2026, and compared them with 4,000 control pages. The effect on citations in ChatGPT and Google's AI Mode, in Ahrefs' words: "Statistically indistinguishable from zero."&lt;/p&gt;

&lt;p&gt;Even if the two guides are right, that alone wouldn't show if schema actually helps. Sites that look after their SEO usually add it, so it would turn up on cited pages either way.&lt;/p&gt;

&lt;p&gt;So I wouldn't put schema at the centre of an AI search plan on the strength of an unsourced number.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Does the number come with a range?
&lt;/h2&gt;

&lt;p&gt;Three of the five "ai visibility" guides recommend tracking a single visibility score, and none of the five shows a range for any number, or says how big a change has to be before you trust it.&lt;/p&gt;

&lt;p&gt;At the end of 2025, 600 volunteers ran 12 prompts through ChatGPT, Claude and Google's AI for a SparkToro and Gumshoe study, 2,961 runs in total. For ChatGPT and Google's AI, the authors put the chance of two responses naming the same list of brands at under 1 in 100.&lt;/p&gt;

&lt;p&gt;A number from one check can move a lot while nothing about your site changes. If you're named in 10 of 30 answers, the 95% range for your real rate is roughly 19% to 51%.&lt;/p&gt;

&lt;p&gt;Semrush's head of organic and AI visibility, Sergei Rogulin, writes that a share of voice "that swings between 20% and 40% over a day is normal". His advice is to report it with a margin.&lt;/p&gt;

&lt;p&gt;Before you react to a change in any AI visibility number, ask how many answers it came from. With 30, a swing of 10 points can be noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Does it cite the vendor's own documentation?
&lt;/h2&gt;

&lt;p&gt;One of the five "how to rank in chatgpt" guides links OpenAI's crawler documentation, and none of them tells you what to make of ChatGPT-User in your logs. OpenAi's page describes several crawlers and three are worth telling apart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OAI-SearchBot gathers pages for ChatGPT's search. Block it and your site "will not be shown in ChatGPT search answers, though can still appear as navigational links."&lt;/li&gt;
&lt;li&gt;ChatGPT-User visits a page on behalf of someone using ChatGPT. For that reason, OpenAI says robots.txt rules "may not apply" to it.&lt;/li&gt;
&lt;li&gt;GPTBot crawls content OpenAI may use to train its models, and OpenAI's page doesn't tie it to search.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My reading of a ChatGPT-User visit: someone using ChatGPT asked for something that needed that page, probably at that moment. That makes the visit one of the few traces a ChatGPT answer leaves in a server log.&lt;/p&gt;

&lt;p&gt;Two things to check on your own site:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A robots.txt rule meant for GPTBot shouldn't also block OAI-SearchBot.&lt;/li&gt;
&lt;li&gt;Before you count a ChatGPT-User visit check its IP against the ranges OpenAI publishes. Any request can call itself ChatGPT-User.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Is the check dated?
&lt;/h2&gt;

&lt;p&gt;AI answers can shift in weeks. In Semrush's tracking, the share of ChatGPT responses citing Reddit dropped from nearly six in ten in early August 2025 to about one in ten by mid September.&lt;br&gt;
A guide with no date on its checks gives you no way to tell whether they still hold.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits of this check
&lt;/h2&gt;

&lt;p&gt;This was one day (18 September 2026), three searches and 15 pages. I saved each page's HTML and searched its text for the points above, rather than reading each page in full. I wouldn't generalise from it.&lt;/p&gt;




&lt;p&gt;We wrote our own guides on the same three topics after these checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LLM SEO: &lt;a href="https://shruwd.io/blog/llm-seo" rel="noopener noreferrer"&gt;https://shruwd.io/blog/llm-seo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AI visibility: &lt;a href="https://shruwd.io/blog/ai-visibility" rel="noopener noreferrer"&gt;https://shruwd.io/blog/ai-visibility&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;How to rank in ChatGPT: &lt;a href="https://shruwd.io/blog/how-to-rank-in-chatgpt" rel="noopener noreferrer"&gt;https://shruwd.io/blog/how-to-rank-in-chatgpt&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>seo</category>
      <category>aeo</category>
    </item>
    <item>
      <title>Pre-launch waitlist tools in 2026: why I'd pick Waitlister, and when I wouldn't</title>
      <dc:creator>Devin D</dc:creator>
      <pubDate>Fri, 14 Aug 2026 14:50:09 +0000</pubDate>
      <link>https://dev.to/devin_daymore/pre-launch-waitlist-tools-in-2026-compared-3kp1</link>
      <guid>https://dev.to/devin_daymore/pre-launch-waitlist-tools-in-2026-compared-3kp1</guid>
      <description>&lt;p&gt;This is guide on selecting a waitlist tool for your pre-launch campaign. The prices and plan limits are all here too, so you can check my reasoning instead of taking my word for it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updated October 10, 2026. I re-checked every price below on the vendor's own page. Since the first version, LaunchList has moved to subscriptions and GrowSurf now has a free plan for affiliate programs, so parts of the old post were wrong.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Short version
&lt;/h2&gt;

&lt;p&gt;For most pre-launch founders, I'd pick Waitlister. Here's why, and all of it is on the &lt;a href="https://waitlister.me/pricing?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The free plan has no clock.&lt;/strong&gt; 100 subscribers, a hosted landing page or an embeddable form, and CSV export. No card.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$19 a month gets you unlimited subscribers.&lt;/strong&gt; The same plan has the referral program, welcome emails and broadcasts, so the signup page, referral rewards and emails to your list are in one tool. LaunchList, KickoffLabs and GrowSurf tie their price to list size or monthly signups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You can drive it from code, or hand it to an agent.&lt;/strong&gt; API keys work on every plan, Free included, and there's an OpenAPI spec, an npm SDK and an MCP server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When I'd pick something else:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A giveaway or contest: &lt;strong&gt;KickoffLabs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A referral program inside a product that's already live: &lt;strong&gt;GrowSurf&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A managed beta at an established company with budget: &lt;strong&gt;Prefinery&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The table
&lt;/h2&gt;

&lt;p&gt;Waitlister first because it's my post. The rest are alphabetical. Monthly prices, as each vendor's site listed them on October 10, 2026.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Paid plans from&lt;/th&gt;
&lt;th&gt;Free option&lt;/th&gt;
&lt;th&gt;Referrals&lt;/th&gt;
&lt;th&gt;Public API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Waitlister&lt;/strong&gt; (mine)&lt;/td&gt;
&lt;td&gt;$19/mo&lt;/td&gt;
&lt;td&gt;Free plan, 100 subscribers&lt;/td&gt;
&lt;td&gt;From $19&lt;/td&gt;
&lt;td&gt;Yes, every plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GetWaitlist&lt;/td&gt;
&lt;td&gt;$15/mo&lt;/td&gt;
&lt;td&gt;7-day trial&lt;/td&gt;
&lt;td&gt;From $15&lt;/td&gt;
&lt;td&gt;Yes, from $15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GrowSurf&lt;/td&gt;
&lt;td&gt;$179/mo ($125 billed yearly)&lt;/td&gt;
&lt;td&gt;14-day trial (free plan is for affiliates only)&lt;/td&gt;
&lt;td&gt;Core product&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KickoffLabs&lt;/td&gt;
&lt;td&gt;$19/mo&lt;/td&gt;
&lt;td&gt;Free plan, 100 uniques/mo&lt;/td&gt;
&lt;td&gt;Yes, plus giveaways&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LaunchList&lt;/td&gt;
&lt;td&gt;$9/mo for 500 contacts&lt;/td&gt;
&lt;td&gt;Free plan, 100 contacts&lt;/td&gt;
&lt;td&gt;Yes, Free included&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prefinery&lt;/td&gt;
&lt;td&gt;$49/mo&lt;/td&gt;
&lt;td&gt;14-day trial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things the table can't show.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens as the list grows.&lt;/strong&gt; Past the free plan, Waitlister doesn't charge by subscriber count. Launch is $19 whether you have 200 people or 20,000. The limit that rises with the plan is email: 2,500 a month on Launch, 5,000 on Pro, 10,000 on Growth. So a big list you email often will push you up a plan. Three of the others scale with the list itself. LaunchList prices by contacts (at 5,000 contacts its plans are $19, $39 and $79). KickoffLabs' $19 plan takes 500 new leads a month. GrowSurf's entry plan covers 2,500 participants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A free plan versus a trial.&lt;/strong&gt; Three of these have a free plan you can keep: Waitlister, KickoffLabs and LaunchList. GrowSurf and Prefinery give you 14 days, and GetWaitlist gives you 7. GetWaitlist's free tier is only for accounts created before June 12, 2025, and GrowSurf's free plan is for affiliate programs, not referral programs. While you're still validating, a plan with no clock matters more than the headline price.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why email to the list matters
&lt;/h2&gt;

&lt;p&gt;A waitlist only works if you fill it and keep it warm until launch. The second half is the one people skip. Someone joins in March, hears nothing until a launch email in June, and by then doesn't remember signing up.&lt;/p&gt;

&lt;p&gt;So before you pick a tool, check whether it emails your list itself, and on which plan. On Waitlister, welcome emails and broadcasts start at $19, and from $49 they can go out from your own domain. LaunchList and GetWaitlist also send broadcasts on their paid plans.&lt;/p&gt;

&lt;h2&gt;
  
  
  Waitlister in detail
&lt;/h2&gt;

&lt;p&gt;What each plan adds. Yearly billing takes off two months.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free, $0:&lt;/strong&gt; 1 waitlist and 100 subscribers. The landing page builder, embeddable forms, surveys, CSV export, basic analytics and API access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Launch, $19:&lt;/strong&gt; unlimited subscribers and 3 waitlists. The referral program with points and a leaderboard, welcome emails and broadcasts (2,500 a month), double opt-in, CAPTCHA, a custom thank-you page, and no Waitlister branding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro, $29:&lt;/strong&gt; a custom domain, 5,000 emails a month, advanced analytics and conversion tracking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Growth, $49:&lt;/strong&gt; sending from your own email domain, one-click translation into 30+ languages, webhooks, integrations (Mailchimp, Klaviyo and others), the subscriber-data API and bulk import.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business, $129:&lt;/strong&gt; 5 team seats and 50,000 emails a month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some things that don't fit in a pricing row:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hosted page or embed.&lt;/strong&gt; Use the hosted landing page, or put the form on the site you already have. There are native embeds for Framer, Webflow, WordPress, Shopify, Squarespace and Bubble, among others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every signup gets a queue position and a share link,&lt;/strong&gt; Free included. Launch adds the points and the leaderboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Referral fraud protection.&lt;/strong&gt; Suspicious referrals don't earn credit, but the signup still goes through, so a real person isn't turned away.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An agent can do the whole setup.&lt;/strong&gt; I've watched one create a waitlist, write and publish its landing page, verify a real signup and clean up after itself. Nobody opened the dashboard. Account API keys work on every plan for creating waitlists, adding signups, building and publishing landing pages, and reading stats. The quickest start is to point your agent at &lt;code&gt;waitlister.me/skill.md&lt;/code&gt;. The OpenAPI spec is at &lt;code&gt;waitlister.me/openapi.json&lt;/code&gt;, the SDK is &lt;code&gt;waitlister&lt;/code&gt; on npm, and the MCP server is &lt;code&gt;@waitlister/mcp&lt;/code&gt; in the official MCP registry. Add &lt;code&gt;.md&lt;/code&gt; to any docs URL for raw markdown.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where Waitlister isn't the answer
&lt;/h3&gt;

&lt;p&gt;I'd rather you hear these from me than find them a week in.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;On a small list, LaunchList is cheaper.&lt;/strong&gt; Its free plan includes referral links, a leaderboard, and spam and fraud protection, and its paid plans start at $9 for 500 contacts. On Waitlister, points and the leaderboard need the $19 plan. The gap closes as the list grows: at 5,000 contacts, LaunchList's cheapest plan is also $19.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your own domain is $29. Sending from your own email domain, webhooks and integrations are $49.&lt;/strong&gt; If you need those on day one, the $19 plan won't cover them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's younger than Prefinery,&lt;/strong&gt; which has been running since 2008. If your procurement team wants a long track record, Prefinery is the pick.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's built for a launch.&lt;/strong&gt; For a referral program that runs inside your app for years, GrowSurf is the right shape.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The others
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GetWaitlist
&lt;/h3&gt;

&lt;p&gt;A lightweight waitlist you embed in your own site. Each waitlist also gets a hosted page.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pricing:&lt;/strong&gt; $15 Basic, $50 Advanced, $250 Pro a month, less billed yearly. New accounts start with a 7-day trial.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick it if:&lt;/strong&gt; you want referrals, a leaderboard, an API and webhooks on a $15 plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The catch:&lt;/strong&gt; the free tier is only for accounts created before June 12, 2025. Sending from your own domain needs the $250 plan. Its own docs say the hosted page isn't meant to compete with full landing page builders.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GrowSurf
&lt;/h3&gt;

&lt;p&gt;Referral and affiliate program software. It also publishes a template for a pre-launch referral waitlist.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pricing:&lt;/strong&gt; $179 a month, or $125 a month billed yearly, for up to 2,500 participants. 14-day trial for referral programs. The $0 plan is for affiliate programs and takes 3% of the revenue affiliates bring in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick it if:&lt;/strong&gt; you want a referral program inside a launched product. It also has the deepest developer tooling here: official API libraries in five languages (Waitlister has one SDK), an OpenAPI 3.1 spec and an MCP server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The catch:&lt;/strong&gt; it doesn't build your landing page. Its own pre-launch template has you build the page elsewhere and embed its referral widget. And $179 a month is several times the entry price of anything else in the table.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  KickoffLabs
&lt;/h3&gt;

&lt;p&gt;Giveaways first. Its homepage says "Launch a viral giveaway in minutes", and it runs waitlists and milestone rewards too.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pricing:&lt;/strong&gt; a free plan for 100 uniques a month, with branding. Then $19, $69, $145 and $289 a month, less billed yearly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick it if:&lt;/strong&gt; you're running a giveaway, where every entry and referral earns points toward a prize.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The catch:&lt;/strong&gt; the $19 plan takes 500 new leads a month and still carries KickoffLabs branding. Waitlister's $19 plan has no subscriber cap and no branding.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  LaunchList
&lt;/h3&gt;

&lt;p&gt;The closest thing to Waitlister on this list. It relaunched as a subscription product (v2), and its old one-time plans are closed to new accounts. The new version also has a REST API with an OpenAPI 3.1 spec, signed webhooks and an MCP server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pricing:&lt;/strong&gt; free up to 100 contacts. The paid plans (Collect, Launch, Grow) are priced by list size, from $9 a month for 500 contacts. LaunchList labels them beta prices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick it if:&lt;/strong&gt; your list will stay small and you want referrals for free or close to it. Its Launch plan also includes your own sending domain, from $19 on a small list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The catch:&lt;/strong&gt; the price rises with your list, and free-plan pages tell search engines not to index them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prefinery
&lt;/h3&gt;

&lt;p&gt;Its site says it's been running since 2008.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pricing:&lt;/strong&gt; $49, $249 and $499 a month, or $39, $199 and $399 a month billed every six months. 14-day trial, no free plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick it if:&lt;/strong&gt; you're an established company running a managed beta, and price isn't the constraint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The catch:&lt;/strong&gt; $49 a month is a steep start while you're still finding out whether anyone wants the product.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Also out there
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ReferralHero:&lt;/strong&gt; waitlists, contests, and affiliate and referral programs. $199 a month on its PRO plan, with a free plan for up to 25 subscribers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EarlyParrot:&lt;/strong&gt; referral campaigns aimed at SaaS, e-commerce, course creators and events, from $99 a month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Viral Loops:&lt;/strong&gt; referral campaigns. Its site blocks automated requests, so I couldn't check current prices. Its help center confirms a free trial.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I'd choose
&lt;/h2&gt;

&lt;p&gt;If you're still validating, start on a free plan, so a test that goes nowhere costs nothing.&lt;/p&gt;

&lt;p&gt;If you're launching, decide the shape of the campaign before the tool. A queue with referrals and emails to the list, a giveaway, and a referral program inside a live app are different products. For the first one, I think Waitlister is the best tool you can use, and that's the job I built it for.&lt;/p&gt;

&lt;p&gt;Everything above is checkable, and some of it will change. If you spot something that's already wrong, tell me in the comments and I'll fix it. If you want to check the Waitlister parts yourself, &lt;code&gt;waitlister.me/pricing.md&lt;/code&gt; has every plan and limit in plain text, and the free plan needs no card.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>startup</category>
      <category>saas</category>
    </item>
    <item>
      <title>I made my SaaS installable by AI agents. Here's what was broken.</title>
      <dc:creator>Devin D</dc:creator>
      <pubDate>Fri, 14 Aug 2026 09:18:10 +0000</pubDate>
      <link>https://dev.to/devin_daymore/i-made-my-saas-installable-by-ai-agents-heres-what-was-broken-3c17</link>
      <guid>https://dev.to/devin_daymore/i-made-my-saas-installable-by-ai-agents-heres-what-was-broken-3c17</guid>
      <description>&lt;p&gt;Two weeks ago I watched an agent run a full product launch on Waitlister, my waitlist tool.&lt;/p&gt;

&lt;p&gt;It created the waitlist, generated and published a landing page, signed up a test address, checked the signup was real by fetching the public page unauthenticated, then unpublished and deleted everything it had made.&lt;/p&gt;

&lt;p&gt;Nobody touched the dashboard.&lt;/p&gt;

&lt;p&gt;The interesting part isn't that run. It's what I found while getting there, because almost none of it was visible from a browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I bothered
&lt;/h2&gt;

&lt;p&gt;My users are pre-launch founders, which is exactly the group now building landing pages by prompting Claude, Cursor, or v0 instead of opening a site builder. "Add a waitlist to my site" is a normal thing to ask an agent to do, and increasingly nobody types my product name at all.&lt;/p&gt;

&lt;p&gt;The uncomfortable part is when an agent hits a 404 or installs a package that doesn't exist, it doesn't debug. It picks a different tool in the next sentence and never tells the user it switched. You lose without ever seeing a bounce.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I shipped, in order of how much it turned out to matter
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Full API coverage for the whole job.&lt;/strong&gt; Not most of it. More below, because this one was worth the other five combined.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A &lt;code&gt;skill.md&lt;/code&gt; route.&lt;/strong&gt; One page written for an agent rather than a person: a decision tree (no API key yet, go this way; account key, go that way), both code paths, and a self-check at the end so the agent can confirm it worked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An OpenAPI spec at a fixed URL.&lt;/strong&gt; Valid 3.0.3 at &lt;code&gt;/openapi.json&lt;/code&gt;, all five endpoints, auth, rate limits, error shapes. Endpoint changes update the spec and the SDK types in the same PR or they don't merge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A real npm SDK&lt;/strong&gt;, plus four aliases under the names an agent is likely to reach for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An MCP server&lt;/strong&gt;, 14 tools, so agents that speak MCP get typed calls instead of reading my docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;llms.txt&lt;/code&gt; and &lt;code&gt;llms-full.txt&lt;/code&gt;&lt;/strong&gt;, an index of the docs in plain text with a short block at the top saying what this product is and where the golden path starts.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Honest list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The file I wrote for agents was the one file agents couldn't read.&lt;/strong&gt; My &lt;code&gt;llms.txt&lt;/code&gt; is proxied from a vendor, the proxy forwards the caller's user-agent, and the vendor had AI-bot blocking switched on by default. Every AI crawler got a 403 on the document whose only purpose is being read by AI&lt;br&gt;
crawlers. I found it by requesting my own files with eight bot user-agents and diffing the status codes. One vendor toggle can put it back, silently, which is why the check now runs on a schedule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;llms-full.txt&lt;/code&gt; is too big to be read at answer time.&lt;/strong&gt; It's 961 KB and grows with every docs page. It serves from my side in about 1.3 seconds, and Claude's answer-time fetcher still timed out on it at 60 seconds. The small index is the one that actually gets read. I haven't fixed this yet;&lt;br&gt;
the options are trimming it or splitting it, and I've done neither.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agents guess your package name.&lt;/strong&gt; &lt;code&gt;waitlister-js&lt;/code&gt;, &lt;code&gt;waitlister-sdk&lt;/code&gt;, &lt;code&gt;waitlister-node&lt;/code&gt;, &lt;code&gt;@waitlister/sdk&lt;/code&gt;. Instead of arguing with that, I published all four as real packages that re-export the SDK and carry a deprecation notice pointing at the canonical name. A wrong guess installs and self-corrects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My email validator rejected valid addresses.&lt;/strong&gt; Agents test with plus-tags, because that's how you make a disposable address on an account you already own. My validator refused some of them. Human users with Gmail aliases had been hitting the same wall for as long as the rule existed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My 404s weren't 404s.&lt;/strong&gt; Unknown doc slugs returned a soft page with a 200. An agent reading status codes concludes the page exists and that it guessed the URL right, then builds on it. Real 404s, plus a 301 from the old getting-started URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The single page that would have saved five fetches was labeled for the wrong reader.&lt;/strong&gt; In the first live test the agent's own friction report said the docs were split across pages with no single page giving the complete picture, so it fetched five. &lt;code&gt;skill.md&lt;/code&gt; is that page, and &lt;code&gt;/docs/api&lt;/code&gt; linked to it in a callout at the very top. The callout was headed "Integrating with an AI agent," which is a label about &lt;em&gt;who it's for&lt;/em&gt;, and the agent was reading through a fetch-summarizer where that reads as a sidebar. Reframed as "Fastest path: complete single-page integration guide," it started landing. The link was never missing. It was filed under the wrong thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every run used to die at the same sentence.&lt;/strong&gt; The agent could create a waitlist through the API and then had to say "now open the dashboard to build your landing page." That one gap ended the automated path every time, no matter how good the rest of the surface was. Creating, updating, and publishing a landing page over the API is what made an end-to-end run possible at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one thing I'd tell someone starting this
&lt;/h2&gt;

&lt;p&gt;Test with the real fetchers, not with curl. Every failure above lived in the gap between what my server sends and what an agent's toolchain actually receives: a user-agent rewritten in transit, a file that serves fine but times out at answer time, a status code that lies, a link that survives the fetch but not the summary. Curl told me everything was fine. It was, for curl.&lt;/p&gt;

&lt;p&gt;Where I've got to: four consecutive live runs with zero wrong guesses, a complete correct integration plan from public surfaces alone in about 90 seconds, and a waitlist created from an empty account in three minutes and eighteen seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check it yourself
&lt;/h2&gt;

&lt;p&gt;All of it is live. If you want to see what an agent actually receives, point yours at &lt;a href="https://waitlister.me/skill.md" rel="noopener noreferrer"&gt;waitlister.me/skill.md&lt;/a&gt; and ask it to set up a waitlist.&lt;/p&gt;

&lt;p&gt;The same path written for a person is at &lt;a href="https://waitlister.me/growth-hub/guides/set-up-waitlist-with-ai-agent" rel="noopener noreferrer"&gt;waitlister.me/growth-hub/guides/set-up-waitlist-with-ai-agent&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>agents</category>
      <category>agentskills</category>
    </item>
  </channel>
</rss>
