From a8124a07b5f065f61d13b2740b5e09eea6f75577 Mon Sep 17 00:00:00 2001 From: Ben Senescu <44480372+bensenescu@users.noreply.github.com> Date: Sun, 17 May 2026 17:53:46 -0400 Subject: [PATCH] Add grouped marketing feature pages and SEO-friendly feature hub (#199) * Refine marketing feature pages and feature navigation * Add SEO feature page polish * Share feature slugs with sitemap generation --- web/scripts/generate-sitemap.js | 4 + web/src/components/feature-page.tsx | 196 ++++++ web/src/lib/feature-page-slugs.js | 10 + web/src/lib/feature-pages.ts | 646 ++++++++++++++++++ web/src/routeTree.gen.ts | 198 ++++++ web/src/routes/_marketing.tsx | 80 ++- .../features/ai-brand-visibility.tsx | 18 + .../_marketing/features/ai-search-prompts.tsx | 18 + .../_marketing/features/backlink-checker.tsx | 18 + .../_marketing/features/domain-overview.tsx | 18 + web/src/routes/_marketing/features/index.tsx | 100 +++ .../_marketing/features/keyword-research.tsx | 18 + web/src/routes/_marketing/features/mcp.tsx | 29 +- .../_marketing/features/rank-tracking.tsx | 18 + .../_marketing/features/saved-keywords.tsx | 18 + .../routes/_marketing/features/site-audit.tsx | 18 + 16 files changed, 1388 insertions(+), 19 deletions(-) create mode 100644 web/src/components/feature-page.tsx create mode 100644 web/src/lib/feature-page-slugs.js create mode 100644 web/src/lib/feature-pages.ts create mode 100644 web/src/routes/_marketing/features/ai-brand-visibility.tsx create mode 100644 web/src/routes/_marketing/features/ai-search-prompts.tsx create mode 100644 web/src/routes/_marketing/features/backlink-checker.tsx create mode 100644 web/src/routes/_marketing/features/domain-overview.tsx create mode 100644 web/src/routes/_marketing/features/index.tsx create mode 100644 web/src/routes/_marketing/features/keyword-research.tsx create mode 100644 web/src/routes/_marketing/features/rank-tracking.tsx create mode 100644 web/src/routes/_marketing/features/saved-keywords.tsx create mode 100644 web/src/routes/_marketing/features/site-audit.tsx diff --git a/web/scripts/generate-sitemap.js b/web/scripts/generate-sitemap.js index b770b98..bf07baa 100644 --- a/web/scripts/generate-sitemap.js +++ b/web/scripts/generate-sitemap.js @@ -3,6 +3,7 @@ import { existsSync, readdirSync, statSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; +import { FEATURE_PAGE_SLUGS } from "../src/lib/feature-page-slugs.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -19,6 +20,9 @@ const STATIC_PATHS = [ "/privacy", "/terms-and-conditions", "/guides", + "/features", + "/features/mcp", + ...Object.values(FEATURE_PAGE_SLUGS).map((slug) => `/features/${slug}`), ]; function getGuideEntries(dir = GUIDE_CONTENT_DIR, segments = []) { diff --git a/web/src/components/feature-page.tsx b/web/src/components/feature-page.tsx new file mode 100644 index 0000000..9458bcd --- /dev/null +++ b/web/src/components/feature-page.tsx @@ -0,0 +1,196 @@ +import type { FeaturePage } from "@/lib/feature-pages"; + +type FeaturePageProps = { + page: FeaturePage; +}; + +export function FeaturePageTemplate({ page }: FeaturePageProps) { + return ( +
+
+

{page.eyebrow}

+

+ {page.title} +

+

+ {page.description} +

+
+ + {page.ctaLabel ?? "Try OpenSEO"} + +
+
+ + + +
+

What you can do

+
    + {page.workflows.map((workflow, index) => ( +
  1. + + {String(index + 1).padStart(2, "0")} + +
    +

    + {workflow.title} +

    +

    + {workflow.description} +

    +
    +
  2. + ))} +
+
+ +
+

Data you can act on

+
+ {page.metrics.map((metric, index) => ( +
+
{metric.label}
+
+ {metric.value} +
+
+ ))} +
+
+ +
+

Use cases

+
    + {page.useCases.map((item) => ( +
  • + + {item} +
  • + ))} +
+
+ +
+

Why OpenSEO

+
    + {page.differentiators.map((item) => ( +
  • + + {item} +
  • + ))} +
+
+ +
+

Related features

+
+ {page.related.map((item) => ( + + {item.label} + + + ))} +
+
+ +
+

FAQ

+
+ {page.faqs.map((faq) => ( +
+

+ {faq.question} +

+

+ {faq.answer} +

+
+ ))} +
+
+ +
+

+ Try OpenSEO +

+

+ The open source alternative to bloated, expensive, legacy SEO tools. +

+
+ + {page.ctaLabel ?? "Try OpenSEO"} + +
+
+
+ ); +} + +function FeatureImage({ page }: FeaturePageProps) { + if (page.imageSrc) { + return ( +
+ {page.imageAlt} +
+ {page.eyebrow} in OpenSEO. +
+
+ ); + } + + return ( +
+
+
+

+ {page.imagePlaceholder} +

+

+ Replace with final product screenshot or short demo asset. +

+
+
+
+ Placeholder for final OpenSEO product imagery. +
+
+ ); +} diff --git a/web/src/lib/feature-page-slugs.js b/web/src/lib/feature-page-slugs.js new file mode 100644 index 0000000..670e59e --- /dev/null +++ b/web/src/lib/feature-page-slugs.js @@ -0,0 +1,10 @@ +export const FEATURE_PAGE_SLUGS = { + keywordResearch: "keyword-research", + siteAudit: "site-audit", + backlinkChecker: "backlink-checker", + domainOverview: "domain-overview", + rankTracking: "rank-tracking", + savedKeywords: "saved-keywords", + aiBrandVisibility: "ai-brand-visibility", + aiSearchPrompts: "ai-search-prompts", +}; diff --git a/web/src/lib/feature-pages.ts b/web/src/lib/feature-pages.ts new file mode 100644 index 0000000..abc1436 --- /dev/null +++ b/web/src/lib/feature-pages.ts @@ -0,0 +1,646 @@ +import { FEATURE_PAGE_SLUGS } from "@/lib/feature-page-slugs"; + +export type FeaturePage = { + slug: string; + eyebrow: string; + navDescription: string; + title: string; + description: string; + primaryKeyword: string; + secondaryKeywords: string[]; + imageAlt: string; + imagePlaceholder: string; + imageSrc?: string; + ctaLabel?: string; + workflows: Array<{ + title: string; + description: string; + }>; + metrics: Array<{ + label: string; + value: string; + }>; + useCases: string[]; + differentiators: string[]; + related: Array<{ + label: string; + href: string; + }>; + faqs: Array<{ + question: string; + answer: string; + }>; +}; + +export const featurePages = { + keywordResearch: { + slug: FEATURE_PAGE_SLUGS.keywordResearch, + eyebrow: "Keyword Research", + navDescription: "Find keyword ideas and SERPs.", + title: "Keyword research tool for practical SEO planning", + description: + "Find keyword ideas, compare search volume and difficulty, inspect SERP results, and save the opportunities worth building around.", + primaryKeyword: "keyword research tool", + secondaryKeywords: [ + "seo keyword research tool", + "free keyword research tool", + "keyword research tools", + ], + imageAlt: "OpenSEO keyword research dashboard", + imagePlaceholder: "Keyword research screenshot placeholder", + imageSrc: + "https://imagedelivery.net/ysLOa6bzFaM49Jxok-TAlw/d77077d0-cdf4-4523-0c41-56a7b4861300/public", + workflows: [ + { + title: "Research seed topics", + description: + "Start with one or more seeds and expand them into keyword ideas with volume, difficulty, CPC, and intent signals.", + }, + { + title: "Inspect the real SERP", + description: + "Open SERP results beside keyword metrics so content decisions are based on the pages ranking for that query.", + }, + { + title: "Save and organize opportunities", + description: + "Keep useful keywords in your workspace and tag them for content planning, rank tracking, or AI-agent workflows.", + }, + ], + metrics: [ + { label: "Search volume", value: "Demand" }, + { label: "Keyword difficulty", value: "Competition" }, + { label: "CPC", value: "Commercial signal" }, + { label: "SERP results", value: "Search context" }, + ], + useCases: [ + "Build a content roadmap from real keyword data.", + "Find lower-competition variants before writing.", + "Group keywords for articles, landing pages, and rank tracking.", + ], + differentiators: [ + "Open-source SEO workflows you can self-host or run in the managed app.", + "DataForSEO-backed metrics without locking the research process into a black box.", + "MCP access so AI agents can research and save keywords for you.", + ], + related: [ + { label: "Rank Tracking", href: "/features/rank-tracking" }, + { label: "Saved Keywords", href: "/features/saved-keywords" }, + { label: "OpenSEO MCP", href: "/features/mcp" }, + ], + faqs: [ + { + question: "What is OpenSEO keyword research best for?", + answer: + "OpenSEO is best for finding SEO keyword ideas, checking demand and difficulty, and turning those ideas into saved keywords you can revisit.", + }, + { + question: "Can I use OpenSEO as a free keyword research tool?", + answer: + "OpenSEO is open source and can be self-hosted. The managed app also keeps keyword research tied to transparent usage instead of a large fixed subscription to a closed SEO suite.", + }, + { + question: "Does OpenSEO show live search results?", + answer: + "Yes. Keyword research can be paired with SERP inspection so you can see ranking pages alongside the metrics.", + }, + ], + }, + siteAudit: { + slug: FEATURE_PAGE_SLUGS.siteAudit, + eyebrow: "Site Audit", + navDescription: "Audit page-level SEO signals.", + title: "SEO audit tool for finding technical issues fast", + description: + "Crawl a site, collect page-level technical signals, and optionally run Lighthouse checks for performance, SEO, accessibility, and best-practice issues.", + primaryKeyword: "seo audit tool", + secondaryKeywords: [ + "seo site audit", + "free seo audit tool", + "seo audit tools", + ], + imageAlt: "OpenSEO site audit report", + imagePlaceholder: "Site audit screenshot placeholder", + imageSrc: + "https://imagedelivery.net/ysLOa6bzFaM49Jxok-TAlw/53149e87-0027-4fa8-5d13-bcaab60c7100/public", + workflows: [ + { + title: "Run a site crawl", + description: + "Inspect pages for status codes, titles, meta descriptions, headings, indexability signals, image alt coverage, links, response time, and optional Lighthouse findings.", + }, + { + title: "Prioritize issues", + description: + "Review crawled pages and optional Lighthouse results so the team can focus on visible page and performance problems.", + }, + { + title: "Drill into affected URLs", + description: + "Move into URLs with missing titles, metadata, heading and image-alt signals, status-code issues, response-time data, or optional Lighthouse findings.", + }, + ], + metrics: [ + { label: "Crawled URLs", value: "Coverage" }, + { label: "Page fields", value: "Checks" }, + { label: "Affected pages", value: "Scope" }, + { label: "Audit history", value: "Progress" }, + ], + useCases: [ + "Audit a new site before publishing SEO work.", + "Find technical issues after a migration or redesign.", + "Export crawled page data and Lighthouse findings for developers and content teams.", + ], + differentiators: [ + "A practical crawler built into the same workspace as keyword and domain research.", + "Open-source implementation for teams that want to inspect or extend the audit flow.", + "Simple reports that expose page-level signals and optional Lighthouse findings instead of relying only on a generic score.", + ], + related: [ + { label: "Domain Overview", href: "/features/domain-overview" }, + { label: "Backlink Checker", href: "/features/backlink-checker" }, + { label: "Keyword Research", href: "/features/keyword-research" }, + ], + faqs: [ + { + question: "What does the OpenSEO site audit tool check?", + answer: + "OpenSEO crawls pages, shows page-level technical signals, and can attach Lighthouse issue details when Lighthouse is enabled.", + }, + { + question: "Is OpenSEO a free SEO audit tool?", + answer: + "OpenSEO is open source and can be self-hosted. Managed usage depends on the crawl and data costs behind each workflow.", + }, + { + question: "Who should use OpenSEO Site Audit?", + answer: + "It is useful for founders, marketers, agencies, and developers who need a shared crawl report and optional Lighthouse issue export.", + }, + ], + }, + backlinkChecker: { + slug: FEATURE_PAGE_SLUGS.backlinkChecker, + eyebrow: "Backlinks", + navDescription: "Check links and referring domains.", + title: "Backlink checker for understanding a domain's link profile", + description: + "Analyze backlinks, referring domains, and linked pages without separating link research from the rest of your SEO workspace.", + primaryKeyword: "backlink checker", + secondaryKeywords: [ + "free backlink checker", + "backlink analysis tool", + "google backlink checker", + ], + imageAlt: "OpenSEO backlinks report", + imagePlaceholder: "Backlink checker screenshot placeholder", + imageSrc: + "https://imagedelivery.net/ysLOa6bzFaM49Jxok-TAlw/d97206ed-bd64-447c-2b9e-1b9f07c5ec00/public", + workflows: [ + { + title: "Check a domain's backlinks", + description: + "Look up backlinks and referring-domain signals for your site, competitors, or pages you are evaluating.", + }, + { + title: "Compare link quality", + description: + "Use backlink rows, referring-domain rows, rank, spam, broken, lost, and nofollow signals to inspect link quality.", + }, + { + title: "Filter and export link data", + description: + "Export and filter backlink, referring-domain, and top-page data for your own outreach, competitor research, or cleanup review.", + }, + ], + metrics: [ + { label: "Backlinks", value: "Links" }, + { label: "Referring domains", value: "Sources" }, + { label: "Target URLs", value: "Distribution" }, + { label: "Rank and spam signals", value: "Quality context" }, + ], + useCases: [ + "See who links to a competitor.", + "Inspect link opportunities for important pages.", + "Understand whether a domain has real authority before investing in content.", + ], + differentiators: [ + "Backlink analysis sits beside keyword research, domain overview, and audit data.", + "Self-host or adapt backlink reporting for your team's workflow.", + "MCP support lets an AI agent pull backlink context during SEO research.", + ], + related: [ + { label: "Domain Overview", href: "/features/domain-overview" }, + { label: "Site Audit", href: "/features/site-audit" }, + { label: "OpenSEO MCP", href: "/features/mcp" }, + ], + faqs: [ + { + question: "What is a backlink checker used for?", + answer: + "A backlink checker helps you understand which sites link to a domain or page, which links have stronger rank, spam, broken, lost, or nofollow signals, and where competitors are earning authority.", + }, + { + question: "Can I check competitor backlinks in OpenSEO?", + answer: + "Yes. OpenSEO's backlink workflow is designed for researching your own domain as well as competitor domains.", + }, + { + question: "How does backlink research connect to SEO planning?", + answer: + "Backlinks add link-profile context that can inform link-building, digital PR, and competitor research alongside your keyword work.", + }, + ], + }, + domainOverview: { + slug: FEATURE_PAGE_SLUGS.domainOverview, + eyebrow: "Domain Overview", + navDescription: "Analyze competitor visibility.", + title: "Domain analysis tool for competitor SEO research", + description: + "Review a domain's estimated organic traffic, organic keyword count, and ranking keyword and page data before deciding where to compete.", + primaryKeyword: "domain analysis tool", + secondaryKeywords: [ + "competitor keyword analysis tool", + "website traffic checker", + "competitor analysis seo tool", + ], + imageAlt: "OpenSEO domain overview", + imagePlaceholder: "Domain overview screenshot placeholder", + imageSrc: + "https://imagedelivery.net/ysLOa6bzFaM49Jxok-TAlw/189e22b8-fdf8-46b4-198c-e912beef2300/public", + workflows: [ + { + title: "Analyze a domain", + description: + "Start with a domain and get an overview of estimated organic traffic, organic keyword count, top ranking keywords, and top organic pages.", + }, + { + title: "Find competitor keywords", + description: + "Inspect keywords a competitor already ranks for and identify topics worth building or defending.", + }, + { + title: "Move into deeper research", + description: + "Use domain insights to open keyword research, backlink analysis, or rank tracking without starting over.", + }, + ], + metrics: [ + { label: "Organic traffic", value: "Visibility" }, + { label: "Organic keywords", value: "Topics" }, + { label: "Top keywords", value: "Rankings" }, + { label: "Top pages", value: "Organic reach" }, + ], + useCases: [ + "Research a competitor before writing a content plan.", + "Estimate a site's organic footprint.", + "Find keyword gaps between your site and the domains already ranking.", + ], + differentiators: [ + "Domain research connects directly to keyword, backlink, and rank tracking workflows.", + "Built around ranking keywords, estimated traffic, and top pages for practical competitor research.", + "Open-source and self-hostable for teams that want control over their SEO stack.", + ], + related: [ + { label: "Keyword Research", href: "/features/keyword-research" }, + { label: "Backlink Checker", href: "/features/backlink-checker" }, + { label: "Rank Tracking", href: "/features/rank-tracking" }, + ], + faqs: [ + { + question: "What does a domain analysis tool show?", + answer: + "It summarizes a domain's organic footprint, including estimated traffic, organic keyword count, ranking keywords, and top organic pages.", + }, + { + question: "Can OpenSEO help with competitor keyword analysis?", + answer: + "Yes. Domain Overview is designed to reveal the keywords and topics a competitor is already visible for.", + }, + { + question: "Is Domain Overview the same as a traffic checker?", + answer: + "It includes traffic-oriented visibility metrics, but the bigger value is connecting that traffic estimate to ranking keywords and top pages.", + }, + ], + }, + rankTracking: { + slug: FEATURE_PAGE_SLUGS.rankTracking, + eyebrow: "Rank Tracking", + navDescription: "Monitor keyword positions.", + title: "Rank tracker for monitoring keyword positions", + description: + "Track the keywords that matter, optionally compare desktop and mobile results, and keep ranking changes connected to your research workflow.", + primaryKeyword: "rank tracker", + secondaryKeywords: [ + "seo rank tracking tool", + "keyword rank tracker", + "google rank tracker", + ], + imageAlt: "OpenSEO rank tracking table", + imagePlaceholder: "Rank tracking screenshot placeholder", + imageSrc: + "https://imagedelivery.net/ysLOa6bzFaM49Jxok-TAlw/4a0f8508-1527-46a8-c91c-086456f21c00/public", + workflows: [ + { + title: "Add tracked domains", + description: + "Create rank tracking configurations for the domains and locations you care about.", + }, + { + title: "Track important keywords", + description: + "Add keywords manually or from ranking suggestions and monitor positions over time.", + }, + { + title: "Compare SERP context", + description: + "Review the configured device results, ranking URLs, movement, and available SERP feature signals.", + }, + ], + metrics: [ + { label: "Desktop rank", value: "When enabled" }, + { label: "Mobile rank", value: "When enabled" }, + { label: "SERP features", value: "Context" }, + { label: "Position change", value: "Movement" }, + ], + useCases: [ + "Monitor target keywords after publishing content.", + "Track launch, migration, and optimization impact.", + "Keep ranking checks close to the keywords your team already researched.", + ], + differentiators: [ + "Rank tracking is part of the same workspace as discovery, audit, and competitor research.", + "Optional desktop and mobile tracking helps teams avoid one-dimensional rank reports.", + "OpenSEO can expose ranking data to AI agents through MCP.", + ], + related: [ + { label: "Keyword Research", href: "/features/keyword-research" }, + { label: "Saved Keywords", href: "/features/saved-keywords" }, + { label: "OpenSEO MCP", href: "/features/mcp" }, + ], + faqs: [ + { + question: "What is a rank tracker?", + answer: + "A rank tracker monitors where a domain appears for selected keywords over time so you can see whether SEO work is improving visibility.", + }, + { + question: "Does OpenSEO track mobile and desktop rankings?", + answer: + "OpenSEO rank tracking can be configured for mobile, desktop, or both, so teams can compare devices when both are enabled.", + }, + { + question: "How should I choose keywords to track?", + answer: + "Start with keywords tied to important pages, active content work, and competitor opportunities discovered in keyword research.", + }, + ], + }, + savedKeywords: { + slug: FEATURE_PAGE_SLUGS.savedKeywords, + eyebrow: "Saved Keywords", + navDescription: "Organize SEO opportunities.", + title: "Saved keywords for turning SEO research into a plan", + description: + "Keep useful keyword ideas organized so they can inform content planning, rank tracking decisions, and AI-agent workflows.", + primaryKeyword: "saved keywords", + secondaryKeywords: [ + "seo keyword list", + "keyword list tool", + "keyword planning", + ], + imageAlt: "OpenSEO saved keywords list", + imagePlaceholder: "Saved keywords screenshot placeholder", + imageSrc: + "https://imagedelivery.net/ysLOa6bzFaM49Jxok-TAlw/8938a529-b443-4d4f-9869-c972f3cef900/public", + workflows: [ + { + title: "Save promising keywords", + description: + "Collect useful ideas from keyword research instead of losing them after each search.", + }, + { + title: "Organize by topic", + description: + "Tag keywords by page, campaign, content cluster, or priority so planning stays readable.", + }, + { + title: "Reuse saved keywords across workflows", + description: + "Use saved keywords and tags as a planning reference for rank tracking, content planning, or MCP-powered research.", + }, + ], + metrics: [ + { label: "Saved ideas", value: "Pipeline" }, + { label: "Tags", value: "Organization" }, + { label: "Volume", value: "Demand" }, + { label: "Difficulty", value: "Priority" }, + ], + useCases: [ + "Tag keyword ideas into topic or page groups from keyword research.", + "Prepare candidate keywords to add to rank tracking.", + "Keep human and AI-agent research in the same workspace.", + ], + differentiators: [ + "Saved keywords bridge research, tracking, and AI workflows.", + "Saved keywords preserve available metrics like volume, CPC, difficulty, intent, and tags.", + "The workflow stays simple enough for repeated planning sessions.", + ], + related: [ + { label: "Keyword Research", href: "/features/keyword-research" }, + { label: "Rank Tracking", href: "/features/rank-tracking" }, + { label: "OpenSEO MCP", href: "/features/mcp" }, + ], + faqs: [ + { + question: "Why save keywords in an SEO tool?", + answer: + "Saved keywords keep research organized so teams can return to the ideas that are worth writing, optimizing, or tracking.", + }, + { + question: "Can saved keywords be used with rank tracking?", + answer: + "Yes. Saved keywords are a natural source for deciding which terms should be monitored over time.", + }, + { + question: "How do saved keywords fit into SEO planning?", + answer: + "Saved Keywords keeps promising ideas organized so they can inform content planning, rank tracking decisions, and future research.", + }, + ], + }, + aiBrandVisibility: { + slug: FEATURE_PAGE_SLUGS.aiBrandVisibility, + eyebrow: "AI Visibility", + navDescription: "Look up brand mentions in AI search.", + title: "Brand lookup for ChatGPT and Google AI Overview visibility", + description: + "Look up a brand or domain and review ChatGPT and Google AI Overview mentions, cited pages, and related prompts.", + primaryKeyword: "ai visibility tool", + secondaryKeywords: [ + "brand visibility ai search", + "ai search visibility", + "answer engine optimization", + ], + imageAlt: "OpenSEO AI brand visibility report", + imagePlaceholder: "AI brand visibility screenshot placeholder", + imageSrc: + "https://imagedelivery.net/ysLOa6bzFaM49Jxok-TAlw/cde3e4f8-079f-4890-cb17-371087107400/public", + workflows: [ + { + title: "Look up a brand", + description: + "Search for a brand or domain and inspect how ChatGPT and Google AI Overview mention or cite it in available results.", + }, + { + title: "Review citations and platforms", + description: + "Review the URLs, domains, and platforms contributing to brand mentions.", + }, + { + title: "Find visibility gaps", + description: + "Use cited pages and related prompts as clues for content, reputation, or comparison coverage to investigate.", + }, + ], + metrics: [ + { label: "Mentions", value: "Presence" }, + { label: "Citations", value: "Sources" }, + { label: "Platforms", value: "Surfaces" }, + { label: "Cited domains", value: "Sources" }, + ], + useCases: [ + "See whether ChatGPT and Google AI Overview data mention or cite your brand or domain.", + "Find pages and domains cited alongside brand mentions.", + "Use cited sources and prompts to plan content experiments for answer-engine visibility.", + ], + differentiators: [ + "AI visibility sits beside classic SEO research instead of replacing it.", + "The workflow focuses on concrete sources and mentions, not vague AI hype.", + "OpenSEO helps teams connect AI mention and citation research to concrete SEO planning.", + ], + related: [ + { label: "AI Search Prompts", href: "/features/ai-search-prompts" }, + { label: "Domain Overview", href: "/features/domain-overview" }, + { label: "OpenSEO MCP", href: "/features/mcp" }, + ], + faqs: [ + { + question: "What is AI brand visibility?", + answer: + "AI brand visibility is how often your brand or domain appears in available ChatGPT and Google AI Overview mention and citation data.", + }, + { + question: "How is AI visibility different from traditional SEO?", + answer: + "Traditional SEO focuses on rankings and pages. OpenSEO's AI visibility workflow looks at mentions, cited pages, related prompts, and platform-level metrics from supported AI-search sources.", + }, + { + question: "Should AI visibility replace keyword research?", + answer: + "No. It should sit beside keyword, domain, backlink, and audit data so teams can understand both search rankings and answer coverage.", + }, + ], + }, + aiSearchPrompts: { + slug: FEATURE_PAGE_SLUGS.aiSearchPrompts, + eyebrow: "Prompt Explorer", + navDescription: "Compare answers across supported models.", + title: "AI search prompt explorer for visibility research", + description: + "Run the same prompt across supported AI models, compare the answers, and review citations when they are returned.", + primaryKeyword: "ai search visibility", + secondaryKeywords: [ + "chatgpt search visibility", + "ai search prompts", + "answer engine optimization tool", + ], + imageAlt: "OpenSEO prompt explorer", + imagePlaceholder: "Prompt explorer screenshot placeholder", + imageSrc: + "https://imagedelivery.net/ysLOa6bzFaM49Jxok-TAlw/9f3d38f2-aa97-417c-ca74-ae378654d700/public", + workflows: [ + { + title: "Test category prompts", + description: + "Compare answers to the questions your customers might ask AI tools.", + }, + { + title: "Inspect web-backed answers", + description: + "When web search is enabled, inspect the pages and domains cited by model responses.", + }, + { + title: "Check brand mentions", + description: + "Highlight a brand and see whether each model mentions it in the answer or cited sources.", + }, + ], + metrics: [ + { label: "Prompts", value: "Questions" }, + { label: "Web context", value: "Sources" }, + { label: "Web search country", value: "Regional context" }, + { label: "Brand mentions", value: "Presence" }, + ], + useCases: [ + "Compare how supported AI models answer the same prompt.", + "Review which pages and domains appear in cited sources.", + "Check whether a brand appears in AI answers and citations.", + ], + differentiators: [ + "Prompt research lives in the same workspace as domain, keyword, and brand visibility workflows.", + "OpenSEO treats AI search as a research layer, not a replacement for SEO fundamentals.", + "OpenSEO MCP exposes keyword, SERP, domain, backlink, saved keyword, and rank-tracking tools to AI agents.", + ], + related: [ + { label: "AI Brand Visibility", href: "/features/ai-brand-visibility" }, + { label: "Keyword Research", href: "/features/keyword-research" }, + { label: "OpenSEO MCP", href: "/features/mcp" }, + ], + faqs: [ + { + question: "What is an AI search prompt explorer?", + answer: + "It lets teams run the same prompt across supported AI models, compare answers, and inspect citation URLs returned with supported model responses.", + }, + { + question: "Why does prompt research matter for SEO?", + answer: + "Prompts reveal comparison, problem, and buying questions that can inform pages, guides, and the pages or domains that appear in returned citations.", + }, + { + question: "Can this help with answer engine optimization?", + answer: + "Yes. Prompt Explorer is a starting point for mapping prompt responses and returned citations back to source pages and possible SEO follow-up work.", + }, + ], + }, +} satisfies Record; + +export const featureGroups = [ + { + label: "Keyword workflows", + description: "Find, organize, and monitor the keywords that matter.", + pages: [ + featurePages.keywordResearch, + featurePages.savedKeywords, + featurePages.rankTracking, + ], + }, + { + label: "Domain research", + description: "Understand competitors, backlinks, and technical health.", + pages: [ + featurePages.domainOverview, + featurePages.backlinkChecker, + featurePages.siteAudit, + ], + }, + { + label: "AI visibility", + description: "Research AI search prompts, citations, and brand visibility.", + pages: [featurePages.aiBrandVisibility, featurePages.aiSearchPrompts], + }, +] as const; diff --git a/web/src/routeTree.gen.ts b/web/src/routeTree.gen.ts index 96e578f..ff63353 100644 --- a/web/src/routeTree.gen.ts +++ b/web/src/routeTree.gen.ts @@ -19,7 +19,16 @@ import { Route as GuidesSplatRouteImport } from './routes/guides/$' import { Route as ApiSubscribeRouteImport } from './routes/api/subscribe' import { Route as ApiEventRouteImport } from './routes/api/event' import { Route as MarketingPricingRouteImport } from './routes/_marketing/pricing' +import { Route as MarketingFeaturesIndexRouteImport } from './routes/_marketing/features/index' +import { Route as MarketingFeaturesSiteAuditRouteImport } from './routes/_marketing/features/site-audit' +import { Route as MarketingFeaturesSavedKeywordsRouteImport } from './routes/_marketing/features/saved-keywords' +import { Route as MarketingFeaturesRankTrackingRouteImport } from './routes/_marketing/features/rank-tracking' import { Route as MarketingFeaturesMcpRouteImport } from './routes/_marketing/features/mcp' +import { Route as MarketingFeaturesKeywordResearchRouteImport } from './routes/_marketing/features/keyword-research' +import { Route as MarketingFeaturesDomainOverviewRouteImport } from './routes/_marketing/features/domain-overview' +import { Route as MarketingFeaturesBacklinkCheckerRouteImport } from './routes/_marketing/features/backlink-checker' +import { Route as MarketingFeaturesAiSearchPromptsRouteImport } from './routes/_marketing/features/ai-search-prompts' +import { Route as MarketingFeaturesAiBrandVisibilityRouteImport } from './routes/_marketing/features/ai-brand-visibility' const TermsAndConditionsRoute = TermsAndConditionsRouteImport.update({ id: '/terms-and-conditions', @@ -70,11 +79,64 @@ const MarketingPricingRoute = MarketingPricingRouteImport.update({ path: '/pricing', getParentRoute: () => MarketingRoute, } as any) +const MarketingFeaturesIndexRoute = MarketingFeaturesIndexRouteImport.update({ + id: '/features/', + path: '/features/', + getParentRoute: () => MarketingRoute, +} as any) +const MarketingFeaturesSiteAuditRoute = + MarketingFeaturesSiteAuditRouteImport.update({ + id: '/features/site-audit', + path: '/features/site-audit', + getParentRoute: () => MarketingRoute, + } as any) +const MarketingFeaturesSavedKeywordsRoute = + MarketingFeaturesSavedKeywordsRouteImport.update({ + id: '/features/saved-keywords', + path: '/features/saved-keywords', + getParentRoute: () => MarketingRoute, + } as any) +const MarketingFeaturesRankTrackingRoute = + MarketingFeaturesRankTrackingRouteImport.update({ + id: '/features/rank-tracking', + path: '/features/rank-tracking', + getParentRoute: () => MarketingRoute, + } as any) const MarketingFeaturesMcpRoute = MarketingFeaturesMcpRouteImport.update({ id: '/features/mcp', path: '/features/mcp', getParentRoute: () => MarketingRoute, } as any) +const MarketingFeaturesKeywordResearchRoute = + MarketingFeaturesKeywordResearchRouteImport.update({ + id: '/features/keyword-research', + path: '/features/keyword-research', + getParentRoute: () => MarketingRoute, + } as any) +const MarketingFeaturesDomainOverviewRoute = + MarketingFeaturesDomainOverviewRouteImport.update({ + id: '/features/domain-overview', + path: '/features/domain-overview', + getParentRoute: () => MarketingRoute, + } as any) +const MarketingFeaturesBacklinkCheckerRoute = + MarketingFeaturesBacklinkCheckerRouteImport.update({ + id: '/features/backlink-checker', + path: '/features/backlink-checker', + getParentRoute: () => MarketingRoute, + } as any) +const MarketingFeaturesAiSearchPromptsRoute = + MarketingFeaturesAiSearchPromptsRouteImport.update({ + id: '/features/ai-search-prompts', + path: '/features/ai-search-prompts', + getParentRoute: () => MarketingRoute, + } as any) +const MarketingFeaturesAiBrandVisibilityRoute = + MarketingFeaturesAiBrandVisibilityRouteImport.update({ + id: '/features/ai-brand-visibility', + path: '/features/ai-brand-visibility', + getParentRoute: () => MarketingRoute, + } as any) export interface FileRoutesByFullPath { '/': typeof MarketingIndexRoute @@ -86,7 +148,16 @@ export interface FileRoutesByFullPath { '/guides/$': typeof GuidesSplatRoute '/js/script.js': typeof JsScriptDotjsRoute '/guides/': typeof GuidesIndexRoute + '/features/ai-brand-visibility': typeof MarketingFeaturesAiBrandVisibilityRoute + '/features/ai-search-prompts': typeof MarketingFeaturesAiSearchPromptsRoute + '/features/backlink-checker': typeof MarketingFeaturesBacklinkCheckerRoute + '/features/domain-overview': typeof MarketingFeaturesDomainOverviewRoute + '/features/keyword-research': typeof MarketingFeaturesKeywordResearchRoute '/features/mcp': typeof MarketingFeaturesMcpRoute + '/features/rank-tracking': typeof MarketingFeaturesRankTrackingRoute + '/features/saved-keywords': typeof MarketingFeaturesSavedKeywordsRoute + '/features/site-audit': typeof MarketingFeaturesSiteAuditRoute + '/features/': typeof MarketingFeaturesIndexRoute } export interface FileRoutesByTo { '/privacy': typeof PrivacyRoute @@ -98,7 +169,16 @@ export interface FileRoutesByTo { '/js/script.js': typeof JsScriptDotjsRoute '/': typeof MarketingIndexRoute '/guides': typeof GuidesIndexRoute + '/features/ai-brand-visibility': typeof MarketingFeaturesAiBrandVisibilityRoute + '/features/ai-search-prompts': typeof MarketingFeaturesAiSearchPromptsRoute + '/features/backlink-checker': typeof MarketingFeaturesBacklinkCheckerRoute + '/features/domain-overview': typeof MarketingFeaturesDomainOverviewRoute + '/features/keyword-research': typeof MarketingFeaturesKeywordResearchRoute '/features/mcp': typeof MarketingFeaturesMcpRoute + '/features/rank-tracking': typeof MarketingFeaturesRankTrackingRoute + '/features/saved-keywords': typeof MarketingFeaturesSavedKeywordsRoute + '/features/site-audit': typeof MarketingFeaturesSiteAuditRoute + '/features': typeof MarketingFeaturesIndexRoute } export interface FileRoutesById { __root__: typeof rootRouteImport @@ -112,7 +192,16 @@ export interface FileRoutesById { '/js/script.js': typeof JsScriptDotjsRoute '/_marketing/': typeof MarketingIndexRoute '/guides/': typeof GuidesIndexRoute + '/_marketing/features/ai-brand-visibility': typeof MarketingFeaturesAiBrandVisibilityRoute + '/_marketing/features/ai-search-prompts': typeof MarketingFeaturesAiSearchPromptsRoute + '/_marketing/features/backlink-checker': typeof MarketingFeaturesBacklinkCheckerRoute + '/_marketing/features/domain-overview': typeof MarketingFeaturesDomainOverviewRoute + '/_marketing/features/keyword-research': typeof MarketingFeaturesKeywordResearchRoute '/_marketing/features/mcp': typeof MarketingFeaturesMcpRoute + '/_marketing/features/rank-tracking': typeof MarketingFeaturesRankTrackingRoute + '/_marketing/features/saved-keywords': typeof MarketingFeaturesSavedKeywordsRoute + '/_marketing/features/site-audit': typeof MarketingFeaturesSiteAuditRoute + '/_marketing/features/': typeof MarketingFeaturesIndexRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath @@ -126,7 +215,16 @@ export interface FileRouteTypes { | '/guides/$' | '/js/script.js' | '/guides/' + | '/features/ai-brand-visibility' + | '/features/ai-search-prompts' + | '/features/backlink-checker' + | '/features/domain-overview' + | '/features/keyword-research' | '/features/mcp' + | '/features/rank-tracking' + | '/features/saved-keywords' + | '/features/site-audit' + | '/features/' fileRoutesByTo: FileRoutesByTo to: | '/privacy' @@ -138,7 +236,16 @@ export interface FileRouteTypes { | '/js/script.js' | '/' | '/guides' + | '/features/ai-brand-visibility' + | '/features/ai-search-prompts' + | '/features/backlink-checker' + | '/features/domain-overview' + | '/features/keyword-research' | '/features/mcp' + | '/features/rank-tracking' + | '/features/saved-keywords' + | '/features/site-audit' + | '/features' id: | '__root__' | '/_marketing' @@ -151,7 +258,16 @@ export interface FileRouteTypes { | '/js/script.js' | '/_marketing/' | '/guides/' + | '/_marketing/features/ai-brand-visibility' + | '/_marketing/features/ai-search-prompts' + | '/_marketing/features/backlink-checker' + | '/_marketing/features/domain-overview' + | '/_marketing/features/keyword-research' | '/_marketing/features/mcp' + | '/_marketing/features/rank-tracking' + | '/_marketing/features/saved-keywords' + | '/_marketing/features/site-audit' + | '/_marketing/features/' fileRoutesById: FileRoutesById } export interface RootRouteChildren { @@ -237,6 +353,34 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof MarketingPricingRouteImport parentRoute: typeof MarketingRoute } + '/_marketing/features/': { + id: '/_marketing/features/' + path: '/features' + fullPath: '/features/' + preLoaderRoute: typeof MarketingFeaturesIndexRouteImport + parentRoute: typeof MarketingRoute + } + '/_marketing/features/site-audit': { + id: '/_marketing/features/site-audit' + path: '/features/site-audit' + fullPath: '/features/site-audit' + preLoaderRoute: typeof MarketingFeaturesSiteAuditRouteImport + parentRoute: typeof MarketingRoute + } + '/_marketing/features/saved-keywords': { + id: '/_marketing/features/saved-keywords' + path: '/features/saved-keywords' + fullPath: '/features/saved-keywords' + preLoaderRoute: typeof MarketingFeaturesSavedKeywordsRouteImport + parentRoute: typeof MarketingRoute + } + '/_marketing/features/rank-tracking': { + id: '/_marketing/features/rank-tracking' + path: '/features/rank-tracking' + fullPath: '/features/rank-tracking' + preLoaderRoute: typeof MarketingFeaturesRankTrackingRouteImport + parentRoute: typeof MarketingRoute + } '/_marketing/features/mcp': { id: '/_marketing/features/mcp' path: '/features/mcp' @@ -244,19 +388,73 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof MarketingFeaturesMcpRouteImport parentRoute: typeof MarketingRoute } + '/_marketing/features/keyword-research': { + id: '/_marketing/features/keyword-research' + path: '/features/keyword-research' + fullPath: '/features/keyword-research' + preLoaderRoute: typeof MarketingFeaturesKeywordResearchRouteImport + parentRoute: typeof MarketingRoute + } + '/_marketing/features/domain-overview': { + id: '/_marketing/features/domain-overview' + path: '/features/domain-overview' + fullPath: '/features/domain-overview' + preLoaderRoute: typeof MarketingFeaturesDomainOverviewRouteImport + parentRoute: typeof MarketingRoute + } + '/_marketing/features/backlink-checker': { + id: '/_marketing/features/backlink-checker' + path: '/features/backlink-checker' + fullPath: '/features/backlink-checker' + preLoaderRoute: typeof MarketingFeaturesBacklinkCheckerRouteImport + parentRoute: typeof MarketingRoute + } + '/_marketing/features/ai-search-prompts': { + id: '/_marketing/features/ai-search-prompts' + path: '/features/ai-search-prompts' + fullPath: '/features/ai-search-prompts' + preLoaderRoute: typeof MarketingFeaturesAiSearchPromptsRouteImport + parentRoute: typeof MarketingRoute + } + '/_marketing/features/ai-brand-visibility': { + id: '/_marketing/features/ai-brand-visibility' + path: '/features/ai-brand-visibility' + fullPath: '/features/ai-brand-visibility' + preLoaderRoute: typeof MarketingFeaturesAiBrandVisibilityRouteImport + parentRoute: typeof MarketingRoute + } } } interface MarketingRouteChildren { MarketingPricingRoute: typeof MarketingPricingRoute MarketingIndexRoute: typeof MarketingIndexRoute + MarketingFeaturesAiBrandVisibilityRoute: typeof MarketingFeaturesAiBrandVisibilityRoute + MarketingFeaturesAiSearchPromptsRoute: typeof MarketingFeaturesAiSearchPromptsRoute + MarketingFeaturesBacklinkCheckerRoute: typeof MarketingFeaturesBacklinkCheckerRoute + MarketingFeaturesDomainOverviewRoute: typeof MarketingFeaturesDomainOverviewRoute + MarketingFeaturesKeywordResearchRoute: typeof MarketingFeaturesKeywordResearchRoute MarketingFeaturesMcpRoute: typeof MarketingFeaturesMcpRoute + MarketingFeaturesRankTrackingRoute: typeof MarketingFeaturesRankTrackingRoute + MarketingFeaturesSavedKeywordsRoute: typeof MarketingFeaturesSavedKeywordsRoute + MarketingFeaturesSiteAuditRoute: typeof MarketingFeaturesSiteAuditRoute + MarketingFeaturesIndexRoute: typeof MarketingFeaturesIndexRoute } const MarketingRouteChildren: MarketingRouteChildren = { MarketingPricingRoute: MarketingPricingRoute, MarketingIndexRoute: MarketingIndexRoute, + MarketingFeaturesAiBrandVisibilityRoute: + MarketingFeaturesAiBrandVisibilityRoute, + MarketingFeaturesAiSearchPromptsRoute: MarketingFeaturesAiSearchPromptsRoute, + MarketingFeaturesBacklinkCheckerRoute: MarketingFeaturesBacklinkCheckerRoute, + MarketingFeaturesDomainOverviewRoute: MarketingFeaturesDomainOverviewRoute, + MarketingFeaturesKeywordResearchRoute: MarketingFeaturesKeywordResearchRoute, MarketingFeaturesMcpRoute: MarketingFeaturesMcpRoute, + MarketingFeaturesRankTrackingRoute: MarketingFeaturesRankTrackingRoute, + MarketingFeaturesSavedKeywordsRoute: MarketingFeaturesSavedKeywordsRoute, + MarketingFeaturesSiteAuditRoute: MarketingFeaturesSiteAuditRoute, + MarketingFeaturesIndexRoute: MarketingFeaturesIndexRoute, } const MarketingRouteWithChildren = MarketingRoute._addFileChildren( diff --git a/web/src/routes/_marketing.tsx b/web/src/routes/_marketing.tsx index 517cdf2..fb662e5 100644 --- a/web/src/routes/_marketing.tsx +++ b/web/src/routes/_marketing.tsx @@ -1,6 +1,7 @@ import { createFileRoute, Link, Outlet } from "@tanstack/react-router"; import { useState } from "react"; import { SiteFooter } from "@/components/site-footer"; +import { featureGroups } from "@/lib/feature-pages"; function GitHubIcon({ size = 18 }: { size?: number }) { return ( @@ -31,12 +32,7 @@ function MarketingLayout() { OpenSEO
- - Guides - + + + Features + + +
+
+
+ {featureGroups.map((group) => ( +
+

+ {group.label} +

+
+ {group.pages.map((page) => ( + + + {page.eyebrow} + + + {page.navDescription} + + + ))} +
+
+ ))} + +
+
+
+
+ ); +} + function useNewsletter() { const [email, setEmail] = useState(""); const [status, setStatus] = useState< diff --git a/web/src/routes/_marketing/features/ai-brand-visibility.tsx b/web/src/routes/_marketing/features/ai-brand-visibility.tsx new file mode 100644 index 0000000..5b858da --- /dev/null +++ b/web/src/routes/_marketing/features/ai-brand-visibility.tsx @@ -0,0 +1,18 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { FeaturePageTemplate } from "@/components/feature-page"; +import { featurePages } from "@/lib/feature-pages"; +import { buildPageSeo } from "@/lib/seo"; + +const page = featurePages.aiBrandVisibility; + +export const Route = createFileRoute("/_marketing/features/ai-brand-visibility")({ + head: () => + buildPageSeo({ + title: "AI Brand Visibility Tool", + description: page.description, + path: "/features/ai-brand-visibility", + titleSuffix: "OpenSEO", + imageAlt: page.imageAlt, + }), + component: () => , +}); diff --git a/web/src/routes/_marketing/features/ai-search-prompts.tsx b/web/src/routes/_marketing/features/ai-search-prompts.tsx new file mode 100644 index 0000000..2d3b22a --- /dev/null +++ b/web/src/routes/_marketing/features/ai-search-prompts.tsx @@ -0,0 +1,18 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { FeaturePageTemplate } from "@/components/feature-page"; +import { featurePages } from "@/lib/feature-pages"; +import { buildPageSeo } from "@/lib/seo"; + +const page = featurePages.aiSearchPrompts; + +export const Route = createFileRoute("/_marketing/features/ai-search-prompts")({ + head: () => + buildPageSeo({ + title: "AI Search Prompt Explorer", + description: page.description, + path: "/features/ai-search-prompts", + titleSuffix: "OpenSEO", + imageAlt: page.imageAlt, + }), + component: () => , +}); diff --git a/web/src/routes/_marketing/features/backlink-checker.tsx b/web/src/routes/_marketing/features/backlink-checker.tsx new file mode 100644 index 0000000..5d5c43c --- /dev/null +++ b/web/src/routes/_marketing/features/backlink-checker.tsx @@ -0,0 +1,18 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { FeaturePageTemplate } from "@/components/feature-page"; +import { featurePages } from "@/lib/feature-pages"; +import { buildPageSeo } from "@/lib/seo"; + +const page = featurePages.backlinkChecker; + +export const Route = createFileRoute("/_marketing/features/backlink-checker")({ + head: () => + buildPageSeo({ + title: "Backlink Checker", + description: page.description, + path: "/features/backlink-checker", + titleSuffix: "OpenSEO", + imageAlt: page.imageAlt, + }), + component: () => , +}); diff --git a/web/src/routes/_marketing/features/domain-overview.tsx b/web/src/routes/_marketing/features/domain-overview.tsx new file mode 100644 index 0000000..bcf7023 --- /dev/null +++ b/web/src/routes/_marketing/features/domain-overview.tsx @@ -0,0 +1,18 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { FeaturePageTemplate } from "@/components/feature-page"; +import { featurePages } from "@/lib/feature-pages"; +import { buildPageSeo } from "@/lib/seo"; + +const page = featurePages.domainOverview; + +export const Route = createFileRoute("/_marketing/features/domain-overview")({ + head: () => + buildPageSeo({ + title: "Domain Analysis Tool", + description: page.description, + path: "/features/domain-overview", + titleSuffix: "OpenSEO", + imageAlt: page.imageAlt, + }), + component: () => , +}); diff --git a/web/src/routes/_marketing/features/index.tsx b/web/src/routes/_marketing/features/index.tsx new file mode 100644 index 0000000..3b2b92a --- /dev/null +++ b/web/src/routes/_marketing/features/index.tsx @@ -0,0 +1,100 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { featureGroups } from "@/lib/feature-pages"; +import { buildPageSeo } from "@/lib/seo"; + +const featuresDescription = + "Explore OpenSEO's open-source SEO tools for AI-agent workflows, keyword research, rank tracking, backlinks, site audits, competitor analysis, and AI visibility."; + +export const Route = createFileRoute("/_marketing/features/")({ + head: () => + buildPageSeo({ + title: "OpenSEO Features", + description: featuresDescription, + path: "/features", + titleSuffix: "OpenSEO", + }), + component: FeaturesIndex, +}); + +function FeaturesIndex() { + return ( + <> +

+ Open-source SEO tools +

+

+ A delightful suite of SEO tools +

+

+ Research keywords, track rankings, audit sites, and understand your AI + visibility from one modern platform. +

+ +
+
+
+

+ AI agent workflows +

+

+ Let supported MCP clients research keywords, SERPs, domains, and + backlinks through OpenSEO. +

+
+ +

OpenSEO MCP

+

+ OpenSEO MCP for your AI agent +

+

+ Connect OpenSEO to Claude, Codex, and supported MCP clients so + agents can call OpenSEO research tools with authorized project + context. +

+

+ Explore MCP +

+
+
+ + {featureGroups.map((group) => ( +
+
+

+ {group.label} +

+

+ {group.description} +

+
+ +
+ ))} +
+ + ); +} diff --git a/web/src/routes/_marketing/features/keyword-research.tsx b/web/src/routes/_marketing/features/keyword-research.tsx new file mode 100644 index 0000000..bdd787f --- /dev/null +++ b/web/src/routes/_marketing/features/keyword-research.tsx @@ -0,0 +1,18 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { FeaturePageTemplate } from "@/components/feature-page"; +import { featurePages } from "@/lib/feature-pages"; +import { buildPageSeo } from "@/lib/seo"; + +const page = featurePages.keywordResearch; + +export const Route = createFileRoute("/_marketing/features/keyword-research")({ + head: () => + buildPageSeo({ + title: "Keyword Research Tool", + description: page.description, + path: "/features/keyword-research", + titleSuffix: "OpenSEO", + imageAlt: page.imageAlt, + }), + component: () => , +}); diff --git a/web/src/routes/_marketing/features/mcp.tsx b/web/src/routes/_marketing/features/mcp.tsx index f44cc8f..e72460e 100644 --- a/web/src/routes/_marketing/features/mcp.tsx +++ b/web/src/routes/_marketing/features/mcp.tsx @@ -4,7 +4,7 @@ import { useState } from "react"; import { buildPageSeo } from "@/lib/seo"; const mcpDescription = - "Connect OpenSEO MCP to your AI agent so it can research keywords, SERPs, domains, backlinks, and rank tracking data."; + "Connect OpenSEO MCP so compatible AI clients can call keyword, SERP, domain, backlink, saved keyword, and rank-tracking tools."; const toolCategories = [ { @@ -16,7 +16,7 @@ const toolCategories = [ }, { title: "Get SERP results", - description: "See live Google results for a keyword.", + description: "See SERP results for a keyword.", }, { title: "Get rank tracking positions", @@ -24,7 +24,7 @@ const toolCategories = [ }, { title: "Get saved keywords", - description: "Pull your saved keyword lists.", + description: "Pull saved keywords from OpenSEO.", }, { title: "Save keywords", @@ -70,8 +70,10 @@ function McpPage() { OpenSEO MCP for your AI agent

- Connect OpenSEO to your AI agent so that it can research keywords, - SERPs, domains, backlinks, and rank tracking data for you. + Connect OpenSEO to your AI agent so your MCP client can call OpenSEO + tools for keyword research, SERP results, domain overview, domain + keywords, backlink overview, saved keywords, and rank-tracking + positions.

What it does

- MCP lets your AI do the most tedious parts of your job faster. Connect - OpenSEO once, then ask your agent to research keywords, inspect search - results, compare domains, and save useful ideas back to your - workspace. + MCP lets compatible AI clients call OpenSEO research tools directly. + After connecting OpenSEO through a supported MCP client, you can ask + your agent to research keywords, inspect search results, compare + domains, and save useful ideas back to your workspace.

@@ -121,8 +123,8 @@ function McpPage() {

Set up OpenSEO MCP

The first connection sends you through OpenSEO login. After - authorization, your AI client can call OpenSEO tools using your - workspace permissions. The MCP server URL is{" "} + authorization, your MCP client can call OpenSEO tools using the + authorized OpenSEO project context and scopes. The MCP server URL is{" "} https://app.openseo.so/mcp. For the most current setup UI and a copyable endpoint, open{" "}

- Follow the setup steps for Claude, Claude Code, Codex, or any - MCP-compatible AI tool. + Follow the setup steps for Claude, Claude Code, Codex, or MCP clients + that support remote HTTP MCP servers and the required authorization + flow.

diff --git a/web/src/routes/_marketing/features/rank-tracking.tsx b/web/src/routes/_marketing/features/rank-tracking.tsx new file mode 100644 index 0000000..abf0487 --- /dev/null +++ b/web/src/routes/_marketing/features/rank-tracking.tsx @@ -0,0 +1,18 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { FeaturePageTemplate } from "@/components/feature-page"; +import { featurePages } from "@/lib/feature-pages"; +import { buildPageSeo } from "@/lib/seo"; + +const page = featurePages.rankTracking; + +export const Route = createFileRoute("/_marketing/features/rank-tracking")({ + head: () => + buildPageSeo({ + title: "Rank Tracker", + description: page.description, + path: "/features/rank-tracking", + titleSuffix: "OpenSEO", + imageAlt: page.imageAlt, + }), + component: () => , +}); diff --git a/web/src/routes/_marketing/features/saved-keywords.tsx b/web/src/routes/_marketing/features/saved-keywords.tsx new file mode 100644 index 0000000..42edaed --- /dev/null +++ b/web/src/routes/_marketing/features/saved-keywords.tsx @@ -0,0 +1,18 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { FeaturePageTemplate } from "@/components/feature-page"; +import { featurePages } from "@/lib/feature-pages"; +import { buildPageSeo } from "@/lib/seo"; + +const page = featurePages.savedKeywords; + +export const Route = createFileRoute("/_marketing/features/saved-keywords")({ + head: () => + buildPageSeo({ + title: "Saved Keyword Lists", + description: page.description, + path: "/features/saved-keywords", + titleSuffix: "OpenSEO", + imageAlt: page.imageAlt, + }), + component: () => , +}); diff --git a/web/src/routes/_marketing/features/site-audit.tsx b/web/src/routes/_marketing/features/site-audit.tsx new file mode 100644 index 0000000..f07d652 --- /dev/null +++ b/web/src/routes/_marketing/features/site-audit.tsx @@ -0,0 +1,18 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { FeaturePageTemplate } from "@/components/feature-page"; +import { featurePages } from "@/lib/feature-pages"; +import { buildPageSeo } from "@/lib/seo"; + +const page = featurePages.siteAudit; + +export const Route = createFileRoute("/_marketing/features/site-audit")({ + head: () => + buildPageSeo({ + title: "SEO Audit Tool", + description: page.description, + path: "/features/site-audit", + titleSuffix: "OpenSEO", + imageAlt: page.imageAlt, + }), + component: () => , +});