Measure and improve your visibility in AI-powered search engines.
Live Demo: Deploy with Vercel + Neon → Deployment Guide
English | 中文
Run the type-level and Prisma generation checks without live LLM credentials:
git clone https://github.com/ZedingZhang/geo-lens.git
cd geo-lens
pnpm install
cp .env.example .env
pnpm db:generate
pnpm typecheckGEO Lens is a Generative Engine Optimization analysis platform for content teams and personal brands. It evaluates whether your brand can be discovered, summarized, and cited by AI answer engines like ChatGPT, Perplexity, and Google AI Overviews.
Traditional SEO measures keyword rankings and organic traffic. But users increasingly ask AI engines natural-language questions, and those AI engines decide which brands to mention — based on entity clarity, citable facts, structured data, and comparison context. GEO Lens measures exactly these signals.
- Project Management: Create GEO analysis projects with brand info, keywords, competitors
- Five-Dimension GEO Scoring: Entity Clarity · Answer Coverage · Citation Readiness · Content Structure · Freshness Signal
- Score Dashboard: Radar/bar charts with strengths, weaknesses, and priority actions
- AI Answer Simulation: Generate 8 realistic AI search queries and see if your brand is mentioned
- Multi-Model Visibility Demo: Show whether major AI answer engines know, recommend, or cite the brand
- Missing Content Map: Turn GEO gaps into a page-level content strategy matrix for homepage, about, comparison, FAQ, blog, and crawlability work
- Content Recommendations: 10 types of GEO-optimized content (FAQ, schema, definitions, meta tags...)
- Before / After Experiment Loop: Run baseline audit, apply content changes, re-run audit, compare delta, and export an experiment report
- Markdown Report Export: Downloadable report with all analysis results
- Citation Failure Diagnosis: Diagnose why AI engines don't cite your brand (12-type taxonomy, primary failure, evidence, impact, fix)
- Brand Name Ambiguity Detection: Detect naming collisions, explain risk, and recommend canonical entity phrasing
- Content Strategy Matrix: Identify missing homepage, about, comparison, FAQ, blog, and crawlability pages
- Before / After GEO Diff: Side-by-side content comparison showing GEO improvement
- Strategy Library: 9 built-in GEO strategies with before/after examples, filterable by dimension
- AI Readiness Technical Audit: 8-point technical check (robots.txt, sitemap.xml, llms.txt, JSON-LD schema...)
- Prompt Portfolio: 12 prompts across 6 intent types with funnel stage and demand scoring
- Citation Source Map: 8 source categories analyzed for AI citation coverage gaps
- GEO Experiment Tracker: Create, run, complete experiments tracking baseline → after score deltas
GEO Lens is now designed as a content strategy workflow, not only a scoring tool:
- Run baseline audit: Score the brand across five GEO dimensions and simulate AI answer questions.
- Explain citation failure: Use the 12-type citation failure taxonomy and brand-name ambiguity detector to explain why the brand may not be cited.
- Plan missing content: Convert failures into a page-level matrix covering entity definition, comparison intent, citation evidence, problem discovery, and technical crawlability.
- Apply recommended changes: Use recommendations, content diffs, and strategy examples to draft the next content update.
- Re-run audit and compare delta: Track before/after improvements in entity clarity, citation readiness, answer coverage, AI mention rate, and failure count.
- Export report: Produce a Markdown report with score tables, primary failure, ambiguity risk, content map, and experiment delta.
Reports explain the primary failure with evidence, impact, and fix:
Primary failure:
AMBIGUOUS_BRAND_NAME
Evidence:
The homepage does not clearly define whether GEO Lens is a SaaS product, research tool, or developer demo.
Impact:
AI answer engines may avoid citing the page because the entity boundary is unclear.
Fix:
Add a 40-word entity definition near the top of the homepage.
The ambiguity detector flags collision risk for overloaded names:
Brand: GEO Lens
Possible ambiguity:
- GEO Lens as Generative Engine Optimization tool
- GeoLens as geolocation / GIS / image privacy tools
- LibreGeoLens as QGIS MLLM plugin
Ambiguity risk: High
Reason:
The name "GeoLens" is already associated with geospatial, GIS, and image privacy projects.
Recommendation:
Use "GEO Lens" consistently with the expanded phrase "Generative Engine Optimization Lens" in title, H1, README, metadata, and schema.
The content map turns analysis gaps into a strategy matrix:
| GEO need | Existing page | Status | Suggested page |
|---|---|---|---|
| entity definition | homepage | weak | improve homepage hero |
| comparison intent | none | missing | /compare/[competitor] |
| citation evidence | about page | weak | add dated metrics |
| problem discovery | blog | missing | add use-case article |
| technical crawlability | sitemap | OK | no action |
Experiment reports compare measurable deltas after content changes:
| Metric | Before | After | Delta |
|---|---|---|---|
| Entity Clarity | 58 | 82 | +24 |
| Citation Readiness | 41 | 73 | +32 |
| Answer Coverage | 62 | 79 | +17 |
| AI Mention Rate | 10% | 35% | +25% |
| Citation Failure Count | 7 | 3 | -4 |
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) + React 19 |
| Language | TypeScript (strict) |
| Styling | Tailwind CSS v4 |
| UI | Lucide React, Recharts |
| Database | PostgreSQL + Prisma 7 |
| LLM Integration | OpenAI SDK (DeepSeek-compatible) |
| Validation | Zod |
| Forms | React Hook Form |
| Deployment | Vercel + Neon, or Docker Compose + VPS |
flowchart TB
user["User / Browser"]
subgraph app["Next.js 16 App Router"]
pages["React Pages<br/>Projects, Model Visibility, Ambiguity<br/>Content Map, Experiments, Reports"]
api["REST API Routes<br/>/api/projects/[id]/*, /api/strategies, /api/health"]
meta["GEO Metadata Routes<br/>robots.txt, sitemap.xml, llms.txt"]
end
subgraph services["Server-Side Services"]
guards["Demo Access + Rate Limit<br/>Session isolation, input limits"]
geo["GEO Domain Logic<br/>scoring, model visibility, ambiguity<br/>taxonomy, content map, readiness, experiments"]
prompts["Prompt Builders + Zod Schemas"]
llm["LLM Client<br/>timeout, JSON validation, fallback"]
fetcher["safe-fetch<br/>SSRF-protected website checks"]
report["Markdown Report Generator"]
mock["Stable Mock Data"]
end
subgraph data["Persistence"]
prisma["Prisma Client"]
db[(PostgreSQL / Neon)]
models["Project, Analysis, Questions<br/>Recommendations, Diagnostics, Readiness<br/>Prompts, Sources, Experiments"]
end
subgraph external["External Systems"]
deepseek["DeepSeek-compatible OpenAI API"]
target["Target Brand Website<br/>HTML, robots.txt, sitemap.xml, llms.txt"]
end
subgraph ops["Deployment + Operations"]
deploy["Vercel + Neon<br/>or Docker Compose + VPS"]
env["Environment Config<br/>DEMO_MODE, LLM_*, DATABASE_URL"]
cleanup["Demo Cleanup Cron<br/>CRON_SECRET protected"]
end
user --> pages
pages --> api
pages --> meta
api --> guards
guards --> geo
geo --> prompts
prompts --> llm
llm -->|"live mode"| deepseek
llm -->|"demo or fallback"| mock
geo --> fetcher
fetcher --> target
api --> report
api --> prisma
geo --> prisma
report --> prisma
prisma --> db
db --> models
cleanup --> prisma
env --> api
env --> llm
deploy --> app
- Node.js 20.19+ or 22+
- pnpm
- PostgreSQL 16+ (or Docker)
# Clone
git clone https://github.com/ZedingZhang/geo-lens.git
cd geo-lens
# Install dependencies
pnpm install
# Start PostgreSQL (if using Docker)
docker compose up -d postgres
# Copy env
cp .env.example .env
# Generate Prisma client
pnpm db:generate
# Run migrations
pnpm db:migrate:dev
# Seed sample data
pnpm db:seed
# Start dev server
pnpm devOpen http://localhost:3000.
See .env.example for the full list. Key variables:
# LLM (leave API_KEY empty for mock mode)
LLM_API_KEY= # DeepSeek API key
LLM_BASE_URL=https://api.deepseek.com
LLM_MODEL=deepseek-v4-flash
# Database
DATABASE_URL=postgresql://geo_lens:geo_lens_password@localhost:5432/geo_lens
# Demo Mode (public demo safety)
DEMO_MODE=true
RATE_LIMIT_PER_HOUR=20
MAX_PROJECTS_PER_DEMO_SESSION=5
DEMO_DATA_RETENTION_DAYS=7
CRON_SECRET=change_meImportant:
deepseek-v4-flashanddeepseek-v4-proare the current recommended models.deepseek-chatis deprecated (EOL 2026-07-24) and should not be used as the default.
Mock Mode (default for public demo):
- No API key required
- Returns stable, realistic mock data
- Full feature flow works without LLM costs
- UI shows "Demo Mode" banner
Live LLM Mode:
- Set
LLM_API_KEYandDEMO_MODE=false - Real LLM calls with timeout and JSON validation
- Rate-limited (
RATE_LIMIT_PER_HOURper IP) - Results tagged as
live,mock, orfallback - Input trimmed to
MAX_INPUT_CHARS
Resume Demo (recommended): Vercel + Neon (free tier) → DEPLOYMENT.md
Engineering Showcase: Docker Compose + VPS → DEPLOYMENT.md
Platform Notes: Free tiers can change. Check Vercel Pricing and Neon Pricing before deploying.
src/
├── app/ # Next.js App Router pages & API routes
│ ├── api/ # REST API (health, projects, analyze, etc.)
│ ├── projects/ # Project pages (CRUD, analysis modules)
│ ├── strategies/ # Strategy Library page
│ ├── settings/ # Environment config display
│ └── robots.txt|sitemap.xml|llms.txt/ # GEO/SEO metadata routes
├── components/ # React components
│ ├── analysis/ # Score charts
│ └── layout/ # AppShell, demo banner
├── lib/ # Business logic
│ ├── llm/ # LLM client, schemas, prompts
│ ├── geo/ # Scoring, taxonomy, ambiguity, content-map, model visibility, diff, readiness, experiments
│ ├── fetch/ # SSRF-safe URL fetching
│ ├── security/ # Rate limiting
│ ├── demo/ # Session isolation, cleanup
│ ├── report/ # Markdown report generation
│ ├── db.ts # Prisma client singleton
│ ├── env.ts # Environment config with Zod validation
│ └── mock-data.ts # Stable mock data for demo mode
└── generated/prisma/ # Generated Prisma client
| Module | Page | API | Main Output |
|---|---|---|---|
| GEO Score | /projects/[id] |
POST /api/projects/[id]/analyze |
Five-dimension GEO score |
| AI Questions | /projects/[id]/questions |
POST /api/projects/[id]/questions |
Simulated answers and brand mentions |
| Model Visibility | /projects/[id]/models |
POST /api/projects/[id]/models |
Demo knows / recommends / cites matrix |
| Brand Ambiguity | /projects/[id]/ambiguity |
POST /api/projects/[id]/ambiguity |
Ambiguity risk, reason, recommendation |
| Citation Diagnostics | /projects/[id]/diagnostics |
POST /api/projects/[id]/diagnostics |
Primary failure, evidence, impact, fix |
| Missing Content Map | /projects/[id]/content-map |
POST /api/projects/[id]/content-map |
Page-level content strategy matrix |
| Before / After Experiments | /projects/[id]/experiments |
/api/projects/[id]/experiments/* |
Before/after score delta table |
| Markdown Report | /projects/[id]/report |
GET /api/projects/[id]/report |
Full exportable strategy report |
- Mock mode by default: No real LLM API calls consume credits
- Rate limiting:
RATE_LIMIT_PER_HOURfor generation endpoints - Input length limits:
MAX_INPUT_CHARSprevents token abuse - Anonymous session isolation: Demo users see only their own projects
- Data expiration: Demo projects auto-expire after
DEMO_DATA_RETENTION_DAYS - Cleanup requires auth:
CRON_SECRETprotects cleanup endpoints
.envand secrets excluded from Git via.gitignore- API keys never exposed to frontend
- Error responses hide stack traces, DB credentials, and internal paths
- URL fetching uses
safe-fetchblocking SSRF (localhost, private IPs, metadata addresses) - Server logs exclude full user input, full prompts, and raw LLM responses
- IP addresses stored as salted hashes
- All LLM outputs validated with Zod schemas
- Timeout control (
LLM_TIMEOUT_MS) prevents hanging - JSON parse failures → graceful mock fallback
- Results tagged by source:
mock|live|fallback
| Dimension | What It Measures |
|---|---|
| Entity Clarity | Can AI engines clearly identify what your brand is? |
| Answer Coverage | Does your content answer the questions users ask AI? |
| Citation Readiness | Is your content quotable with specific facts, numbers, dates? |
| Content Structure | Is content structured for AI extraction (FAQs, lists, schema)? |
| Freshness Signal | Does content have dates, versions, update indicators? |
GEO Lens is not just an AI content generator. It implements:
- A structured scoring model for AI citation potential
- Citation failure diagnosis connecting symptoms → root causes → fixes
- Brand ambiguity detection explaining whether the name collides with adjacent entities
- Missing content mapping turning audit gaps into a page-level strategy plan
- Before/after experiment loop showing measurable GEO improvement
- A strategy library of reusable optimization patterns
- Source map analysis identifying where AI engines get citation signals
- Its own
/robots.txt,/sitemap.xml, and/llms.txtas GEO best practice
- Next.js App Router + TypeScript
- Prisma data model with project/session isolation
- Rule-based explainability for taxonomy, ambiguity, content maps, and experiment deltas
- Demo-safe mode with anonymous sessions and expiration
- SSRF protection for external URL analysis
- Deployment profiles: Vercel + Neon, Docker Compose + VPS
| Decision | Rationale |
|---|---|
| No user authentication | MVP targets resume demo; auth adds complexity without demo value |
| Mock mode default | Prevents API key abuse on public demo; makes project self-contained |
| PostgreSQL (not SQLite) | Required for production deployment; Neon free tier makes it accessible |
| TypeScript constants for strategies | Simple, version-controlled, no DB migration for content |
| Markdown reports (not PDF) | Faster to implement, more useful for copy-paste workflows |
| No real search API integration | Keeps project zero-cost; mock data demonstrates the concept |
"GEO Lens is a full-stack SaaS prototype I built to address the emerging field of Generative Engine Optimization. As AI answer engines like ChatGPT and Perplexity become primary information sources, traditional SEO metrics don't capture whether brands get cited in AI-generated answers.
I designed a five-dimension scoring model — Entity Clarity, Answer Coverage, Citation Readiness, Content Structure, and Freshness Signal — and built the entire analysis pipeline from project creation through AI simulation, citation failure diagnosis, and structured recommendations.
The tech stack uses Next.js 16 with the App Router, Prisma 7 with PostgreSQL, and an OpenAI-compatible LLM layer that supports DeepSeek. I implemented LLM JSON schema validation with Zod, graceful mock fallbacks, rate limiting, SSRF-safe URL fetching, and anonymous session isolation for the public demo.
The product goes beyond scoring: Citation Failure Diagnosis maps symptoms to root causes, Brand Ambiguity Detection explains naming collisions, Missing Content Map turns gaps into a page plan, and the Before/After Experiment Loop compares measurable score deltas after changes. I also included lightweight enterprise features like Technical Audit, Prompt Portfolio, Source Map, and Model Visibility.
The project deploys two ways: Vercel + Neon for a zero-cost resume demo, and Docker Compose + VPS to demonstrate production engineering skills. It includes CI/CD, health checks, and comprehensive security hardening."
GEO Lens | Generative Engine Optimization Platform
• Built full-stack SaaS prototype with Next.js 16, TypeScript, Prisma, PostgreSQL
• Designed five-dimension GEO scoring model quantifying AI citation potential
• Implemented LLM service layer with Zod schema validation, mock fallback, and rate limiting
• Created Citation Failure Taxonomy, Brand Ambiguity Detection, Missing Content Map, and Strategy Library
• Added Model Visibility, AI Readiness Technical Audit, Prompt Portfolio, Citation Source Map, and Experiment Loop
• Deployed via Vercel + Neon (resume demo) and Docker Compose + VPS (engineering showcase)
• Implemented demo mode with anonymous session isolation, data expiration, and SSRF protection
| Dashboard | AI Answer Simulation | Citation Diagnosis |
|---|---|---|
![]() |
![]() |
![]() |
MIT — see LICENSE for details.
This is a portfolio project. Bug reports and suggestions are welcome via GitHub Issues.


