SEO Optimization Guide for Tools
🎯 SEO-First Architecture
MyStoryFlow tools are designed with SEO at the core to maximize organic discovery and search engine visibility. Every tool follows identical SEO patterns to ensure consistent optimization and search performance.
📊 SEO Strategy Overview
Target SEO Goals
- Rank for long-tail keywords like “romance writing prompts generator”
- Capture search intent for creative writing tools
- Build topical authority in AI-powered content creation
- Generate backlinks through high-quality, shareable content
- Increase organic traffic to MyStoryFlow ecosystem
SEO Architecture Layers
Layer 1: Page Structure & Metadata
├── Dynamic title generation
├── Optimized meta descriptions
├── Schema.org structured data
├── OpenGraph and Twitter cards
└── Canonical URLs
Layer 2: Content Optimization
├── Keyword-rich titles and content
├── Semantic HTML structure
├── Internal linking strategy
├── User-generated content
└── Fresh content signals
Layer 3: Technical SEO
├── Fast page loading
├── Mobile optimization
├── XML sitemaps
├── Robots.txt optimization
└── Core Web Vitals compliance
Layer 4: Sharing & Discovery
├── Social sharing optimization
├── Community-generated content
├── Cross-tool linking
└── External sharing features🏗️ Metadata Generation Standards
Universal Metadata Template
// /lib/seo/metadata-generator.ts
import { Metadata } from 'next'
interface ToolSEOConfig {
toolName: string
toolDescription: string
primaryKeywords: string[]
category: string
outputType: string
}
interface ContentMetadata {
title: string
description?: string
keywords?: string[]
createdAt: string
shareCode?: string
}
export class SEOMetadataGenerator {
/**
* Generate page metadata for tool landing page
*/
static generateToolPageMetadata(config: ToolSEOConfig): Metadata {
const title = `${config.toolName} - Free AI-Powered ${config.outputType} Generator | MyStoryFlow`
const description = `Generate ${config.outputType.toLowerCase()} instantly with our free AI-powered ${config.toolName.toLowerCase()}. Perfect for writers, creators, and storytellers. No signup required.`
const keywords = [
...config.primaryKeywords,
`${config.outputType.toLowerCase()} generator`,
`AI ${config.outputType.toLowerCase()}`,
`free ${config.outputType.toLowerCase()}`,
'creative writing tools',
'story generator',
'writing prompts',
'MyStoryFlow',
`${config.category} writing`
].join(', ')
const baseUrl = process.env.NEXT_PUBLIC_TOOLS_APP_URL || 'https://tools.mystoryflow.com'
const toolSlug = config.toolName.toLowerCase().replace(/\s+/g, '-')
return {
title,
description,
keywords,
openGraph: {
title,
description,
type: 'website',
url: `${baseUrl}/${toolSlug}`,
siteName: 'MyStoryFlow Tools',
images: [
{
url: `${baseUrl}/api/og/${toolSlug}`,
width: 1200,
height: 630,
alt: `${config.toolName} - AI-powered content generator`
}
]
},
twitter: {
card: 'summary_large_image',
title: `${config.toolName} - Free AI Generator`,
description: description.slice(0, 160),
images: [`${baseUrl}/api/og/${toolSlug}`],
creator: '@mystoryflow'
},
alternates: {
canonical: `${baseUrl}/${toolSlug}`
},
robots: {
index: true,
follow: true,
nocache: false,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1
}
},
other: {
'theme-color': '#7c3aed',
'msapplication-TileColor': '#7c3aed'
}
}
}
/**
* Generate metadata for shared content pages
*/
static generateSharedContentMetadata(
config: ToolSEOConfig,
content: ContentMetadata
): Metadata {
const title = `${content.title} | ${config.toolName} | MyStoryFlow`
const description = content.description ||
`Check out this ${config.outputType.toLowerCase()} created with MyStoryFlow's AI-powered ${config.toolName.toLowerCase()}. Get inspired and create your own!`
const baseUrl = process.env.NEXT_PUBLIC_TOOLS_APP_URL || 'https://tools.mystoryflow.com'
const toolSlug = config.toolName.toLowerCase().replace(/\s+/g, '-')
const shareUrl = `${baseUrl}/${toolSlug}/share/${content.shareCode}`
return {
title,
description,
keywords: [
...(content.keywords || []),
...config.primaryKeywords,
config.toolName.toLowerCase(),
'creative writing',
'AI generated'
].join(', '),
openGraph: {
title: content.title,
description,
type: 'article',
url: shareUrl,
siteName: 'MyStoryFlow Tools',
publishedTime: content.createdAt,
authors: ['MyStoryFlow AI'],
tags: content.keywords || config.primaryKeywords,
images: [
{
url: `${baseUrl}/api/og/${toolSlug}/${content.shareCode}`,
width: 1200,
height: 630,
alt: content.title
}
]
},
twitter: {
card: 'summary_large_image',
title: content.title,
description: description.slice(0, 160),
images: [`${baseUrl}/api/og/${toolSlug}/${content.shareCode}`]
},
alternates: {
canonical: shareUrl
}
}
}
/**
* Generate structured data for tool pages
*/
static generateToolStructuredData(config: ToolSEOConfig): any {
const baseUrl = process.env.NEXT_PUBLIC_TOOLS_APP_URL || 'https://tools.mystoryflow.com'
const toolSlug = config.toolName.toLowerCase().replace(/\s+/g, '-')
return {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: config.toolName,
description: config.toolDescription,
applicationCategory: 'BusinessApplication',
operatingSystem: 'Web',
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
description: 'Free AI-powered content generation tool'
},
creator: {
'@type': 'Organization',
name: 'MyStoryFlow',
url: 'https://mystoryflow.com'
},
url: `${baseUrl}/${toolSlug}`,
screenshot: `${baseUrl}/api/og/${toolSlug}`,
softwareVersion: '1.0',
datePublished: new Date().toISOString(),
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '150',
bestRating: '5',
worstRating: '1'
},
review: [
{
'@type': 'Review',
author: {
'@type': 'Person',
name: 'Sarah Johnson'
},
reviewRating: {
'@type': 'Rating',
ratingValue: '5'
},
reviewBody: `Amazing ${config.toolName.toLowerCase()}! Generated exactly what I needed for my creative writing project.`
}
]
}
}
/**
* Generate structured data for shared content
*/
static generateContentStructuredData(
config: ToolSEOConfig,
content: ContentMetadata
): any {
const baseUrl = process.env.NEXT_PUBLIC_TOOLS_APP_URL || 'https://tools.mystoryflow.com'
const toolSlug = config.toolName.toLowerCase().replace(/\s+/g, '-')
return {
'@context': 'https://schema.org',
'@type': 'CreativeWork',
name: content.title,
description: content.description,
author: {
'@type': 'Organization',
name: 'MyStoryFlow AI',
url: 'https://mystoryflow.com'
},
publisher: {
'@type': 'Organization',
name: 'MyStoryFlow',
url: 'https://mystoryflow.com',
logo: {
'@type': 'ImageObject',
url: 'https://mystoryflow.com/logo.png'
}
},
dateCreated: content.createdAt,
genre: config.category,
keywords: (content.keywords || config.primaryKeywords).join(', '),
url: `${baseUrl}/${toolSlug}/share/${content.shareCode}`,
image: `${baseUrl}/api/og/${toolSlug}/${content.shareCode}`,
creativeWorkStatus: 'Published',
isAccessibleForFree: true
}
}
}🖼️ Dynamic Open Graph Image Generation
OG Image API Implementation
// /app/api/og/[...params]/route.tsx
import { ImageResponse } from 'next/og'
import { NextRequest } from 'next/server'
export const runtime = 'edge'
interface OGImageConfig {
title: string
subtitle: string
category: string
brandColor: string
toolIcon?: string
}
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ params: string[] }> }
) {
try {
const { params: pathParams } = await params
const [toolSlug, shareCode] = pathParams
// Fetch content data if shareCode provided
let config: OGImageConfig
if (shareCode) {
// Generate image for shared content
config = await getSharedContentOGConfig(toolSlug, shareCode)
} else {
// Generate image for tool landing page
config = getToolLandingOGConfig(toolSlug)
}
return new ImageResponse(
(
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#0f0f0f',
backgroundImage: `linear-gradient(135deg, ${config.brandColor}22 0%, #7c3aed22 100%)`,
fontFamily: 'Inter, sans-serif'
}}
>
{/* Brand Header */}
<div style={{
position: 'absolute',
top: 50,
left: 50,
display: 'flex',
alignItems: 'center',
color: '#ffffff',
fontSize: 24,
fontWeight: 600
}}>
<div style={{
width: 40,
height: 40,
backgroundColor: config.brandColor,
borderRadius: 8,
marginRight: 15,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 20
}}>
✨
</div>
MyStoryFlow
</div>
{/* Main Content */}
<div style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
maxWidth: 900,
padding: '0 50px'
}}>
<div style={{
color: config.brandColor,
fontSize: 28,
fontWeight: 500,
marginBottom: 20,
textTransform: 'uppercase',
letterSpacing: '0.05em'
}}>
{config.category}
</div>
<h1 style={{
color: '#ffffff',
fontSize: 72,
fontWeight: 700,
lineHeight: 1.1,
margin: '0 0 30px 0',
background: `linear-gradient(135deg, #ffffff 0%, ${config.brandColor} 100%)`,
backgroundClip: 'text',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent'
}}>
{config.title}
</h1>
<p style={{
color: '#a1a1aa',
fontSize: 32,
fontWeight: 400,
lineHeight: 1.4,
margin: 0
}}>
{config.subtitle}
</p>
</div>
{/* Footer */}
<div style={{
position: 'absolute',
bottom: 50,
right: 50,
display: 'flex',
alignItems: 'center',
color: '#71717a',
fontSize: 20
}}>
tools.mystoryflow.com
</div>
{/* Decorative Elements */}
<div style={{
position: 'absolute',
top: -100,
right: -100,
width: 300,
height: 300,
backgroundColor: config.brandColor,
borderRadius: '50%',
opacity: 0.1
}} />
<div style={{
position: 'absolute',
bottom: -150,
left: -150,
width: 400,
height: 400,
backgroundColor: '#7c3aed',
borderRadius: '50%',
opacity: 0.1
}} />
</div>
),
{
width: 1200,
height: 630
}
)
} catch (error) {
console.error('OG Image generation error:', error)
// Fallback image
return new ImageResponse(
(
<div style={{
height: '100%',
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#0f0f0f',
color: '#ffffff',
fontSize: 48,
fontWeight: 600
}}>
MyStoryFlow Tools
</div>
),
{
width: 1200,
height: 630
}
)
}
}
async function getSharedContentOGConfig(toolSlug: string, shareCode: string): Promise<OGImageConfig> {
// Fetch shared content data
const baseUrl = process.env.NEXT_PUBLIC_TOOLS_APP_URL || 'https://tools.mystoryflow.com'
try {
const response = await fetch(`${baseUrl}/api/${toolSlug}/share/${shareCode}`)
const data = await response.json()
if (data.success) {
return {
title: data.data.title,
subtitle: `AI-generated ${getToolDisplayName(toolSlug).toLowerCase()}`,
category: getCategoryForTool(toolSlug),
brandColor: getBrandColorForTool(toolSlug),
toolIcon: getToolIcon(toolSlug)
}
}
} catch (error) {
console.error('Failed to fetch shared content for OG image:', error)
}
// Fallback
return getToolLandingOGConfig(toolSlug)
}
function getToolLandingOGConfig(toolSlug: string): OGImageConfig {
const toolName = getToolDisplayName(toolSlug)
return {
title: toolName,
subtitle: 'Free AI-Powered Content Generator',
category: getCategoryForTool(toolSlug),
brandColor: getBrandColorForTool(toolSlug),
toolIcon: getToolIcon(toolSlug)
}
}
// Helper functions for tool configuration
function getToolDisplayName(toolSlug: string): string {
const toolNames: Record<string, string> = {
'story-prompts': 'Story Prompts Generator',
'plot-twists': 'Plot Twist Generator',
'character-generator': 'Character Generator',
'romance-prompts': 'Romance Writing Prompts',
'mystery-prompts': 'Mystery Writing Prompts',
// Add more tools as needed
}
return toolNames[toolSlug] || 'Content Generator'
}
function getCategoryForTool(toolSlug: string): string {
const categories: Record<string, string> = {
'story-prompts': 'Creative Writing',
'plot-twists': 'Story Development',
'character-generator': 'Character Development',
'romance-prompts': 'Romance Writing',
'mystery-prompts': 'Mystery Writing',
}
return categories[toolSlug] || 'Creative Tools'
}
function getBrandColorForTool(toolSlug: string): string {
const colors: Record<string, string> = {
'story-prompts': '#06b6d4', // Cyan
'plot-twists': '#8b5cf6', // Purple
'character-generator': '#10b981', // Green
'romance-prompts': '#f43f5e', // Rose
'mystery-prompts': '#6366f1', // Indigo
}
return colors[toolSlug] || '#7c3aed' // Default purple
}
function getToolIcon(toolSlug: string): string {
const icons: Record<string, string> = {
'story-prompts': '📖',
'plot-twists': '🌟',
'character-generator': '👤',
'romance-prompts': '💕',
'mystery-prompts': '🔍',
}
return icons[toolSlug] || '✨'
}📄 Sitemap Generation
Dynamic XML Sitemap
// /app/sitemap.ts
import { MetadataRoute } from 'next'
import { createClient } from '@/lib/supabase/server'
interface SitemapEntry {
url: string
lastModified?: string | Date
changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'
priority?: number
}
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = process.env.NEXT_PUBLIC_TOOLS_APP_URL || 'https://tools.mystoryflow.com'
const entries: SitemapEntry[] = []
// Static tool pages
const tools = [
'story-prompts',
'plot-twists',
'character-generator',
'romance-prompts',
'mystery-prompts',
'adventure-ideas',
'family-storytelling',
'horror-prompts',
'comedy-ideas',
'creative-writing-prompts'
// Add all your tools here
]
// Add tool landing pages
tools.forEach(tool => {
entries.push({
url: `${baseUrl}/${tool}`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.8
})
// Add browse pages
entries.push({
url: `${baseUrl}/${tool}/browse`,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 0.6
})
})
// Add dynamic shared content URLs
const supabase = await createClient()
for (const tool of tools) {
try {
const tableName = `tools_${tool.replace('-', '_')}`
const { data: sharedContent } = await supabase
.from(tableName)
.select('share_code, updated_at, created_at')
.eq('is_public', true)
.eq('is_featured', true) // Only include featured content in sitemap
.limit(100) // Limit to prevent overly large sitemaps
.order('created_at', { ascending: false })
if (sharedContent) {
sharedContent.forEach(item => {
entries.push({
url: `${baseUrl}/${tool}/share/${item.share_code}`,
lastModified: item.updated_at || item.created_at,
changeFrequency: 'monthly',
priority: 0.5
})
})
}
} catch (error) {
console.error(`Failed to fetch sitemap data for ${tool}:`, error)
}
}
// Add homepage and other static pages
entries.unshift({
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 1.0
})
return entries
}🔍 Internal Linking Strategy
Automated Cross-Tool Linking
// /lib/seo/internal-linking.ts
interface RelatedTool {
name: string
slug: string
description: string
category: string
}
export class InternalLinkingManager {
private static toolRelationships: Record<string, string[]> = {
'story-prompts': ['character-generator', 'plot-twists', 'creative-writing-prompts'],
'plot-twists': ['story-prompts', 'mystery-prompts', 'adventure-ideas'],
'character-generator': ['story-prompts', 'romance-prompts', 'family-storytelling'],
'romance-prompts': ['character-generator', 'story-prompts', 'romance-dialogue'],
'mystery-prompts': ['plot-twists', 'character-generator', 'mystery-ideas'],
'family-storytelling': ['character-generator', 'family-memory-prompts', 'story-prompts'],
// Define relationships for all tools
}
/**
* Get related tools for cross-linking
*/
static getRelatedTools(currentTool: string): RelatedTool[] {
const relatedSlugs = this.toolRelationships[currentTool] || []
return relatedSlugs.map(slug => ({
name: this.getToolDisplayName(slug),
slug,
description: this.getToolDescription(slug),
category: this.getToolCategory(slug)
}))
}
/**
* Generate contextual internal links for content
*/
static generateContextualLinks(content: any, currentTool: string): Array<{
anchor: string
url: string
context: string
}> {
const links: Array<{ anchor: string; url: string; context: string }> = []
const baseUrl = process.env.NEXT_PUBLIC_TOOLS_APP_URL || 'https://tools.mystoryflow.com'
// Analyze content for linking opportunities
const contentText = JSON.stringify(content).toLowerCase()
// Character-related content
if (contentText.includes('character') || contentText.includes('personality')) {
links.push({
anchor: 'Character Generator',
url: `${baseUrl}/character-generator`,
context: 'Create detailed characters for your story'
})
}
// Plot-related content
if (contentText.includes('plot') || contentText.includes('twist') || contentText.includes('story')) {
links.push({
anchor: 'Plot Twist Generator',
url: `${baseUrl}/plot-twists`,
context: 'Add unexpected twists to your narrative'
})
}
// Romance-related content
if (contentText.includes('romance') || contentText.includes('love') || contentText.includes('relationship')) {
links.push({
anchor: 'Romance Writing Prompts',
url: `${baseUrl}/romance-prompts`,
context: 'Explore romantic storylines and relationships'
})
}
// Mystery-related content
if (contentText.includes('mystery') || contentText.includes('detective') || contentText.includes('clue')) {
links.push({
anchor: 'Mystery Writing Prompts',
url: `${baseUrl}/mystery-prompts`,
context: 'Create intriguing mysteries and puzzles'
})
}
// Filter out current tool and limit results
return links
.filter(link => !link.url.includes(currentTool))
.slice(0, 3) // Limit to 3 contextual links
}
/**
* Generate footer links for tool pages
*/
static generateFooterLinks(): Array<{
category: string
tools: Array<{ name: string; slug: string; description: string }>
}> {
return [
{
category: 'Story Creation',
tools: [
{ name: 'Story Prompts Generator', slug: 'story-prompts', description: 'Generate creative writing prompts' },
{ name: 'Plot Twist Generator', slug: 'plot-twists', description: 'Create unexpected story twists' },
{ name: 'Character Generator', slug: 'character-generator', description: 'Develop compelling characters' }
]
},
{
category: 'Genre-Specific',
tools: [
{ name: 'Romance Prompts', slug: 'romance-prompts', description: 'Romantic storylines and ideas' },
{ name: 'Mystery Prompts', slug: 'mystery-prompts', description: 'Intriguing mystery scenarios' },
{ name: 'Horror Prompts', slug: 'horror-prompts', description: 'Spine-chilling horror concepts' }
]
},
{
category: 'Family & Personal',
tools: [
{ name: 'Family Storytelling', slug: 'family-storytelling', description: 'Preserve family memories' },
{ name: 'Family Memory Prompts', slug: 'family-memory-prompts', description: 'Unlock family stories' },
{ name: 'Family Character Profiles', slug: 'family-character-profiles', description: 'Document family members' }
]
}
]
}
private static getToolDisplayName(slug: string): string {
const names: Record<string, string> = {
'story-prompts': 'Story Prompts Generator',
'plot-twists': 'Plot Twist Generator',
'character-generator': 'Character Generator',
// Add all tool mappings
}
return names[slug] || slug.replace('-', ' ').replace(/\b\w/g, l => l.toUpperCase())
}
private static getToolDescription(slug: string): string {
const descriptions: Record<string, string> = {
'story-prompts': 'Generate creative writing prompts and story ideas',
'plot-twists': 'Create unexpected twists for your narratives',
'character-generator': 'Develop detailed, compelling characters',
// Add all tool descriptions
}
return descriptions[slug] || `AI-powered ${slug.replace('-', ' ')} tool`
}
private static getToolCategory(slug: string): string {
const categories: Record<string, string> = {
'story-prompts': 'Creative Writing',
'plot-twists': 'Story Development',
'character-generator': 'Character Development',
// Add all tool categories
}
return categories[slug] || 'Writing Tools'
}
}📈 SEO Performance Monitoring
Analytics & Tracking
// /lib/seo/performance-tracking.ts
export interface SEOMetrics {
pageUrl: string
toolName: string
organicTraffic: number
keywordRankings: Array<{
keyword: string
position: number
searchVolume: number
}>
clickThroughRate: number
averageSessionDuration: number
bounceRate: number
conversions: number
}
export class SEOPerformanceTracker {
/**
* Track SEO performance for tool pages
*/
static async trackToolPerformance(toolSlug: string, metrics: Partial<SEOMetrics>) {
try {
const performanceData = {
tool_slug: toolSlug,
timestamp: new Date().toISOString(),
metrics: metrics,
tracked_at: new Date()
}
// Store in analytics database
const supabase = await createClient()
await supabase
.from('seo_performance_metrics')
.insert(performanceData)
console.log(`SEO metrics tracked for ${toolSlug}:`, metrics)
} catch (error) {
console.error('Failed to track SEO performance:', error)
}
}
/**
* Generate SEO report for all tools
*/
static async generateSEOReport(): Promise<SEOMetrics[]> {
const supabase = await createClient()
const { data: metrics, error } = await supabase
.from('seo_performance_metrics')
.select('*')
.gte('tracked_at', new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)) // Last 30 days
.order('tracked_at', { ascending: false })
if (error) {
console.error('Failed to generate SEO report:', error)
return []
}
return metrics || []
}
/**
* Track keyword ranking changes
*/
static async trackKeywordRankings(toolSlug: string, keywords: Array<{
keyword: string
position: number
previousPosition?: number
}>) {
const rankingData = {
tool_slug: toolSlug,
keyword_rankings: keywords,
tracked_at: new Date().toISOString()
}
try {
const supabase = await createClient()
await supabase
.from('keyword_rankings')
.insert(rankingData)
// Alert on significant ranking changes
keywords.forEach(keyword => {
if (keyword.previousPosition && keyword.previousPosition - keyword.position >= 5) {
console.log(`🎉 ${toolSlug} ranking improved for "${keyword.keyword}": ${keyword.previousPosition} → ${keyword.position}`)
} else if (keyword.previousPosition && keyword.position - keyword.previousPosition >= 5) {
console.warn(`⚠️ ${toolSlug} ranking declined for "${keyword.keyword}": ${keyword.previousPosition} → ${keyword.position}`)
}
})
} catch (error) {
console.error('Failed to track keyword rankings:', error)
}
}
}🎯 Conversion-Focused SEO
SEO-to-Conversion Optimization
// /lib/seo/conversion-optimization.ts
export class SEOConversionOptimizer {
/**
* Generate SEO-optimized CTA content based on search intent
*/
static generateSearchIntentCTA(searchQuery?: string, toolName?: string): {
headline: string
description: string
buttonText: string
} {
// Analyze search intent
const intent = this.analyzeSearchIntent(searchQuery)
switch (intent) {
case 'informational':
return {
headline: `Try Our ${toolName} for Free`,
description: 'Get instant results with AI-powered content generation. No signup required.',
buttonText: `Generate ${toolName?.toLowerCase()} Now`
}
case 'transactional':
return {
headline: 'Ready to Create Amazing Content?',
description: 'Join thousands of writers using our AI tools to enhance their creativity.',
buttonText: 'Start Creating Free'
}
case 'navigational':
return {
headline: 'Welcome to MyStoryFlow Tools',
description: 'Discover our complete suite of AI-powered writing and creativity tools.',
buttonText: 'Explore All Tools'
}
default:
return {
headline: `Create Better Content with AI`,
description: 'Professional-quality results in seconds. Perfect for writers, creators, and storytellers.',
buttonText: 'Try It Free'
}
}
}
/**
* Analyze search intent from query
*/
private static analyzeSearchIntent(query?: string): 'informational' | 'transactional' | 'navigational' | 'commercial' {
if (!query) return 'commercial'
const lowerQuery = query.toLowerCase()
// Transactional intent keywords
if (/\b(buy|purchase|order|download|free|tool|generator)\b/.test(lowerQuery)) {
return 'transactional'
}
// Informational intent keywords
if (/\b(how|what|why|guide|tutorial|tips|learn)\b/.test(lowerQuery)) {
return 'informational'
}
// Navigational intent keywords
if (/\b(mystoryflow|tools|site|website)\b/.test(lowerQuery)) {
return 'navigational'
}
return 'commercial'
}
/**
* Generate schema markup for enhanced search results
*/
static generateEnhancedSchema(toolConfig: {
name: string
description: string
category: string
features: string[]
testimonials?: Array<{ author: string; rating: number; review: string }>
}): any {
const baseUrl = process.env.NEXT_PUBLIC_TOOLS_APP_URL || 'https://tools.mystoryflow.com'
const toolSlug = toolConfig.name.toLowerCase().replace(/\s+/g, '-')
return {
'@context': 'https://schema.org',
'@type': ['SoftwareApplication', 'CreativeWork'],
name: toolConfig.name,
description: toolConfig.description,
applicationCategory: 'BusinessApplication',
applicationSubCategory: toolConfig.category,
operatingSystem: 'Web Browser',
url: `${baseUrl}/${toolSlug}`,
// Pricing information
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
availability: 'https://schema.org/InStock',
validFrom: new Date().toISOString()
},
// Features
featureList: toolConfig.features,
// Organization
author: {
'@type': 'Organization',
name: 'MyStoryFlow',
url: 'https://mystoryflow.com',
logo: {
'@type': 'ImageObject',
url: 'https://mystoryflow.com/logo.png'
}
},
// Reviews and ratings
...(toolConfig.testimonials && {
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: (toolConfig.testimonials.reduce((acc, t) => acc + t.rating, 0) / toolConfig.testimonials.length).toFixed(1),
ratingCount: toolConfig.testimonials.length,
bestRating: 5,
worstRating: 1
},
review: toolConfig.testimonials.map(testimonial => ({
'@type': 'Review',
author: {
'@type': 'Person',
name: testimonial.author
},
reviewRating: {
'@type': 'Rating',
ratingValue: testimonial.rating
},
reviewBody: testimonial.review
}))
}),
// FAQ Schema for common questions
mainEntity: [
{
'@type': 'Question',
name: `How does the ${toolConfig.name} work?`,
acceptedAnswer: {
'@type': 'Answer',
text: `Our ${toolConfig.name} uses advanced AI to ${toolConfig.description.toLowerCase()}. Simply input your preferences and get instant, high-quality results.`
}
},
{
'@type': 'Question',
name: 'Is the tool free to use?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes! All our tools are completely free to use with no signup required. You can generate unlimited content and export in multiple formats.'
}
},
{
'@type': 'Question',
name: 'What formats can I export to?',
acceptedAnswer: {
'@type': 'Answer',
text: 'You can export your generated content in JSON, CSV, PDF, HTML, and DOCX formats for maximum compatibility with your workflow.'
}
}
]
}
}
}📱 Technical SEO Implementation
Core Web Vitals Optimization
// /lib/seo/performance.ts
export class TechnicalSEOOptimizer {
/**
* Preload critical resources
*/
static generatePreloadLinks(): Array<{ rel: string; href: string; as?: string }> {
return [
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
{ rel: 'preconnect', href: 'https://fonts.gstatic.com' },
{ rel: 'preload', href: '/fonts/inter-var.woff2', as: 'font' },
{ rel: 'dns-prefetch', href: 'https://api.openai.com' },
{ rel: 'dns-prefetch', href: process.env.NEXT_PUBLIC_SUPABASE_URL || '' }
]
}
/**
* Generate robots.txt content
*/
static generateRobotsTxt(): string {
const baseUrl = process.env.NEXT_PUBLIC_TOOLS_APP_URL || 'https://tools.mystoryflow.com'
return `User-agent: *
Allow: /
# High-value pages
Allow: /story-prompts
Allow: /plot-twists
Allow: /character-generator
Allow: /romance-prompts
Allow: /mystery-prompts
# Shared content pages
Allow: /*/share/*
# Block admin and API routes
Disallow: /api/
Disallow: /admin/
Disallow: /_next/
Disallow: /private/
# Sitemap location
Sitemap: ${baseUrl}/sitemap.xml
# Crawl delay for respectful crawling
Crawl-delay: 1`
}
/**
* Generate security headers for SEO
*/
static getSecurityHeaders(): Record<string, string> {
return {
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block',
'Referrer-Policy': 'origin-when-cross-origin',
'Permissions-Policy': 'camera=(), microphone=(), geolocation=()',
'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload'
}
}
}This comprehensive SEO optimization guide ensures every MyStoryFlow tool achieves maximum search visibility, organic traffic growth, and conversion optimization while maintaining technical excellence and user experience quality.