<?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: Eliran Yihye</title>
    <description>The latest articles on DEV Community by Eliran Yihye (@elirany).</description>
    <link>https://dev.to/elirany</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%2F4186732%2Fcc5a21a3-4338-4bd4-a083-6b16bcb10d49.jpg</url>
      <title>DEV Community: Eliran Yihye</title>
      <link>https://dev.to/elirany</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/elirany"/>
    <language>en</language>
    <item>
      <title>What AI Crawler Logs Showed Us: Bots vs Fetches</title>
      <dc:creator>Eliran Yihye</dc:creator>
      <pubDate>Thu, 15 Oct 2026 19:12:23 +0000</pubDate>
      <link>https://dev.to/elirany/what-ai-crawler-logs-showed-us-bots-vs-fetches-4g5f</link>
      <guid>https://dev.to/elirany/what-ai-crawler-logs-showed-us-bots-vs-fetches-4g5f</guid>
      <description>&lt;h2&gt;
  
  
  Which AI crawler fetches mean a real person asked a question?
&lt;/h2&gt;

&lt;p&gt;User-fetch agents such as ChatGPT-User, Claude-User and Perplexity-User fire when a person asks an assistant a question and it needs a live page. Index crawlers such as OAI-SearchBot build a search index ahead of time. A user fetch means you were considered for a real question, so report it separately.&lt;/p&gt;

&lt;p&gt;I am Eliran, founder of Cuanto Labs, a software company in Fort Lauderdale, Florida. We log crawler requests on our own marketing site on the server side, because most of these bots never run JavaScript and so never appear in a browser-based tool. This post is what the first eight days of that log showed.&lt;/p&gt;

&lt;p&gt;A warning about sample size, up front. Our log starts on October 7, 2026, and this is a small site. Every number below is a count from that window, not a rate and not a trend. Treat them as direction, not proof.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did the counts look like?
&lt;/h2&gt;

&lt;p&gt;This is the server-side log for our main domain plus an old alias domain that now redirects to it, from October 7 to October 15, 2026. Total user fetches were 90, of which 75 were ChatGPT-User. We saw zero hits from GPTBot or Applebot, which is a fact about our log and not a claim about those bots elsewhere.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bot&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Requests&lt;/th&gt;
&lt;th&gt;Distinct paths&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bingbot&lt;/td&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;683&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PerplexityBot&lt;/td&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;448&lt;/td&gt;
&lt;td&gt;89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OAI-SearchBot&lt;/td&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;345&lt;/td&gt;
&lt;td&gt;61&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ClaudeBot&lt;/td&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Googlebot&lt;/td&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;86&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChatGPT-User&lt;/td&gt;
&lt;td&gt;user fetch&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude-User&lt;/td&gt;
&lt;td&gt;user fetch&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Perplexity-User&lt;/td&gt;
&lt;td&gt;user fetch&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPTBot, Applebot&lt;/td&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  When do index crawlers show up?
&lt;/h2&gt;

&lt;p&gt;They arrive in bursts, near deploys. OAI-SearchBot's 345 hits were not spread evenly: nearly all fell into three short windows, the morning of October 10, midday and evening of October 12, and the morning of October 13. Every new page from our October 12 evening release was fetched within minutes of going live.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which pages do assistants fetch for users?
&lt;/h2&gt;

&lt;p&gt;Mostly the plain-facts pages. Of the 90 user fetches, brand, home and portfolio pages took 59, pricing, buy and service hubs took 12, city pages took 7, AI automation pages took 6, and research and blog took 6. These are counts of fetches, not conversions.&lt;/p&gt;

&lt;p&gt;An assistant that fetches only the home page should be able to answer who you are, where you are and what you do. A few plain sentences matter more than a clever one. Say what you do, where you are and what it costs, in words an assistant can lift.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does the daily curve follow what you publish?
&lt;/h2&gt;

&lt;p&gt;It did for us, though one peak proves little. Daily user fetches in our window were 12 on October 10, 32 on October 12 (the peak), 9 on October 13 and 14 on October 14. The October 12 peak lines up with the release day. The shape is consistent with new content being looked at when it exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can an index hit come before a live fetch?
&lt;/h2&gt;

&lt;p&gt;Yes, and it can come days earlier. One example, without identifying anyone: a page on automation services was first fetched by OAI-SearchBot on the evening of October 12. On the afternoon of October 14, ChatGPT-User fetched the same page. About an hour later, a business owner emailed us directly asking to talk about AI and lead generation.&lt;/p&gt;

&lt;p&gt;We cannot prove the two are linked, and nothing contradicts it. We put it at roughly even odds on timing alone.&lt;/p&gt;

&lt;p&gt;What it does show is that this channel can leave no trace in the usual places. There was no chatgpt.com referrer, no campaign tag and no form submission, because the person went straight to email. If you only look at referrals and forms, a conversation like this is invisible. The server-side fetch log is the only place the chain shows up at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should you log to see AI bot traffic?
&lt;/h2&gt;

&lt;p&gt;Log four fields on every request whose user agent matches a known AI bot, then report index crawlers and user fetches in two separate tables. You do not need an enterprise tool, and the log costs very little to start keeping.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Timestamp, converted to the time zone you read reports in.&lt;/li&gt;
&lt;li&gt;User agent family, normalized to a short name.&lt;/li&gt;
&lt;li&gt;Host and path, and whether the response was a 200, a redirect or a 404.&lt;/li&gt;
&lt;li&gt;Whether the request came from a data-center network, which helps separate bot traffic from ordinary visitors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two cautions. User agent strings can be spoofed, so where a vendor publishes IP ranges, verify against them before you treat a hit as real. And log server-side only: these agents mostly do not execute your analytics script, so a browser-based tool shows you none of this. Make sure your tracking script does not fire for them either, or your human counts get polluted.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does this suggest you do?
&lt;/h2&gt;

&lt;p&gt;These follow from the log. They are suggestions, not a record of results. Put the plain facts on the home page and the pricing page, since those were fetched most. Keep your sitemap current so new pages are discoverable on the first crawl.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you have an old domain, redirect it to the main one. In our log, 14 of the 75 ChatGPT-User fetches went to the old alias domain, which now redirects, so fetches land on one canonical site.&lt;/li&gt;
&lt;li&gt;Do not read meaning into a probe path that returns a 404. Fix it or filter it out of your crawl report.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are we not claiming?
&lt;/h2&gt;

&lt;p&gt;We are not claiming that appearing in this log produces customers at any rate. Our sample is small, our window is eight days, and the one possible conversion above is a single timing coincidence. The narrower claim: the log is the only way to see user-fetch behavior at all.&lt;/p&gt;

&lt;p&gt;If you want help with AI automation, agents or the visibility side of it, our &lt;a href="https://cuantolabs.com(/ai-automation-florida)" rel="noopener noreferrer"&gt;AI automation page&lt;/a&gt; lists what we build and what it costs. Related: &lt;a href="https://cuantolabs.com(/blogs/seo-for-ai-businesses)" rel="noopener noreferrer"&gt;SEO for AI businesses&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Written by Eliran Yihye, founder of Cuanto Labs, on October 15, 2026.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://cuantolabs.com/blogs/what-ai-crawler-logs-showed-us" rel="noopener noreferrer"&gt;cuantolabs.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>seo</category>
      <category>analytics</category>
      <category>webdev</category>
    </item>
    <item>
      <title>AI Lead Follow-Up on Next.js and a CRM</title>
      <dc:creator>Eliran Yihye</dc:creator>
      <pubDate>Thu, 15 Oct 2026 19:07:07 +0000</pubDate>
      <link>https://dev.to/elirany/ai-lead-follow-up-on-nextjs-and-a-crm-8i5</link>
      <guid>https://dev.to/elirany/ai-lead-follow-up-on-nextjs-and-a-crm-8i5</guid>
      <description>&lt;h2&gt;
  
  
  How should you wire lead capture before adding an AI agent?
&lt;/h2&gt;

&lt;p&gt;Save the lead first, notify second, and make silence queryable. The database row is the durable record, the visitor never waits on a downstream service, and a missing notification must be distinguishable from a missing lead. An AI follow-up agent only works if the lead arrives intact, exactly once.&lt;/p&gt;

&lt;p&gt;I am Eliran, founder of Cuanto Labs, a software company in Fort Lauderdale, Florida. Most AI lead follow-up content is about the clever part, the agent that texts a prospect within a minute. This post covers the capture side on our own Next.js site, then where an agent and a CRM plug in. The capture pattern is what we run, simplified. The agent section is design guidance, and I label it as such.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Failure it prevents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Validate&lt;/td&gt;
&lt;td&gt;Rate limit, honeypot, field checks&lt;/td&gt;
&lt;td&gt;Bots and junk rows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insert&lt;/td&gt;
&lt;td&gt;Parameterized write, answers 500 only if the write failed&lt;/td&gt;
&lt;td&gt;Reporting a saved lead as unsaved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notify after the response&lt;/td&gt;
&lt;td&gt;Runs once the visitor has their reply&lt;/td&gt;
&lt;td&gt;A slow mail provider blocking the form&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bound each channel&lt;/td&gt;
&lt;td&gt;Hard timeout per channel&lt;/td&gt;
&lt;td&gt;One provider holding the function open&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stamp the row&lt;/td&gt;
&lt;td&gt;Records that a channel delivered&lt;/td&gt;
&lt;td&gt;Silent failures looking like a quiet week&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What should the route handler validate first?
&lt;/h2&gt;

&lt;p&gt;Validate everything before the database is touched. Our route handler rate limits to 5 requests per minute per IP, rejects invalid JSON with a 400, checks every field's shape and length, and uses an allow-list for the source value. A hidden honeypot input gets a normal success reply and nothing else.&lt;/p&gt;

&lt;p&gt;The in-memory rate limiter is the right size for a marketing site and the wrong size for anything under real abuse pressure. Know which one you are.&lt;/p&gt;

&lt;p&gt;The honeypot is an off-screen input with no label and no autofill hint, so real visitors never fill it. The silent success is deliberate: an error would tell the bot which field tripped you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why insert the lead before notifying anyone?
&lt;/h2&gt;

&lt;p&gt;Because the insert is the only step that may answer "failed to save". Keep notification code out of the same try block. If a mail call threw inside it, the handler would answer 500 for a lead that was in fact saved, the client would retry, and you would get duplicate rows and still no notification.&lt;/p&gt;

&lt;p&gt;Reporting a saved lead as unsaved is worse than a missed notification, so the error handling ends the moment the row exists. Use parameterized queries only: values travel as parameters and are never concatenated into the SQL string.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you notify without making the visitor wait?
&lt;/h2&gt;

&lt;p&gt;Use the &lt;code&gt;after()&lt;/code&gt; function from &lt;code&gt;next/server&lt;/code&gt;, which runs work after the response has flushed. The visitor gets their success reply at once while the notification runs behind it. Wrap the call in a helper that never throws, and pass &lt;code&gt;after&lt;/code&gt; in as an argument so it can be tested.&lt;/p&gt;

&lt;p&gt;Two traps apply. A floating promise is not a substitute: on serverless, work not registered with &lt;code&gt;after()&lt;/code&gt; can die when the function freezes after the response. And &lt;code&gt;after()&lt;/code&gt; can throw synchronously outside a request scope, so log and swallow that failure. The row exists, so the response is still a success.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you stop one slow channel from breaking the rest?
&lt;/h2&gt;

&lt;p&gt;Give every channel its own hard timeout and race the send against it. Ours is 5 seconds, with an abort signal passed to the provider, so one slow provider cannot hold the other channels or the function open. Email is the only channel today, and others can be added without touching the route.&lt;/p&gt;

&lt;p&gt;Two smaller rules have paid for themselves. Every channel degrades to logging when its configuration is missing, so a missing API key is a no-op and not a crash. And provider error strings are a privacy surface, since a raw mail API error can contain the recipient address. Redact before logging.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you make a silent failure visible?
&lt;/h2&gt;

&lt;p&gt;Stamp the row. After the notifier runs, check whether any channel reported delivered, and if so set a &lt;code&gt;notified_at&lt;/code&gt; timestamp on the lead. The check is stricter than "not failed": a channel in log-only mode reports logged, and counting that would mark every preview-environment lead as handled.&lt;/p&gt;

&lt;p&gt;Now a small watchdog can ask the database a plain question: which leads are older than N minutes, 15 in ours, with no &lt;code&gt;notified_at&lt;/code&gt;? Run it on a schedule and send yourself the result. Error monitoring tells you about failures after you suspect something. The stamp tells you about the ones you never suspected.&lt;/p&gt;

&lt;p&gt;If the stamp update itself fails, swallow it. The email went out, and the worst case is a duplicate ping from the watchdog, which is noisier than silence and far better than the reverse.&lt;/p&gt;

&lt;p&gt;We also send a server-side conversion event from &lt;code&gt;after()&lt;/code&gt; in production when the row is created, because ad blockers and closed tabs lose browser events. It carries the lead id and source, never the name, email or message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where does the AI follow-up agent plug in?
&lt;/h2&gt;

&lt;p&gt;Everything above is the trigger. Once a lead is a row with an id, the agent should subscribe to "lead created" from the database or a queue, not be called inline from the route. The route stays fast and the agent can be retried on its own.&lt;/p&gt;

&lt;p&gt;This is how I would wire it and how we scope it for clients.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A state machine, not a chat log.&lt;/strong&gt; A lead moves through new, contacted, replied, qualified, handed to a person and closed. The agent reads and writes the state, and your existing CRM stays the system of record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approved templates.&lt;/strong&gt; A person approves the sequence templates once and the agent fills them in. Anything outside a template goes to a person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop conditions built first.&lt;/strong&gt; Any reply pauses automated sends and alerts a human. An opt-out phrase ends sends on that channel and is recorded. Attempts are capped per lead, with quiet hours and a human takeover flag the CRM can set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write back to the CRM.&lt;/strong&gt; Every send and reply becomes an activity on the lead record. Otherwise a salesperson will contact someone the agent already contacted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Texting rules on consent, quiet hours and opt-outs are real legal constraints. Have counsel review your sequences. This is engineering experience, not legal advice.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do we claim, and not claim?
&lt;/h2&gt;

&lt;p&gt;We do not quote a response-time improvement, because our own sample is small. The design guarantees three things: a saved lead is never reported as unsaved, the visitor never waits on a mail provider, and a missing notification shows up in a query.&lt;/p&gt;

&lt;p&gt;We build follow-up systems for Florida businesses at a fixed price from $5K, typically in 2 to 6 weeks, with the code and accounts transferring to you. Scope depends on how many lead sources it watches, which channels it sends on and which CRM it connects to. See the &lt;a href="https://cuantolabs.com(/ai-lead-follow-up-automation-florida)" rel="noopener noreferrer"&gt;AI lead follow-up automation page&lt;/a&gt;, or read &lt;a href="https://cuantolabs.com(/blogs/how-fast-to-follow-up-with-a-lead-ai-follow-up)" rel="noopener noreferrer"&gt;how fast to follow up with a lead&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Written by Eliran Yihye, founder of Cuanto Labs, on October 15, 2026.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://cuantolabs.com/blogs/ai-lead-follow-up-nextjs-crm" rel="noopener noreferrer"&gt;cuantolabs.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>nextjs</category>
      <category>crm</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How an AI Voice Receptionist Works, and Fails</title>
      <dc:creator>Eliran Yihye</dc:creator>
      <pubDate>Thu, 15 Oct 2026 19:06:59 +0000</pubDate>
      <link>https://dev.to/elirany/how-an-ai-voice-receptionist-works-and-fails-ejk</link>
      <guid>https://dev.to/elirany/how-an-ai-voice-receptionist-works-and-fails-ejk</guid>
      <description>&lt;h2&gt;
  
  
  How does an AI voice receptionist work?
&lt;/h2&gt;

&lt;p&gt;A voice receptionist is a loop with a hard real-time budget. The carrier streams the caller's audio to your server, speech-to-text turns it into words, a language model decides what to say or which tool to call, and text-to-speech streams the answer back before the caller says "hello?" a second time.&lt;/p&gt;

&lt;p&gt;I run Cuanto Labs, a software studio in Fort Lauderdale, Florida. A few weeks ago we put our own phone agent on a real number. It answers, screens, takes messages and hands calls to a person. This post covers the architecture and the bugs that cost us the most time, because most voice-agent write-ups stop at the diagram. It describes components, not products.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;What to test&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Telephony carrier&lt;/td&gt;
&lt;td&gt;Carries the call and streams audio both ways&lt;/td&gt;
&lt;td&gt;Audio direction, webhook verification, spend caps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speech-to-text&lt;/td&gt;
&lt;td&gt;Turns caller audio into words&lt;/td&gt;
&lt;td&gt;Accents, noise, phone numbers spoken aloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language model&lt;/td&gt;
&lt;td&gt;Decides the reply or the tool call&lt;/td&gt;
&lt;td&gt;Time to first token, tool-use accuracy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text-to-speech&lt;/td&gt;
&lt;td&gt;Turns the reply into audio&lt;/td&gt;
&lt;td&gt;Naturalness on a phone line, second languages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent framework&lt;/td&gt;
&lt;td&gt;Runs the frame pipeline between them&lt;/td&gt;
&lt;td&gt;Interruptions, voice activity detection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We used an open source agent framework for voice activity detection, interruption handling and partial transcripts, so we did not own that plumbing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use WebSocket media instead of SIP?
&lt;/h2&gt;

&lt;p&gt;Use WebSocket media when your agent runs behind a home or office router. SIP needs public UDP ports for signalling and audio, while a WebSocket stream is ordinary TCP, so it passes through a tunnel with no port forwarding. If your server has a public IP address, revisit SIP, which is a good system.&lt;/p&gt;

&lt;p&gt;We evaluated SIP first, but our agent runs behind a residential router, so the carrier's WebSocket media stream was the easier path. &lt;/p&gt;

&lt;h2&gt;
  
  
  How do you keep a voice agent from doing something dangerous?
&lt;/h2&gt;

&lt;p&gt;Give the model a short, fixed list of tools and keep dangerous arguments out of its reach. Our agent can call exactly three tools: transfer to a human, take a message, and end the call. The transfer destination is fixed in the server environment, so the model never supplies a number.&lt;/p&gt;

&lt;p&gt;That is the cheapest safety decision in the build: a prompt injection from the caller cannot redirect a call to a premium-rate number if the model has no argument to put it in. &lt;/p&gt;

&lt;p&gt;We also run a small, fast classifier before answering, to catch spam and robocalls, and on each turn, to decide whether to escalate to a person. It has a hard timeout, because a slow check must never stall the call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which language model works best on a phone call?
&lt;/h2&gt;

&lt;p&gt;Pick the model by time to first token, not by benchmark rank. On a phone call, quality that arrives late is quality the caller never hears. In our tests a small fast model answered in well under a second, while a larger model took more than a second and a half, and that gap decided it.&lt;/p&gt;

&lt;p&gt;A fast model is not free. One otherwise capable model mangled messy phone-number extraction in half of our runs, because callers say numbers like "seven eight six, uh, four one three, zero four one six." Treat number capture as something you verify by reading it back, never as something the model got right.&lt;/p&gt;

&lt;h2&gt;
  
  
  How should you choose a text-to-speech voice?
&lt;/h2&gt;

&lt;p&gt;Choose by listening, because the measurable metrics tie. We compared six voices on the same script at telephone audio quality. Time to first audio and word error rate on a round-trip transcription test were effectively tied. A blind human-likeness rating was the only measure that separated them.&lt;/p&gt;

&lt;p&gt;A second language costs you. In a Hebrew test, replies took several seconds, against well under a second in English. Plan the greeting and filler phrases accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What bugs make a voice agent go silent?
&lt;/h2&gt;

&lt;p&gt;Three bugs cost us days, and all three were configuration, not code. The first left the agent unable to hear, the second left it silent in the recording, and the third made webhook signature checks fail, even though the logs looked healthy.&lt;/p&gt;

&lt;h3&gt;
  
  
  The agent that could not hear
&lt;/h3&gt;

&lt;p&gt;The bot greeted the caller, then never responded. We had asked the carrier for both audio directions, which sends the bot's own voice back to us as a media message tagged as outbound. Our framework's stock serializer did not filter by direction, so the bot's own speech fed the speech recognizer and the voice activity detector. The bot kept "listening" to itself.&lt;/p&gt;

&lt;p&gt;The fix was a small serializer subclass that drops every frame not tagged as inbound. Five lines of code, two days of confusion.&lt;/p&gt;

&lt;h3&gt;
  
  
  The agent that was silent in the recording
&lt;/h3&gt;

&lt;p&gt;Calls connected and transcripts looked fine, but the bot's channel in the recording was empty. One carrier option routes the bot's audio to a bridged call leg. Our call had no bridged leg, so the audio went nowhere. Pointing the option at the call itself fixed it.&lt;/p&gt;

&lt;p&gt;We caught it by comparing the two channels of the recording, not the logs. A pipeline can log "audio sent" faithfully while the carrier discards it. Listen to a real recorded call after any change to stream parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  The webhook that verified against the wrong key
&lt;/h3&gt;

&lt;p&gt;Webhook signatures should be verified against the public key the carrier serves from its own key endpoint. A key we had copied into our secrets file looked right, was a different length, and did not match. If signature verification passes in tests and fails in production, or is quietly disabled, check the key source first.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else belongs on a voice agent checklist?
&lt;/h2&gt;

&lt;p&gt;Four smaller items belong on every checklist before launch. They are the ones we hit in the first week of running real calls, and each one is cheap to handle once at build time and expensive to find later, in production, with a caller waiting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Carrier command payloads can require base64 encoding for state fields, and call identifiers can contain characters that need URL-encoding in paths.&lt;/li&gt;
&lt;li&gt;A 403 when creating a call can mean the call-control application was set inactive. Read the response body, which says so.&lt;/li&gt;
&lt;li&gt;The first call after a restart can time out while models and sockets warm up. Place a warm-up call in your deploy script.&lt;/li&gt;
&lt;li&gt;Telephony is not chat. Set an outbound allowlist where empty means deny everything, an hourly call cap, and a daily spend cap on the carrier profile.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do you test a voice agent without a phone?
&lt;/h2&gt;

&lt;p&gt;Write a fake carrier. Ours is a WebSocket client that speaks the carrier's media protocol and plays synthesized caller audio, so the full pipeline runs in continuous integration with no real phone numbers, no carrier charges and no cost beyond speech processing.&lt;/p&gt;

&lt;p&gt;For real-audio checks, one of our numbers answers with a listener persona, and a test asserts that both call logs contain user turns. If either side has zero user turns, you have a one-way audio bug like the two above.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does Florida law say about recording a voice agent's calls?
&lt;/h2&gt;

&lt;p&gt;Florida generally requires the consent of all parties to record a phone call. Our greeting states that the call is recorded, and the disclosure is spoken in the caller's language. Have an attorney confirm the wording for your business, since this post is engineering experience and not legal advice.&lt;/p&gt;

&lt;p&gt;If your agent talks to the public, also decide up front when it admits it is an AI (ours does when asked directly) and keep a human fallback for urgent or sensitive calls. The agent should never triage an emergency. It should tell the caller to dial 911 and stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would we tell a client?
&lt;/h2&gt;

&lt;p&gt;The parts are not exotic. What decides whether it works is a short list: pick the model by latency, keep dangerous arguments out of the model's reach, listen to real recorded calls, and build the spend caps and kill switches before launch, not after.&lt;/p&gt;

&lt;p&gt;We build scoped voice agents for Florida businesses at a fixed price from $5K, typically in 2 to 6 weeks, and the code and accounts transfer to you. Details and the questions to ask any vendor are on the &lt;a href="https://cuantolabs.com(/ai-voice-receptionist-florida)" rel="noopener noreferrer"&gt;AI voice receptionist page&lt;/a&gt;. For prices, see &lt;a href="https://cuantolabs.com(/blogs/ai-voice-receptionist-cost-florida-2026)" rel="noopener noreferrer"&gt;what an AI voice receptionist costs in Florida&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Written by Eliran Yihye, founder of Cuanto Labs, on October 15, 2026.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://cuantolabs.com/blogs/building-an-ai-voice-receptionist" rel="noopener noreferrer"&gt;cuantolabs.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>webdev</category>
      <category>voiceagents</category>
    </item>
  </channel>
</rss>
