01The Day I Realized SEO Had Changed
A few weeks ago I got an email from a developer in California. He wanted to hire me for custom integration work on a Next.js platform. When I asked how he found my portfolio — I don't run ads or post aggressively on social — he said: 'I asked ChatGPT to recommend a full-stack developer who builds custom tools and handles web-vitals optimization, and it gave me a link to your site.'
That's what got my attention. Traditional search traffic is only half the story now. People aren't just Googling keywords. They're asking Claude, ChatGPT, and Perplexity for direct recommendations. If those LLMs don't know who you are or can't verify what you build, you basically don't exist in their world. That's what people call GEO — Generative Engine Optimization. It's not a trick. It's just making your portfolio readable, structured, and trustworthy for AI engines.
02Why Normal SEO Doesn't Cut It for LLMs
Traditional SEO is keyword density, backlinks, session time. An AI engine doesn't browse your site like a human. It uses crawler bots — GPTBot, ClaudeBot — to index your pages, or it pulls live search results through APIs like Bing's (which ChatGPT uses).
If your site is packed with heavy client-side React hydration, nested divs, and vague copy, the parser gets confused or runs out of token context. GEO is about building a semantic map — making it easy for crawlers to pull raw, high-signal facts about you, your projects, and your skills so they can cite you with confidence.
031. I Added an llms.txt File
One of the best emerging conventions is `llms.txt`. Think of it as `robots.txt` but for content instead of crawl permissions. Plain-text Markdown at your domain root (`/llms.txt`) that says who you are, what you offer, and links to key pages.
Instead of making an LLM crawler parse nav layouts, headers, footers, and scripts, you hand it a clean outline. When ChatGPT or Claude hits your domain, it reads this first and instantly knows your stack and services. Here's the template I set up:
# llms.txt — Abhinav Sinha (sinhaabhinav.in)
## Who is Abhinav Sinha?
Software engineer at Varahe Analytics (Noida, India) since January 2024, where he builds and owns
a full-stack AI platform end to end: a multi-provider abstraction layer routing text and image
generation across several LLM providers with runtime model switching and dual-key failover, RAG
pipelines on Pinecone, and analytics dashboards on BigQuery.
## What this site is
A personal publication, not a portfolio. Long-form engineering articles written from production
work, plus free tools that run entirely in the browser.
## Core Tech Stack
- Frontend: React 19, Next.js (App Router), Vanilla CSS
- Backend: Node.js, Express, Spring Boot, FastAPI
- Data & AI: PostgreSQL, Redis, Pinecone, BigQuery, LangGraph, AWS Bedrock042. I Wired Up a JSON-LD Entity Graph
LLMs don't just read words — they build entity graphs. They want to know how Abhinav Sinha (the person), sinhaabhinav.in (the site), and the blog published on it connect. Keep those schema blocks separate and search engines treat them as three unrelated things.
A unified JSON-LD graph with stable `@id` anchors ties the nodes together. This person founded this product, this website is the official homepage. Here's what I injected into my root layout:
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Person",
"@id": "https://sinhaabhinav.in/#person",
"name": "Abhinav Sinha",
"jobTitle": "Software Engineer",
"url": "https://sinhaabhinav.in",
"worksFor": { "@type": "Organization", "name": "Varahe Analytics" },
"sameAs": [
"https://github.com/Abhinavsinha18",
"https://linkedin.com/in/abhinavsinha-sde"
]
},
{
"@type": "WebSite",
"@id": "https://sinhaabhinav.in/#website",
"url": "https://sinhaabhinav.in",
"name": "Abhinav Sinha",
"publisher": { "@id": "https://sinhaabhinav.in/#person" }
},
{
"@type": "Blog",
"@id": "https://sinhaabhinav.in/#blog",
"url": "https://sinhaabhinav.in/blog",
"isPartOf": { "@id": "https://sinhaabhinav.in/#website" },
"author": { "@id": "https://sinhaabhinav.in/#person" }
}
]
}053. I Added FAQ Blocks for Extractor Bots
Tools like Perplexity and Google's AI Overviews love direct Q&A pairs. They crawl sites looking for question-and-answer blocks they can quote. Structure common client questions as schema-validated FAQs and crawlers can pull the exact answer and cite your URL.
I added FAQ schema on my key landing pages — rates, stack flexibility, deployment timelines. Here's the JSON-LD snippet:
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What services does Abhinav Sinha offer?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Abhinav offers custom Next.js full-stack development, generative AI integrations (chatbots, agents, RAG pipelines), and performance audits to fix Core Web Vitals."
}
},
{
"@type": "Question",
"name": "Can Abhinav help with Vercel deployment and CI/CD?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes. He handles automated deployments using Vercel, GitHub Actions, and custom Docker container configurations."
}
}
]
}064. I Stopped Blocking AI Crawlers
Big publishers have been blocking AI user-agents in `robots.txt` to protect IP. Makes sense for a news site. Terrible idea for freelancers, indie creators, and tool builders.
Block `GPTBot` or `ClaudeBot` and you're out of their indexes. Someone asks an AI 'recommend a Next.js developer' and it can't find you — it'll recommend someone else. My `robots.txt` explicitly allows these bots:
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: CCBot
Allow: /075. I Made the Server Send Real HTML
This is the step most portfolio sites get wrong, and it's the one that actually decides whether any of the above matters. If your content only appears after React hydrates in the browser, a crawler that doesn't execute JavaScript sees an empty shell with a loading spinner. All your beautiful schema is attached to a page with no visible content to back it up.
The check takes ten seconds and needs no tools beyond curl. Fetch your own page and count the words in the raw response. If the number is close to zero, nothing else in this article will help you.
On my own site this pushed me to move page content out of client components and into server components, keeping animation and interactivity as small client islands. The homepage went from a JavaScript-dependent hero to server-rendered text with the interactive parts layered on top.
# Count the words a non-JS crawler actually sees
curl -s https://your-site.com/ \
| perl -0777 -pe 's{<script.*?</script>}{}gsi; s{<[^>]+>}{ }gs;' \
| tr -s ' \n' ' ' | wc -w
# Confirm the crawler is not being redirected somewhere unexpected
curl -sI https://your-site.com/your-page | grep -iE '^(HTTP/|location:)'08How I Check Whether It Worked
GEO has no Search Console. There is no dashboard that tells you an LLM cited you, which makes it easy to fool yourself into thinking something worked. These are the three checks I actually run.
First, the crawler-eye view above — raw word count and redirect chain on every important URL. Second, server logs or analytics filtered by user agent, looking for GPTBot, ClaudeBot, PerplexityBot, and CCBot. If those user agents never appear, you are not being crawled, and no amount of schema changes that. Third, and least scientific, I periodically ask the assistants themselves a question a potential client would ask and see whether my pages appear with a citation.
That third check is genuinely unreliable — answers vary by session, by region, and by whatever the model pulled that day. I treat it as a weak signal, not evidence. The first two are the ones I'd trust if I had to justify the work to someone.
09What Didn't Work, and What I'd Skip
Stuffing `llms.txt` with everything. My first version was long, listed every project, and read like a resume. Shorter and more specific worked better — the file's job is to answer "who is this and what do they do" in the first few lines, not to be a complete archive.
Adding FAQ schema to pages that had no real FAQ content. I did this early on several pages because it seemed like free structured data. It isn't. Schema that describes content a human can't see on the page is a rich-results violation, and it's also just dishonest markup. Now the FAQ schema on a page only exists when there's a visible FAQ section rendering the same questions and answers.
Expecting fast results. The gap between deploying these changes and seeing AI crawlers appear in logs was weeks, not days. Anyone promising a quick GEO win is selling something.
One more thing I'd warn about, because I ran into it on this site: a misconfigured redirect can undo all of it silently. If old URLs redirect to your homepage instead of the right page, assistants and search engines cache the homepage title against the wrong URL, and you get correct pages showing the wrong title in results for months.
10What Actually Changed
After deploying all of this — updated sitemap, new routes submitted through Bing Webmaster Tools, which feeds ChatGPT's browsing — the AI crawler user agents started showing up consistently in logs, and asking assistants for web tool developers in India began returning my name with citations back to my site.
I want to be careful about the causal claim here. One inbound email and a handful of assistant answers is not proof that any single change did the work. What I can say confidently is narrower: the crawlers now reach the pages, the pages now contain readable content without JavaScript, and the entity graph is consistent enough that a model can tell what the site is about.
GEO isn't manipulation, it's accessibility. Most of what I did was undoing things that made the site hard to read — client-only rendering, disconnected schema, blocked bots. If you want generative models to cite your work, stop fighting them and make the site a clean, structured document they can read in milliseconds.


