Answer Engine Optimization analytics: track how LLMs mention and position your brand vs competitors.
- Multi-LLM support: Query OpenAI, Anthropic, and Google models in parallel
- Competitive analysis: LLM-powered analysis extracts brand mentions, sentiment, and rankings
- Link tracking: Detect and attribute URLs in LLM responses to tracked brands
- Insights dashboard: Visualize mention frequency, sentiment distribution, and rankings over time
This project is a template for building your own AEO analytics dashboard. Use it to track how AI models mention your brand, product, or company compared to competitors.
- Click Use this template at the top of this repository.
- Name your new repository and set visibility.
- Clone your new repository locally.
Edit web/src/db/seed.dev.ts to configure your industry, brands, and prompts.
await db.insert(industries).values({
id: industryId,
name: "Your Industry", // e.g., "Cloud Storage", "CRM Software", "Design Tools"
description: "Description of your industry",
});Replace the demo brands with your own. Set isOwnBrand: true for your brand:
const brandData = [
{
name: "YourBrand",
aliases: ["yourbrand.com", "YourBrand.com"],
domains: ["yourbrand.com", "docs.yourbrand.com"],
isOwnBrand: true, // This is YOUR brand
},
{
name: "Competitor1",
aliases: ["competitor1.com"],
domains: ["competitor1.com"],
isOwnBrand: false,
},
{
name: "Competitor2",
aliases: ["competitor2.com"],
domains: ["competitor2.com"],
isOwnBrand: false,
},
// Add more competitors...
];The domains array is used to match URLs in LLM responses back to brands.
Create prompts that potential customers might ask AI assistants about your industry:
const samplePrompts = [
{
name: "Best solution 2026",
content: "What is the best [your category] solution in 2026?",
},
{
name: "Comparison",
content: "Compare the top [your category] tools for small businesses.",
},
{
name: "Alternative to competitor",
content: "What are the best alternatives to [top competitor]?",
},
{
name: "Recommendation",
content: "Which [your category] tool would you recommend for [use case]?",
},
// Add 5-10 prompts that cover different angles
];Tips for effective prompts:
- Include recency terms ("in 2026", "currently", "latest") to get up-to-date responses
- Ask comparison questions that naturally invite multiple brand mentions
- Cover different user intents: research, comparison, recommendation, alternatives
- Avoid prompts that only mention one or two specific brands
-
Push your customized code to your repository.
-
Go to the Render Dashboard and create a new Blueprint.
-
Connect your repository and select the branch to deploy.
-
Set the required environment variables:
Variable Description DATABASE_URLAutomatically set by Render PostgreSQL OPENAI_API_KEYYour OpenAI API key ANTHROPIC_API_KEYYour Anthropic API key GOOGLE_API_KEYYour Google AI API key -
Deploy the Blueprint.
-
Run the database seed to create your initial configuration:
pnpm db:seed:dev
-
Set up a Render Workflow to run the
daily-jobtask on a schedule (e.g., daily at 9am).
Once deployed, the workflow:
- Pings all LLMs with your configured prompts
- Analyzes responses for brand mentions, sentiment, and rankings
- Generates a digest summarizing insights about your brand's AI visibility
View results in the dashboard. Data accumulates over time, showing trends in how AI models perceive and recommend your brand.
The default seed tracks a fictional brand called SprintHub competing against real developer tools:
| Brand | Type |
|---|---|
| SprintHub | Own brand (fictional) |
| GitHub | Competitor |
| GitLab | Competitor |
| Linear | Competitor |
| Jira | Competitor |
| Notion | Competitor |
| Bitbucket | Competitor |
This demonstrates the dashboard with a realistic competitive landscape. Replace this with your own configuration when using as a template.
- Framework: Next.js 15 (App Router)
- Styling: Tailwind CSS v4
- Database: PostgreSQL with Drizzle ORM
- LLM SDK: LangChain
- Workflows: Render Workflows SDK
├── web/ # Next.js application
│ └── src/db/
│ ├── schema.ts # Database schema
│ ├── seed.ts # Production seed (providers only)
│ └── seed.dev.ts # Dev seed (industry, brands, prompts)
├── workflows/ # TypeScript workflow tasks
│ ├── index.ts # Task definitions
│ ├── llm.ts # LLM provider logic
│ ├── utils.ts # URL extraction, brand matching
│ └── db/ # Database client
├── workflows-python/ # Python workflow tasks (alternative)
│ ├── main.py # Task definitions
│ ├── llm.py # LLM provider logic
│ ├── utils.py # URL extraction, brand matching
│ └── db.py # Database connection
├── render.yaml # Render Blueprint
└── pnpm-workspace.yaml
- Node.js 20+
- pnpm
- Docker (optional, for local PostgreSQL)
Copy .env.example to .env and add your API keys:
cp .env.example .envRequired keys:
DATABASE_URL: PostgreSQL connection stringOPENAI_API_KEY: For GPT modelsANTHROPIC_API_KEY: For Claude modelsGOOGLE_API_KEY: For Gemini models
Start the database and run the app:
# Start PostgreSQL
docker compose up -d
# Install dependencies
pnpm install
# Set up database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/citations_tracker pnpm db:push
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/citations_tracker pnpm db:seed:dev
# Start dev server
pnpm devThe dev seed creates the SprintHub demo configuration. To populate real data, run the workflows.
-
Install dependencies:
pnpm install
-
Set up PostgreSQL and update
DATABASE_URLin.env. -
Run migrations and seed:
pnpm db:generate pnpm db:migrate pnpm db:seed:dev
-
Start development:
pnpm dev