{"slug": "building-a-voice-english-practice-app-in-the-browser-what-broke-first", "title": "Building a voice English-practice app in the browser (what broke first)", "summary": "Gabriel Luis Pacheco, founder of Brazilian English-practice product BataTalk, built a browser-based voice app that pairs AI characters in everyday scenes with an in-scene coach called Tato that cues the start of a sentence when learners freeze. The build post details the stack (Node 24, vanilla JS, Supabase Auth and Postgres, Stripe, Cloudflare Turnstile, Render) and reports that collapsing distinct failures into one error string poisoned analytics, while guest access is gated by Turnstile, daily caps and transcription health checks. Pacheco also publishes an /llms.txt with stable facts and deliberately allows major AI crawlers in robots.txt, arguing that blocking bots while asking to be cited is self-defeating.", "body_md": "*I'm Gabriel Luis Pacheco, founder of [BataTalk](https://batatalk.com.br) — a Brazilian product for spoken English practice with AI characters and an in-scene coach (Tato). This is a build post, not a growth flex.*\n\nBataTalk helps Brazilians who understand English but freeze when it's their turn to speak. Practice happens by voice in the browser: AI characters in everyday scenes (café, airport, interview), and Tato cues the start of the sentence when you blank. Levels A1–C2. Free plan: one guided conversation per day, no card. Paid plans are priced in BRL on [/planos](https://batatalk.com.br/planos). Honest limits: AI can err; not a certificate; not a live teacher; no accent score theater.\n\nNode 24+, vanilla JS for the app shell, marketing pages SSR'd as HTML, Supabase Auth + Postgres (service role on the API, RLS as second layer), Stripe, Resend, Cloudflare Turnstile, Render + Cloudflare. Voice path: browser mic → our API → transcription / model reply. We intentionally **do not** store the audio file.\n\nThe target user will not \"just prompt ChatGPT every day.\" So the product ships **scenes with goals** and a coach for the freeze moment. That kills tempting features: social feed, streak theater, fake certificates, pronunciation grades based on flaky ASR text.\n\nBrowser-first matters in Brazil: cold start on mobile Chrome during a work break beats \"download our app first.\"\n\n\"First line without signup\" is great UX and catnip for bots. We gate with Turnstile + daily caps + health checks on transcription. When any dependency is down, the client must fail with a *specific* reason. Mapping \"browser has no SpeechRecognition\" to the same bucket as \"trial off\" poisoned our analytics and made us chase the wrong incident.\n\nLesson: error taxonomy is product infrastructure. If you collapse distinct failures into one string, you will \"fix\" the wrong thing for a week.\n\nPassword minimum length, email confirmation, Turnstile, IP rate limits. Funnel math is brutal: many client-side `signup_started` events versus few completed accounts. Instrument failure reasons *before* you simplify auth into oblivion. Also: mobile layout that pushes the CTA below the fold is a silent killer — we shipped a CSS order fix after measuring absurd scroll height on small screens.\n\nIf marketing content only exists after JS hydration, you lose search and LLM citation. We keep substantive copy in SSR HTML for landings, FAQ, and compare pages, and we publish `/llms.txt` with stable facts (what it is, what it is not, pricing page link, privacy posture). `robots.txt` allows major AI crawlers on purpose — GEO needs third-party mentions too, but blocking bots while asking to be cited is self-owning.\n\nVoice is not a free client-side feature. Quotas (daily + rolling 30-day) and plan gates are core product. The free tier teaches the loop; it is not infinite GPT with your brand on top. Day boundary at 21:00 America/Sao_Paulo surprised early testers who thought \"midnight\" — document clock skew in the UI, not only in the terms.\n\nShipping many thin intent landings (interview ×3, airport ×2) diluted authority. Consolidation with 301s toward one strong URL per intent is boring editorial work and better SEO than another 400-word page.\n\nSite: [https://batatalk.com.br](https://batatalk.com.br) — first spoken line can work without an account. If you're building similar voice UX, I'm especially interested in how you handle guest quotas without training a fraud dataset on your credit card, and how you explain mic permission inside in-app browsers (Instagram/TikTok WebViews are hostile).\n\nComments welcome — especially dissenting UX takes from people who teach English for a living.\n\nSupport tickets often start with \"my free conversation disappeared.\" Nine times out of ten it is the Brasília day boundary, a Turnstile failure inside a WebView, or the user opening the site through Instagram's in-app browser where the mic never appears. Write those three cases into the UI empty-states. Your future self will spend fewer nights re-explaining the same incident.\n\nIf you ship voice in production, budget for: transcription spend, captcha fails, and the emotional cost of a demo that works on your laptop and dies on a mid-range Android Chrome tab with three other media tabs open.", "url": "https://wpnews.pro/news/building-a-voice-english-practice-app-in-the-browser-what-broke-first", "canonical_source": "https://dev.to/gabriel_luispacheco_6835/building-a-voice-english-practice-app-in-the-browser-what-broke-first-4ncf", "published_at": "2026-11-09 23:08:03+00:00", "updated_at": "2026-11-09 23:23:48.938799+00:00", "lang": "en", "topics": ["ai-products", "ai-tools", "generative-engine-optimization", "ai-crawlers", "agent-protocols"], "entities": ["BataTalk", "Gabriel Luis Pacheco", "Tato", "Supabase", "Stripe", "Cloudflare", "Render", "Resend"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/building-a-voice-english-practice-app-in-the-browser-what-broke-first", "markdown": "https://wpnews.pro/news/building-a-voice-english-practice-app-in-the-browser-what-broke-first.md", "text": "https://wpnews.pro/news/building-a-voice-english-practice-app-in-the-browser-what-broke-first.txt", "jsonld": "https://wpnews.pro/news/building-a-voice-english-practice-app-in-the-browser-what-broke-first.jsonld"}}