<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shue Zheng</title>
    <description>The latest articles on DEV Community by Shue Zheng (@shue_zheng_a1d2e9cc33f6fd).</description>
    <link>https://dev.to/shue_zheng_a1d2e9cc33f6fd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3754855%2F3c6e846b-50eb-4eb4-96a4-0d50b991065b.png</url>
      <title>DEV Community: Shue Zheng</title>
      <link>https://dev.to/shue_zheng_a1d2e9cc33f6fd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shue_zheng_a1d2e9cc33f6fd"/>
    <language>en</language>
    <item>
      <title>Why Our Next.js 15 App Lost 80% of Its Traffic Overnight (And How We Fixed It) 📉</title>
      <dc:creator>Shue Zheng</dc:creator>
      <pubDate>Tue, 03 Mar 2026 11:08:11 +0000</pubDate>
      <link>https://dev.to/shue_zheng_a1d2e9cc33f6fd/why-our-nextjs-15-app-lost-80-of-its-traffic-overnight-and-how-we-fixed-it-4ke4</link>
      <guid>https://dev.to/shue_zheng_a1d2e9cc33f6fd/why-our-nextjs-15-app-lost-80-of-its-traffic-overnight-and-how-we-fixed-it-4ke4</guid>
      <description>&lt;p&gt;📉 My Traffic Dropped to 0 overnight: The Next.js 15 Hydration Trap&lt;br&gt;
Imagine waking up, checking your Google Analytics 4 (GA4) dashboard for your shiny new SaaS product, and seeing a horrifying number: 0 Users. 0 Views. 100% Drop.&lt;/p&gt;

&lt;p&gt;Did the servers crash? Did Google de-index my domain?&lt;/p&gt;

&lt;p&gt;Neither. The site was running perfectly fine. The culprit? A sneaky Hydration Mismatch in &lt;strong&gt;Next.js 15&lt;/strong&gt; that silently murdered my tracking script.&lt;/p&gt;

&lt;p&gt;Here is how a seemingly innocent&lt;code&gt;&amp;lt;GoogleAnalytics /&amp;gt;&lt;/code&gt; component placement caused a complete tracking blackout on sandagent.dev, and how you can avoid this exact trap.&lt;/p&gt;
&lt;h2&gt;
  
  
  🕵️ The Crime Scene
&lt;/h2&gt;

&lt;p&gt;Like any good Next.js developer, I wanted to add Google Analytics to my &lt;code&gt;app/layout.tsx&lt;/code&gt;. Standard procedure, right? I used a third-party GA package (or standard &lt;code&gt;next/third-parties/google&lt;/code&gt;) and placed it right where it belongs—in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ The Deadly Mistake&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Looks perfectly normal, doesn't it? */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoogleAnalytics&lt;/span&gt; &lt;span class="na"&gt;gaId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"G-XXXXXXXXXX"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔍 The Investigation: Why it broke
&lt;/h2&gt;

&lt;p&gt;In Next.js 15 (with React 19), the hydration process has become incredibly strict.&lt;/p&gt;

&lt;p&gt;When you place dynamic script components inside the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, the server renders the HTML with the injected &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags. However, during the client-side hydration phase, third-party browser extensions, or even React's own strict &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; reconciliation, can cause a mismatch.&lt;/p&gt;

&lt;p&gt;Instead of just throwing a red warning in your console and moving on, the hydration failure caused React to effectively &lt;strong&gt;drop or bypass the execution of the GA tracking scripts&lt;/strong&gt; in the client-side DOM tree.&lt;br&gt;
The result? The page visually loads perfectly, the user clicks around, but the &lt;code&gt;collect?v=2&lt;/code&gt; network request is &lt;strong&gt;never sent to Google&lt;/strong&gt;. Complete data blackout.&lt;/p&gt;
&lt;h2&gt;
  
  
  🛠️ The Fix (The 1-Line Solution)
&lt;/h2&gt;

&lt;p&gt;After digging through the Next.js docs and debugging the React tree, the fix was almost embarrassingly simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not put the GA component in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. Put it inside the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ The Correct Way&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Leave standard meta tags here */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Place it here instead! */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoogleAnalytics&lt;/span&gt; &lt;span class="na"&gt;gaId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"G-XXXXXXXXXX"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why does this work?
&lt;/h3&gt;

&lt;p&gt;By placing the script tag inside the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; (or at the very end of it), it avoids conflicting with React's strict &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; management during the initial render pass. The script still loads asynchronously, performance isn't impacted, but most importantly: &lt;strong&gt;React hydration no longer swallows your tracking code.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Takeaways for Next.js 15 Developers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Don't trust the visual load:&lt;/strong&gt; Just because your site didn't 500 error doesn't mean your background scripts are running. Check your Network tab for &lt;code&gt;collect&lt;/code&gt; requests after a major Next.js version bump.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Move scripts to &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;:&lt;/strong&gt; Unless strictly required by the provider to be the &lt;em&gt;first&lt;/em&gt; thing in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, placing analytics components inside the body tag is much safer against React 19 hydration mismatches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up traffic anomaly alerts:&lt;/strong&gt; If I hadn't had an automated cron job fetching daily GA reports, I might have gone weeks without realizing my traffic was zeroed out.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Have you run into weird React 19 / Next.js 15 hydration bugs yet? Let me know in the comments!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(P.S. If you're building AI agents, you can check out the project that almost lost all its metrics at &lt;a href="https://sandagent.dev" rel="noopener noreferrer"&gt;sandagent.dev&lt;/a&gt; 🚀)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;*&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>@sandagent/sdk — Run Claude in a Sandbox with Vercel AI SDK Streams</title>
      <dc:creator>Shue Zheng</dc:creator>
      <pubDate>Thu, 05 Feb 2026 12:14:54 +0000</pubDate>
      <link>https://dev.to/shue_zheng_a1d2e9cc33f6fd/sandagentsdk-run-claude-in-a-sandbox-with-vercel-ai-sdk-streams-1ed3</link>
      <guid>https://dev.to/shue_zheng_a1d2e9cc33f6fd/sandagentsdk-run-claude-in-a-sandbox-with-vercel-ai-sdk-streams-1ed3</guid>
      <description>&lt;h1&gt;
  
  
  @sandagent/sdk — Run Claude in a Sandbox with Vercel AI SDK Streams
&lt;/h1&gt;

&lt;p&gt;I’m sharing &lt;strong&gt;@sandagent/sdk&lt;/strong&gt;, a TypeScript/JavaScript SDK for running Claude agents in a sandboxed environment (local or cloud) that exposes &lt;strong&gt;Vercel AI SDK-compatible streaming&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Run AI agents in a controlled sandbox without exposing API keys&lt;/li&gt;
&lt;li&gt;Stream messages using &lt;strong&gt;Vercel AI SDK protocol&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Optional React chat hooks for building UI&lt;/li&gt;
&lt;li&gt;Expose the sandboxed agent as an &lt;strong&gt;SDK-compatible model&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;npm: &lt;a href="https://www.npmjs.com/package/@sandagent/sdk" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@sandagent/sdk&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Example Usage
&lt;/h3&gt;

&lt;p&gt;This example demonstrates how to create a sandboxed session and stream messages in a way compatible with the Vercel AI SDK. The React chat hooks can be used to integrate real-time UI components seamlessly.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
ts
import { SandAgentClient } from "@sandagent/sdk";

const client = new SandAgentClient({ apiKey: process.env.SANDAGENT_API_KEY });

// Create a sandboxed agent session
const session = await client.createSession("example-session", {
  model: "claude-2",
});

// Stream messages
const stream = client.streamMessages(session.id, { prompt: "Hello!" });
for await (const chunk of stream) {
  console.log(chunk);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>showdev</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
