<?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>Forem: Henrique Martins</title>
    <description>The latest articles on Forem by Henrique Martins (@hsnrique).</description>
    <link>https://forem.com/hsnrique</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%2F3780227%2F77baf289-0b54-4213-959a-cbd77acd2a86.png</url>
      <title>Forem: Henrique Martins</title>
      <link>https://forem.com/hsnrique</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hsnrique"/>
    <language>en</language>
    <item>
      <title>How We Built an AI Deep Research Engine — And the SEO Strategy Behind It</title>
      <dc:creator>Henrique Martins</dc:creator>
      <pubDate>Wed, 18 Feb 2026 23:01:23 +0000</pubDate>
      <link>https://forem.com/hsnrique/how-we-built-an-ai-deep-research-engine-and-the-seo-strategy-behind-it-4bk</link>
      <guid>https://forem.com/hsnrique/how-we-built-an-ai-deep-research-engine-and-the-seo-strategy-behind-it-4bk</guid>
      <description>&lt;p&gt;If you've ever spent hours digging through Google results, opening 30+ tabs, cross-referencing sources, and trying to synthesize everything into a coherent answer — you know how painful deep research is.&lt;/p&gt;

&lt;p&gt;That's the problem we set out to solve with &lt;a href="https://neiro.it" rel="noopener noreferrer"&gt;Neiro&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Neiro?
&lt;/h2&gt;

&lt;p&gt;Neiro is an AI-powered deep research engine. You ask a complex question — the kind that Google can't answer in a single snippet — and Neiro goes to work.&lt;/p&gt;

&lt;p&gt;It doesn't just search. It &lt;strong&gt;researches&lt;/strong&gt;. It scans thousands of live web sources, reads them, cross-references data points, and delivers a structured intelligence dossier with full citations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who is it for?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;VC analysts doing due diligence on startups&lt;/li&gt;
&lt;li&gt;Strategy teams running competitive intelligence&lt;/li&gt;
&lt;li&gt;Researchers conducting literature reviews&lt;/li&gt;
&lt;li&gt;Product managers sizing markets&lt;/li&gt;
&lt;li&gt;Anyone who needs answers that require more than a quick search&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Technical Challenge
&lt;/h2&gt;

&lt;p&gt;Building a research engine is fundamentally different from building a chatbot. Here's why:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Breadth of Sources
&lt;/h3&gt;

&lt;p&gt;A chatbot responds from training data. A search engine returns 10 links. Neiro needs to actively crawl and process thousands of sources per query — in real time. This means the system needs to be highly parallelized, with intelligent source selection to avoid noise.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Zero Hallucinations
&lt;/h3&gt;

&lt;p&gt;When you're producing research that professionals rely on for million-dollar decisions, you can't afford hallucinations. Every data point in a Neiro dossier needs to be traceable to its original source. This is a hard constraint that shapes the entire architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Structured Output
&lt;/h3&gt;

&lt;p&gt;Raw text isn't useful for research. Neiro produces structured dossiers with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Executive summaries&lt;/li&gt;
&lt;li&gt;Data tables&lt;/li&gt;
&lt;li&gt;Source citations&lt;/li&gt;
&lt;li&gt;Risk assessments&lt;/li&gt;
&lt;li&gt;Competitive matrices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This requires a fundamentally different output pipeline than a typical LLM chat interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our SEO Strategy (The Fun Part for Devs)
&lt;/h2&gt;

&lt;p&gt;As a startup, we can't just build a great product and hope people find it. We needed a comprehensive organic growth strategy. Here's what we implemented:&lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamic Sitemap
&lt;/h3&gt;

&lt;p&gt;Our blog content is published automatically. A static sitemap.xml wouldn't cut it — it would go stale immediately.&lt;/p&gt;

&lt;p&gt;We built a dynamic sitemap endpoint on our Express backend that queries the database for all published posts and generates the XML on-the-fly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sitemap.xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT slug, updated_at FROM blog_posts WHERE status = 'published'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&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="s2"&gt;`
    &amp;lt;url&amp;gt;
      &amp;lt;loc&amp;gt;https://yoursite.com/blog/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/loc&amp;gt;
      &amp;lt;lastmod&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updated_at&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;T&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/lastmod&amp;gt;
    &amp;lt;/url&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;?xml version="1.0"?&amp;gt;
    &amp;lt;urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"&amp;gt;
      &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
    &amp;lt;/urlset&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;p&gt;Since our frontend is a Vite SPA on Vercel, we use Vercel rewrites to proxy /sitemap.xml to this backend endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  RSS Feed for Syndication
&lt;/h3&gt;

&lt;p&gt;We added an RSS 2.0 feed endpoint that enables automatic syndication to platforms like Feedly, dev.to, and Google News.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Discoverability with &lt;code&gt;llms.txt&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is a newer concept — a file at /llms.txt that tells AI models (ChatGPT, Perplexity, Claude) about your product. Think of it as robots.txt for AI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Neiro — AI Deep Research Engine

&amp;gt; Neiro is an AI-powered deep research platform that 
&amp;gt; synthesizes knowledge from 10,000+ real-time sources 
&amp;gt; into verified intelligence dossiers.

## What Neiro Does
- Deep research on any topic
- Verified citations for every claim
- Structured dossiers, not chat responses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dynamic OG Tags with Edge Middleware
&lt;/h3&gt;

&lt;p&gt;SPAs have a classic problem: social media crawlers can't read client-rendered meta tags. When someone shares a blog post on LinkedIn or Twitter, the preview shows generic site info instead of the post's actual title and image.&lt;/p&gt;

&lt;p&gt;Our solution: Vercel Edge Middleware.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ua&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;CRAWLERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/blog/post/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;generateOgHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&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;p&gt;Crawlers get pre-rendered HTML with correct meta tags. Real users get the normal SPA experience. Best of both worlds.&lt;/p&gt;

&lt;h3&gt;
  
  
  IndexNow for Instant Indexing
&lt;/h3&gt;

&lt;p&gt;Instead of waiting for search engines to discover new content, we proactively notify them using the IndexNow protocol:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pingIndexNow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.indexnow.org/IndexNow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yoursite.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INDEXNOW_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;urlList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;postUrl&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&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;p&gt;This fires automatically every time a new blog post is published. Bing, Yandex, and other supporting engines pick it up within minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Programmatic SEO Pages
&lt;/h3&gt;

&lt;p&gt;We created landing pages targeting high-intent keywords:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use case pages: /use-cases/ai-due-diligence, /use-cases/market-research, etc.&lt;/li&gt;
&lt;li&gt;Comparison pages: /compare/neiro-vs-perplexity, /compare/neiro-vs-chatgpt, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each page has unique content, FAQ structured data (for Google rich snippets), breadcrumb schema, and proper OG tags. These are data-driven — a single React component renders different content based on a data file, making it easy to add new pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results So Far
&lt;/h2&gt;

&lt;p&gt;We're early, but the infrastructure is solid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ All blog posts indexed within hours of publishing&lt;/li&gt;
&lt;li&gt;✅ Correct social previews when shared on LinkedIn/Twitter&lt;/li&gt;
&lt;li&gt;✅ AI models (ChatGPT, Claude) can discover and reference Neiro&lt;/li&gt;
&lt;li&gt;✅ Growing organic traffic from long-tail keywords&lt;/li&gt;
&lt;li&gt;✅ RSS feed enables automatic cross-posting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;If you're curious about what AI deep research looks like in practice, &lt;a href="https://neiro.it" rel="noopener noreferrer"&gt;try Neiro for free&lt;/a&gt; — 3 researches, no credit card.&lt;br&gt;
I'd love to hear your feedback, especially from anyone working on similar problems in the AI/search space.&lt;/p&gt;




&lt;p&gt;What SEO strategies are you using for your side projects? Drop them in the comments — always looking to learn from the community.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
