<?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"><channel><title><![CDATA[Yaman's Blog]]></title><description><![CDATA[Yaman's Blog]]></description><link>https://blog.yamansarabariya.com.np</link><generator>RSS for Node</generator><lastBuildDate>Sun, 18 Oct 2026 00:23:18 GMT</lastBuildDate><atom:link href="https://blog.yamansarabariya.com.np/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Our AI examiner was a black box. SigNoz told us what a student actually costs]]></title><description><![CDATA[Hi, I am Yaman, co-founder of Mockacad. We are building a universal adaptive mock test preparation platform. Students use it to prepare for exams like IELTS, PTE, SAT, JFT and many more, and two of ou]]></description><link>https://blog.yamansarabariya.com.np/our-ai-examiner-was-a-black-box-signoz-told-us-what-a-student-actually-costs</link><guid isPermaLink="true">https://blog.yamansarabariya.com.np/our-ai-examiner-was-a-black-box-signoz-told-us-what-a-student-actually-costs</guid><category><![CDATA[observability]]></category><category><![CDATA[signoz]]></category><category><![CDATA[nestjs]]></category><category><![CDATA[pipecat]]></category><category><![CDATA[Vertex-AI]]></category><category><![CDATA[OLTP]]></category><dc:creator><![CDATA[Yaman]]></dc:creator><pubDate>Sat, 18 Jul 2026 19:41:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6277641edc122f5a4f21f37d/21f54e35-aec2-4b47-b5cb-4dfeaa07f8c8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi, I am Yaman, co-founder of <a href="https://mockacad.com">Mockacad</a>. We are building a universal adaptive mock test preparation platform. Students use it to prepare for exams like IELTS, PTE, SAT, JFT and many more, and two of our features run on AI in production every single day. The first is our voice examiner: a Pipecat agent on Gemini Live that conducts real speaking tests over WebRTC. The second is instant AI grading, which scores writing and speaking attempts minutes after submission. It is the feature our users love most.</p>
<p>Both features worked fine. The problem was that I could not answer the two questions that mattered most. Why does the voice agent sometimes feel slow? And what does one student actually cost us in AI spend? We were about to make subscription pricing decisions based on guesses.</p>
<p>For the Agents of SigNoz pre-hackathon challenge, I self-hosted SigNoz and instrumented the whole path: voice agent, NestJS backend, Postgres, and the Vertex AI calls behind grading. A week later we have per-turn latency numbers, a price-per-student figure, and two discoveries I did not see coming.</p>
<h2>Self-hosting SigNoz, and the two gotchas nobody mentions</h2>
<p>SigNoz now installs through its Foundry CLI. A <code>casting.yaml</code> and one command generate the whole Docker Compose stack (ClickHouse, ingester, UI):</p>
<pre><code class="language-bash">curl -fsSL https://signoz.io/foundry.sh | bash
foundryctl forge   # generate compose files without starting them
docker compose -f pours/deployment/compose.yaml up -d
</code></pre>
<p>I used <code>forge</code> instead of <code>cast</code> because our VM already had an app on port 8080, which is SigNoz's default UI port. So I remapped ports first, and bound OTLP ingest to <code>127.0.0.1</code> so telemetry is never exposed to the internet.</p>
<p>Two things then bit me:</p>
<ol>
<li><p><strong>The OTLP ports accept connections but reset every request until the first admin user exists.</strong> The ingester gets its pipeline config from the SigNoz server over OpAMP, and that handshake fails with <code>cannot create agent without orgId</code> until you register. The collector logs say "Everything is ready" while <code>curl</code> to port 4318 dies. Very confusing until you know.</p>
</li>
<li><p><strong>SigNoz ships without a JWT secret</strong> and logs a critical warning about it. Set <code>SIGNOZ_TOKENIZER_JWT_SECRET</code> before exposing the UI anywhere.</p>
</li>
</ol>
<h2>Instrumenting a production voice agent took three lines</h2>
<p>Pipecat has OpenTelemetry support built in. This is the entire voice-side change:</p>
<pre><code class="language-python">task = PipelineTask(
    pipeline,
    params=PipelineParams(enable_metrics=True, enable_usage_metrics=True),
    enable_tracing=True,
    enable_turn_tracking=True,
    conversation_id=session.session_id,
)
</code></pre>
<p>Plus an OTLP exporter at startup. Every conversation now produces a span tree (<code>conversation</code>, then <code>turn</code>, then <code>llm_response</code>) carrying per-turn token counts, time to first byte, and user-to-bot latency for Gemini Live.</p>
<p>The NestJS backend needed zero code changes. Node auto-instrumentation through <code>NODE_OPTIONS</code> and a few <code>OTEL_*</code> env vars in the pm2 app definition picked up Express, NestJS, and every Postgres query. One warning from experience: never <code>export NODE_OPTIONS</code> in the shell where you run pm2. The pm2 CLI is itself a Node process and it crashes trying to load the preload. Scope the env to the app definition instead.</p>
<p>For grading, we wrapped our single Vertex AI client so every LLM call reports its token usage plus a <code>purpose</code> attribute (<code>grading</code>, <code>transcription</code>, <code>translation</code>) and the quiz attempt it belongs to. One wrapper, and every AI feature in the product is accounted for.</p>
<h2>What the traces said about latency and cost</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6277641edc122f5a4f21f37d/00bd73d5-bb93-4172-a18a-6d51eb2448eb.png" alt="Screenshot 2026-07-19 at 00.46.33" style="display:block;margin:0 auto" />

<p>Here is the first real speaking test after instrumentation. It lasted 54 seconds and had 4 turns:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6277641edc122f5a4f21f37d/ad758665-5651-486a-99f7-861187b0f82f.png" alt="Screenshot 2026-07-19 at 00.59.30" style="display:block;margin:0 auto" />

<ul>
<li><p><strong>Input tokens per turn: 1,148 then 1,384 then 1,535 then 1,778.</strong> Gemini Live re-sends the conversation context on every turn, so each turn costs more than the last. Session cost grows faster than session length. If you price long speaking sessions linearly, you are quietly subsidizing them.</p>
</li>
<li><p>User-to-bot latency became a p95 graph instead of a feeling. "The examiner sometimes lags" is now a number with a threshold and an alert on it.</p>
</li>
</ul>
<h2>The alert I did not believe</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6277641edc122f5a4f21f37d/54e87899-332c-43be-bc02-0715b684054d.png" alt="Screenshot 2026-07-19 at 01.01.23" style="display:block;margin:0 auto" />

<p>We set a simple guardrail: more than 300k LLM tokens in one hour sends a Discord ping. Two days in, it fired with a current value of 322,155. Our token dashboard said around 148k. I assumed the alert was broken and went into ClickHouse to prove it wrong.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6277641edc122f5a4f21f37d/214618b4-d6b2-4b30-b98a-149ae782b97e.png" alt="Screenshot 2026-07-19 at 01.08.48" style="display:block;margin:0 auto" />

<p>The alert was right, twice over. First, the dashboard panel was scoped to the voice agent only. Grading traffic, which had just started that day, was invisible to it. Second, and much more interesting: the grading spans showed a <code>totalTokenCount</code> of 367,911 against input plus output of only 203,956. The missing 164k tokens were <strong>Gemini 2.5's thinking tokens</strong>. They are billed at output rates, but they do not appear in the input or output counts. About 40% of our grading spend was hidden reasoning that our cost formulas never saw.</p>
<p>We fixed the price formula to charge the output rate on <code>total minus input</code>, and because the price mapping lives in the dashboard query rather than in code, all our historical data corrected itself instantly.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6277641edc122f5a4f21f37d/79a12959-6c4f-48cf-a98d-74690ddb2dab.png" alt="Screenshot 2026-07-19 at 01.10.10" style="display:block;margin:0 auto" />

<p>That was not the only time alerting proved useful early. Within thirty minutes of creating an error-spike rule, it caught our own frontend middleware hammering <code>/auth/profile</code> with an expired token at 12 requests per second. A silent retry loop that had probably been running for months.</p>
<h2>What a student costs</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6277641edc122f5a4f21f37d/ecc675d3-8309-441c-96ae-5c9e90cbc6f6.png" alt="Screenshot 2026-07-19 at 01.13.50" style="display:block;margin:0 auto" />

<p>With tokens tagged by purpose and attempt, the pricing questions finally have real answers (at Gemini list rates, so treat them as close estimates):</p>
<ul>
<li><p>Voice examiner: about <strong>$0.039 per conversation minute</strong>, roughly $2.30 per hour of live speaking test (measured across 74 conversation minutes)</p>
</li>
<li><p>Instant grading: about <strong>$0.32 per graded attempt</strong>, around 15 LLM calls and 170k tokens per attempt, thinking included (measured across 74 graded attempts)</p>
</li>
<li><p>A 15-minute speaking test plus AI grading: about <strong>$0.90 per student. Measured, not guessed.</strong></p>
</li>
</ul>
<p>That number, and how it scales with session length and question count, is now the foundation of our subscription pricing. It came from a dashboard, not a spreadsheet of assumptions.</p>
<h2>Takeaways</h2>
<ul>
<li><p><strong>A voice agent is three lines away from full observability</strong> if your framework speaks OpenTelemetry. The hard part is deciding what to measure, not how.</p>
</li>
<li><p><strong>Gemini's thinking tokens hide inside</strong> <code>totalTokenCount</code><strong>.</strong> If your cost math uses input plus output, you are undercounting every reasoning model. Price output as total minus input.</p>
</li>
<li><p><strong>An alert you do not believe is an alert doing its job.</strong> Checking it against raw ClickHouse taught us more about our spend than any dashboard.</p>
</li>
<li><p><strong>Instrument the process, not the codebase.</strong> And never let <code>NODE_OPTIONS</code> leak into pm2's own CLI.</p>
</li>
<li><p><strong>The OpAMP first-admin gotcha</strong> will convince you SigNoz ingest is broken when it is not.</p>
</li>
<li><p>What I would do differently: put SigNoz on its own small VM from day one. Right now our observability lives on the same box as production, which means the smoke detector is plugged into the stove.</p>
</li>
</ul>
<h2>What's next</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6277641edc122f5a4f21f37d/79894928-88a8-488b-8cda-8dfd30e00247.png" alt="Screenshot 2026-07-19 at 01.21.22" style="display:block;margin:0 auto" />

<p>This stack has since grown into seven dashboards: per-attempt debugging (paste an attempt ID and see every request, payload, token, and error it caused), grading failure tracking, VM health, and distributed traces from our in-development MCP server that stitch a laptop tool call to a cloud SQL query in one flamegraph. That is our hackathon submission story for next week.</p>
<p><em>Setup: SigNoz self-hosted via Foundry on Debian 12, Pipecat 1.2.1 native tracing, OTel JS auto-instrumentations 0.78 on NestJS. Your latencies and prices will differ. Measure them.</em></p>
<h2>References</h2>
<ul>
<li><p><a href="https://signoz.io/docs/install/docker/">SigNoz docs: Docker self-host install</a></p>
</li>
<li><p><a href="https://docs.pipecat.ai/server/utilities/opentelemetry">Pipecat docs: OpenTelemetry tracing</a></p>
</li>
<li><p><a href="https://opentelemetry.io/docs/zero-code/js/">OpenTelemetry JS: zero-code instrumentation</a></p>
</li>
<li><p><a href="https://ai.google.dev/gemini-api/docs/thinking">Gemini API docs: thinking</a></p>
</li>
<li><p><a href="https://cloud.google.com/vertex-ai/generative-ai/pricing">Vertex AI generative AI pricing</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Event propagation in JavaScript]]></title><description><![CDATA[Recently I was working on some frontend stuffs at my job where I had to implement a modal open on row-click of a datatable. My data table structure was like this:

Under the Action column, the Buttons would trigger some fetch API calls. I had to impl...]]></description><link>https://blog.yamansarabariya.com.np/event-propagation-in-javascript</link><guid isPermaLink="true">https://blog.yamansarabariya.com.np/event-propagation-in-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Event Loop]]></category><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[Event propagation]]></category><dc:creator><![CDATA[Yaman]]></dc:creator><pubDate>Mon, 29 Jan 2024 16:07:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706544381757/bcdefcac-c354-4f9c-9a8a-c2a740f25f2c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently I was working on some frontend stuffs at my job where I had to implement a <code>modal</code> open on <code>row-click</code> of a <code>datatable</code>. My data table structure was like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706540743888/1c27a34b-fbb3-41cc-8de0-fcb4c2efd8c5.png" alt class="image--center mx-auto" /></p>
<p>Under the Action column, the Buttons would trigger some fetch API calls. I had to implement a click-listener for each row, which would show the detailed information of that row on a <code>modal</code> component. Everything went well. Modal was working fine. But, when I clicked on the Buttons of Action column, it triggered the fetch API call and the modal would open too.</p>
<p>This was an issue because no one would want to see a modal pop-up on their screen every time they clicked another action button. My brain stopped working for a moment as I could not figure out what was happening there. On further investigating the issue, I found out there is something called event propagation on the DOM tree that occurs whenever we attach some event listeners to the DOM node.</p>
<h3 id="heading-how-does-event-propagation-work-bubbling-and-capturing">How does Event Propagation work? (Bubbling and Capturing)</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706542089534/edd4badd-c52c-4660-ad61-b205dec87326.png" alt class="image--center mx-auto" /></p>
<p>Let's consider <code>Grand parent</code> , <code>parent</code> and <code>child</code> are three HTML divs. I'll attach three listeners to the three divs.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> grand_parent = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"grand_parent"</span>),
parent = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"parent"</span>),
child = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"child"</span>);

grand_parent.addEventListener(<span class="hljs-string">"click"</span>, triggerClick(<span class="hljs-string">"grand parent clicked"</span>));
parent.addEventListener(<span class="hljs-string">"click"</span>, triggerClick(<span class="hljs-string">"parent clicked"</span>));
child.addEventListener(<span class="hljs-string">"click"</span>, triggerClick(<span class="hljs-string">"child clicked"</span>));

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">triggerClick</span>(<span class="hljs-params">data</span>) </span>{
    <span class="hljs-built_in">console</span>.log(data)
}
</code></pre>
<p>On clicking the child, we will see the following things in the console:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706542680201/cc3641fb-4541-4d98-a175-c15a9af9d6dc.png" alt class="image--center mx-auto" /></p>
<p>On clicking the parent, we will see the parent and grandparent logged-in console. Finally, on clicking grandparent, we will just see the grandparent logged.</p>
<p>This phenomenon is known as the <code>Bubbling</code> phase of event propagation. The event bubbles up from the target element through its ancestors in the DOM tree. This is the more commonly used phase for handling events and the default behavior of any event handlers in JavaScript.</p>
<p>Another phase is known as <code>Capturing</code> phase which does exactly the opposite of the Bubbling. During the capturing phase, the event travels from the root of the DOM tree down to the target element. This phase allows you to intercept and handle the event before it reaches its target. Capturing is less commonly used but can be helpful in certain scenarios.</p>
<p>The code below sets the event handlers to work in <code>Capturing</code> phase.</p>
<pre><code class="lang-javascript">grand_parent.addEventListener(<span class="hljs-string">"click"</span>, triggerClick(<span class="hljs-string">"grand parent clicked"</span>), <span class="hljs-literal">true</span>);
parent.addEventListener(<span class="hljs-string">"click"</span>, triggerClick(<span class="hljs-string">"parent clicked"</span>), <span class="hljs-literal">true</span>);
child.addEventListener(<span class="hljs-string">"click"</span>, triggerClick(<span class="hljs-string">"child clicked"</span>), <span class="hljs-literal">true</span>);
</code></pre>
<p>Passing <code>true</code> property will tell the event listener to work in <code>Capturing</code> mode. Now, whenever we click the child. We will see the exact opposite of the previous output.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706543337983/bdc33cfc-c03e-4b5a-a030-ff848cf2c4a8.png" alt class="image--center mx-auto" /></p>
<p>Here, when the child is clicked, first of all, the topmost parent's event handler is executed and it travels down to the target through all its ancestors. This is known as <code>Capturing</code> phase of event propagation.</p>
<h3 id="heading-stopping-event-propagation">Stopping Event Propagation:</h3>
<p>To fix the issue with my data table row click modal and action button click, I had to stop the propagation of the events in my action buttons. JavaScript has a method on the event object that lets us stop the event propagation on that target element.</p>
<p>Let's see how is it done.</p>
<pre><code class="lang-javascript">grand_parent.addEventListener(<span class="hljs-string">"click"</span>, triggerClick(<span class="hljs-string">"grand parent clicked"</span>));
parent.addEventListener(<span class="hljs-string">"click"</span>, triggerClick(<span class="hljs-string">"parent clicked"</span>));

child.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    triggerClick(<span class="hljs-string">"child clicked"</span>)
    <span class="hljs-comment">// stop propagation of events (bubbling / capturing)</span>
    event.stopPropagation();
});
</code></pre>
<p><code>stopPropagation()</code> method will tell the handler to stop executing the click handlers on the ancestors of the target element, hence, other listeners are not executed. Here, if you click the child, you will only see <code>child clicked</code> in the console screen.</p>
<p>I set the <code>event.stopPropagation();</code> on my Buttons under the action columns and now the modal component was not triggered whenever I clicked the action buttons. This was the fix for my issue with the data table row click.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Understanding event propagation in JavaScript is crucial for effective event handling in web development. Whether you're working with the capturing or bubbling phase, being aware of how events propagate through the DOM tree allows you to create more interactive and responsive web applications. Remember to choose the appropriate phase based on your requirements and use the <code>stopPropagation</code> method wisely to control event flow.</p>
]]></content:encoded></item><item><title><![CDATA[Webhooks]]></title><description><![CDATA[Introduction
In the ever-evolving landscape of the digital world, communication between different applications and services is paramount. Webhooks, often hailed as the unsung heroes of modern development, play a crucial role in facilitating this seam...]]></description><link>https://blog.yamansarabariya.com.np/webhooks</link><guid isPermaLink="true">https://blog.yamansarabariya.com.np/webhooks</guid><category><![CDATA[realtime systems]]></category><category><![CDATA[webhooks]]></category><category><![CDATA[realtime apps]]></category><category><![CDATA[http]]></category><dc:creator><![CDATA[Yaman]]></dc:creator><pubDate>Wed, 17 Jan 2024 15:06:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1705503904841/f28aea54-ffcd-431d-bb3f-e76dc481bc69.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>In the ever-evolving landscape of the digital world, communication between different applications and services is paramount. Webhooks, often hailed as the unsung heroes of modern development, play a crucial role in facilitating this seamless interaction. In this blog, we will dive into the world of webhooks, exploring what they are, how they work, and the myriad ways in which they contribute to the efficiency and responsiveness of web applications.</p>
<h3 id="heading-understanding-webhooks">Understanding Webhooks</h3>
<p>At its core, a webhook is a mechanism that enables one system to notify another about specific events in real time. Unlike traditional APIs, which rely on polling to retrieve information periodically, webhooks initiate the communication process by sending data automatically when a predefined event occurs. This event-driven architecture minimizes latency, enhances efficiency, and fosters more dynamic and responsive applications.</p>
<h3 id="heading-how-webhooks-work">How Webhooks Work</h3>
<p>Webhooks operate on a simple principle: event-driven communication. Here's a step-by-step breakdown of how webhooks typically work:</p>
<ol>
<li><p><strong>Event Occurs:</strong></p>
<ul>
<li>An event, such as a user action or a system event, triggers the need for information to be communicated to another system.</li>
</ul>
</li>
<li><p><strong>HTTP POST Request:</strong></p>
<ul>
<li>The system generating the event sends an HTTP POST request to a predefined URL, which acts as an endpoint for the webhook.</li>
</ul>
</li>
<li><p><strong>Payload Delivery:</strong></p>
<ul>
<li>The HTTP POST request contains a payload – data related to the event. This payload is received by the webhook endpoint, which processes the information.</li>
</ul>
</li>
<li><p><strong>Processing and Response:</strong></p>
<ul>
<li>The receiving system processes the payload and may perform additional actions based on the received data. A response may be sent back to acknowledge the successful reception of the payload.</li>
</ul>
</li>
</ol>
<h3 id="heading-use-cases-and-benefits">Use Cases and Benefits</h3>
<ol>
<li><p><strong>Real-time Updates:</strong></p>
<ul>
<li>Webhooks are instrumental in scenarios where real-time updates are crucial, such as chat applications, stock market feeds, or collaborative tools. Users receive immediate notifications, ensuring they stay informed and engaged.</li>
</ul>
</li>
<li><p><strong>Automation and Integration:</strong></p>
<ul>
<li>Webhooks streamline automation by connecting different services and triggering actions based on events. This facilitates seamless integration between applications, reducing manual intervention and enhancing overall workflow efficiency.</li>
</ul>
</li>
<li><p><strong>Enhanced User Experience:</strong></p>
<ul>
<li>Applications utilizing webhooks provide a more responsive and interactive user experience. Users can receive timely updates, notifications, and personalized content, contributing to a more engaging digital environment.</li>
</ul>
</li>
<li><p><strong>Efficient Data Synchronization:</strong></p>
<ul>
<li>In scenarios involving multiple systems or databases, webhooks help maintain data consistency by synchronizing information in real time. This is particularly valuable for e-commerce platforms, content management systems, and collaborative tools.</li>
</ul>
</li>
</ol>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Webhooks represent a pivotal advancement in the realm of web development, offering a robust solution for real-time communication and event-driven workflows. As we continue to witness the rapid evolution of digital ecosystems, the adoption of webhooks is poised to grow, enabling developers to create more responsive, interconnected, and user-friendly applications. Embrace the power of webhooks, and unlock a new dimension of efficiency and connectivity in the digital era.</p>
]]></content:encoded></item><item><title><![CDATA[Server-Sent Event (SSE)]]></title><description><![CDATA[In the ever-evolving web development landscape, real-time communication between servers and clients has become crucial to building dynamic and interactive web applications. One of the technologies that facilitate this seamless communication is Server...]]></description><link>https://blog.yamansarabariya.com.np/server-sent-event-sse</link><guid isPermaLink="true">https://blog.yamansarabariya.com.np/server-sent-event-sse</guid><dc:creator><![CDATA[Yaman]]></dc:creator><pubDate>Tue, 16 Jan 2024 20:20:11 GMT</pubDate><content:encoded><![CDATA[<p><img src="https://media.geeksforgeeks.org/wp-content/cdn-uploads/20220131095922/Group-4-1.jpg" alt="Difference between server sent events and Websockets in HTML5 -  GeeksforGeeks" /></p>
<p>In the ever-evolving web development landscape, real-time communication between servers and clients has become crucial to building dynamic and interactive web applications. One of the technologies that facilitate this seamless communication is Server-Sent Events (SSE). In this blog post, we will delve into the world of SSE, exploring its key features, use cases, and advantages.</p>
<h3 id="heading-what-are-server-sent-events"><strong>What are Server-Sent Events?</strong></h3>
<p>Server-sent events (SSE) is a simple and efficient mechanism that enables servers to push real-time updates to web clients over a single HTTP connection. Unlike traditional polling or complex solutions, SSE provides a lightweight and standardized approach for establishing a persistent, bidirectional communication channel between the server and the client.</p>
<h3 id="heading-key-features-of-server-sent-events"><strong>Key Features of Server-Sent Events:</strong></h3>
<ol>
<li><p><strong>Text-Based Protocol:</strong><br /> SSE uses a text-based protocol, making it human-readable and easy to implement. The communication is established using the EventSource API on the client side, which handles the incoming events.</p>
</li>
<li><p><strong>Simple Connection Setup:</strong></p>
<p> SSE establishes a single, long-lived HTTP connection between the server and the client, eliminating the need for repeated requests. This reduces latency and resource consumption compared to traditional polling methods.</p>
</li>
<li><p><strong>Event Stream Format:</strong><br /> Events are sent from the server to the client as plain text, with each event being prefixed by the "data:" tag. The format is simple, making it easy to parse on the client side.</p>
</li>
</ol>
<h3 id="heading-how-server-sent-events-work"><strong>How Server-Sent Events Work:</strong></h3>
<ol>
<li><p><strong>Client-Side Implementation:</strong><br /> On the client side, developers can use the EventSource API, a built-in browser feature, to create a connection to the server. The client subscribes to specific event types and listens for updates.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> eventSource = <span class="hljs-keyword">new</span> EventSource(<span class="hljs-string">'/sse-endpoint'</span>);

 eventSource.addEventListener(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
     <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Received message:'</span>, event.data);
     <span class="hljs-comment">// Handle the incoming event data</span>
 });
</code></pre>
</li>
</ol>
<p><strong>Server-Side Implementation:</strong><br />On the server side, developers need to set up an endpoint that generates a stream of events. The server sends updates to the connected clients as needed.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Express.js example</span>
app.get(<span class="hljs-string">'/sse-endpoint'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'text/event-stream'</span>);
    res.setHeader(<span class="hljs-string">'Cache-Control'</span>, <span class="hljs-string">'no-cache'</span>);
    res.setHeader(<span class="hljs-string">'Connection'</span>, <span class="hljs-string">'keep-alive'</span>);

    <span class="hljs-comment">// Send updates to the client at intervals</span>
    <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
        res.write(<span class="hljs-string">`data: <span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString()}</span>\n\n`</span>);
    }, <span class="hljs-number">1000</span>);
});
</code></pre>
<h3 id="heading-use-cases-for-server-sent-events"><strong>Use Cases for Server-Sent Events:</strong></h3>
<ol>
<li><p><strong>Real-Time Notifications:</strong></p>
<p> SSE is ideal for applications that require instant notifications, such as social media updates, chat applications, or collaborative editing tools.</p>
</li>
<li><p><strong>Live Updates:</strong> Websites with live content, like financial market data, sports scores, or news feeds, can benefit from SSE to deliver real-time updates to users.</p>
</li>
<li><p><strong>Monitoring and Dashboards:</strong> SSE is well-suited for building monitoring dashboards where live data visualizations need to be updated continuously.</p>
</li>
</ol>
<h3 id="heading-advantages-of-server-sent-events"><strong>Advantages of Server-Sent Events:</strong></h3>
<ol>
<li><p><strong>Reduced Latency:</strong> SSE reduces latency by eliminating the need for repeated requests, as the connection is kept open for real-time updates.</p>
</li>
<li><p><strong>Simplicity and Ease of Use:</strong> The simplicity of SSE makes it easy to implement on both the client and server sides, requiring minimal setup.</p>
</li>
<li><p><strong>Efficient Resource Usage:</strong> Since SSE relies on a single, long-lived connection, it is more resource-efficient compared to alternatives like WebSockets for certain use cases.</p>
</li>
</ol>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Server-sent events offer a straightforward and efficient solution for building real-time, event-driven web applications. With its simplicity, reduced latency, and suitability for various use cases, SSE is a valuable tool in the modern web developer's toolkit. Whether you're building a chat application, live dashboard, or any real-time feature, consider incorporating Server-Sent Events for a seamless and responsive user experience.</p>
]]></content:encoded></item></channel></rss>