<?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: Sai Prasanna H</title>
    <description>The latest articles on DEV Community by Sai Prasanna H (@sai_prasannah_df7f0fcd85).</description>
    <link>https://dev.to/sai_prasannah_df7f0fcd85</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%2F3875088%2Fe12255b3-ed27-4e9c-97cb-c6b1c63f9542.jpg</url>
      <title>DEV Community: Sai Prasanna H</title>
      <link>https://dev.to/sai_prasannah_df7f0fcd85</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sai_prasannah_df7f0fcd85"/>
    <language>en</language>
    <item>
      <title>How I Designed TerraShield's Enterprise CTA to Not Annoy Researchers</title>
      <dc:creator>Sai Prasanna H</dc:creator>
      <pubDate>Sun, 12 Apr 2026 15:53:46 +0000</pubDate>
      <link>https://dev.to/sai_prasannah_df7f0fcd85/how-i-designed-terrashields-enterprise-cta-to-not-annoy-researchers-51nk</link>
      <guid>https://dev.to/sai_prasannah_df7f0fcd85/how-i-designed-terrashields-enterprise-cta-to-not-annoy-researchers-51nk</guid>
      <description>&lt;p&gt;There's a particular kind of UI failure that doesn't show up in error logs: a button that appears on every page when it should only appear on one. Nobody throws an exception. The page renders fine. But every time a field ecologist uploads a photo and sees "Enterprise API Access" plastered across their analysis results, it breaks the context of what they're doing and makes the product feel unfinished.&lt;/p&gt;

&lt;p&gt;I'm Sai Prasanna, and I worked on TerraShield's frontend polish the Enterprise API call-to-action placement, the home page layout, and UI consistency across the platform. This is shorter than a story about building the core ML pipeline, but it's about a class of frontend decisions that quietly determine whether a product feels professional or amateur.&lt;/p&gt;

&lt;h2&gt;
  
  
  What TerraShield Is
&lt;/h2&gt;

&lt;p&gt;TerraShield detects invasive species from citizen-uploaded photos. A field observer uploads a geo-tagged image; we extract EXIF data, pull satellite NDVI readings for that GPS coordinate, recall nearby past sightings from an &lt;a href="https://vectorize.io/what-is-agent-memory" rel="noopener noreferrer"&gt;agent memory&lt;/a&gt; layer powered by &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt;, and run the whole context through Gemini 2.5 Flash for classification. The result is a risk score, species tags, and an ecological summary that gets retained in memory to make the next analysis in that region smarter.&lt;/p&gt;

&lt;p&gt;The platform serves four distinct user types: citizen scientists, field researchers and ecologists, government environmental agencies, and NGOs. Each of them has different reasons to be on TerraShield and different actions they'd want to take.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Enterprise CTA Problem
&lt;/h2&gt;

&lt;p&gt;TerraShield has an Enterprise API tier — &lt;code&gt;TSK-&lt;/code&gt; prefixed keys that let government GIS systems and NGO data pipelines pull outbreak data programmatically. It's a real feature. It just doesn't need to be advertised to a citizen scientist who's uploading a photo of a plant they found on a hiking trail.&lt;/p&gt;

&lt;p&gt;The original implementation rendered the Enterprise API CTA as a card component across multiple pages: the home page, the analysis results page, and the profile page. The card had a border, a background color, and enough visual weight that it competed with the actual content of every page it appeared on.&lt;/p&gt;

&lt;p&gt;My fix was two things: scope the CTA to the home page only, and remove the visual container styling so it blends with the surrounding layout rather than announcing itself as a separate element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before: rendered on every page with card styling&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;enterprise-card card-border card-bg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Enterprise&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;Access&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Integrate&lt;/span&gt; &lt;span class="nx"&gt;TerraShield&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;into&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;systems&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// After: home page only, no border/bg, seamless blend&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;enterprise-cta&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Enterprise&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;Access&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Integrate&lt;/span&gt; &lt;span class="nx"&gt;TerraShield&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;into&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;systems&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The change is small. The effect on the analysis results page is significant removing the card from there means the risk score, the species identification, and the ecological summary get the full visual attention they deserve. When a researcher is looking at an 8.4/10 risk score for a confirmed &lt;em&gt;Lantana camara&lt;/em&gt; outbreak 500m from a protected forest, they don't need a sales prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Placement Is a Product Decision
&lt;/h2&gt;

&lt;p&gt;This is something that gets treated as a designer's job but is actually an engineering judgment call: where does a feature live in the navigation hierarchy, and what does its visual weight communicate about its priority?&lt;/p&gt;

&lt;p&gt;TerraShield's user roles matter here. The platform is free for citizens, researchers, and NGOs. Enterprise API access is for organizations that need programmatic integration government agencies pulling outbreak data into their GIS workflows, research institutions running bulk analysis. That audience finds the product through the home page, not through the analysis results flow. An ecologist mid-upload is not evaluating API pricing.&lt;/p&gt;

&lt;p&gt;Restricting the CTA to the home page respects the context of every other page. It also makes the CTA itself more effective users who see it on the home page are in an exploratory mindset; users who are mid-task and see it are just annoyed.&lt;/p&gt;

&lt;p&gt;The Broader Frontend Context&lt;/p&gt;

&lt;p&gt;TerraShield's frontend is vanilla JS — no React, no Vue. The UI is built as a collection of page modules in &lt;code&gt;frontend/pages/&lt;/code&gt;, each managing its own DOM and state. The home page (&lt;code&gt;home.js&lt;/code&gt;) is 73KB of vanilla JS handling the map rendering (Leaflet.js), the agent memory live panel, the upload flow, and several dashboard widgets.&lt;/p&gt;

&lt;p&gt;The agent memory live panel on the home page is one of the more interesting UI elements: it polls the &lt;code&gt;/api/agent-memory&lt;/code&gt; endpoint and shows real-time stats — total sightings in memory, the most-detected species, and a feed of the five most recent retained memories. It makes the &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt;-backed memory layer visible to users without them needing to understand the underlying architecture. The numbers change as reports come in. The agent is visibly learning.&lt;/p&gt;

&lt;p&gt;The Enterprise CTA sits below this panel on the home page, which is intentional placement — users who've just watched the memory panel and understood that TerraShield accumulates ecological intelligence over time are better positioned to understand why an API integration would be valuable.&lt;/p&gt;

&lt;p&gt;What Polishing Frontend Actually Means&lt;/p&gt;

&lt;p&gt;"UI polish" is often used dismissively, as if it means tweaking colors. What it actually means is making a series of judgment calls about context, priority, and attention. The blinking logo animation that we removed from the Memory nav — that was a distraction from the content it was labeling. The brain emoji that was also removed — same reason. These aren't aesthetic preferences; they're decisions about what the interface is communicating.&lt;/p&gt;

&lt;p&gt;TerraShield processes serious ecological data. When a government inspector opens the platform to assess an outbreak cluster that covers three districts, the interface needs to feel like a tool, not a demo. Every element that draws attention away from the data is a failure of that goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Scope features to the pages where they're relevant.&lt;/strong&gt; A CTA that appears everywhere becomes invisible through repetition and annoying through interruption. One well-placed appearance on the right page outperforms five appearances on the wrong ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual weight is a signal about priority.&lt;/strong&gt; Card containers with borders and backgrounds tell users "this is important." Use that signal intentionally. If something isn't more important than the surrounding content, strip the container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Animations in nav elements are almost always wrong.&lt;/strong&gt; A nav label that blinks or pulses is competing with the content the user is trying to navigate to. Nav should be quiet. Content should have the energy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context determines relevance.&lt;/strong&gt; The same piece of information (Enterprise API access exists) can be welcome or intrusive depending on what the user is doing when they see it. Frontend decisions are UX decisions are product decisions. They compound.&lt;/p&gt;

&lt;p&gt;TerraShield is at &lt;a href="https://github.com/Nitish-k-s/TerraShield" rel="noopener noreferrer"&gt;github.com/Nitish-k-s/TerraShield&lt;/a&gt;. The agent memory layer that powers the live panel on the home page uses &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt; — worth looking at if you're building systems that need to accumulate and reason over field-collected data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Felfk9bm6xuzj6fd845w7.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Felfk9bm6xuzj6fd845w7.jpeg" alt=" " width="800" height="446"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7ycs4y5ztfe4xatjlpp.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7ycs4y5ztfe4xatjlpp.jpeg" alt=" " width="800" height="454"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8fb3hxd51yasxzjo8zh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8fb3hxd51yasxzjo8zh.jpeg" alt=" " width="800" height="570"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdybt2sxomip2bsq3jap.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdybt2sxomip2bsq3jap.jpeg" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>design</category>
      <category>frontend</category>
      <category>ui</category>
      <category>ux</category>
    </item>
  </channel>
</rss>
