Skip to content

Agent Landing Pages — Content Guide

How to create and maintain the expanded SEO content that powers /ai-agents/{slug} pages.


Overview

Each agent landing page is built from two layers:

  1. Core config — defined in useAgentPurposes.ts. Provides the hero, features, FAQs, conversation demo, and ideal-for personas. Required for every agent type. You do not author this layer here.

  2. Expanded content — a TypeScript file at app/data/agents/{slug}.ts. Provides additional sections (How It Works, Why Conversations, Related Agents), extra FAQs, extra features, custom sections, and structured data for rich results.

The expanded content layer exists to differentiate each agent page for organic search. A booking assistant page and a lead collector page must not look or read the same. Google penalizes near-duplicate pages. This system makes structural and topical differentiation systematic.

When to create an expanded content file: Every agent type with a live landing page should have one. A page without expanded content ranks lower and provides less value to visitors than one with it.


Content File Structure

All content files live at app/data/agents/{slug}.ts. The slug must exactly match an AgentPurposeSlug value.

Minimal valid file:

typescript
import type { AgentExpandedContent } from './types'

const content: AgentExpandedContent = {
  slug: 'customer-support',
  lastUpdated: '2026-03-06',
}

export default content

Complete file anatomy (all optional fields shown):

typescript
import type { AgentExpandedContent } from './types'

const content: AgentExpandedContent = {
  // Required
  slug: 'booking-assistant',
  lastUpdated: '2026-03-05',       // ISO date string — update when content changes

  // Override default section headings
  sectionTitleOverrides: { ... },

  // Merge with core FAQs (appended after)
  additionalFAQs: [ ... ],

  // Merge with core features (appended after)
  additionalFeatures: [ ... ],

  // Adds "How It Works" section (3-5 steps)
  howItWorks: [ ... ],

  // Adds "Why Conversations" section (3-4 points)
  whyConversations: [ ... ],

  // Adds "Related Agents" section (3-5 links)
  relatedAgents: [ ... ],

  // Adds custom sections between Features and IdealFor
  customSections: [ ... ],

  // JSON-LD HowTo schema steps (separate from visual howItWorks)
  howToSteps: [ ... ],

  // Stats shown in custom stats-highlight sections
  statHighlights: [ ... ],

  // Internal link registry for tracking coverage
  internalLinks: [ ... ],
}

export default content

After creating the file, register it in app/data/agents/index.ts:

typescript
const contentModules = {
  // ... existing entries
  'your-slug': () => import('./your-slug'),
}

Type Contracts and Constraints

AgentExpandedContent

FieldTypeRequiredNotes
slugAgentPurposeSlugYesMust match an existing agent purpose slug
lastUpdatedstringRecommendedISO date string, e.g. '2026-03-05'. Signals content freshness.
sectionTitleOverridesSectionTitleOverridesNoReplaces category-computed defaults for named sections
additionalFAQsFAQItem[]NoMerged after core FAQs. Target total: 10-15 across core + additional
additionalFeaturesUseCaseFeature[]NoMerged after core features
howItWorksHowItWorksStep[]No3-5 steps. Section hidden if absent
whyConversationsWhyConversationsPoint[]No3-4 points. Section hidden if absent
relatedAgentsRelatedAgentLink[]No3-5 links. Section hidden if absent
customSectionsCustomSectionContent[]NoInserted between Features and IdealFor
howToStepsHowToSchemaStep[]NoJSON-LD only — not rendered visually
statHighlightsStatHighlight[]NoUsed in stats-highlight custom sections
internalLinksArray<{anchorText, href, context}>NoRegistry for auditing internal link coverage

Hard Constraints

No testimonials or fabricated reviews.

Do not add testimonial quotes, star ratings, or any content presented as a real user review. Google's spam policies can penalise AI-generated review content. If you want to show social proof, use StatHighlight with a cited source.

StatHighlight.source is optional but strongly recommended.

Any statistic should include a source string (e.g. "HBR, 2024") for credibility. Uncited statistics erode trust.

FAQ questions must be globally unique across all agent pages.

Duplicate FAQ questions across different agent pages are treated as duplicate content by Google and suppress rankings for both pages. Before adding a question, verify it does not appear in any other agent's FAQs.

HowItWorksStep.stepNumber must start at 1 and be sequential.

The step number is rendered in the numbered circle. Non-sequential numbers (e.g. 1, 2, 5) will display incorrectly.

CustomSectionContent uses a discriminated union — type determines the required data shape.

TypeScript will catch mismatches at compile time, but verify the data structure matches the type you declared.


Content Guidelines

Word Counts

SectionTarget
HowItWorksStep.description30-60 words
WhyConversationsPoint.description40-70 words
WhyConversationsPoint.formComparison15-30 words
RelatedAgentLink.reason20-40 words
FAQItem.answer60-120 words
IndustryUseCaseItem.description50-80 words

Uniqueness

Every piece of content in an agent file should be specific to that agent's use case. Avoid generic phrases that could apply to any agent.

Bad (generic): "Our AI helps you save time and work more efficiently."

Good (specific to booking-assistant): "Visitors describe what they need and the AI recommends the right service, duration, and price. No scrolling through menus or guessing which option fits."

Each agent page should contain 5-8 internal links total across all content sections. Include links naturally inside FAQ answers, contextSentence fields, and any custom section HTML.

Useful internal link targets:

DestinationPath
All AI agents listing/ai-agents
Specific agent landing pages/ai-agents/{slug}
Pricing page/pricing
Agent builder (by type)/build/{slug}
Guides/guides/{guide-slug}

Track your internal links in the internalLinks array. This field has no runtime effect — it serves as an audit trail.

HowTo Steps vs. Visual Steps

Two separate fields exist for step-by-step content:

  • howItWorks — the visual timeline rendered by UseCaseHowItWorks. Describes the product experience in 3-5 user-facing steps.
  • howToSteps — the JSON-LD HowTo schema injected into <head> for Google rich results. Describes actionable instructions a user follows to complete a task. These can differ in tone and detail from the visual steps.

Both are optional but having howToSteps (3-5 steps) qualifies the page for HowTo rich results in Google Search.


How to Create Content for a New Agent

Follow this checklist when writing an expanded content file for a new or unfinished agent page.

Before you start:

  • [ ] Confirm the agent slug exists in AgentPurposeSlug type
  • [ ] Read the core config entry in useAgentPurposes.ts to understand what is already covered
  • [ ] Read two existing content files (e.g. booking-assistant.ts, customer-support.ts) to calibrate tone and depth

Write the content file:

  • [ ] Create app/data/agents/{slug}.ts
  • [ ] Set slug to match exactly
  • [ ] Set lastUpdated to today's date (ISO format)
  • [ ] Write sectionTitleOverrides for at least features, faq, and whyConversations
  • [ ] Write howItWorks with 3-5 steps specific to this agent
  • [ ] Write whyConversations with 3-4 points that argue for conversations over forms (agent-specific)
  • [ ] Write relatedAgents with 3-5 links to complementary agent pages
  • [ ] Write additionalFAQs with 5-8 questions not already covered by core config
  • [ ] Check that no FAQ question duplicates questions in other agent files
  • [ ] Add at least one customSection (e.g. industry-use-cases or comparison)
  • [ ] Write howToSteps for JSON-LD (3-5 actionable steps)
  • [ ] Populate internalLinks with all links embedded in the content
  • [ ] Verify link count: 5-8 internal links total

Register and verify:

  • [ ] Add entry to contentModules in app/data/agents/index.ts
  • [ ] Run npx nuxi typecheck to verify no TypeScript errors
  • [ ] Open the page locally at /ai-agents/{slug} and visually inspect each section

Component Mapping

This table shows which AgentExpandedContent fields drive which rendered sections on the page.

Content FieldRendered SectionComponentCondition
whyConversationsWhy ConversationsUseCaseWhyConversationsShown if field is present and non-empty
howItWorksHow It WorksUseCaseHowItWorksShown if field is present and non-empty
relatedAgentsRelated AgentsUseCaseRelatedAgentsShown if field is present and non-empty
customSectionsCustom section(s)Dynamic by typeEach item renders one section
additionalFAQsFAQ sectionMerged into core FAQ listAlways present; additional items appended
additionalFeaturesFeatures sectionMerged into core features listAlways present; additional items appended
sectionTitleOverridesMultiple sectionsReplaces computed defaultsApplied to each named section if override exists
howToStepsNone (schema only)JSON-LD in <head>Injected when present

Custom section types and their components:

typeWhat renders
how-it-worksAnother UseCaseHowItWorks instance with custom title
why-conversationsAnother UseCaseWhyConversations instance with custom title
stats-highlightStatistics grid with optional source attribution
industry-use-casesIndustry-specific use case cards
comparisonSide-by-side traditional vs. Gnosari comparison table
customRaw HTML block (use sparingly; ensure content is sanitized)

Merge Utility Behavior

getExpandedContent(slug) in app/data/agents/index.ts dynamically imports the content file for the given slug. The module is lazy-loaded — it is only bundled into the page chunk for the specific agent, not all pages.

import('app/data/agents/booking-assistant.ts')
  → { default: AgentExpandedContent }

If no entry exists in contentModules for the slug, the function returns null. The page renders with core config only — no errors.

Merge rules applied in [slug].vue:

Core dataExpanded dataMerged result
core.faqexpanded.additionalFAQs[...core.faq, ...expanded.additionalFAQs]
core.featuresexpanded.additionalFeatures[...core.features, ...expanded.additionalFeatures]
core.sectionTitles[x]expanded.sectionTitleOverrides[x]Override wins if present, core default otherwise
expanded.howItWorksSection rendered if present
expanded.whyConversationsSection rendered if present
expanded.relatedAgentsResolved to RelatedAgentDisplay[], section rendered if present
expanded.customSectionsEach item renders in order, inserted between Features and IdealFor

The page renders the same 10-section structure regardless of whether expanded content exists — additional sections simply appear or are skipped based on presence of data.


Troubleshooting

TypeScript: Type error on slug

Type '"my-new-agent"' is not assignable to type 'AgentPurposeSlug'

The slug must first be added to the AgentPurposeSlug union type in app/types/domains/agent-purpose.ts. Add it there, then use it in your content file.

TypeScript: Type error on customSections[].data

Each CustomSectionContent variant has a different required data shape. The type field is the discriminant. Example:

typescript
// Correct
{ type: 'industry-use-cases', data: { items: [...] } }

// Wrong — 'items' is not valid for type 'how-it-works'
{ type: 'how-it-works', data: { items: [...] } }
// Should be:
{ type: 'how-it-works', data: { steps: [...] } }

Section not rendering despite data being present

Check that:

  1. The content file is registered in contentModules in app/data/agents/index.ts
  2. The field array is non-empty (an empty array [] causes the section to be skipped)
  3. The slug in the content file matches the URL slug exactly

RelatedAgents section shows wrong names or icons

relatedAgents in the content file stores only slug and reason. The page resolves them to RelatedAgentDisplay (name, tagline, icon, href) by looking up each slug in useAgentPurposes. If a slug does not exist in useAgentPurposes, that agent is silently dropped from the related agents section. Verify each related agent slug is a valid AgentPurposeSlug.

FAQ duplicate content concern

If two agent pages have the same or very similar FAQ question, Google may apply a duplicate content signal to both pages. Each FAQ question must be answerable only from the context of that specific agent. If you find yourself writing the same question for two agents, rewrite it to be agent-specific or remove one instance.