<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by getstream.io on Medium]]></title>
        <description><![CDATA[Stories by getstream.io on Medium]]></description>
        <link>https://medium.com/@getstream_io?source=rss-7d292f5ec55a------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*m-gTGzrcRxlkNF3gxGbgdQ.png</url>
            <title>Stories by getstream.io on Medium</title>
            <link>https://medium.com/@getstream_io?source=rss-7d292f5ec55a------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 04 Nov 2026 23:07:28 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@getstream_io/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Prediction Markets Have a Trust Problem. Here’s How to Solve It.]]></title>
            <link>https://medium.com/getstream-io/prediction-markets-have-a-trust-problem-heres-how-to-solve-it-338b94cb777f?source=rss-7d292f5ec55a------2</link>
            <guid isPermaLink="false">https://medium.com/p/338b94cb777f</guid>
            <category><![CDATA[app-moderation]]></category>
            <category><![CDATA[ai-moderation]]></category>
            <category><![CDATA[prediction-markets]]></category>
            <category><![CDATA[content-moderation]]></category>
            <dc:creator><![CDATA[getstream.io]]></dc:creator>
            <pubDate>Tue, 29 Sep 2026 19:41:48 GMT</pubDate>
            <atom:updated>2026-09-29T19:41:48.962Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OvvsdMoshvFfgOFt_3XOrg.avif" /></figure><p>In under two years, prediction markets went from a niche corner of the internet for political junkies to platforms with sportsbook-level engagement.</p><p>Kalshi and Polymarket alone have hit millions of monthly active users.</p><p>For most industries, that growth curve gets a headline and a victory lap. For anyone responsible for trust and safety, it’s the exact scenario that keeps them up at night. You inherit a flood of users (and every bad actor who follows them) before your infrastructure has had time to catch up.</p><blockquote>“These companies don’t know what or how they should moderate yet,” says Sam Richardson, Enterprise Account Executive at Stream who spends most weeks talking to the platforms building this category from scratch. “But they know they need to be catching everything now, before it gets out of control.”</blockquote><p>Enter: <a href="https://getstream.io/moderation/">moderation</a>.</p><p>Quite possibly the most critical element for prediction markets right now. Why? Because the alternative (no moderation, free-for-all) could mean the end of an industry.</p><p>Sounds extreme, but we wouldn’t be afraid to bet on it.</p><p>Let’s get into it — and why you should care.</p><h3>The Blind Spot Nobody Built For</h3><p>Real-money <a href="https://getstream.io/chat/solutions/real-money-gaming/">gaming and gambling apps</a> have existed for decades, but they were never social products.</p><blockquote>“Historically, these companies were never thinking about moderation because there was no need. There were no user-to-user interactions. You logged in, transacted, and left.”</blockquote><p>Prediction markets broke that model.</p><p>With trade chats, comment threads, and <a href="https://getstream.io/activity-feeds/">social feeds</a> built around live events, engagement is now a feature. <strong>So what? </strong>Well, these platforms inherited millions of users and a genuinely social product, running on moderation infrastructure that was never designed to watch user-to-user behavior at all, let alone the specific kind that shows up when real money is moving on a live outcome.</p><p>Yes, it’s dangerous.</p><h3>What’s Actually at Stake?</h3><p>It’s easy to forget how new this category actually is.</p><p>Kalshi and Polymarket went from effectively nothing to millions of monthly active users in about a year and a half. That’s the entire lifespan of the industry so far.</p><blockquote>“In prediction markets, you basically figure out your brand integrity in the first year and a half. After that, it’s locked in. The platforms that get ahead of it now are the ones setting the standard next year.”</blockquote><p>For a builder in this space, it’s a <strong>product-integrity issue</strong>, on par with getting custody or settlement wrong.</p><p>Not to mention… the whole world is watching.</p><p>If prediction market apps drop the ball on moderation, <strong>the fallout could end the app entirely</strong>, and not always at the hands of a regulator.</p><p>App stores, cloud providers, and payment processors have shown they’ll pull support before any court does:</p><ul><li><a href="https://www.npr.org/2021/01/15/957234803/parler-executive-responds-to-amazon-cutoff-and-defends-approach-to-moderation">Parler found that out in January 2021</a>. Apple, Google, and Amazon Web Services all cut it off within days over its failure to moderate content inciting violence, and it was fully offline for more than a month.</li><li><a href="https://www.bbc.com/news/business-67364634">Omegle shut down for good in 2023</a> after years of lawsuits alleging its lack of moderation let predators target minors; its founder said the platform simply couldn’t carry that weight anymore.</li><li><a href="https://www.theguardian.com/technology/2019/aug/05/8chan-far-right-message-board-hosting">8chan lost its infrastructure protection in 2019</a> after a mass shooter posted a manifesto there unchecked, and it never came back at scale.</li></ul><p>A category like prediction markets that’s moving this much money, under this much scrutiny, won’t get a longer grace period than any of those did.</p><h3>Compliance &amp; Moderation Are Not the Same Bet</h3><p>If Richardson had to guess, he’d say prediction markets are going to force the entire gambling and fintech industry to admit that compliance and moderation solve two different problems, and treating them as interchangeable is a mistake that’s about to get expensive.</p><blockquote>“You can be fully licensed and still attract manipulation and abuse. Compliance asks ‘are we legal.’ Moderation asks ‘are we safe.’ Right now this category’s got the first one down and is winging the second.”</blockquote><p>His prediction:</p><p>The platforms that survive the next two years of regulatory chaos will be the ones that put moderation first. Fancy lawyers aren’t the solution. And frankly, they should never have to get involved if moderation is dealt with upfront.</p><h3>Now What?</h3><p>Stream already <a href="https://getstream.io/blog/prediction-markets-at-scale/">powers moderation for 80% of prediction markets</a>.</p><p>And with good reason.</p><p>While most of the moderation market is still selling one-size-fits-all detection, <a href="https://getstream.io/moderation/docs/node/engines/ai-llm-text/">Stream’s models</a> are built around context. They know the difference between a five-year user blowing off steam after a bad trade and a brand-new account running the exact same message pattern ten times in a row.</p><blockquote>“Prediction markets mix finance, sports, and gambling, so people talk like it’s a gambling forum. Most of that’s harmless. The problem is the same language shows up right before something worse happens. Without context on who’s talking and how they’ve changed, a moderator looking at one message will miss it.”</blockquote><p>That, on top of powerful <a href="https://getstream.io/blog/nlp-vs-llm-moderation/">LLM models</a>, multilingual protection, and highly customizable rule builders, make one thing true. If you’re building a prediction market platform right now, there’s a real chance your biggest competitor is already using Stream.</p><h3>The Bottom Line</h3><p>Richardson’s read on where this goes? The apps that win in this category are the ones focused on retention. And retention is downstream of whether users trust what they’re walking into.</p><blockquote>“If moderation isn’t part of the picture, this isn’t sustainable.”</blockquote><p>It’s black and white.</p><p>The lawyers can keep you legal. They can’t keep you trusted. In a category this young, with this much money and this much regulatory attention, trust will determine who’s still around in two years.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=338b94cb777f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/getstream-io/prediction-markets-have-a-trust-problem-heres-how-to-solve-it-338b94cb777f">Prediction Markets Have a Trust Problem. Here’s How to Solve It.</a> was originally published in <a href="https://medium.com/getstream-io">Stream</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Multimodal AI Agent Architecture: Designing Voice and Video Apps]]></title>
            <link>https://medium.com/getstream-io/multimodal-ai-agent-architecture-designing-voice-and-video-apps-acc540a45b18?source=rss-7d292f5ec55a------2</link>
            <guid isPermaLink="false">https://medium.com/p/acc540a45b18</guid>
            <category><![CDATA[video-app]]></category>
            <category><![CDATA[multimodal-ai]]></category>
            <category><![CDATA[ai-agent-architecture]]></category>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[voice-app]]></category>
            <dc:creator><![CDATA[getstream.io]]></dc:creator>
            <pubDate>Thu, 10 Sep 2026 17:13:56 GMT</pubDate>
            <atom:updated>2026-09-28T15:48:17.368Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VNAV3ufDc-SIGux6s7xFuw.png" /></figure><p>TL;DR</p><ul><li><em>Speech, text, and vision should share a single realtime loop with shared rules for turn-taking, tool use, and fallback.</em></li><li><em>Turn-taking and state are core design work. Think voice activity detection, a turn policy, narrow tool calls, and memory that doesn’t make the conversation brittle.</em></li><li><em>Vision involves sampled frames. Route precision tasks (like small on-screen text) to a specialized CV model instead of expecting the multimodal model to catch everything.</em></li><li><em>Track turn latency, interruption recovery, tool round-trip time, and session drop rate.</em></li></ul><p>If your app needs to listen, watch, and respond in the same session, a normal speech-to-text plus text-to-speech stack quickly starts to feel clumsy.</p><p>The best <a href="https://getstream.io/vision-agents/">multimodal agents</a> are not built as three separate pipelines stitched together. Rather, they should be designed as one realtime workflow that can process speech, text, and vision together, with clear rules for turn-taking, tool use, retrieval, and fallback behavior.</p><p><strong>This guide breaks down how to design multimodal AI agent architecture for voice and video apps that hold up in production, using the architectural choices, transport options, and model constraints that matter most.</strong></p><h3>How To Think About Multimodal Realtime Agents</h3><p>Evaluating a <a href="https://getstream.io/blog/realtime-ai-agents-latency/">realtime agent</a> starts with three questions.</p><ol><li>How fast does it respond when the user interrupts?</li><li>What happens when vision input arrives late or is missing?</li><li>And can the system keep state across a long call without drifting into nonsense?</li></ol><p>Those questions come from the same failure modes showing up over and over. A clean demo often falls apart on barge-in, noisy audio, or a camera feed that updates slower than the conversation. A useful agent needs a turn detector, a transport that stays stable under load, and a way to decide when speech, text, or vision should drive the next action.</p><p>The other thing worth checking is whether the system treats multimodality as one loop or as separate services. If a product sends audio to one service, images to another, then tries to reconcile the outputs in a third layer, the user usually pays for that in delay.</p><p>The better systems keep the conversation together and make each input type part of the same session state.</p><h3>One Loop, Not Three Pipelines</h3><p>The old chain of ASR to LLM to <a href="https://getstream.io/blog/text-to-speech/">TTS</a> still works for short prompts, but it gets awkward the moment the user talks over the assistant or points the camera at something that changes quickly.</p><p>In a live support call, even a 700 ms pause can feel long. In a coaching or telehealth flow, a delayed response can make the agent miss the moment that matters.</p><p>The shift is architectural. Audio, images, and text flow through a single live session instead of separate services stitched together after the fact. The model is part of the live loop.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*FRPRQScvghyJuNJS.png" /></figure><p>That matters for interruption handling, too.</p><p>If the model hears the user start talking before the previous response has finished, it can stop, adjust, or defer. If the camera feed changes while the call is active, the agent can use that frame as part of the same turn instead of waiting for a separate vision pipeline to catch up.</p><h3>Choosing Your Transport</h3><p>Transport choices decide how much control you have over the session, where media can originate, and how hard the whole thing is to debug.</p><p><a href="https://getstream.io/blog/build-ai-voice-agent/"><strong>WebRTC is the default choice</strong></a><strong> for browser-based voice and video agents</strong> because it was standardized for real-time audio and video on the web. In practice, that means lower friction for mic and camera capture, a better fit for bidirectional media, and fewer awkward hops through a backend that was never meant to handle media timing.</p><p><strong>For </strong><a href="https://getstream.io/blog/voice-ai-phone-support/"><strong>phone-based agents</strong></a><strong>, Twilio is usually the practical path</strong> since the media already lives in telephony, bridging a call into the agent session rather than asking the user to switch to a browser.</p><h3>Turn-Taking, Tools, and State</h3><p>The core work is session design.</p><p>A production agent needs a voice activity detector, a turn policy, a tool router, and some memory of what just happened.</p><p>In a real call, the sequence is usually messy:</p><ul><li>The user starts speaking before the agent has finished</li><li>A tool call returns while the agent is still generating audio</li><li>The same user asks a follow-up that depends on the previous answer</li><li>The session needs to fall back to text if audio drops</li></ul><p>The agent should know when to pause, when to continue, and when to call a tool.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*oWH5DpUiZJcMXgFI.png" /></figure><p>Tool calls work best when they are explicit and narrow. A calendar check, a CRM lookup, and a policy search should not all go through one generic endpoint if the output needs to be dependable.</p><p>And state matters as much as the tool layer. A live session needs enough memory to keep context, but not so much that the conversation becomes brittle. That means server-side controls, guardrails, conversation lifecycle management, and cost monitoring. Not just a longer prompt.</p><h3>Vision: Frames, Not Video</h3><p>One common mistake is assuming a <a href="https://getstream.io/blog/what-is-a-vision-agent/">video agent</a> is watching everything all the time. That is rarely true in production.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*YCp1pPUYWXdHnydr.png" /></figure><p>Most systems use sampled frames, short clips, or still images, then combine those with audio and text. In practice, the model treats a frame more like a photo dropped into the conversation than a continuous stream it’s watching. That distinction matters because it changes what you can expect from the model and where you need extra CV logic.</p><p>For applications that need precise visual cues, a specialized vision model often does the first pass:</p><blockquote><a href="https://visionagents.ai/">Vision Agents</a> leans into that pattern with pluggable vision pipelines, frame-by-frame processors, and <a href="https://getstream.io/blog/ultralytics-yolo-vision-guide/">support for models such as YOLO</a> and Roboflow alongside larger language models. That is the sensible split for use cases like golf coaching, form checks, or screen walkthroughs.</blockquote><p>The other constraint is context length.</p><p><a href="https://getstream.io/blog/how-vision-models-work/">Video understanding</a> gets weaker in longer continuous sessions, especially after roughly 30 seconds, and that small text is a weak spot. That lines up with what to expect from any live system: if the user needs OCR-level accuracy on a tiny UI element, route that task to the right model instead of waiting for the multimodal model to guess.</p><h3>Grounding With Retrieval</h3><p>Live multimodal agents break down quickly when the answer depends on policy, product details, or account-specific context. Retrieval is the difference between a fluent answer and a confident mistake.</p><p>For voice and video apps, the retriever needs to be fast enough to stay inside the session. <a href="https://getstream.io/blog/vision-agents-v0-3/">Vision Agents supports two practical paths here</a>: Gemini File Search for quick setup, and TurboPuffer for hybrid vector plus BM25 search with reciprocal rank fusion. The details matter because the agent may need a short policy paragraph, a meeting note, or a case file while the user is still talking.</p><p>RAG is also what keeps phone and support agents from hallucinating on local rules. In a telephony workflow, the agent can answer an intake question, check a knowledge base, then hand off a concise summary to a human if needed. That is a better fit than trying to make the model remember everything in the prompt.</p><h3>Deploying and Monitoring</h3><p>A realtime agent is easy to launch and harder to keep healthy.</p><p>The things that usually show up first are <a href="https://getstream.io/glossary/packet-loss/">packet loss</a>, slow turn detection, and cost creep from long sessions. After that comes observability. With no trace of which turn triggered which tool call, you’re stuck guessing what happened.</p><p>Vision Agents takes a practical approach here. The project includes HTTP server support, Prometheus metrics via OpenTelemetry instrumentation, Docker, and Kubernetes deployment. In practice, teams can watch LLM, STT, TTS, and turn detection metrics without rebuilding the same plumbing themselves.</p><p>For production tuning, the numbers that matter most are:</p><ul><li>end-to-end turn latency</li><li>interruption recovery time</li><li>tool-call round-trip time</li><li>frame processing delay</li><li>session drop rate</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*xw4BGgJMBcxzoIEP.png" /></figure><p>If those are not measured, the agent is being tuned by feel.</p><h3>Is Vision Agents a Fit?</h3><p><a href="https://getstream.io/vision-agents/">Vision Agents</a> makes sense when the app is truly multimodal and the team wants Python-first control over transport, tools, and deployment. It fits best when the workflow needs voice, video, RAG, and a clear path to production monitoring in the same codebase.</p><p>A simple way to judge fit is to ask whether the app needs frame-level vision plus live audio in one session.</p><p>If the answer is yes, the framework’s modular agent design, WebRTC support, Twilio calling flow, and deployment tooling line up with that problem.</p><p>If the answer is only voice, with no real vision or custom tool layer, it may be more framework than the project needs.</p><p>For teams evaluating it, run one interruption test before anything else. Start a live session, point the camera at a page with small on-screen text, then interrupt the agent mid-answer and ask it to read a specific line from the frame. A useful system should stop cleanly, recover the turn, and send the right visual task to the vision pipeline without losing the conversation state. If that fails, the rest of the stack usually has the same weakness.</p><p>The <a href="https://visionagents.ai/">Vision Agents quickstart</a> is the fastest way to set up that test.</p><h3>Frequently Asked Questions</h3><h4>What is a multimodal AI agent for voice and video?</h4><p>A multimodal agent processes speech, text, and vision in one live session. In practice, that usually means audio streaming, sampled frames or images, tool calls, and a response loop that can handle interruptions.</p><h4>Should voice and video agents use WebRTC or WebSockets?</h4><p>WebRTC is the better fit for browser audio and video because it is built for real-time media. <a href="https://getstream.io/blog/webrtc-websockets/">WebSockets</a> still make sense for server-side orchestration, control messages, or middle-tier apps that are not sending media directly from the client.</p><h4>Do multimodal agents need continuous video understanding?</h4><p>Usually not. Many production systems use discrete frames or sampled clips, then combine that with live audio. That keeps latency lower and makes the vision side easier to control.</p><h4>Why does turn detection matter so much?</h4><p>Without turn detection, the agent will talk over the user, cut off too early, or wait too long to answer. Voice activity detection and turn policy are what keep the session usable.</p><h4>When does RAG matter in a live voice or video app?</h4><p>RAG matters any time the answer depends on policy, product details, a support article, or account-specific context. It keeps the agent from guessing when the correct answer is already in a source document.</p><h4>Is Vision Agents more suited to voice-only or multimodal builds?</h4><p>It is better suited to multimodal builds. The framework is built around voice, video, retrieval, and deployment in one workflow, so it makes more sense when vision is part of the product rather than a side feature.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=acc540a45b18" width="1" height="1" alt=""><hr><p><a href="https://medium.com/getstream-io/multimodal-ai-agent-architecture-designing-voice-and-video-apps-acc540a45b18">Multimodal AI Agent Architecture: Designing Voice and Video Apps</a> was originally published in <a href="https://medium.com/getstream-io">Stream</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The New Security Requirements for Real-Time Video Infrastructure]]></title>
            <link>https://medium.com/getstream-io/the-new-security-requirements-for-real-time-video-infrastructure-d12c52380ef7?source=rss-7d292f5ec55a------2</link>
            <guid isPermaLink="false">https://medium.com/p/d12c52380ef7</guid>
            <category><![CDATA[video-security]]></category>
            <category><![CDATA[video-encryption]]></category>
            <category><![CDATA[real-time-video]]></category>
            <category><![CDATA[video-infrastructure]]></category>
            <category><![CDATA[e2ee]]></category>
            <dc:creator><![CDATA[getstream.io]]></dc:creator>
            <pubDate>Fri, 21 Aug 2026 21:37:19 GMT</pubDate>
            <atom:updated>2026-09-28T15:48:08.126Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VK6rzgiGlsTj2pbMBUc5wQ.jpeg" /></figure><p>TL;DR</p><ul><li><em>Deepfakes broke the old assumption that seeing a face on a call proves who’s on it. Encryption and account logins were never designed to check that.</em></li><li><em>A video call has four separate security layers: transport encryption (DTLS), media encryption (E2EE/SFrame), account authorization (tokens and roles), and human verification. Only the last one checks who’s actually on camera.</em></li><li><em>Stream covers transport encryption today and is adding native E2EE (SFrame) to the React SDK. Verifying the person on screen stays the developer’s responsibility.</em></li><li><em>Zoom and Microsoft shipped identity verification into mainstream video products in 2026. The question for developers is which of their own call types need the same guarantee.</em></li></ul><p>In January 2024, a finance worker at the engineering firm Arup joined a video call with his company’s CFO and several colleagues. The request was unusual: a series of confidential transfers, authorized on the spot. But the people asking were familiar faces, live on camera. He made 15 transfers totaling HK$200 million (about US$25.6 million) to five bank accounts.</p><p><a href="https://www.cnn.com/2024/02/04/asia/deepfake-cfo-scam-hong-kong-intl-hnk/index.html">Everyone else on that call was a deepfake</a>, assembled from publicly available footage and voice samples.</p><p>Nothing about the session was compromised in the traditional sense. The connection was encrypted. The meeting was real. The attack worked because every security control involved verified the session, and none of them verified the humans in it.</p><p>This piece walks through what a video call actually secures today, where the gaps are, and what closing them looks like in practice.</p><h3>Why is Human Verification Arriving Now?</h3><p>Like they say in “All The President’s Men,” always follow the money. The costs explain the urgency. <a href="https://www.deloitte.com/us/en/insights/industry/financial-services/deepfake-banking-fraud-risk-on-the-rise.html">Deloitte’s Center for Financial Services</a> estimates that AI-enabled fraud losses in the US could grow from $12.3 billion in 2023 to $40 billion by 2027.</p><p>We can think about AI-enabled fraud along two axes:</p><ol><li><strong>Quantity</strong>. Generative AI collapses the cost of volume. Scams that once needed a human to write every message, business email compromise being the classic case, can now run against thousands of targets at once, each message fluent, personalized, and free of the tells that used to give phishing away.</li><li><strong>Quality</strong>. The same models collapse the cost of fidelity. Producing a convincing human face in real time used to require resources far beyond a typical fraud operation, and now it runs on cheap, accessible tooling.</li></ol><p>Volume is a problem the industry already has defenses for: spam filters, rate limits, anomaly detection, all tuned across years of email and payment fraud. Fidelity has nothing comparable yet.</p><p>Two years after the Arup call, that gap is reshaping product roadmaps. In April 2026, <a href="https://news.zoom.com/zoom-and-tools-for-humanity/">Zoom announced a partnership with Tools for Humanity</a> to integrate World ID Deep Face into Zoom Meetings, verifying in real time that participants are actual humans. Verified attendees get a “Verified Human” badge on their video tile.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Vq7zD8IiLmbZADQx.png" /></figure><p>Microsoft has been moving in the same direction with <a href="https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-verified-id">Entra Verified ID</a>, and its identity team frames the problem plainly: existing systems verify credentials, sessions, and devices, not the person behind them.</p><p>The two efforts sound similar but make two different promises, and the distinction matters when you’re deciding what your product actually needs. World ID is proof of humanity. It confirms that a real, unique human is present without revealing who they are. Microsoft Entra Verified ID sits closer to traditional identity proofing. Its Face Check flow compares a real-time selfie against the photo from a government ID and shares only the match result with the relying application.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uVNRwdoDVIUdrGitnEaZ7Q.png" /></figure><p>Different products need different guarantees. A marketplace fighting bot armies needs proof of human. A payroll approval flow needs proof of person. A telehealth platform probably needs both, plus a record that verification happened. Knowing which guarantee your high-stakes moments require shapes every downstream build decision.</p><h3>What Can a Video Call Verify?</h3><p>There are four things a video call can verify: the connection, the media, the account, and the person. Each has its own control, each control answers exactly one question, and none of them covers for the others. That sounds obvious written down. In practice, the four get collapsed into one word, “secure,” which is how a company ends up wiring $25 million to a face on a screen.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9h6opI9VefYWv9-0Fv-bEA.png" /></figure><p>The first three check the connection, the media, and the account. None of them looks at the person, so their gaps all reduce to the same case: a fake face in a legitimate session. The fourth control closes exactly that gap, and until this year, no mainstream video product shipped it.</p><h3>The Connection: Transport Encryption Stops at the Media Server</h3><p>Transport encryption is the control that every video product already ships. Its job is to keep anyone sitting on the network path from reading or tampering with your packets, whether that’s a coffee shop router, an ISP, or a compromised hop somewhere in the middle.</p><p>In <a href="https://getstream.io/glossary/webrtc-protocol/">WebRTC</a>, that means <a href="https://getstream.io/glossary/datagram-transport-layer-security/">DTLS</a> (Datagram Transport Layer Security), because media travels over UDP and TLS assumes a reliable, ordered connection that UDP doesn’t provide. DTLS is TLS reworked for packets that arrive late, out of order, or not at all. It produces the keys <a href="https://getstream.io/glossary/srt-protocol/">SRTP</a> uses to encrypt the audio and video, and it encrypts data channels directly.</p><p>The current version is <a href="https://www.rfc-editor.org/info/rfc9147/">DTLS 1.3</a>, and it’s the reasonable minimum to ask of any video infrastructure in 2026. Plenty of deployments are still running 1.2. If you want to know if your stack is running it, the WebRTC stats API reports it directly:</p><pre>// pc is your RTCPeerConnection<br>const stats = await pc.getStats();<br>stats.forEach((report) =&gt; {<br>  if (report.type === &quot;transport&quot;) {<br>    // tlsVersion is wire-format hex: &quot;FEFD&quot; is DTLS 1.2, &quot;FEFC&quot; is DTLS 1.3<br>    console.log(report.tlsVersion, report.dtlsCipher, report.srtpCipher);<br>  }<br>});</pre><p>If that prints FEFD, you’re on 1.2. If it prints FEFC, it’s 1.3. If you’re using Stream, you also have access to the WebRTC stats API through the useCallStatsReport() hook:</p><pre>import { useEffect } from &quot;react&quot;;<br>import { useCallStateHooks } from &quot;@stream-io/video-react-sdk&quot;;<br><br>// Maps the hex `tlsVersion` reported in RTCTransportStats to a readable name.<br>const DTLS_VERSIONS: Record&lt;string, string&gt; = {<br>  FEFD: &quot;DTLS 1.2&quot;,<br>  FEFC: &quot;DTLS 1.3&quot;,<br>};<br>const readTransports = (stats, leg) =&gt; {<br>  const out = [];<br>  stats?.forEach((r) =&gt; {<br>    if (r.type === &quot;transport&quot;) {<br>      out.push({<br>        leg,<br>        dtlsState: r.dtlsState,<br>        tlsVersion: r.tlsVersion,<br>        dtlsCipher: r.dtlsCipher,<br>        srtpCipher: r.srtpCipher,<br>      });<br>    }<br>  });<br>  return out;<br>};<br>export const DtlsCheck = () =&gt; {<br>  const { useCallStatsReport } = useCallStateHooks();<br>  const report = useCallStatsReport();<br>  useEffect(() =&gt; {<br>    if (!report) return;<br>    const transports = [<br>      ...readTransports(report.publisherRawStats, &quot;publisher&quot;),<br>      ...readTransports(report.subscriberRawStats, &quot;subscriber&quot;),<br>    ];<br>    transports.forEach((t) =&gt; {<br>      // Until the handshake completes, tlsVersion/ciphers are undefined.<br>      if (t.dtlsState !== &quot;connected&quot; || !t.tlsVersion) {<br>        console.log(`[dtls:${t.leg}] handshaking… (state=${t.dtlsState})`);<br>        return;<br>      }<br>      console.log(<br>        `[dtls:${t.leg}] ${DTLS_VERSIONS[t.tlsVersion] ?? t.tlsVersion}`,<br>        `| dtlsCipher=${t.dtlsCipher}`,<br>        `| srtpCipher=${t.srtpCipher}`,<br>      );<br>    });<br>  }, [report]);<br>  return null;<br>};</pre><p>Here’s the catch.</p><p>Almost every production video product routes calls through an SFU (selective forwarding unit) because peer-to-peer meshes stop scaling past a handful of participants. And in an SFU architecture, transport encryption is hop-by-hop: the server terminates the encrypted connection, handles your media as plaintext frames, and re-encrypts on the way out to each recipient.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*pEF23R_ZMdSdzIuK.png" /></figure><p>The server needs that access to route packets, and features like recording depend on it, so this is by design. But it means transport encryption alone never gave you end-to-end anything in a group call. It secures the path to the server and the path from it, and the server itself sees everything.</p><p>Stream runs DTLS 1.3 across the whole media path, including the hops between its own media servers when a call cascades across multiple edge locations.</p><h3>The Media: Encryption the Server Can’t Read</h3><p>If the SFU sees plaintext, the fix is to encrypt the media itself in a way the SFU can route without reading it. That’s what <a href="https://www.rfc-editor.org/rfc/rfc9605">SFrame</a> does. Each media frame is encrypted and authenticated end-to-end between participants, while the packet metadata the SFU needs for forwarding decisions stays visible. It was designed for server-routed conferencing from the start, and it’s the approach the industry has converged on.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*F1XDOYfS2VPUG9-g.png" /></figure><p>Browser support is through <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Using_Encoded_Transforms">WebRTC Encoded Transforms</a>. This API lets you intercept and modify encoded frames before they’re sent. You can use this to roll your own media encryption, but doing so can fall apart for a few reasons:</p><ul><li><strong>The SFU has to be in on it. </strong>A frame carries two separable things: the content (pixels, audio) and the structure (is this a keyframe, which quality layer, what it depends on). For routing, the server only ever needs the structure. E2EE splits the two: content gets encrypted, and structure moves to cleartext fields the server can still read. Clients and servers have to agree on that split, which is what SFrame standardizes.</li><li><strong>Keys need their own secure channel. </strong>Everyone on the call has to hold the same frame keys while the server holds none of them, and the set of people changes mid-call: someone joins, someone leaves, and the keys rotate so the newcomer can’t read the past and the leaver can’t read the future. There is an entire protocol for this problem, <a href="https://www.rfc-editor.org/rfc/rfc9420">MLS</a>, and it’s not a gap you can vibe-code through.</li><li><strong>Every server-side media feature breaks. </strong>Recording, transcription, captions, AI summaries: they all depend on the server decoding your media, and a server that can’t read frames can’t process them. Zoom and Teams both ship E2EE and publish the same kind of trade-off list. Zoom’s E2EE mode turns off cloud recording, live transcription, AI Companion features, streaming, whiteboards, and polling. <a href="https://learn.microsoft.com/en-us/microsoftteams/teams-end-to-end-encryption">Teams E2EE</a> drops recording, captions, and transcription, and limits which clients can join.</li></ul><p>Those tradeoffs are real product decisions: which call types get E2EE, what users are told about the features they lose, how compliance recording works when regulation requires it. They get made at the platform level, in coordination between the SDKs and the media servers. Bolting frame encryption onto app code skips the coordination and inherits all the breakage.</p><p>Stream is adding native end-to-end encryption to the React SDK in Q3 2026, with other SDKs to follow, built on the SFrame approach so it works with Stream’s SFU and cascading architecture rather than around it. Stream has already made <a href="https://getstream.io/blog/future-video-technology/">the public argument for this direction</a>: SFrame is what makes E2EE viable for group calls without giving up the scalability of selective forwarding.</p><h3>The Account: Tokens and Roles You Can Tighten Today</h3><p>When building video, this is where weaknesses are usually self-inflicted. Stream won’t admit anyone to a call without a JWT your server signed, and the role attached to that token decides what the account can do once it’s in: join, publish, record, moderate. Call-scoped tokens handle narrow cases, such as granting a guest access to a specific call.</p><p>All of it is only as strict as you configure it. For anything sensitive:</p><ul><li><strong>Generate tokens server-side with short expirations. </strong>Tokens are signed with your API secret, and anyone holding that secret can mint a valid identity for any user in your app, so it never touches a client. A long-lived token is a bearer credential waiting to leak.</li><li><strong>Keep default roles minimal. </strong>Grant join and publish, then add capabilities per role on purpose. It’s much easier to widen a narrow role than to walk back a broad one.</li><li><strong>Don’t ship permissive call types. </strong>Stream’s development call type has everything enabled by design to keep friction low while you prototype. It has no place in a production flow that touches money or health data.</li><li><strong>Prefer call-level grants over app-wide ones. </strong>A support agent who needs recording on one call type doesn’t need recording rights across all call types.</li></ul><p>A deepfake defense means very little if anonymous users can wander into sensitive calls because a call type is shipped wide open. That’s the full extent of it, though. Token auth verifies an account and authorizes what it can do. It has no opinion about the face on screen.</p><h3>The Person: The Gap No SDK Closes For You</h3><p>A user signs in and gets a valid token from your server. Their device is real. The call is end-to-end encrypted with keys only the participants hold.</p><p>And the “camera” the browser is capturing from is a virtual camera device, playing a real-time deepfake.</p><p>Nothing in the stack objects. The transport encrypts it, SFrame encrypts it, the token checks out, and the encryption even works against you here: no intermediary can inspect the stream. Every control below this one is doing exactly what it was designed to do.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*LkVcVlBeAfjFhI8Z.png" /></figure><p><strong>Stream verifies the session, not the human</strong>, and so does every other video infrastructure provider today. A valid token tells you your app admitted the right account. It can’t tell you the webcam feed belongs to the person who owns that account, that the feed is live, or that a virtual camera isn’t sitting in the capture path. No SDK flag changes that, whatever the marketing around “deepfake protection” implies.</p><p>Zoom’s implementation shows what closing the gap looks like in practice, and it breaks down into five pieces:</p><ol><li><strong>An enrolled reference. </strong>Users verify once at an Orb, and that enrollment becomes the reference for every subsequent check.</li><li><strong>A gate at entry. </strong>With a <a href="https://www.biometricupdate.com/202605/zoom-opens-beta-for-world-id-deepfake-verification-in-enterprise-meetings">Deep Face Waiting Room</a> on, nobody gets into the meeting until they’ve verified against it.</li><li><strong>A check at the moment of decision. </strong>Any participant can trigger re-verification of another participant mid-meeting when a request seems off.</li><li><strong>A check bound to the live stream.</strong> What gets matched is the video Zoom is actually transmitting on the person’s own device, so there’s no way to verify with one camera while streaming from another.</li><li><strong>A visible result. </strong>Verified participants carry a badge on their tile that everyone else can see.</li></ol><p>You can build every part of this:</p><ol><li><strong>Your enrolled reference. </strong>Decide what identity you trust: an IdP account with MFA at the low end (it proves the account, not the face), a verifiable credential like Entra Verified ID, or a document-plus-selfie enrollment with an identity verification vendor at the high end.</li><li><strong>Your gate at entry.</strong> Your server already issues the call token, so the gate is the token endpoint: for sensitive call types, no verification, no token.</li><li><strong>Your check at the moment of decision.</strong> Before the wire transfer or the account recovery, force a fresh challenge: a step-up IdP login (SSO, passkey, MFA), a liveness check, or, for irreversible actions, out-of-band confirmation on a second channel. The Arup attack dies here.</li><li><strong>Your check bound to the stream. </strong>This is the piece that’s hardest to buy today. Most identity verification products capture in their own flow, separate from the call. A virtual camera can feed that flow the same way it feeds yours using synthetic frames written straight into the pipeline. So a liveness check that only sees what the “camera” shows is checking the deepfake itself.</li><li><strong>Your visible result.</strong> Surface verification state on the participant in your UI, and write it to an audit log, because “we verified them at 2:14 pm” is the record that matters afterward.</li></ol><p>Four of the five are buildable today from parts that already exist. The check that would have caught the Arup call is the out-of-band step in number three, and that’s ordinary engineering.</p><p>Number four, binding the check to the stream itself, is the piece the market hasn’t productized yet; Zoom shipping it is the clearest signal the gap is temporary. And the asymmetry runs in your favor. An attacker has to get past every check you put in the path, while you only need one of them to fire.</p><h3>What to Build, By Stakes</h3><p>None of this needs deciding product-wide. The controls sort by workflow, and most products end up running all three tiers side by side:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WGhgq8FG7M9y8Qpen8YYzA.png" /></figure><p>The first two rows are becoming the platform’s job. Stream covers the first today, and the second arrives with native E2EE in the React SDK in Q3. The third stays with your application, and it should, because an infrastructure provider can’t know that one particular button in one particular call authorizes a wire transfer.</p><p>That third row is also getting easier to fill. Zoom shipped proof-of-human verification into meetings this year, and Microsoft is certifying identity-verification partners for Entra Verified ID. What was an exotic enterprise add-on eighteen months ago is turning into a standard part of the stack.</p><p>The Arup employee did everything his tools asked of him. He joined a real meeting through real software and trusted the encrypted, authenticated faces on screen. Every control in that call did its job; none of them was pointed at the people. That’s the part that finally changed this year. Deciding which of your calls need it is the part that’s yours.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d12c52380ef7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/getstream-io/the-new-security-requirements-for-real-time-video-infrastructure-d12c52380ef7">The New Security Requirements for Real-Time Video Infrastructure</a> was originally published in <a href="https://medium.com/getstream-io">Stream</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building An Astronomy App with Agent Skills]]></title>
            <link>https://medium.com/getstream-io/building-an-astronomy-app-with-agent-skills-32002f2aaf82?source=rss-7d292f5ec55a------2</link>
            <guid isPermaLink="false">https://medium.com/p/32002f2aaf82</guid>
            <category><![CDATA[claude-code]]></category>
            <category><![CDATA[nextjs-tutorial]]></category>
            <category><![CDATA[agent-skills]]></category>
            <category><![CDATA[ai-agent-skills]]></category>
            <category><![CDATA[astronomy-app]]></category>
            <dc:creator><![CDATA[getstream.io]]></dc:creator>
            <pubDate>Fri, 21 Aug 2026 19:36:54 GMT</pubDate>
            <atom:updated>2026-09-28T15:47:58.367Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JnpLyNbDIg1ULTrZSaT4Pw.png" /></figure><p>A few years ago, I visited my uncle in Spain. A professional painter and photographer, he’d recently turned his camera to the sky at night.</p><p>His images were incredible. Bright, sharp, and full of detail, his images were mesmerizing, and I completely got the astrophotography bug. One problem: my photography skills are closer to that of a <a href="https://en.wikipedia.org/wiki/Monkey_selfie_copyright_dispute">macaque</a> than a professional photographer, and I don’t have the $20k he spent on his rig.</p><p>Enter <a href="https://www.highpointscientific.com/telescopes/smart-telescopes">smart telescopes</a>. These incredible little machines give people with “limited” ability the chance to capture images that used to demand years of practice and thousands of dollars worth of equipment. I share these with my family and friends, and once in a while online on the right subreddits, but it would be great to have a proper place to share, discuss, and compare notes with other people who’ve caught the same bug.</p><p>That is what we’re going to build here: <a href="https://github.com/argotdev/stream-astronomy/">AstroFeed</a>. Members post their astrophotography with target, equipment, and exposure metadata, talk in channels and DMs, and join a standing “star party” video call.</p><p>But when I say <em>“what we’re going to build here,”</em> I don’t mean you and me; <strong>I mean Claude and Agent Skills.</strong></p><h3>So, What Are Agent Skills?</h3><p>Claude Code has a feature called <a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview">skills</a>: folders of instructions, reference docs, and rules that sit in your project and that Claude reads when they’re relevant to what you ask. The simple idea is that Claude can reference the exact knowledge it needs via these skills rather than searching the web and finding outdated or wrong information.</p><p><a href="https://github.com/GetStream/agent-skills">Stream’s Agent Skills</a> are the Stream SDK expertise packaged that way. One command (getstream skills — claude) installs a router that reads your prompt and figures out what you’re trying to do, a docs-search skill, and a general builder. The platform packs (React, React Native, Swift, Android, Flutter) install themselves on demand when the router needs one. AstroFeed is a Next.js app, so everything here runs through stream-react, which brings:</p><ul><li><strong>Bundled references and blueprints</strong>. The agent works from Stream’s current docs rather than whatever it half-remembers from training, and only fetches live docs when the bundled knowledge runs out.</li><li><strong>Hard rules</strong>. Never read .env.local, don’t touch files the current track forbids, and check the schema before any CLI write.</li><li><strong>Tracks for different jobs</strong>. Scaffold a new app, enhance an existing one, or audit what’s already built.</li><li><strong>A verification step</strong>. Every phase ends with type checks, a production build, and a headless browser test that takes actual screenshots.</li></ul><p>That’s the promise. I wanted to see the practice. So I ran this build as a bit of an experiment. Each phase starts in a fresh Claude Code session with a deliberately cold one-line prompt, to check whether the router lands on the right track with no help.</p><p>For the record, this is built with Claude Code 2.1.220 running Fable 5, and using getstream CLI 1.1.0.</p><h3>The Plan in the Prompt</h3><p>The only real input I gave this build was a plan document. Phase 0’s opening prompt in Claude Code was the plan itself, pasted whole. Every prompt after that was a one-liner or a two-sentence follow-up.</p><p>It’s also the input that matters most. An agent will build confidently with whatever you give it, so a vague plan doesn’t fail loudly. It fails as drift, and you spend the whole build nudging Claude back on course one correction at a time. The plan is where you spend that effort once, up front: what to build, in what order, what not to build, and what happens when something goes wrong.</p><p>I drafted mine in a regular Claude chat before any code existed, then handed the finished document to Claude Code. Here it is, trimmed of the per-phase prompts and expected-behavior notes:</p><pre>## What we&#39;re building<br><br>A web app where amateur astronomers share their astrophotography and talk<br>about it. Next.js, built through the `stream-react` skill.<br><br>Features, in build order:<br><br>- **Photo feed.** Members post shots: the image, a target name (M31, the<br>  Orion Nebula), the equipment used, an optional exposure line, a short<br>  caption. The card is image-forward with the metadata laid out under it,<br>  which means custom feed UI and image attachments, both of which should<br>  force docs lookups.<br>- **Discussion chat.** Two channels (#general and #gear) plus DMs.<br>- **Star party call.** One page that joins a standing video call by ID.<br>  Minimal on purpose: it exists so the Video audit (Track F) applies at<br>  the end.<br>- **Moderation.** Blocklist and automod on both chat and feed content,<br>  configured through the CLI.<br><br>Keep the product surface exactly this. No gold-plating, no extra features.<br>If something in this spec conflicts with what a skill wants to do, stop<br>and ask me rather than improvising.<br><br>## Build log protocol<br><br>Maintain BUILD_LOG.md. After each phase, append: the exact prompt<br>(verbatim), which skill and track activated, what the skill did, manual<br>interventions, and surprises. Prefer verbatim capture over summary.<br>Never fix a skill&#39;s mistake silently.<br><br>## Session discipline<br><br>Start Phases 1, 2, and 3 in fresh Claude Code sessions. Part of what<br>this evaluates is whether the router picks the right track from a cold<br>prompt, and carried-over context contaminates that. BUILD_LOG.md is the<br>cross-session record, so read it at the start of each new session.<br><br>## Phases<br><br>0. Prerequisites and versions<br>1. Scaffold the feed (Track A)<br>2. Add chat (Track E)<br>3. Add the star party call (Track E)<br>4. Moderation via CLI<br><br>## Hard rules<br><br>- Never read or print `.env.local` or any secrets.<br>- No SDK upgrades, no migration tracks.<br>- If a skill fails or misroutes: log it first, retry once with a<br>  rephrased prompt, then escalate to me.<br>- Ask before any deviation from the spec above.</pre><p>It didn’t make me immune to my own mistakes, though. Two of the plan’s follow-up steps never got sent, and both times it was the log that caught it before I did.</p><h3>One Sentence to a Running Feed</h3><p>Phase 1’s prompt, in full:</p><pre>&quot;Build me a Feeds app for sharing astronomy photos.&quot;</pre><p>That one sentence allowed Claude and Agent Skills to do a lot of work:</p><ul><li><strong>Routing and self-install</strong>. The router classified the prompt, picked stream-react, noticed the pack wasn’t installed yet, and downloaded it before moving on.</li><li><strong>Onboarding</strong>. It logged me into Stream through the browser and had the CLI write credentials to .env.local, which the agent never reads, per its own rules.</li><li><strong>Recovery</strong>. My project folder sits inside a yarn Berry workspace, and the standard shadcn scaffold command picked up the parent workspace and broke. The session scaffolded with create-next-app into a temp directory instead, moved the files in, ran shadcn on top, and checked nothing had leaked into the parent.</li><li><strong>A self-caught bug</strong>. tsc flagged a missing field on the SDK’s Attachment type. Fixed before I ever saw it.</li><li><strong>Verification</strong>. Clean production build, then a headless Playwright pass: log in, post an image, confirm it renders on the timeline, delete the test post.</li></ul><p>A few minutes after the prompt, I had a token endpoint, a login page, and a working feed: composer, post cards, comments, follows, profiles.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Rra9BTxtqXQfcBeCcVM09Q.png" /></figure><p>The app was ready to use:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yW4c-i1j1-kMfBLPvOYKWA.png" /></figure><p>An interesting point here is that there were zero live docs fetches. I’d expected the custom feed work to send it off to Stream’s documentation. Instead, every API decision came from reference files bundled inside the skill itself, and the docs-search skill never fired once.</p><p>But probably the nicest part here for any developer was the getstream login:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OdabUt35nZhX7IVsQpFZxw.png" /></figure><p>Almost any app you build requires you to share your API key or secret; Stream is no different. Usually that means logging into the dashboard manually and copying them over. Using the CLI, this is all automatic. It even looks through the possible apps in your account and will choose the most logical one (e.g., my astronomy app here).</p><h3>Forgetting the Spec</h3><p>Unfortunately, “Build an astronomy app. Make no mistakes” might work on Claude, but doesn’t work on me, because I made a mistake. The initial prompt was a little too sparse. Claude had told me to expand, but I’d forgotten.</p><p>This is a good lesson for LLM coding: you are still at the mercy of stupidity.</p><p>The cold prompt built a correct, generic photo feed. Caption box, image upload, done. The target and equipment fields, the image-forward card, all of it existed only in my plan document, because I never sent the follow-up. Look closely at the screenshots above, and you’re looking at the generic composer.</p><p>The log caught it. The log-keeping pass audited the phase against the plan’s done-when line and marked Phase 1 incomplete. So I resumed the session and sent the spec, word for word:</p><pre>Photo posts need structured metadata: a target name (e.g. M31, Orion Nebula), <br>equipment used, an optional exposure line, and a short caption. The card <br>should be image-forward with the metadata laid out under it.</pre><p>About five minutes later:</p><ul><li><strong>The right data model, with a citation</strong>. It put the metadata on the activity’s custom field and pointed at the bundled Feeds reference documenting exactly that pattern.</li><li><strong>A rewritten composer and card</strong>. Target required, equipment and exposure optional, full-bleed photo with the metadata laid out underneath.</li><li><strong>Its own re-verification</strong>. A fresh Playwright pass posted a test M31 shot, checked the card rendered per spec, and deleted it.</li><li><strong>Zero docs lookups</strong>. Everything it needed was already loaded from the first pass.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_1L5MeV8LkYLXM_vusqVqQ.png" /></figure><p>The lesson here is explicitness: The model doesn’t know what you want; your plan must contain every detail (or a way to catch missing details).</p><h3>Adding Chat, and a Fight With the CSS Cascade</h3><p>Fresh session, cold prompt:</p><pre>&quot;Add Chat to this app.&quot;</pre><p>The harness recognized an existing app with Stream already in it and built around it:</p><ul><li><strong>Zero server configuration</strong>. Stream ships a built-in messaging channel type, and it just works. Not one CLI call in the whole main pass.</li><li><strong>The first live docs fetches of the entire build</strong>. Two of them. “Start a DM by username” isn’t in any bundled blueprint, so it went to the live docs to confirm the distinct-channel pattern and the context API for switching channels.</li><li><strong>The usual wiring</strong>. Dual tokens from the token route, a chat client alongside the feeds client, and a chat panel assembled from Stream’s prebuilt components.</li></ul><p>By this point I had two browser windows logged in as different users, and the feed side had comments and reactions flowing between them while chat took shape.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OA950HDDwIA2IeyKZ802Pw.png" /></figure><p>This is where the first issue came up. Stream’s chat stylesheet ships flex: 0 1 auto on the channel window, so my chat pane rendered at 460 pixels inside a 700-pixel space. The session’s first fix, a Tailwind arbitrary variant ([&amp;_.str-chat__channel]:flex-1), silently did nothing, for two stacked reasons:</p><ul><li>Tailwind converts underscores to spaces inside arbitrary variants, so a selector containing __ can never match anything.</li><li>Stream’s stylesheet is unlayered while Tailwind v4 utilities live in a layer, so the SDK wins the cascade anyway, even with an ! modifier.</li></ul><p>The working fix was a small scoped CSS module that simply out-specifics the SDK’s single-class rules:</p><pre>.channelPane :global(.str-chat__channel),<br>.channelPane :global(.str-chat__container),<br>.channelPane :global(.str-chat__main-panel) {<br>flex: 1 1 0%;<br>min-width: 0;<br>}</pre><p>Worth noting how this got caught: tsc and next build were green the whole time. Only the Playwright screenshot check saw the squashed layout.</p><p>I also wanted to add specific #general and #gear channels at this point. Instead of creating the channels through the CLI or client code, the session put idempotent get-or-create and add-member calls in the token route. Every login converges on membership, and the existing channel list picks them up with zero client changes:</p><pre>const SHARED_CHANNELS = [<br>{ id: &quot;general&quot;, name: &quot;#general&quot; },<br>{ id: &quot;gear&quot;, name: &quot;#gear&quot; },<br>];<br>// In the token route, on every login:<br>await Promise.all(<br>SHARED_CHANNELS.map(async ({ id, name }) =&gt; {<br>const channel = chatClient.channel(&quot;messaging&quot;, id, {<br>name,<br>created_by_id: userId,<br>});<br>await channel.create(); // no-op get-or-create after the first call<br>await channel.addMembers([userId]);<br>}),<br>);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1ZdgtRc5UvDBwAt41Pfoww.png" /></figure><h3>A Star Party in One Page</h3><p>Fresh session, cold prompt:</p><pre>&quot;Add a video call page for our star party nights. One page, one standing call <br>joined by ID, no lobby, no ringing, no call lists.&quot;</pre><p>The track picked it up and continued the build:</p><ul><li><strong>No gold-plating</strong>. One nav tab, one page, the prebuilt SpeakerLayout and CallControls, and nothing else. It didn’t try to build a calling experience.</li><li><strong>Mostly bundled knowledge again</strong>. The video references shipped with the pack covered nearly everything, with a single live fetch for running chat and video clients side by side. Where the bundled snippet and the live page disagreed, the pack’s stricter version won, which is the precedence its own rules prescribe.</li><li><strong>The first CLI write of the entire build</strong>. A one-field app update setting the video use case, which the reference calls for and which had been sitting at null.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yvELblmxFpPh43Z2uynN1g.png" /></figure><p>Getting to two clean tiles took a fight. The first smoke test showed four participant tiles for two users.</p><p>The cause is a React strict mode classic. Strict mode mounts every component twice in development. The first mount kicks off join(), cleanup fires while that join is still in flight, and leave() does nothing because there’s nothing to leave yet. Then the original join resolves anyway and orphans a session that keeps right on publishing.</p><p>The session diagnosed it and extended the canonical join pattern with a liveness check:</p><pre>useEffect(() =&gt; {<br>if (!client) return;<br>const c = client.call(&quot;default&quot;, STAR_PARTY_CALL_ID);<br>let active = true;<br>c.join({ create: true }).then(() =&gt; {<br>// If the effect was cleaned up while join was in flight, the cleanup&#39;s<br>// leave() no-oped (not joined yet) - leave now to avoid a ghost session.<br>if (active) setCall(c);<br>else c.leave().catch(() =&gt; {});<br>});<br>return () =&gt; {<br>active = false;<br>c.leave().catch(() =&gt; {});<br>};<br>}, [client]);</pre><p>tsc was clean, the production build was clean, and the console was clean. Only the screenshot check saw four tiles where two belonged. That’s the second bug of this build that no static check could have found, and the fix is three lines that arguably belong upstream in the reference snippet itself.</p><h3>Moderation with Zero App Code</h3><p>Final prompt to add moderation:</p><pre>&quot;Set up moderation: a blocklist and automod on chat messages and feed posts.&quot;</pre><p>This phase changed no application code at all, which is the correct answer. <a href="https://getstream.io/moderation/">Moderation on Stream</a> is server-side configuration, and the session treated it that way: everything through the CLI, with the review UI left to the Dashboard, where it already lives.</p><p>It was also the phase where the docs machinery finally got a real workout:</p><ul><li><strong>The first true escalation</strong>. The pack’s docs map has no moderation section at all. The session guessed a URL and got a 404. The docs-search skill resolved the right index and worked from there.</li><li><strong>It checked for existing config before writing any</strong>. Stream apps ship with a built-in profanity blocklist, 1,105 words. The session found it and skipped creating a duplicate.</li><li><strong>Three writes</strong>. Attach the blocklist to the messaging channel type. Set app-level moderation config for chat. Set it again for feeds, which turns out to be a separate config key, with AI text rules like HATRED, INSULT, THREAT, and SCAM. Everything set to flag, nothing to remove.</li><li><strong>Verification</strong>. It read the config back, then ran the moderation engine against sample text in a test mode that persists nothing. A blocklist word flags and a strong insult flags, but “worthless idiot” doesn’t, which tells you the AI engine has severity thresholds.</li></ul><p>Two findings from this phase belong in Stream’s docs backlog. The policies page’s example labels, SPAM and HARASSMENT, but Claude tells me the API rejected both, and the real label set (34 of them) lives on a different page and contains neither. And that test mode isn’t mentioned in any reference the session had. It found it by reading the CLI’s own help output.</p><p>Obviously I wanted to test it, so I added a “This is f***ing sick!!” under a nebula shot (which is sick!). The comment was sitting there in plain view, which was unexpected to me, but expected to the model:</p><pre>Review queue: 2 items, both processed automatically (status: complete), <br>nothing awaiting human review.<br><br>1. The flagged feeds comment (by user jo): text &quot;This is f***ing sick!!&quot; - <br>tripped the blocklist, matched word fucking under the profanity rule, <br>recommended_action: flag. Because the configured action is flag (not <br>remove/bounce/shadow_block), the comment was still delivered to readers and <br>just filed for review - that&#39;s the trade-off the Phase 4 config deliberately <br>chose.<br>2. A user-level item for jo - the aggregate record that tracks the flagged <br>user (flagged_count: 1), auto-resolved with recommended_action: keep.</pre><p>This is working as configured. Flag means the content gets delivered and a human gets a case to review.</p><h3>Where Agent Skills Excelled, And What Needs Work</h3><p>The core promises held. Every cold prompt routed to the right track, the agent asked for input exactly once all afternoon, and the guardrails did their job: it wrote credentials without ever reading them, stayed out of the files its rules forbid, and checked the schema before every CLI write. The standout was the verification habit. Both real bugs of this build sailed past type checks, builds, and the console, but the Playwright screenshots caught them.</p><p>A simple build like this doesn’t give you all the information, but it left me with four things:</p><ul><li>Managing Stream <a href="https://getstream.io/cli/">directly through the CLI</a> is a great feature, and it was great for this build. Everything the Dashboard can do, an agent can now do, which is why moderation needed zero app code and why so much of this can be automated.</li><li>Agent skills work excellently with a good model. Not perfectly, but the model starts with about 95% of the information it needs already on disk and can easily find the rest through the references. It never had to guess.</li><li>The skills encode Stream’s defaults, and on those defaults the build is trivial. Both times the model had to change happened exactly where AstroFeed strayed from them, so the more specific your app, the more of that you should budget for.</li><li>I built linearly on purpose so I could watch the router work. Real projects will run agents in parallel under an orchestrator or a loop, and that’s where skills matter most: they keep every model tied to the same current references and the same rules instead of improvising from memory.</li></ul><p>If you want to try this yourself, <a href="https://getstream.io/agent-skills/">Agent Skills</a> are free on GitHub and work with any Stream account, including a <a href="https://getstream.io/try-for-free/">free trial</a>. Install them with getstream skills — claude, point Claude Code at your own app idea, and see how far one prompt gets you. And if you want to see exactly how this build went, prompt by prompt, the full log is in the <a href="https://github.com/argotdev/stream-astronomy/">AstroFeed repo</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=32002f2aaf82" width="1" height="1" alt=""><hr><p><a href="https://medium.com/getstream-io/building-an-astronomy-app-with-agent-skills-32002f2aaf82">Building An Astronomy App with Agent Skills</a> was originally published in <a href="https://medium.com/getstream-io">Stream</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Architecting Real-Time Moderation for Live Video]]></title>
            <link>https://medium.com/getstream-io/architecting-real-time-moderation-for-live-video-36eaecef5edf?source=rss-7d292f5ec55a------2</link>
            <guid isPermaLink="false">https://medium.com/p/36eaecef5edf</guid>
            <category><![CDATA[video-moderation]]></category>
            <category><![CDATA[ai-content-moderation]]></category>
            <category><![CDATA[real-time-moderation]]></category>
            <category><![CDATA[content-moderation]]></category>
            <category><![CDATA[moderation]]></category>
            <dc:creator><![CDATA[getstream.io]]></dc:creator>
            <pubDate>Tue, 11 Aug 2026 17:13:29 GMT</pubDate>
            <atom:updated>2026-08-11T17:14:02.253Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UFnc_IuKvnXMuC46c625eg.jpeg" /></figure><p>TL;DR</p><ul><li><a href="https://getstream.io/blog/live-content-moderation/"><em>Live moderation</em></a> <em>splits into two paths: a fast, shallow check that blocks content before it ships, and a slower, deeper check that corrects the decision after the fact.</em></li><li><em>Your delivery protocol sets the size of that window before any model runs. WebRTC’s sub-second delivery leaves almost no time to block; LL-HLS’s few seconds of delay leaves room to work with.</em></li><li><em>Keep the blocking path inside its window by scoring fewer frames, compressing the model, and running it at the edge; give the correcting path the time and context (multimodal fusion, human review) the blocking path doesn’t have.</em></li><li><em>Track precision, recall, and F1 by category instead of one accuracy number, and keep an immutable decision log.</em></li></ul><p>A creator goes live on your platform. It’s a <a href="https://getstream.io/video/live-shopping/">shopping stream</a> with thousands of viewers and chat running fast.</p><p>Twenty minutes in, something crosses a line. A counterfeit item on camera… a slur in the chat… a claim the policy doesn’t allow.</p><p>Viewers have already watched it happen by the time anyone notices, and it’s your platform’s rules on the line, not just the creator’s.</p><p>That’s what makes <a href="https://getstream.io/moderation/">live stream moderation</a> different from every other content type. There’s no queue to hold a violation in, and no way to recall what’s already gone out.</p><p><strong>This piece covers the architecture for it: </strong>a fast, shallow path that beats your delivery window and blocks content outright; a slower, deeper path that corrects the call after the fact; and the protocols, models, and queues that make both work.</p><h3>What You Must Decide: Whether To Block Now or Correct After</h3><p>The core idea is to sort every check you run by its deadline rather than by what it looks at.</p><p>That means you’re not building one moderation pipeline for <a href="https://getstream.io/chat/">chat</a>, another for <a href="https://getstream.io/video/">video</a>, and another for audio. Instead, you ask a timeline question about every check: <em>how long do I have before a viewer sees this, and can the check answer inside that time?</em></p><p>The time you have is the gap between content reaching your servers and a player showing it, and your protocols and product decisions set this number: a few seconds of segment delay on LL-HLS, or just a few hundred milliseconds on <a href="https://getstream.io/glossary/webrtc-protocol/">WebRTC</a>, plus whatever small hold you can add without viewers feeling it.</p><ul><li><strong>A check that beats the window can block the content. </strong>Its verdict arrives while the content is still only on your side, so acting on it means the chat message never appears or the video segment never gets published. Nothing was seen, so there’s nothing to undo.</li><li><strong>A check that misses the window has to act after viewers have watched the content. </strong>This means you’re correcting the decision, not the violation. Whatever was seen was seen, and no correction resets someone’s eyeballs.</li></ul><p>So you effectively end up with two streams of moderation, one fast and shallow, the other slow and deep. The same live video gets both treatments at once: a small image model scores sampled frames quickly enough to hold a segment back, while a temporal model that needs a few seconds of clip runs behind it and flags more subtle problems.</p><p>Chat works the same way, with a lightweight classifier gating each message and a slower context check reconsidering it.</p><p>So the design work splits into three pieces:</p><ol><li><strong>The window,</strong> which your protocols fix before any classifier runs.</li><li><strong>The blocking path, </strong>everything that has to beat the window.</li><li><strong>The correcting path,</strong> everything allowed to miss it as long as it can still act.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*pKVAhQni9QC0Qgop.png" /></figure><p>The window comes first because you inherit it rather than choose it.</p><h3>The Window Your Protocols Set</h3><p>Protocols are what define livestreams, and they matter to moderation in different ways:</p><ul><li><strong>Delivery protocols, </strong>server-to-player, set the window itself. This is where the time in the timeline question comes from.</li><li><strong>Ingest protocols, </strong>encoder-to-server, decide what condition the stream arrives in. They don’t change the window, but a stream that stalls on the way in leaves nothing for either path to work with.</li></ul><p>Most of the latency spread comes down to TCP versus UDP. RTMP runs over TCP, so one lost packet holds up everything queued behind it until retransmission. That’s <a href="https://getstream.io/blog/protocol-comparison/">head-of-line blocking</a>, and on a congested stream it turns into stalls and jitter. The UDP protocols skip the missing packet and move on, since a frame that shows up late isn’t worth waiting for in a live stream.</p><p>Here’s a breakdown of <a href="https://getstream.io/blog/low-latency-video-streaming/">low-latency streaming</a> and the different tradeoffs:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qaYm6RLfc7co4XIaAam58g.png" /></figure><p>On the ingest side, RTMP is still the default because nearly every encoder speaks it. On the delivery side, the choice decides how much room the blocking path gets:</p><ul><li><strong>LL-HLS: seconds of delay, cheap scale, real working room. </strong>Segments ride the same CDN caches as static content, so big passive audiences stay affordable, and players run a few seconds behind your encoder.</li><li><strong>WebRTC: sub-second delivery, per-viewer cost, almost no window.</strong> Every viewer holds a session with a <a href="https://getstream.io/blog/what-is-a-selective-forwarding-unit-in-webrtc/">selective forwarding unit</a> (SFU), and a frame is on screens before most checks return.</li></ul><p>In practice, most platforms mix them: WebRTC for the hosts and guests on stage, and LL-HLS via a CDN for everyone watching.</p><p>But we can see immediately how these decisions matter for moderation. With LL-HLS, a violation caught now stops the next segment from ever being published, or ends the stream before any player requests it, holding the violation’s airtime to seconds.</p><p>But if you deliver entirely through WebRTC, your options are limited, as blocking mostly means acting on the frames that follow. Sub-second delivery is a real feature; you just pay for part of it out of the moderation budget.</p><h3>One Stream In, Two Paths Out</h3><p>At ingest, you fork the stream. One copy goes straight to transcode and delivery. The other feeds moderation, and nothing that happens to it can slow the first copy down.</p><p>On the moderation copy, the two paths map onto straightforward engineering:</p><ul><li><strong>The blocking path runs synchronously,</strong> inline with the content. A verdict comes back before the message posts or the segment ships.</li><li><strong>The correcting path runs asynchronously, </strong>behind a queue. Verdicts come back as webhooks, on their own time.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*xtTvtsK9Gd7ZxzHf.png" /></figure><h3>What Runs Inline</h3><p>A <a href="https://getstream.io/moderation/docs/engines/semantic-filters/">semantic filter</a> scoring each chat message before it posts, a small image model scoring sampled frames before the next segment ships. There’s deliberately little infrastructure here, because every extra hop spends window time.</p><p>The inline check doesn’t have to live on your servers either. You can <a href="https://getstream.io/blog/vision-ai-integration-app/">put it on the device</a>: a light model screens every frame locally, and only suspicious 2–6 second clips, keyframes, or compact embeddings get uploaded for a deeper look. The blocking path sits next to the content, and the correcting path picks up at the upload.</p><h3>What Runs Behind the Queue</h3><p>Ingestion publishes frames and chat events to a bus like Kafka, rules and heavy models consume them from a stateful processor like Flink, and decisions flow back to enforcement on their own schedule. A model that takes ten seconds, or a review backlog forty items deep, delays a correction and touches nothing else.</p><p>The consumers can be a whole pipeline of their own. In AWS’s <a href="https://aws.amazon.com/blogs/machine-learning/dynamic-video-content-moderation-and-policy-evaluation-using-aws-generative-ai-services/">generative-AI moderation pattern</a>, a segment landing in S3 starts a Step Functions state machine that fans out: Transcribe on the audio, Rekognition on sampled frames for labels and moderation flags, a Claude model for frame summaries, and Titan embeddings. Everything collects in OpenSearch, where a Bedrock LLM reads the metadata against the policy prompt.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ThAJvBkiGlwVUfWm.png" /></figure><p>The worry with acting after the fact is how long after. The <a href="https://aws.amazon.com/blogs/machine-learning/moderate-your-amazon-ivs-live-stream-using-amazon-rekognition/">Amazon IVS variant</a> gives real numbers: under 500 ms for the Rekognition call on frames below 1 MB, about two seconds from frame to notification through the rules engine, and the stream stops automatically when a rule fires. <strong>A correction that lands in two seconds means the violation aired for two seconds, not the rest of the hour.</strong></p><p><em>In short: cheap checks sit next to the content, expensive checks sit behind a queue, and enforcement flows back into delivery.</em></p><h3>The Blocking Path: Beating the Window</h3><p>Everything on this path answers the same timeline question: <em>Can this check return a verdict before the window closes?</em></p><p>The work splits into four pieces, in order:</p><ol><li>Find where the time actually goes.</li><li>Score fewer frames.</li><li>Make the model fit the budget.</li><li>Move the whole thing next to the stream.</li></ol><h3>Find Where the Time Actually Goes</h3><p>A software profiler measures the model, not the pipeline. It can report a 5 ms model while the full pipeline runs 50 ms behind. The number to watch is glass-to-glass: how long from a photon hitting the camera sensor to a processed result coming out the other end.</p><p>Much of that time is spent before inference runs. Sensor exposure takes 1–33 ms depending on light, a rolling shutter reads rows out one at a time, and an encoder with B-frames enabled buffers several frames before it can emit anything. By the time the blocking path sees a frame, part of the budget is gone.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*cakrvBOtz-vz5S6H.png" /></figure><p>Instrument every stage and fix the biggest contributors first. They’re often decode, transport, and buffering rather than the model.</p><h3>Score Fewer Frames</h3><p>Most violations persist across many consecutive frames; a nudity or weapon detection doesn’t appear and vanish inside 33 ms. <a href="https://aws.amazon.com/blogs/machine-learning/how-to-decide-between-amazon-rekognition-image-and-video-api-for-video-moderation/">AWS samples at two frames per second</a> and describes that as typical.</p><p>On top of sampling, drop the frames that carry nothing new:</p><ul><li><strong>Embedding similarity. </strong>AWS’s generative-AI pattern embeds each sampled frame, runs a cosine similarity check against the previous one, and discards any frame too close to its predecessor.</li><li><strong>Image hashing.</strong> Amazon IVS skips a frame if its hash is near the previous frame’s for the same channel.</li></ul><p>Sampling plus deduplication can cut inference volume by an order of magnitude. The saving applies to both paths, since the correcting path’s heavy models see the same reduced stream.</p><h3>Make the Model Fit the Budget</h3><p>Once the model is the bottleneck, the goal is fewer operations per frame. <a href="https://getstream.io/blog/low-latency-vision-ai/">Three compression techniques</a>:</p><ul><li><strong>INT8 quantization</strong> maps weights and activations from 32-bit floats to 8-bit integers. The model shrinks roughly 4x, and Tensor Cores run the integer math 2–4x faster than FP32. It costs some accuracy, so teams train with quantization awareness and keep the sensitive first and last layers in FP16.</li><li><strong>Structured pruning</strong> removes whole filters, channels, or attention heads. Zeroing individual weights produces sparse matrices that standard GPUs can’t accelerate; removing entire filters preserves the dense matrix operations the hardware runs fast.</li><li><strong>Temporal shift modules </strong>give a 2D model temporal reasoning without 3D convolutions. They shift a fraction of the feature-map channels along the time axis before a normal 2D convolution, so the model reasons about motion at close to 2D speed.</li></ul><p>Past the model, several pipeline settings reduce buffering:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5FXGocvG0LPc0lenBeaXSw.png" /></figure><p>When a downstream stage falls behind, a leaky queue drops the oldest frames instead of building a backlog. A verdict on a frame from two seconds ago arrives too late to act on. SRT makes the same tradeoff at the transport layer when it drops stale packets.</p><h3>Run It Next to the Stream</h3><p>Pure cloud makes sense when the model is too big to quantize for edge hardware and the application can tolerate more than 300 ms of round-trip latency. Running at the edge keeps raw frames on the device, which helps privacy, and ships events or short clips instead of full video, which cuts egress cost.</p><p>In practice, almost every production system lands on the same hybrid: a quantized detector at the edge screens everything, and ambiguous frames escalate to a heavier model in the cloud. That’s the blocking and correcting split expressed in hardware: <strong>the edge model does the blocking, and the cloud model does the correcting.</strong></p><p>Cold starts are the operational detail to plan for. <a href="https://getstream.io/blog/realtime-vision-ai-architecture/">TensorRT engine builds and model loads can take 30 to 300 seconds</a>, so pre-warm with a synthetic inference at startup and pin model files to NVMe. <strong>Otherwise, the first stream after a deploy goes unmoderated.</strong></p><h3>The Correcting Path: Getting the Call Right</h3><p>Everything here has already missed the window, so a verdict can take seconds or minutes instead of milliseconds. That time goes to bigger models, more context, and human judgment.</p><p>The work splits into two pieces:</p><ol><li>Score the modalities together, with context the inline checks don’t have.</li><li>Route the judgment calls to humans, without putting one in the request path.</li></ol><h3>Score the Modalities Together</h3><p>Blocking-path checks look at one track at a time, because that’s what fits inside the window. Each classifier answers a narrow question: what’s visible in this frame, what was said in the last few seconds of audio, what’s in this chat message.</p><p>Per-track checks miss harm that only exists in the combination. A chat message that’s innocuous on its own but aimed at the person on screen passes the text check, because the text check can’t see the screen. A pitch that calls an item authentic passes the audio check, footage of the item passes the frame check, but together they count as a counterfeit sale. Each classifier answered its own question correctly, and the violation went through.</p><p>Scoring the tracks jointly closes that gap, and multimodal ML has three standard ways to combine them:</p><ul><li><strong>Early fusion </strong>concatenates feature vectors straight after the encoders. It catches low-level cross-modal signals but needs expensive joint training.</li><li><strong>Late fusion</strong> combines each modality’s final scores with learned weights. Modular and easy to maintain, but the interaction between modalities is lost.</li><li><strong>Hybrid fusion</strong> does both, running cross-modal attention over raw features while correlating the intermediate scores. It captures the most context and is the most work to build and run.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/605/0*OA2KxIhWP1NNLq9O.png" /></figure><p>The joint score still needs context from outside the content. The same phrase can be fine in one channel and a violation in another. This is <a href="https://getstream.io/blog/scaling-content-moderation/">context collapse</a>. A semantic embedding check runs in 10–50 ms, but the final call needs user history, channel type, and conversation flow. Aggregating those signals server-side cuts false positives and makes the system harder to game.</p><h3>Route the Judgment Calls to Humans</h3><p>Satire, political speech, and harassment phrased politely end up in front of a person. Review time is unpredictable, so a human inside a synchronous pipeline backs the queue up behind them. Redis’s <a href="https://redis.io/blog/ai-human-in-the-loop/">write-up on oversight patterns</a> lays out the three ways to wire people in:</p><ul><li><strong>Human-in-the-loop </strong>gates on explicit approval. The latency is unbounded, so it can’t sit on a live path.</li><li><strong>Human-on-the-loop</strong> lets the system act in real time while people monitor with veto power. Live moderation runs this way, and the cost is a short exposure window before an override lands.</li><li><strong>Human-out-of-the-loop </strong>runs autonomously inside policy bounds, with people involved only at design and evaluation time.</li></ul><p>Escalation routes on confidence. The same write-up pairs a trust score for model agreement and classification confidence with a risk score that flags severity regardless of confidence. High trust triggers automated action. Low trust or moderate risk goes to review.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/954/0*xc6QKtHCnY59uopu.png" /></figure><p>You can’t predict when a reviewer will get to an item, so the system saves the whole event before it escalates: the flagged clip, the transcript, the model scores, and the conversation around it. The reviewer opens the case with everything already in front of them.</p><p>Redis Streams works as that queue. Escalations sit as persistent logs you can query later, and a sorted set ranks them by urgency, scored on viewer count, creator tier, and severity. Whatever’s most urgent gets seen first.</p><p>When the reviewer makes the call, the item flips from pending to approved or rejected. That status change triggers enforcement asynchronously, and the decision becomes a labeled example for active learning, so the models learn the edge cases and send fewer of them to review over time.</p><p><a href="https://getstream.io/moderation/">Stream Moderation</a> is built around the same loop. Flagged content lands in a <a href="https://getstream.io/moderation/docs/dashboard/reviewing-content/">review queue</a> sorted by severity; each severity level can have its own action, and webhooks fire whether the flag came from a model, a blocklist, or a person. The <a href="https://getstream.io/moderation/docs/">Check API</a> takes text, images, video, or a user profile, so chat and video share one queue and one enforcement layer.</p><h3>Measuring Both Paths</h3><p>Plain accuracy will flatter the system because moderation data is heavily imbalanced. Almost everything is fine, so a model can post a high accuracy number while missing most of the abuse.</p><p><a href="https://getstream.io/blog/moderation-performance-metrics/">Moderation metrics</a> are what to track instead:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*d9F4H0P7XDiFqubIsVZrWw.png" /></figure><p>Split all three by category, because a system strong on spam can be weak on bullying, and by language and region, because models are best in the languages they were trained on. Operationally, track system latency, throughput at peak, review time per item, reviewer agreement rate, and escalation rate. A rising rate of escalation usually indicates ambiguous policy rather than a weak model.</p><h3>The Audit Trail Is a Legal Requirement Now</h3><p>Under the EU’s Digital Services Act, a live platform owes users a notice-and-action mechanism, prompt removal of illegal content once notified, and a statement of reasons for every removal. Annual transparency reports have to describe the automated systems in use and disclose their accuracy and error rates.</p><p>The penalties are serious money. The Commission can impose a fine of <a href="https://digital-strategy.ec.europa.eu/en/policies/dsa-enforcement">up to 6% of global annual turnover</a> for serious infringements, plus periodic penalties of up to 5% of average daily worldwide turnover for each day of delay in compliance. Enforcement started in December 2025 with the <a href="https://digital-strategy.ec.europa.eu/en/news/commission-fines-x-eu120-million-under-digital-services-act">first DSA non-compliance fine</a>, €120 million against X, for transparency failures rather than slow removal, and well below the cap, but the framework is clearly live.</p><p>The useful part is that <a href="https://getstream.io/blog/content-compliance/">compliance mostly asks for things</a> this architecture already produces: a sub-second automated path for clearly illegal content, which is the blocking path, and an immutable log of every automated and human decision. The event log the correcting path keeps for review queues and active learning is the same artifact a regulator asks for.</p><h3>The Whole System, Job by Job</h3><p>Everything in this article comes down to three jobs: pick your window, make sure the inline checks beat it, and give the deeper checks a way to act once they’re done.</p><ul><li><strong>Pick your window deliberately.</strong> Ingest over SRT so a creator’s bad hotel wifi doesn’t stall the stream, deliver LL-HLS through a CDN to viewers, and save WebRTC for the hosts and guests who actually need it. Every bit of delivery latency you cut is time your inline checks lose, so sub-second delivery is a cost you should choose on purpose.</li><li><strong>Make sure the inline checks beat it. </strong>Sample around two frames per second, throw away near-duplicate frames with embedding similarity or hashing, and run a quantized model at the edge with zero-copy buffers and leaky queues. Warm it up before traffic hits, otherwise the first stream after a deploy goes out unmoderated.</li><li><strong>Give the deep checks time and a way back in.</strong> Put them behind Kafka so nothing slow touches delivery, run the fused multimodal scoring and LLM policy checks on their own schedule, and act through webhooks. Anything the models aren’t sure about goes to a review queue in Redis Streams, ranked by urgency, and every human decision goes back into training.</li><li><strong>Watch both sides and write everything down.</strong> Track precision and recall by category and language instead of one headline accuracy number, keep an eye on review time and escalation rate, and log every decision somewhere immutable. That log is also what the DSA asks you to produce.</li></ul><h3>Where Stream Fits</h3><p>The whole design keeps coming back to the same question: <em>Does this check beat the window or miss it?</em></p><p>Beat it, and you can block. Miss it, and you’re correcting the decision, so the check needs a way to act on the stream, the replay, and the account.</p><p>Stream covers a lot of these pieces on shared infrastructure: chat, feeds, and video with <a href="https://getstream.io/blog/ai-content-moderation/">AI moderation</a> built in, a Check API that takes text, images, video, or user profiles, review queues ranked by severity with webhooks, and the open-source <a href="https://getstream.io/vision-agents/">Vision Agents</a> SDK for running models at the edge. It doesn’t make the tradeoffs go away, but you end up tuning a pipeline instead of building one.</p><p>If you want to try it, the <a href="https://getstream.io/moderation/docs/">moderation docs</a> cover setup for chat and video. Wiring the Check API into chat is the smallest version of the blocking path, and a sensible place to start before the video pipeline.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=36eaecef5edf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/getstream-io/architecting-real-time-moderation-for-live-video-36eaecef5edf">Architecting Real-Time Moderation for Live Video</a> was originally published in <a href="https://medium.com/getstream-io">Stream</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[5 Lessons from Building a Voice AI Prescription Agent]]></title>
            <link>https://medium.com/getstream-io/5-lessons-from-building-a-voice-ai-prescription-agent-8084aa71dcaf?source=rss-7d292f5ec55a------2</link>
            <guid isPermaLink="false">https://medium.com/p/8084aa71dcaf</guid>
            <category><![CDATA[prescription-agent]]></category>
            <category><![CDATA[assemblyai]]></category>
            <category><![CDATA[vision-agent]]></category>
            <category><![CDATA[text-to-speech]]></category>
            <category><![CDATA[voice-ai]]></category>
            <dc:creator><![CDATA[getstream.io]]></dc:creator>
            <pubDate>Mon, 10 Aug 2026 16:45:56 GMT</pubDate>
            <atom:updated>2026-08-10T19:27:58.479Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZDnV5DwZ5Gk_Y2EmXu11ng.jpeg" /></figure><p>Picture this scenario:</p><p>A patient calls a pharmacy line and says: <em>“Hi, I need to refill my mom’s Augmentin, the 875.”</em></p><p>A <a href="https://getstream.io/video/voice-ai/">voice agent</a> takes care of this request. It listens, pulls out the structured details, asks one clarifying question, accepts the request, and sends the medication out.</p><p>That setup is both technically impressive and <strong>incredibly dangerous</strong>. Automation is one of the big promises we’re getting from the agentic era of AI. However, blindly implementing a use case without questioning its implications can pose great dangers.</p><p>That’s why we built a demo to see what it actually takes to run a voice agent in a domain where being wrong has consequences.</p><p>Let’s break it down.</p><h3>What’s at Stake?</h3><p>A few examples where the exact path we laid out can go wrong:</p><ul><li>Auto-accepting prescription requests can lead to incorrect deliveries that might have serious health implications for patients.</li><li>A fully-automated process can miss important details and context with medication.</li><li>Small transcription errors can lead to major problems if the wrong medication is prescribed and delivered for a specific treatment.</li></ul><p>And, these errors are increasingly more likely with modern technology. The sheer wiring up of a voice agent is now a straightforward task. You…</p><ul><li>capture audio,</li><li>run speech-to-text,</li><li>send the transcript to an LLM,</li><li>speak the response back.</li></ul><p>This is where most tutorials stop.</p><p>As with many other things, the devil lies in the details. The steps laid out are not wrong, but without further thinking and guardrails, <strong>this is not enough</strong>. That’s why we’re laying out five decisions that allowed us to <a href="https://getstream.io/blog/best-voice-ai-platforms/">build a trustworthy agent</a>.</p><p>(Note: <em>We’re applying these lessons to the medical space, but they’re also applicable to any voice agent where mistakes have serious implications</em>.)</p><h3>The Stack</h3><ul><li><a href="https://getstream.io/video/voice-agents/">Stream’s Vision Agents SDK</a> to handle the real-time call and agent orchestration</li><li><a href="https://www.assemblyai.com/">AssemblyAI</a> for speech-to-text</li><li>LLM (Gemini 3.5 Flash, in this build) for the reasoning</li><li>TTS model from <a href="https://visionagents.ai/integrations/realtime/inworld">Inworld</a> to give our agent a voice</li></ul><h3>Lesson 1: Design the Flow Around the Stakes</h3><p>The version that looks great in a demo is where the agent closes the loop itself: caller asks, agent confirms, “Great, your refill is approved and on the way.”</p><p>It’s satisfying to watch. It’s also the wrong design for anything with real consequences.</p><p>We made the agent an intake assistant, not an approver. Its job starts when the call connects and ends at “prepared for pharmacist review.” A human is always in the loop before anything happens. The agent’s own instructions spell out what it’s not allowed to do:</p><pre>You are not a doctor, pharmacist, or prescriber.<br>You must not provide medical advice.<br>You must not approve, prescribe, dispense, recommend, or modify medication.<br>You must not say that an order is complete or approved.</pre><p>But instructions alone are a soft boundary, and anyone with a bit of experience can argue an LLM out of them. So the boundary needs to also be enforced structurally. The agent cannot declare the intake finished on its own by design. In our case that means that it has to call a prepare_pharmacist_handoff tool, and that tool refuses to return a &quot;ready&quot; state until every required field is present:</p><pre>REQUIRED_FIELDS = (<br>    &quot;patient_name&quot;, &quot;request_type&quot;, &quot;medication&quot;, &quot;strength&quot;,<br>    &quot;instructions&quot;, &quot;quantity&quot;, &quot;prescriber&quot;, &quot;delivery_preference&quot;,<br>)</pre><p>The frontend has a “<strong>Send to pharmacist</strong>” button which is only active when the exact same conditions are met, so the UI and the agent agree on what “done” means.</p><p>The general takeaway here is that for any high-consequence workflow, the first design question is not: what can the agent do? Instead, it’s: where does the agent stop?</p><p>Define the handoff boundary before you write the prompt, and encode it somewhere deterministic that imposes a hard limit that the model can’t bypass.</p><h3>Lesson 2: Pick the Right Tool for the Job</h3><p>Speech-to-text providers look interchangeable until you point them at your actual vocabulary. On a generic benchmark, they cluster together. Then your agent hears “atorvastatin” as “a tour of a statin”. That leads to an issue where everything that follows (extraction, validation, the handoff packet) is built on a wrong transcript. In this domain, garbage in — garbage out means a major safety issue.</p><p>The number that mattered to us was the word error rate <em>on the words that carry the risk</em>: drug names, strengths, and units. That’s exactly where general-purpose models tend to slip, because those terms are rare in ordinary training data and easy to confuse with common words.</p><p>We used <a href="https://visionagents.ai/integrations/stt/assemblyai">AssemblyAI</a> because it held up well on dense pharmaceutical terminology, which is where it separated from more general STT for this use case. Because the Vision Agents SDK abstracts the call transport, the STT provider is a pluggable component.</p><p>This allowed us to evaluate and change different options with a one-liner:</p><pre>stt = assemblyai.STT(<br>    api_key=settings.assemblyai_api_key,<br>    speech_model=&quot;universal-3-5-pro&quot;,<br>    keyterms_prompt=ASSEMBLYAI_KEYTERMS,  # more on this in Lesson 3<br>)</pre><p>The broader lesson here is that <strong>the metric for choosing the best model should not be an arbitrary leaderboard on the web</strong>.</p><p>Instead, we should first declare “for what” we’re using the model and evaluate its quality only on that specific use case. We’re not building a product that needs to work in any setting, so we shouldn’t choose a model that tries to be applicable for all scenarios.</p><h3>Lesson 3: Give the Agent a World Model</h3><p>With the right selection of an STT provider and a capable LLM, they still don’t know our domain out of the box. The recognizer doesn’t know “amox clav” is a thing a caller might say; the model doesn’t know which strengths of levothyroxine are plausible. We have to supply that knowledge, and it turned out to matter at two different layers.</p><ol><li><strong>At the ear (recognition)</strong>. AssemblyAI accepts a keyterms_prompt, which is a list of terms to bias recognition toward. We fill it with the vocabulary this agent actually encounters: medication names, brand/generic pairs, the prescriber&#39;s name, even the agent&#39;s own name. Here is a simplified list of key terms we feed to the model:</li></ol><pre>ASSEMBLYAI_KEYTERMS = [<br>    &quot;atorvastatin&quot;, &quot;Lipitor&quot;, &quot;amoxicillin clavulanate&quot;, &quot;amoxicillin-clavulanate&quot;, &quot;Augmentin&quot;,<br>    &quot;levothyroxine&quot;, &quot;Synthroid&quot;, &quot;pharmacist review&quot;,<br>]</pre><p>This is where Lesson 2 and Lesson 3 meet: picking a strong recognizer is step one, but you get a further accuracy jump by telling it which uncommon words to expect. We can already see here that building a product means connecting multiple approaches.</p><p><strong>2. At the brain (reasoning).</strong> The agent has a medication reference that it can use to look things up in a database. These can be canonical names, aliases, common strengths, and a per-drug review flag. Here is an example for a medication:</p><pre>{<br>  &quot;name&quot;: &quot;Amoxicillin-clavulanate&quot;,<br>  &quot;aliases&quot;: [&quot;amoxicillin clavulanate&quot;, &quot;Augmentin&quot;, &quot;amox clav&quot;],<br>  &quot;commonStrengths&quot;: [&quot;500 mg / 125 mg&quot;, &quot;875 mg / 125 mg&quot;],<br>  &quot;type&quot;: &quot;antibiotic&quot;,<br>  &quot;requiresPharmacistReview&quot;: true<br>}</pre><p>So when a caller says “amox clav,” the agent normalizes it to the canonical “Amoxicillin-clavulanate” rather than guessing, and it knows “the 875” maps to a real strength.</p><p>We can summarize that an LLM is a reasoning engine, not a knowledge base. Don’t assume it memorized your catalog, your SKUs, or your entity names. It’s our job to give it a source of truth to consult. This will then enrich both the layer that hears and the layer that thinks.</p><h3>Lesson 4: Don’t Make the LLM Do Everything</h3><p>It’s tempting to hand the LLM the whole job, including extraction, validation, flow control, and tone. A cleaner split is to let the model do the fuzzy work and let plain code do the mechanical work.</p><p>The deterministic side handles anything that’s verifiable and boring. Normalizing units and frequencies, for example. This can be a simple lookup and does not need to be a judgment call:</p><pre>STRENGTH_ALIASES = {<br>    &quot;20 milligrams&quot;: &quot;20 mg&quot;,<br>    &quot;875 125&quot;: &quot;875 mg / 125 mg&quot;,<br>}<br>FREQUENCY_ALIASES = {<br>    &quot;every night&quot;: &quot;Once nightly&quot;,<br>    &quot;twice a day&quot;: &quot;Twice daily&quot;,<br>    &quot;every 12 hours&quot;: &quot;Every 12 hours&quot;,<br>}</pre><p>Completeness is enforced in code, too. Instead of trusting the model to remember every field it still needs, a function checks the intake state against the required list and reports what’s missing.</p><p>This is the exact condition that gates the handoff we described in Lesson 1:</p><pre>def missing_required_fields(state) -&gt; list[str]:<br>    return [f for f in REQUIRED_FIELDS if not getattr(state, f, None)]</pre><p>Meanwhile, the LLM does what it’s genuinely good at: interpreting what the caller meant, deciding which clarifying question is worth asking, and keeping replies short and warm. Its instructions push it toward that role through formulations like this:</p><ul><li>Ask at most one clarification question at a time</li><li>Keep spoken replies short, usually one sentence</li></ul><p>The principle is a division of labor by reliability.</p><p>If a rule can be checked with a for loop, check it with a for loop; you don’t want correctness riding on a probabilistic system when a deterministic one is exact. Save the model for the calls that actually require judgment.</p><h3>Lesson 5: Guardrails Are Not Simply a Line in the Prompt</h3><p>“Be safe and don’t give medical advice” in a system prompt is both necessary and, at the same time, nowhere near enough.</p><p>Prompts can be worked around. On the other hand, if we add deterministic logic checks to each phase of the flow, we can assure that our safeguards can’t be breached.</p><p>Our demo has three cooperating layers.</p><ol><li><strong>A deterministic safety net. </strong>Before the LLM’s judgment enters into it, transcript text is scanned for high-risk language. Emergency terms trigger a hard stop; dosage-change requests and medical-advice questions get forced into pharmacist review regardless of what the model would have done.</li></ol><pre>EMERGENCY_TERMS = [&quot;chest pain&quot;, &quot;can&#39;t breathe&quot;, &quot;overdose&quot;,<br>                   &quot;allergic reaction&quot;, &quot;suicidal&quot;, ...]<br><br>def run_safety_checks_on_text(text):<br>    if _contains_any(text, EMERGENCY_TERMS):<br>        return SafetyResult(status=&quot;blocked&quot;, blocked=True,<br>                            response=EMERGENCY_RESPONSE)=</pre><p>If a caller says “chest pain,” the agent breaks out of the intake flow and points them to urgent care. That behavior does not depend on the LLM deciding to be careful.</p><p><strong>2. Instruction guardrails. </strong>The behavioral rules from Lesson 1 (never approve, never diagnose) always frame the outcome as “prepared for pharmacist review.” These shape the model’s default behavior.</p><p><strong>3. Structural gates. </strong>The prepare_pharmacist_handoff tool makes the unsafe end-state (&quot;the agent said it&#39;s done&quot;) unreachable until the required data exists. There&#39;s also a standing &quot;pharmacist review required&quot; check applied to every request, plus extra checks when a caregiver is calling on someone&#39;s behalf or a second medication comes up.</p><p>The idea is defense in depth. Assume any single layer can fail, and arrange things so the next layer catches it. For any agent that touches health, money, legal, or identity, the guardrails need to hold even when the model behaves in a way you didn’t anticipate.</p><h3>Conclusion</h3><p>We see one theme across all five lessons. <strong>A trustworthy voice agent is a systems problem, not a prompt problem (alone).</strong></p><p>The LLM is one component among several. Most of the value is in how you surround it. That means the right transport, an STT model that holds up on your vocabulary, real domain knowledge fed to both the recognizer and the reasoner, deterministic checks for anything verifiable, and guardrails that reliably catch when the model is misbehaving.</p><p>This tooling lets us spend our effort in the right place. <a href="https://getstream.io/vision-agents/">Stream’s Vision Agents SDK</a> made the real-time call, orchestration, and provider swapping cheap, so the work went into the domain decisions above rather than plumbing. AssemblyAI made the speech layer accurate enough on medical terms to build the rest on top of.</p><p>The end result is a demo that <em>deliberately</em> is a limited one.</p><p>No real fulfillment, no medical advice, a human pharmacist at the end of every request.</p><p>But the pattern generalizes well beyond pharmacy, with real-time voice, a high-stakes domain, and a human kept firmly in the loop. If you’re building in that shape, the five lessons here are a reasonable place to start.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8084aa71dcaf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/getstream-io/5-lessons-from-building-a-voice-ai-prescription-agent-8084aa71dcaf">5 Lessons from Building a Voice AI Prescription Agent</a> was originally published in <a href="https://medium.com/getstream-io">Stream</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a Live Shopping App with One-Shot AI]]></title>
            <link>https://medium.com/getstream-io/building-a-live-shopping-app-with-one-shot-ai-857a30db5a0d?source=rss-7d292f5ec55a------2</link>
            <guid isPermaLink="false">https://medium.com/p/857a30db5a0d</guid>
            <category><![CDATA[videostream]]></category>
            <category><![CDATA[live-shopping-app]]></category>
            <category><![CDATA[cli]]></category>
            <category><![CDATA[one-shot-ai]]></category>
            <dc:creator><![CDATA[getstream.io]]></dc:creator>
            <pubDate>Mon, 10 Aug 2026 16:35:16 GMT</pubDate>
            <atom:updated>2026-08-10T19:28:09.026Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U-_0mfmauyKpCeGd9LjIPA.jpeg" /></figure><p>The humble programming tutorial has recently been thoroughly transformed from copy-paste toil to one-click wonder. Cinderella’s fairy grandmother waved her magic wand and turned a pumpkin and mice into a fabulous carriage pulled by white horses; today’s AI coding agents have an almost as magical-seeming ability to turn the barest of specs into a full-fledged application.</p><p>Stream’s <a href="https://getstream.io/cli/">CLI tool</a> is the magic wand for building realtime apps on web and mobile. It offers a powerful <a href="https://getstream.io/agent-skills/">AI skill</a> that knows how to generate and update complete applications that use Stream’s API. It works so well that almost any classic Getting Started tutorial has effectively become a single line, like this:</p><p>/stream make me a video call web app with chat</p><p>The agent will go ahead and plan for the project, ask you to log in on Stream, create the app in your account, set it up with sensible defaults, and build a whole React single-page app for the example given above.</p><blockquote>For better or worse, if you just ask for “web app”, the default on all LLMs is React because it’s so prevalent in AI training material. If you want some other framework, you need to ask for it by name. Of course Stream agents also know how to write iOS, Android, Flutter…</blockquote><p>It’s impressive to watch it work. But when you move past tutorials and experiments into real apps, you eventually run into problems. A one-sentence prompt simply can’t describe your real world problem well enough to be a fully solid base for an app. Where the specification is lacking, the magic wand of AI will just go ahead and guess on the fly. Some of these guesses inevitably become bugs, or at least undesirable behavior that’s already been baked into code and then you have to make an extra effort to get rid of it.</p><p>So when it comes to one-shot app generation, it needs to be well-grounded. By spending a bit more time upfront planning your design, you’ll be saving a lot more time down the road by avoiding the slow iterations needed to fix AI’s initial misassumptions.</p><h3>Building a complete live shopping app</h3><p>In this post I’ll show you the design process used to create a one-shot application called VinylStream, a live shopping app that lets people buy and sell vinyl records online. Sellers can schedule live shows where they show their record finds on camera, and viewers can bid on live auctions and ask questions on Stream chat.</p><ul><li>Try it live: <a href="https://vinylstream-live-shopping-react-demo.vercel.app/">vinylstream-live-shopping-react-demo.vercel.app</a></li><li>View the full source code: <a href="https://github.com/GetStream/vinylstream-live-shopping-react-demo">GetStream/vinylstream-live-shopping-react-demo</a></li><li>Read the design document: <a href="https://github.com/GetStream/vinylstream-live-shopping-react-demo/blob/main/docs/vinylstream-concept.md">vinylstream-concept.md</a></li></ul><p>The exact steps are described in the <a href="https://getstream.io/video/sdk/react/tutorial/live-shopping/">companion tutorial</a>, but it’s so simple that you barely need to read it. I just created a new folder for the project, copied the design doc under docs, added the Stream skill using the getstream CLI, opened Claude Code, and entered this prompt:</p><p>/stream Build me the app described in docs/vinylstream-concept.md</p><blockquote>I’ve tested this one-shot creation on several models including Claude Opus 4.8, Fable 5, and Sonnet 5. There wasn’t a significant difference in the output. Opus was the most token-efficient at around 90k tokens, but the other models were not far off. This is really a testament to how the Stream agent skill provides the essential intelligence for building the app — you don’t need the fanciest LLM because so much knowledge is encoded already in the skill, you just need baseline smarts and enough context window (Sonnet 5 at 1M context clears the bar handsomely).</blockquote><p>Although this is a video-centric app, the lessons of this process are general. You can apply them to any realtime-oriented app you’d build with an AI agent. Stream’s agent skill has a lot of built-in intelligence that routes based on target platform and use case, but it’s always worth getting the basics right in your design phase. It will save you tokens and frustration.</p><p>In effect, the design document is the real source code. You still need to tell the computer what to do — that part of programming isn’t going away. With AI and agent skills you can do it on a much higher level than thinking in terms of if sentences and API calls. So take a moment to get it right.</p><p>Something important to note about the VinylStream design document is that it was made for a demo and intentionally leaves some questions open so it can better function as an app skeleton. When you’re bootstrapping a finished application, decisions can be settled already at the design stage. I’ll highlight these differences when appropriate, so you’ll know what transfers from VinylStream and what you can fix already.</p><h3>1. Name the core pattern</h3><p>Don’t jump to discussing your specific vertical too early. If you tell the agent to build a “vinyl app” or “telehealth app”, it will jump to optimizing surface features like buttons and screens rather than the mechanism that makes the app work. You get a demo that looks convincing, but feels wrong as soon as you try to do something in it.</p><p>For VinylStream, the core pattern is “binding canonical product data to a live video stream”. That’s the heart of any live shopping app, whatever is being sold.</p><p>Superficial mechanics can be misleading. If you think of live shopping as “QVC-style TV home shopping channel in a browser”, you might assume the core pattern is “a video stream with a chat and a buy button”. That would work for a single person experience, but the internet is not television — a live shopping app is both multiplayer (there are other people bidding) and uses multiple data sources (potentially thousands of sellers each making their own TV show). Your app needs to be aware of which item is live right now, where the price comes from, and who’s winning. Stream’s infrastructure and APIs will make sure the video and chat work, but to close the sale, you need to own the product experience.</p><p>Consider telehealth. It looks like “a video call with a doctor”, but the call is the easy part. The core pattern is conducting a properly documented and consented clinical encounter tied to a verified patient and their record. Video is just one channel for what the doctor needs to know. If that’s your business, Stream will let you handle the boring but complicated video part reliably, and you can focus on delivering results to patients and doctors. But you need to focus your AI coding agent’s attention on that.</p><h3>2. Map your realtime planes and the source of truth</h3><p>Most realtime apps — well, the ones that do something useful or fun, anyway! — are not just one stream, but several planes running at once. For live shopping, there’s video, chat, and shared application state like bids, auction status, etc.</p><p>When preparing your design document, list these planes. Then, for each piece of shared state, write one sentence: <em>where does the source of truth live?</em></p><p>Traditional database-backed “CRUD apps” are fairly uniform in how data is treated. (Whether your entity is big or small, a CRUD app will expose the same essential API patterns.) For realtime, it’s easy to apply that same thinking and assume that everything that moves in realtime is the same kind of thing. Video frames, chat messages, and an auction’s current price all “update live,” but they have completely different correctness requirements. If you let the coding agent blur these lines, it will often do whatever it finds most convenient in the moment when developing the solution because it’s eager to move ahead. That could mean trusting a bid price which happened to arrive over the chat channel, or something worse. (Reading a product price from a video overlay? Why not? The data is right there…)</p><p>For VinylStream, the auction’s current price, high bidder, and countdown are authoritative on the server. Bid events can ride the same realtime channels as chat — it’s a fine transport for this purpose — but the ultimate truth lives server-side, never in a transient source like the seller’s client or the chat stream. Video and chat are views of the auction, not the source of truth.</p><h3>3. Find your integration seams</h3><p>List the major parts of your app one at a time: video, chat, the product catalog, payments, shipping, notifications… Then mark each one with one of these labels: is it real, mocked, or shaped?</p><p>Real is what you build now. Mocked is a throwaway stand-in. Shaped is the interesting one, an in-between state where you expect things to evolve. You don’t build it yet, but you design the data model to make it easy to drop in the real thing later.</p><p>AI agents will happily do “vibe mocking” where they fill in the gaps with whatever shape is easiest in the moment. Replacing those can be a complex rewrite. Providing the right shape early avoids those detours.</p><p>For VinylStream, shipping is an example of a feature that’s the last one real sellers and buyers would encounter, so it would be easy to brush it aside as irrelevant. But a moment spent thinking and researching about the shape will help the agent focus. A state like “label printed, in transit” stands in for any real fulfillment. The data model underneath can already be shaped for the real thing, so each order carries a shipment with a destination address, a tracking reference, and a status that moves from pending to shipped to delivered.</p><p>For a demo, you wouldn’t care if everything outside of the core pattern is mocked. But for a real app, the shape becomes important. Instead of “what can I fake?”, you should be asking: “What are my seams to the outside world, and do I know their shape already?”</p><h3>4. Decide your external dependencies</h3><p>In the previous section you drew the boundaries. Now look at that other side which is out of your control: things like third-party APIs, keys, rate limits, licensing, network quality… And make decisions about each.</p><p>If decisions are not laid out explicitly in your design, an agent may guess in ways that become expensive (or at least annoying) to undo: it wires up whatever API call looks “obvious” with no key management, has no fallback for when the service is down, and so on.</p><p>For VinylStream, there was a big external dependency: the catalog that provides the vinyl records. Thanks to the tireless efforts of vinyl fans, there exists a free site called Discogs which provides exactly the canonical database we need. We don’t want to abuse their API or their terms, so the catalog for this demo was built from the Discogs monthly data dump — a full XML export under a CC0 public domain license — rather than by hitting the Discogs API for each request. It makes the demo run smoothly because the data is always available.</p><p>This is the section where a real app would diverge most sharply from the VinylStream demo, so be careful when copying from it. For a demo, you want to eliminate external dependencies to make sure it works everywhere. A real app on the other hand wants the opposite: it needs to solve problems like getting the fresh record inventory and dealing with practical issues like Discogs’ API terms (if you build a product on someone else’s data, it’s highly advisable to get legal advice early on). The exercise is the same — enumerate your dependencies — but the answers tend to run in the opposite direction. So be careful about copying a demo’s decisions into a real product.</p><h3>5. Trace your critical user paths</h3><p>Language models know an awful lot of things that they’ve read on the internet, but so far nothing beats human intuition about how things should actually work. You should tell the model explicitly what happens inside the app, rather than trust that it can play human long enough to figure it out.</p><p>So write the shortest end-to-end user paths that exercise the core pattern. One sentence per role is enough. Then write down what’s explicitly left out.</p><p>For VinylStream, the seller side is: create a show -&gt; add about five items via Discogs search -&gt; go live with the item queue.</p><p>The buyer side is: join the stream -&gt; see the current item card -&gt; bid -&gt; win -&gt; cart. Explicitly out: real payments, shipping, notifications.</p><p>For a demo or throwaway prototype, those “out” features never get built, they’re just design placeholders that feed the audience’s imagination. In a real app, “out” instead means “deferred to phase 2”. So the critical path doesn’t change, but how you track the missing features is different. You can ask your AI agent to maintain another design document for what you need to build beyond the one-shot.</p><h3>The design document is the real source code</h3><p>AI hasn’t taken away the essence of programming, and probably won’t: deciding what the thing should actually do. A language model is great at typing API boilerplate, and it can also role-play all kinds of scenarios, but ultimately only you know why you’re building something and why someone might want it. Everything discussed in this blog post is about getting you faster to the point where that motivation can be expressed and validated in working application code.</p><p>The one-shot magic wand really does work. But if you point it at a vague wish, you get a vague result. (Or, to continue with my Disney analogies, worst case is that you end up like Mickey Mouse in “Sorcerer’s Apprentice” and your agents are running amok doing things on their own, completely oblivious to your wishes because you didn’t express them clearly enough…)</p><p>And notice how little of the thinking involved here was about video or chat specifically, even though we built a live shopping app whose hardest technical bits are those realtime components? That’s the whole point. Stream’s APIs and skills makes the realtime plumbing reliable and auto-scalable and boring, so you can focus on doing the product work that only you can do. So why not start building today? You could have something real up and running in less than an hour, armed with any old LLM and the Stream agent skill.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=857a30db5a0d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/getstream-io/building-a-live-shopping-app-with-one-shot-ai-857a30db5a0d">Building a Live Shopping App with One-Shot AI</a> was originally published in <a href="https://medium.com/getstream-io">Stream</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Content Moderation Ethics: Navigating Bias, Censorship & Fairness]]></title>
            <link>https://medium.com/getstream-io/content-moderation-ethics-navigating-bias-censorship-fairness-ea75e9990d79?source=rss-7d292f5ec55a------2</link>
            <guid isPermaLink="false">https://medium.com/p/ea75e9990d79</guid>
            <category><![CDATA[content-ethic]]></category>
            <category><![CDATA[ethics]]></category>
            <category><![CDATA[content-moderation]]></category>
            <dc:creator><![CDATA[getstream.io]]></dc:creator>
            <pubDate>Mon, 12 Jan 2026 23:06:27 GMT</pubDate>
            <atom:updated>2026-08-10T19:28:16.780Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O382KP4OiJubVW62HxEcgg.jpeg" /></figure><p>Online communities rely on moderation to function, yet every moderation decision carries significant ethical implications.</p><p>The platforms that choose to remove, allow, promote, or downrank content directly shape culture, discourse, and safety. As <a href="https://getstream.io/moderation/">AI systems</a> take on more moderation responsibilities and regulatory scrutiny increases, the stakes continue to rise. Ethical moderation is no longer only a product concern. It is a societal concern.</p><p>This guide explains the ethical challenges behind content moderation, why fairness matters, the tensions between safety and expression, and the best practices that can help teams build trustworthy and transparent systems.</p><h3>Introducing the Ethics Problem</h3><p><a href="https://getstream.io/blog/content-moderation/">Content moderation</a> determines what billions of people see, share, and experience online.</p><p>When models or human reviewers make mistakes, those errors can perpetuate inequities, silence marginalized communities, or facilitate the spread of harmful content. Ethical concerns arise not only from the decisions made, but also from how those decisions are made and who they impact.</p><p>Bias is a central part of this challenge. Bias appears in data, tools, guidelines, and human judgment. It can be subtle and unintentional, yet it can still create meaningful harm. Ethical frameworks help teams ensure their moderation systems are safe, fair, and accountable.</p><h3>Why Ethical Moderation Matters</h3><p>Fair and transparent moderation is crucial because these decisions significantly impact public discourse and user trust. If communities feel targeted or unfairly censored, participation drops. When harmful content slips through, safety collapses.</p><p>Both outcomes create real consequences for individuals and for the broader information ecosystem.</p><p>At the same time, global regulations like the <a href="https://getstream.io/blog/dsa-moderation-requirements/">Digital Services Act</a> and emerging Online Safety Acts put additional pressure on platforms to demonstrate due diligence. Teams must show that their models are trained responsibly, that oversight is consistent, and decisions can be explained. As a platform grows, the importance of ethical alignment becomes increasingly essential.</p><p>Ethical moderation is a product necessity, not a nice-to-have. And it’s essential to earning trust.</p><h3>Understanding Bias in Moderation</h3><p><a href="https://getstream.io/resources/projects/moderation-course/moderator/bias/">Bias</a> enters moderation systems in many ways.</p><p>Machine learning models mirror the data they are trained on. Human reviewers bring cultural and contextual assumptions. Over time, these biases compound into systematic patterns that can disadvantage certain groups or amplify harmful narratives.</p><h3>Algorithmic Bias</h3><p>AI models are powerful for scaling moderation, yet they are only as fair as their training data. When datasets underrepresent certain dialects, languages, or communities, the model cannot accurately identify intent or nuance.</p><p>For example, certain varieties of English used by marginalized communities have historically been mislabeled as harassment. Similarly, languages with limited online data often experience underdetection, allowing harmful content to slip by.</p><p>Differences in sensitivity across categories also create ethical questions. Political speech, for example, may be treated with more caution than hate speech, which can confuse both users and reviewers.</p><h3>Human Reviewer Bias</h3><p><a href="https://getstream.io/blog/content-moderators/">Human moderation</a> remains crucial, especially for content that is ambiguous. These reviewers rely on lived experience, cultural norms, and personal judgment. Their perspectives are valuable but inconsistent. Fatigue, emotional strain, and the volume of content can also lead to uneven enforcement across teams or regions.</p><p>These inconsistencies can lead to unequal treatment, where similar cases receive different outcomes, thereby undermining both fairness and trust.</p><h3>Why Fairness Is a Core Requirement</h3><p>Fairness sits at the heart of ethical moderation. More than simply making the right decision, it ensures that the process leading to that decision is just, explainable, and accountable.</p><h3>Procedural Fairness</h3><p>Users expect clear rules that are consistently applied. Procedural fairness means every step of the moderation process is transparent.</p><p>This includes having stable community guidelines, predictable enforcement, and meaningful appeal systems. Users are more likely to accept outcomes when they believe the process is legitimate.</p><h3>Distributional Fairness</h3><p>Moderation systems must ensure that no group is unfairly targeted or disproportionately silenced. Automated systems that overflag content from certain demographics can create real harm by reducing representation or discouraging participation. Evaluating false positives and false negatives across demographic groups is essential for building equitable systems.</p><h3>Transparency and Explainability</h3><p>Users deserve to understand why their content was flagged or removed. Explainability also fulfills regulatory expectations and creates a healthier relationship between platforms and communities.</p><p>Even <a href="https://getstream.io/blog/moderation-appeals-transparency/">simple explanations</a> can reduce confusion, build trust, and mitigate the chilling effect of overly strict or unclear rules.</p><h3>The Challenge With Ethical Moderation</h3><p>Balancing safety, expression, and fairness is inherently difficult. Platforms must make tradeoffs between preventing harm and protecting legitimate discourse. These tradeoffs vary across regions, cultures, laws, and community expectations.</p><h3>Censorship vs Safety</h3><p>One of the strongest tensions in moderation appears in the interplay between censorship concerns and safety needs. Removing harmful content protects users, but removing too much content can restrict open dialogue.</p><p>Ethical moderation attempts to find a middle ground that prioritizes safety without diminishing diverse expression.</p><p>Platform norms and public norms also differ. Community guidelines reflect the values of the platform, while users may hold other expectations rooted in their own cultural or political context. Meanwhile, governments may create additional pressure by imposing <a href="https://getstream.io/blog/content-compliance/">content compliance</a> rules that risk regulatory overreach.</p><h3>Tradeoffs Around Free Speech</h3><p>Traditional free speech laws do not govern online spaces. Platforms are not required to host all speech. Yet users generally expect neutrality and ideological balance. This expectation becomes more complicated when legal speech is still harmful. Disinformation, bullying, and coordinated manipulation campaigns can cause damage without technically breaking laws.</p><p>The paradox of tolerance also applies. Allowing intolerant speech may reduce the total amount of speech in a community by driving people away.</p><h3>The Chilling Effect</h3><p>When rules are unclear or inconsistently applied, users may self-censor out of fear. Over-moderation discourages creativity, participation, and discussion.</p><p>Ethical moderation aims to avoid this chilling effect by making decisions predictable and guidelines easy to interpret.</p><h3>Best Practices for Ethical Moderation</h3><p>Solutions to ethical challenges involve a combination of better data, stronger processes, more transparent communication, and thoughtfully designed AI systems.</p><h3>Build Bias Mitigation Into the Moderation Lifecycle</h3><p>Bias is inevitable in moderation systems. Ethical moderation assumes bias will appear and builds mechanisms to detect and reduce it continuously.</p><p>Effective teams move through a recurring cycle:</p><ol><li>Detection — Measure false positives and false negatives across content categories, languages, regions, and dialects, not just overall accuracy.</li><li>Diagnosis — Identify whether disparities stem from training data gaps, model thresholds, unclear guidelines, or reviewer interpretation.</li><li>Intervention — Adjust datasets, retrain models, recalibrate reviewers, or update policy language.</li><li>Verification — Re-test changes against the same fairness metrics to confirm improvement.</li><li>Communication — Document and explain changes internally and, where appropriate, externally.</li></ol><h3>Use Diverse and Representative Data to Prevent Systematic Harm</h3><p>Moderation models inherit the strengths and weaknesses of their training data. Datasets that underrepresent certain communities, dialects, or regions often lead to disproportionate enforcement errors.</p><p>To reduce this risk:</p><ul><li>Include linguistic and cultural variation in training and evaluation data</li><li>Test performance across demographic and regional slices</li><li>Avoid relying solely on globally aggregated metrics</li></ul><p>The goal is not perfect neutrality, but proportional accuracy that does not consistently disadvantage specific groups.</p><h3>Combine AI Scale With Human Judgment</h3><p>AI moderation is essential for scale, consistency, and speed, but ethical systems avoid full automation in high-impact or high-context scenarios.</p><p>Best practice architectures:</p><ul><li>Use AI for first-pass classification, prioritization, and volume reduction</li><li>Route ambiguous, sensitive, or high-impact decisions to human reviewers</li><li>Maintain human oversight over automated enforcement pipelines</li></ul><p>This hybrid approach reduces reviewer fatigue while preserving nuance, accountability, and contextual understanding.</p><h3>Standardize Human Review Through Calibration</h3><p>Human reviewers bring cultural awareness and contextual reasoning, but inconsistency is a major ethical risk.</p><p>To improve fairness:</p><ul><li>Run regular calibration sessions using real edge cases</li><li>Align reviewers on how guidelines apply in ambiguous scenarios</li><li>Monitor inter-reviewer agreement rates over time</li></ul><p>Calibration turns subjective judgment into a shared standard, improving both consistency and trust.</p><h3>Design for Procedural Fairness, Not Just Outcomes</h3><p>Ethical moderation depends as much on how decisions are made as on what decisions are reached.</p><p>Procedural fairness requires:</p><ul><li>Clear, stable community guidelines written in accessible language</li><li>Predictable enforcement patterns across similar cases</li><li>Meaningful appeal processes with human review</li><li>Timely and understandable responses to user actions</li></ul><p>When users believe the process is fair, they are more likely to accept outcomes (even unfavorable ones).</p><h3>Make Decisions Explainable by Default</h3><p>Opaque moderation decisions undermine trust and increase frustration, appeals, and accusations of bias.</p><p>Explainability does not require exposing models or internal systems. Even simple explanations help:</p><ul><li>Identify which rule was triggered</li><li>Clarify whether the decision was automated or human-reviewed</li><li>Indicate how users can avoid future violations</li></ul><h3>Use Ethical Frameworks to Guide Hard Decisions</h3><p>Moderation teams regularly face gray areas where no outcome is universally correct. Ethical frameworks provide consistency when rules alone are insufficient.</p><p>Common lenses include:</p><ul><li>Utilitarian — Which decision minimizes overall harm?</li><li>Rights-based — Are individual freedoms being unnecessarily restricted?</li><li>Justice-focused — Does the decision disproportionately affect vulnerable groups?</li><li>Pragmatic — What is enforceable at scale without creating new risks?</li></ul><p>Documenting which lens informed a decision helps teams align internally and explain reasoning externally.</p><h3>Monitor and Publish Fairness Signals</h3><p>Ethical moderation requires accountability. Transparency reporting demonstrates that systems are measured, audited, and improved over time.</p><p>Useful signals include:</p><ul><li>Accuracy and error rates by category and region</li><li>Appeal volumes and reversal rates</li><li>Known limitations or edge cases</li><li>Changes made in response to identified disparities</li></ul><p>These reports build credibility with users, regulators, and internal stakeholders.</p><h3>Common Ethical Failure Modes to Avoid</h3><p>Many moderation failures stem from predictable gaps:</p><ul><li>Over-reliance on automation without oversight</li><li>Inconsistent reviewer enforcement across regions</li><li>Measuring success only through aggregate accuracy</li><li>Unclear or shifting guidelines</li><li>No feedback loop from appeals into model improvement</li></ul><p>Recognizing these failure modes early helps teams design systems that degrade gracefully rather than fail silently.</p><h3>Ethical Moderation as a Product Discipline</h3><p>Yes, ethical moderation reduces harm, but it should also establish clear rules, explain decisions, and ensure consistent enforcement. Well-designed moderation systems both assume complexity and plan for disagreement.</p><p>Over time, these qualities support safer communities and sustainable growth.</p><h3>The Role of AI in Ethical Moderation</h3><p>AI is essential for <a href="https://getstream.io/blog/scaling-content-moderation/">scaling moderation</a>, especially on large platforms.</p><p>When built carefully, AI enhances consistency, alleviates human burden, and promotes fairness. It can also detect patterns and categories humans struggle to identify.</p><p>However, AI introduces its own risks. Opaque models can make it challenging to explain decisions. Biased training data can amplify harmful patterns. Automated decisions without oversight can lead to unfair outcomes.</p><p>Human-in-the-loop and human-on-the-loop systems mitigate these concerns. Moderators review edge cases, interpret nuance, and oversee automated pipelines. This partnership between AI and human judgment is critical for accountability.</p><p>Platforms must also define responsibility. When an AI system makes a decision, the accountability still lies with the platform. Ethical governance means documenting model behavior, decision boundaries, training data sources, and known limitations.</p><h3>Where Moderation Ethics Is Headed</h3><p>Moderation ethics are evolving rapidly.</p><p>Global regulations are increasing transparency requirements, safety obligations, and expectations for explainable AI. The Digital Services Act, in particular, sets new standards for algorithmic accountability.</p><p>Platforms will face stronger expectations to justify automated decisions, measure fairness, and provide users with recourse. Public institutions and private companies are starting to collaborate on establishing norms that will guide the future of online governance.</p><p>The rise of constitutional AI approaches also signals a shift toward models trained with ethical principles built directly into their reasoning. These approaches offer new opportunities for more consistent, values-aligned moderation.</p><p>As online communities become increasingly complex, ethical moderation becomes both more challenging and more crucial. Teams that embrace transparency, AI moderation support, fairness, and thoughtful design will be best positioned to build safe, inclusive, and trustworthy platforms.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ea75e9990d79" width="1" height="1" alt=""><hr><p><a href="https://medium.com/getstream-io/content-moderation-ethics-navigating-bias-censorship-fairness-ea75e9990d79">Content Moderation Ethics: Navigating Bias, Censorship &amp; Fairness</a> was originally published in <a href="https://medium.com/getstream-io">Stream</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[From Cameras to Action: Real‑World Applications of Vision and Speech AI]]></title>
            <link>https://medium.com/getstream-io/from-cameras-to-action-real-world-applications-of-vision-and-speech-ai-be19f3d8325a?source=rss-7d292f5ec55a------2</link>
            <guid isPermaLink="false">https://medium.com/p/be19f3d8325a</guid>
            <category><![CDATA[vision-ai]]></category>
            <dc:creator><![CDATA[getstream.io]]></dc:creator>
            <pubDate>Mon, 12 Jan 2026 21:35:01 GMT</pubDate>
            <atom:updated>2026-08-10T19:28:27.200Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GygALDo9yl1ZLlZHHujfxQ.jpeg" /></figure><p>You’re working in a warehouse when you see an automated forklift barreling towards a coworker. You whip out your phone and type “STOP!” into the app controlling the vehicle. You add another exclamation point to make sure it knows it’s an emergency.</p><p>That’s not good enough, and it’s not how things have to be.</p><p>AI can revolutionize real-world workplaces, but not the way it works right now. There can be no typing when your hands are full, and there can be no “<em>Thinking…</em>” when milliseconds mean safety. To work alongside humans, any real-world AI needs to see, hear, and perceive the world as a human does. It needs to hear a shouted “STOP!” and do so, or see the forklift out of control and immediately shut it down without human intervention.</p><p><a href="https://visionagents.ai/">Vision and speech AI</a> gives machines the ability to see and hear in ways that actually connect to human behavior. These systems can interact with the world in the natural way we do, integrating directly into real-world workflows.</p><p>How is this happening today? And how can developers start to think about and build AI out in the real world?</p><h3>Vision AI Keeps Industrial Workers Safe</h3><p>Construction and industrial environments are some of the hardest places to deploy AI. You have people and machinery constantly moving, in poorly lit environments, where a single missed hazard can result in injury and death.</p><p>Human behavior, machine behavior, and environmental state are all part of the perceptual mix, and decisions need to be made on-site, under strict latency requirements.</p><p><a href="https://kajimausa.com/">Kajima</a>, one of Japan’s largest construction firms, deployed <a href="https://www.archetypeai.io/blog/kajima-archetype-physical-ai-in-construction">Archetype’s physical AI</a> across active job sites to monitor high-risk human-machine interactions in real time. Unlike single-model or single-sensor systems, Kajima’s deployment fused video, depth, LiDAR, and environmental data into a unified spatial model of the site.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*3FOfyvDkxVlBp0if" /></figure><p>This enabled the system to track:</p><ul><li>Worker proximity to heavy machinery (cranes, excavators, autonomous vehicles)</li><li>Unauthorized entry into hazardous or exclusion zones</li><li>Unsafe behavioral patterns, such as workers standing in blind spots</li><li>Equipment anomalies (unexpected motion, machinery operating out of sequence)</li></ul><p>Because construction sites have unreliable connectivity and high privacy requirements, Kajima ran the perception models entirely on-site, on local GPUs. This eliminated cloud latency and ensured that when the vision AI recognized a dangerous event, such as a worker stepping into a moving excavator’s turning radius, it could trigger an instant local alert, a signal to the machine operator, or an automatic stop condition if integrated with control systems.</p><p>This highlights core architectural patterns developers need to adopt for industrial perception:</p><ol><li><a href="https://getstream.io/blog/multimodal-ai-agents/">Multimodal fusion</a> is mandatory. Text alone doesn’t work. You need video and audio at a minimum to start to understand these environments. Depth, LiDAR, and sensor telemetry then help to stabilize the model of the world and reduce failure modes.</li><li>Edge inference is the default. If your model’s output is tied to safety or machine control, you cannot afford cloud round-trips. Latency budgets are on the order of tens of milliseconds. On-prem GPU boxes with embedded AI are the only viable option.</li><li>Safety requires continuous state estimation. Developers should think in terms of temporal reasoning: tracking trajectories, modeling intent, and prediction. In these environments, users need not just detection, but intervention.</li><li>Event-driven integrations turn perception into action. This is mission-critical AI. It stops machines, sends alerts, logs incidents, and saves lives.</li></ol><p>As with Kajima, vision and speech AI systems will become core infrastructure that changes how safety protocols are enforced, how incidents are prevented, and how human and machine workflows are coordinated.</p><h3>Speech AI is Critical in Operations</h3><p>Speech is part of the operational control loop. In high-noise, high-tempo environments, a “shut it down!” shouted across the room can be faster than reaching for an emergency button and more reliable than hoping someone sees a hand waving.</p><p>Audio then needs to be treated as a parallel channel rather than a separate subsystem. If you are thinking in text rather than speech, the extra step means seconds that the machine isn’t shut down. Speech AI needs to fuse with vision AI and sensor data to generate reliable, real-time interpretations of events.</p><p>Modern <a href="https://getstream.io/glossary/real-time-transcription/">ASR systems</a> (such as <a href="https://github.com/openai/whisper">Whisper</a>, <a href="https://deepgram.com/">Deepgram</a>, or custom domain-tuned models) are <a href="https://aiola.ai/use-case/food-cpg-industry/">now robust enough</a> to operate in factories, warehouses, and construction sites where noise floors routinely exceed safe listening levels.</p><p>These are only transcription services. They can classify operational intent, detect urgency, and be used to build out workflows. With speech AI, developers can build:</p><ul><li>Voice-logged maintenance and inspection systems. Technicians performing inspections or repairs can dictate findings while working, instead of pausing to write logs (e.g., “<em>Unusual vibration on Pump A, bearings likely failing.</em>”) The ASR output can feed directly into CMMS/maintenance databases.</li><li>Safety-critical speech triggers. <a href="https://getstream.io/blog/realtime-speech-language-models/">Speech models</a> can run continuously on edge devices, listening for predefined emergency phrases like “<em>Emergency!</em>” or our “<em>Shut it down!</em>” example above. These can be paired with visual AI (e.g., recognizing a person entering a danger zone) so the system can trigger stop signals for machinery and alarms.</li><li>Hands-free queries for real-time data. Operators frequently need sensor values without dropping tools. Speech AI can run a loop with the plant’s telemetry systems, returning data verbally or via heads-up displays.</li></ul><p>Deploying speech understanding in operations isn’t about transcription accuracy alone. There are key principles developers have to consider:</p><ol><li>Noise is the default condition. Industrial environments have baseline noise levels of 85–100 dB, requiring models trained on augmented datasets with machinery sounds, alarms, and overlapping voices, not clean office recordings.</li><li>On-prem inference is required for safety-grade latency. When a worker yells “stop,” the speech AI needs to process that command and halt machinery in under 100 milliseconds, which means <a href="https://getstream.io/blog/best-local-llm-tools/">running models locally</a> on edge hardware rather than waiting for cloud round-trips.</li><li>Speech must feed into an event model. Raw transcription becomes actionable only when the speech AI understands context: who said it, where they are, what equipment they’re near, and whether the command requires immediate machine intervention or just logging.</li><li>The value emerges when speech and vision converge. A worker pointing at a gauge while saying “this reading looks wrong” requires the vision AI to fuse visual object detection with speech understanding to identify which specific gauge, read its value, and determine if intervention is needed.</li></ol><p>When speech and vision AI operate as a unified perception layer, they create systems that understand not just what workers are saying or what the cameras see, but the full context of human intent and machine state. This multimodal fusion is what transforms perception from a monitoring tool into an active participant in operational workflows.</p><h3>Multimodal AI Powers Assistive and Accessibility Tools</h3><p>Accessibility systems are among the purest expressions of real-time perception: they must continuously interpret a user’s environment, respond within strict latency, and adapt their output to the user’s cognitive and sensory constraints.</p><p>Unlike industrial systems that optimize for throughput or safety margins, assistive vision and speech AI optimize for clarity, privacy, and contextual relevance. You need to describe not just what’s in a scene, but what matters to the user. Assistive technologies need to combine on-device vision models, speech recognition, and language-model reasoning to deliver <a href="https://getstream.io/blog/realtime-ai-agents-latency/">real-time understanding</a>.</p><p>Apps like Be My Eyes’ “<a href="https://www.bemyeyes.com/news/introducing-be-my-ai-formerly-virtual-volunteer-for-people-who-are-blind-or-have-low-vision-powered-by-openais-gpt-4/">Virtual Volunteer</a>” demonstrate how multimodal models move beyond object detection and OCR. Users submit a photo or a continuous video stream, and the system:</p><ul><li>Identifies salient objects (food items, signage, screens)</li><li>Reads and summarizes text</li><li>Infers context (e.g., “these ingredients could make a pasta dish”)</li><li>Answers follow-up questions with conversational precision</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7xhigcoXf-6sP4d1" /></figure><p>Wearables like <a href="https://xrai.glass/">XRAI Glass</a> take this further, pairing ASR with AR displays to caption speech in the user’s field of view. These include low-latency, on-device ASR, continuous streaming transcription, diarization (identifying who’s speaking), and projection to overlay text in physical space.</p><p>These systems need to handle overlapping speech, reverberant rooms, and mixed accents, all in real time.</p><p>Assistive vision and speech AI force developers to solve some of the most challenging perception problems:</p><ol><li>A spoken caption that appears 700ms late is unusable, and a scene description that lags by a second destroys the interaction. Developers must design for sub-200-ms feedback loops.</li><li>On-device inference is the default privacy posture. Many users cannot (or should not) upload raw video/audio, so models must be optimized to run on mobile GPUs, NPUs, or edge accelerators.</li><li>Summarization &gt; enumeration. Blind users do not want “<em>There is a table. There is a chair. There is a lamp.</em>” They want contextual interpretation: “<em>Your coffee mug is on the far right side of the table, near the edge.</em>” This requires multimodal perception + LLM reasoning, not raw detection.</li><li>Developers must build for not just what the system detects, but how it communicates: concise TTS, AR text, haptic cues, and summaries.</li></ol><p>The accessibility domain generalizes to other real-time perception problems. Design constraints developed here, such as <a href="https://getstream.io/blog/low-latency-video-streaming/">low latency</a>, privacy-preserving inference, contextual summarization, map directly to robotics, industrial safety, and autonomous systems.</p><h3>Temporal AI is Essential for Sports Analytics</h3><p>Sports environments push vision AI to its limits. Players move at high speed, balls travel even faster, camera angles shift constantly, and multiple events compete for attention. Unlike controlled industrial settings, <a href="https://getstream.io/blog/ai-sports-analytics/">sports vision AI</a> must track everything while maintaining player identity across multiple camera feeds and delivering insights fast enough for broadcasting, coaching, and officiating.</p><p>The challenge isn’t just detecting what happened, but understanding the context and significance of each moment. A spike in crowd noise could signal a goal, a near-miss, or a controversial call. A player’s sudden deceleration might indicate fatigue, tactical positioning, or injury.</p><p><a href="https://www.hawkeyeinnovations.com/">Hawk-Eye</a> (tennis, cricket) and <a href="https://inside.fifa.com/innovation/standards/video-assistant-referee">VAR</a> (soccer) use multi-camera triangulation to track ball position and player movements for officiating decisions. <a href="https://pr.nba.com/nba-genius-sports-second-spectrum-expanded-partnership/">Second Spectrum</a> (NBA) and <a href="https://nextgenstats.nfl.com/">Next Gen Stats</a> (NFL) provide real-time analytics by processing multiple video feeds to track players, ball trajectories, and game events.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*JFGLEmUoPNbB7xvh" /></figure><p>These systems combine computer vision with audio processing to create comprehensive game understanding.</p><ul><li>Player and ball tracking across the entire field of play</li><li>Automatic offside detection and line-call verification</li><li>Team formation and spacing analysis</li><li>Injury risk detection through biomechanical analysis</li><li>Automated highlight detection using crowd noise and visual cues</li></ul><p>The technical requirements for sports perception create unique developer challenges:</p><ol><li>Single-frame detection is insufficient. Single-frame detection fails when tracking fast-moving players who cluster, occlude each other, or temporarily leave the frame.</li><li>Sports systems often ingest 8–24+ feeds simultaneously. Officiating decisions require perfect frame alignment across feeds to determine the exact moment of rule violations.</li><li>Multimodal fusion reduces false positives. Vision identifies player actions, audio captures crowd reactions, and commentary provides semantic context that no single modality can deliver alone.</li><li>Latency requirements vary by use case. Officiating can tolerate seconds for review, while injury detection must flag risks immediately.</li></ol><p>Sports perception systems are blueprints for any fast-moving, multi-agent scenario. The same principles that track basketball players through screens apply to warehouse robots, autonomous vehicles, and drone coordination, but with every decision visible to millions of viewers in real-time.</p><h3>Frequently Asked Questions</h3><h3>How can I combine vision and audio inputs to interpret real-time events?</h3><p>You must treat audio as a parallel channel for multimodal fusion rather than relying solely on text. Speech AI captures intent and urgency (e.g., a shouted “Stop!”), while vision AI provides physical context (e.g., a worker in a danger zone). When fused, these inputs allow the system to understand the full context of human intent and machine state.</p><h3>What’s the best architecture for low-latency perception in edge environments?</h3><p>Edge inference is the required default for safety-critical operations. To meet latency budgets of under 100 milliseconds, you must use on-premise GPU hardware or embedded AI to process data locally. This architecture eliminates cloud round-trips, allowing the vision AI to trigger instant alerts or machine stops immediately upon detecting a hazard.</p><h3>How can accessibility features use perception AI safely and privately?</h3><p>Accessibility tools should utilize on-device inference as the default posture to ensure user privacy, avoiding the need to upload raw video or audio. These systems combine vision and speech AI to deliver contextual summaries — interpreting what matters to the user rather than just listing objects — and must operate with sub-200ms feedback loops to remain usable.</p><h3>What’s the difference between industrial and sports vision systems?</h3><p>Industrial vision AI optimizes for safety and immediate intervention in poorly lit environments with heavy machinery. In contrast, sports vision AI must track high-speed, multi-agent scenarios across 8–24+ simultaneous camera feeds, maintaining player identity and alignment for broadcasting and officiating decisions.</p><h3>How do I evaluate real-world perception systems for accuracy and reliability?</h3><p>You should evaluate systems based on “continuous state estimation” (temporal reasoning) rather than single-frame detection, which often fails in dynamic environments. Reliability is achieved through multimodal fusion (combining vision, speech, and sensor data) to stabilize the world model, reduce false positives, and enable the system to predict trajectories and intent.</p><h3>Building Perception Systems for the Real World</h3><p>Every deployment faces the same architectural decision tree.</p><p>Safety-critical systems like Kajima’s construction monitoring require edge inference with sub-100ms latency, processing everything locally on GPUs to avoid network dependencies. Broadcasting and analytics systems can leverage hybrid architectures, using edge devices for initial processing and cloud resources for deeper analysis. Accessibility tools require on-device inference by default, both for privacy and responsiveness, while sports systems often distribute processing across multiple tiers to handle dozens of camera feeds simultaneously.</p><p>The convergence of vision, speech, and temporal AI isn’t just enabling new applications; it’s creating a blueprint for how AI systems interact with the physical world. Developers <a href="https://github.com/GetStream/Vision-Agents">building these systems</a> are creating the sensory layer that lets AI understand, respond to, and ultimately reshape how we work, play, and live in real environments.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=be19f3d8325a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/getstream-io/from-cameras-to-action-real-world-applications-of-vision-and-speech-ai-be19f3d8325a">From Cameras to Action: Real‑World Applications of Vision and Speech AI</a> was originally published in <a href="https://medium.com/getstream-io">Stream</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Content Moderation Circumvention: Algospeak, Obfuscation, and Adversarial Tactics]]></title>
            <link>https://medium.com/getstream-io/content-moderation-circumvention-algospeak-obfuscation-and-adversarial-tactics-285db35c2b9e?source=rss-7d292f5ec55a------2</link>
            <guid isPermaLink="false">https://medium.com/p/285db35c2b9e</guid>
            <category><![CDATA[text-moderation]]></category>
            <category><![CDATA[content-moderation]]></category>
            <category><![CDATA[moderation]]></category>
            <dc:creator><![CDATA[getstream.io]]></dc:creator>
            <pubDate>Tue, 23 Dec 2025 14:39:54 GMT</pubDate>
            <atom:updated>2026-08-10T19:28:36.914Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wSWRJPpXvBG5pG85UQr-gQ.jpeg" /></figure><p>As online platforms strengthen their safety frameworks, malicious users respond with increasingly creative ways to evade detection. The rise of content moderation circumvention is not a surprise. Modern apps support global <a href="https://getstream.io/blog/scaling-content-moderation/">conversations at scale</a>, and as moderation becomes more effective, the incentive to outsmart it grows.</p><p>But circumvention isn’t increasing solely because moderation is improving. It’s also rising because today’s digital environments make evasion easier.</p><p>AI-generated text, global user bases, and real-time formats give bad actors the perfect cover to hide within rapid, fragmented communication patterns. At the same time, trust and safety teams are expected to operate faster with fewer resources while catching more nuanced misconduct.</p><p>In this guide, we’ll explore the most common evasion tactics: algospeak, obfuscation, and adversarial manipulation. We’ll also outline how platforms can counter them using modern detection strategies, multimodal AI, and human-in-the-loop workflows.</p><h3>What Is Moderation Circumvention?</h3><p>Content moderation circumvention refers to actions taken deliberately to avoid safety checks, filters, or enforcement. These behaviors can be human-generated, AI-assisted, or fully automated. Regardless of the method, the intent is the same: pass harmful content through systems designed to block it.</p><p>People evade moderation for many reasons. Some simply want to bypass profanity filters. Others attempt to coordinate harassment, share self-harm content, or spread misinformation while avoiding bans. In marketplace or transactional apps, evasion often aims to lure buyers away from secure channels to complete scams through external payments.</p><p>Several factors are accelerating circumvention patterns:</p><ul><li>Easy access to AI tools</li><li>Cultural shifts in online spaces where euphemism communities form</li><li>Growth of global platforms with <a href="https://getstream.io/blog/multilingual-moderation/">multilingual challenges</a></li><li>High-risk categories like dating, marketplaces, gaming, and live chat, where <a href="https://getstream.io/blog/live-content-moderation/">real-time content</a> is harder to review</li></ul><p>These forces make <a href="https://getstream.io/moderation/docs/guides/platform-circumvention-prevention/">platform circumvention</a> more widespread and more difficult to stop with traditional moderation alone.</p><h3>Algospeak: The Language of Evasion</h3><p>Algospeak is community-driven coded language intentionally designed to avoid detection by automated systems. It often emerges organically when users realize that certain keywords trigger moderation. Over time, entire subcultures develop around alternative phrasing.</p><p>You see this across mainstream communities on TikTok, Discord, and Reddit. Instead of using terms directly associated with sensitive topics, users swap in replacements that models are less likely to flag. Although this sometimes happens for non-malicious reasons, it is equally common in harmful contexts, including self-harm forums or extremist spaces.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*IaVgdLxRRw6Oib08" /></figure><h3>Common Algospeak Strategies</h3><p>A few patterns recur consistently across platforms.</p><ul><li>Phonetic substitutes such as “seggs,” “unalive,” or “sewer slide”</li><li>Emoji codes where symbols replace banned words</li><li>Euphemism communities that invent full vocabularies</li><li>Mandated language shifts in stigmatized or high-risk groups, such as eating disorder recovery spaces, hate groups, or self-harm clusters</li></ul><p>These strategies evolve quickly because communities rapidly copy each other and modify terms as they become detectable.</p><h3>Why Algospeak Works Against AI</h3><p>Algospeak is effective because it exploits known weaknesses of automated models.</p><ul><li>AI depends on patterns it has seen before</li><li>New terms appear faster than models can be retrained</li><li>Cultural nuance is difficult to capture across languages</li><li>Many terms are context-dependent and harmless in certain settings</li></ul><p>A simple vocabulary change can bypass systems that rely solely on keyword lists or outdated models.</p><h3>Obfuscation: Hiding Harm in Plain Sight</h3><p>Obfuscation refers to techniques that disguise harmful content so it appears harmless to moderation systems, making it difficult for automated filters to recognize or block violations.</p><p>Below are a few of the most common ways users do this.</p><h3>Character Manipulation</h3><p>One of the oldest forms of circumvention involves tampering with characters so that text appears normal to humans but unreadable to models.</p><p>Common character-based methods include:</p><ul><li>Leetspeak substitutions like “h4t3”</li><li>Zero-width spaces that break up words</li><li>Unicode homoglyphs that look identical to common characters</li><li>Deliberate misspellings or strategic spacing</li></ul><p>These tricks require minimal effort yet completely bypass traditional keyword filters.</p><h3>Format Manipulation</h3><p>Bad actors often switch formats to remove or blend the harmful text into a medium that automated systems struggle to scan.</p><p>Examples include:</p><ul><li>Screenshots of text</li><li>Handwritten words inserted into images</li><li>Embedded text in videos or livestream overlays</li><li>Encoded messages using Base64 or ROT13</li></ul><p>Image-only or audio-only pipelines often lag behind text classification, making these attacks effective in <a href="https://getstream.io/blog/chat-moderation/">real-time chat</a> or community apps.</p><h3>Intent-Based Obfuscation</h3><p>Some users rely on ambiguity rather than explicit manipulation.</p><p>Common patterns include:</p><ul><li>Sarcasm or “ironic” wording that still conveys harm</li><li>Dog whistles familiar only to specific groups</li><li>Jokes that double as harassment</li><li>Friendly language masking malicious intent</li><li>Innocent phrasing with contextual red flags</li></ul><p>These tactics make moderation difficult because they require deeper semantic understanding.</p><h3>Adversarial Tactics Targeting AI Models</h3><p>Some users go beyond obfuscation and intentionally manipulate inputs to mislead AI systems.</p><p>These attacks often fall into three categories: input manipulation, context evasion, and coordinated evasion, each targeting different parts of the detection pipeline.</p><h3>Input Manipulation</h3><p>Bad actors can introduce tiny modifications specifically designed to confuse classifiers. These attacks exploit the way AI interprets patterns.</p><p>Common examples include:</p><ul><li>Random punctuation inserted in harmful phrases</li><li>Visual noise added to images</li><li>Slight audio warping that hides keywords</li><li>Distracting symbols woven into text</li></ul><p>To humans, the content still appears clear. To an unprepared model, it looks entirely different.</p><p>Get started! Activate your <a href="https://getstream.io/try-for-free/">free Stream account today</a> and start prototyping with moderation.</p><h3>Context Evasion</h3><p>Instead of hiding words, some users fragment harmful meaning across multiple messages or imply meaning indirectly.</p><p>Methods include:</p><ul><li>Splitting a harmful sentence into several posts</li><li>Suggestive phrasing that implies outcomes without naming them</li><li>Role-playing scenarios that violate platform policy</li><li>Context windows manipulated to mislead AI</li></ul><p>This is common in real-time chat where velocity and message order matter.</p><h3>Coordinated Evasion</h3><p>Some communities work together to defeat moderation.</p><p>These groups often create:</p><ul><li>Dictionaries of coded terms</li><li>Versioning systems where new vocabulary replaces flagged language</li><li>Organized raids where users post in synchronized patterns</li><li>Group training on how to bypass filters</li></ul><p>Coordinated networks can scale evasion faster than platforms can respond.</p><h3>Real World Examples of Evasion</h3><p>Modern apps see circumvention patterns across nearly every risk category.</p><p>Examples include:</p><ul><li>Hate speech hidden through symbols that look innocent at first glance</li><li>Self-harm content disguised as aesthetic trends using pastel imagery and coded language</li><li>Scams that mask product names to lure <a href="https://getstream.io/blog/tradeblock/">marketplace buyers</a> into off-platform payments</li><li>Child safety evasion through mislabelled hashtags or emojis</li><li>Misinformation disguised as parody that exploits the blurred line between humor and harmful narratives</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Ef-5djzcyHZgvy6w" /></figure><p>Marketplace and transactional apps face a specific threat: scammers intentionally skirt moderation to pull buyers away from safe in-app payments. Once outside the platform, users lose payment protection and become easy targets. These evasion tactics often mix obfuscation with persuasion patterns that appear legitimate.</p><h3>Why Traditional Moderation Struggles to Keep Up</h3><p><a href="https://getstream.io/blog/chat-moderation-tools/">Moderation stacks</a> often rely on a mix of static rules, manual review, and outdated machine learning. Circumvention evolves faster than these approaches can adapt.</p><p>Key challenges include:</p><ul><li>Long lag time between term emergence and model updates</li><li>Cultural nuance that cannot be captured with one-size-fits-all rules</li><li>Massive volume and velocity in real-time chat</li><li>Single-model systems that fail to catch multimodal content</li><li>Human reviewers overwhelmed by obfuscated and ambiguous content</li></ul><p>If your platform relies solely on keywords, basic classifiers, or slow escalation workflows, evasive behavior will always stay one step ahead.</p><h3>How Platforms Can Fight Moderation Evasion</h3><p>No single model or rule can stop evasion on its own. Effective defense requires multiple layers, including modern detection systems, continuously updated pipelines, powerful moderation tools, and strong human — AI collaboration.</p><h3>Multi-Layered Detection Systems</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*p9Q5nFl7Mvsl4h_1" /></figure><p>The most effective strategy against circumvention is layering multiple techniques. No single model is strong enough to catch every type of evasion across every <a href="https://getstream.io/blog/content-moderation/">content type</a>.</p><p>A multilayer system may include:</p><ul><li>AI-powered classifiers for <a href="https://getstream.io/moderation/docs/engines/ai-llm-text/">text</a>, <a href="https://getstream.io/moderation/docs/engines/image-moderation/">image</a>, and <a href="https://getstream.io/moderation/docs/engines/ai-video-file-moderation/">video</a></li><li>Heuristics that look for velocity anomalies</li><li>Behavioral signals such as rapid channel switching or repeated failed sends</li><li>Reputation scoring based on long-term user patterns</li><li>Anomaly detection for suspicious spikes or unusual vocabulary</li></ul><p>Combining rule-based and AI-based systems reduces blind spots.</p><h3>Updated Moderation Pipelines</h3><p>Modern platforms must treat moderation as a living system. That means continual updates and adaptation.</p><p>Effective pipelines often include:</p><ul><li>Continuous model retraining with fresh examples</li><li>Real-time feedback loops from <a href="https://getstream.io/blog/content-moderators/">moderators</a></li><li>Strong community reporting features</li><li>Alignment between policy teams and model training teams</li><li>Rapid incorporation of new slang and cultural references</li></ul><p>This allows platforms to respond the moment new circumvention patterns emerge.</p><h3>Moderation Tools and Dashboards</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1QRj-8EIAJ0xEGcZ" /></figure><p>Trust and safety teams need tools that surface patterns instead of burying them.</p><p>Helpful capabilities include:</p><ul><li>Dashboards that highlight suspicious content</li><li>Contextual conversation threads that reveal intent</li><li>Multi-language coverage</li><li>Queue systems that split cases by severity</li><li>Insights into user history or known evasion patterns</li></ul><p>The goal is not only to catch harmful content but also to make moderation workflows efficient.</p><h3>Human and AI Collaboration</h3><p>AI alone cannot solve the issue of moderation circumvention. Humans provide cultural understanding, nuance, and judgment that models cannot match.</p><p>Teams benefit from:</p><ul><li>Human verification for ambiguous or high-risk content</li><li>Linguistic specialists who understand regional slang</li><li>A trust and safety team structure that allows fast escalation</li><li>Clear response protocols for urgent cases</li></ul><p>Blending machine speed with human insight removes blind spots and reduces errors.</p><h3>Your Best Defense Against Bad Actors</h3><p>Content moderation circumvention is an inevitable part of running a digital platform. As long as filters exist, people will search for ways to evade them. The key is not eliminating evasion but minimizing its impact through adaptive, multi-modal, and constantly evolving strategies.</p><p>For product managers, developers, and <a href="https://getstream.io/blog/trust-safety/">trust and safety teams</a>, the priority is <a href="https://getstream.io/blog/build-vs-buy-moderation/">building moderation systems</a> flexible enough to learn, adjust, and scale. Multi-layer detection, continuous retraining, intelligent dashboards, and human expertise create a strong foundation against evasion attempts.</p><p>When platforms invest in dynamic safety infrastructure, they not only reduce harm but also protect the integrity of transactions, conversations, and communities. With the right approach, moderation circumvention becomes manageable and far less disruptive to user trust. Solutions like Stream’s flexible <a href="https://getstream.io/moderation/">AI Moderation API</a>, real-time signals, and automated classifiers can strengthen this foundation and provide your team with the tools needed to stay ahead of bad actors as their tactics evolve.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=285db35c2b9e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/getstream-io/content-moderation-circumvention-algospeak-obfuscation-and-adversarial-tactics-285db35c2b9e">Content Moderation Circumvention: Algospeak, Obfuscation, and Adversarial Tactics</a> was originally published in <a href="https://medium.com/getstream-io">Stream</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>