Skip to content

feat(marketing): add SEO comparison pages#1160

Merged
saddlepaddle merged 2 commits into
mainfrom
research-competitors-and-plan-seo-comparison-pages
Feb 3, 2026
Merged

feat(marketing): add SEO comparison pages#1160
saddlepaddle merged 2 commits into
mainfrom
research-competitors-and-plan-seo-comparison-pages

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented Feb 3, 2026

Summary

  • Adds /compare/[slug] dynamic route infrastructure (content reader, layout, JSON-LD, sitemap integration)
  • Ships 4 comparison pages: Superset vs Cursor, OpenCode, Conductor, and Warp
  • Each page is ~800 words with comparison tables, key differences, pricing, and FAQ sections
  • Adds remark-gfm for markdown table rendering and prose table styles

New files

  • apps/marketing/src/lib/compare.ts / compare-utils.ts — content reader + types
  • apps/marketing/src/app/compare/[slug]/page.tsx — dynamic route
  • apps/marketing/src/app/compare/[slug]/components/CompareLayout/ — page layout
  • apps/marketing/content/compare/*.mdx — 4 comparison pages

Modified files

  • apps/marketing/src/components/JsonLd/JsonLd.tsx — added ComparisonJsonLd
  • apps/marketing/src/app/sitemap.ts — includes comparison pages
  • apps/marketing/src/app/globals.css — prose table styles

Test plan

  • bun run lint:fix — no issues
  • bun run typecheck — 16/16 pass
  • bun test — 1193 pass, 0 fail
  • Verify /compare/superset-vs-cursor renders correctly in dev
  • Verify tables are styled properly
  • Verify JSON-LD in page source
  • Verify sitemap includes comparison pages

Summary by CodeRabbit

  • New Features

    • Four comparison pages added: Superset vs Conductor, Cursor, OpenCode, and Warp, with side-by-side tables, guidance, pricing, and FAQs.
    • New comparison page layout and page-level structured data for richer previews.
  • Documentation

    • Added a comprehensive SEO & publication plan for comparison pages and content workflow.
  • Style

    • Improved blog/prose table styling and Markdown table support for clearer comparisons.
  • Chores

    • Comparison pages included in the site sitemap for discoverability.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 3, 2026

📝 Walkthrough

Walkthrough

Adds a comparison-pages feature to the marketing site: four new MDX comparison articles, content model and parsing utilities, a dynamic Next.js compare route with metadata and JSON‑LD, a CompareLayout component, table styling, sitemap inclusion, and remark-gfm support for MDX tables.

Changes

Cohort / File(s) Summary
Comparison content
apps/marketing/content/compare/superset-vs-conductor.mdx, apps/marketing/content/compare/superset-vs-cursor.mdx, apps/marketing/content/compare/superset-vs-opencode.mdx, apps/marketing/content/compare/superset-vs-warp.mdx
Adds four new MDX comparison pages with frontmatter, at-a-glance tables, sections (what is X, key differences, pricing, FAQ), and content tailored for SEO.
Content plan / docs
apps/marketing/docs/SEO_COMPARISON_PAGES_PLAN.md
New SEO and rollout plan describing routing, frontmatter schema, page ordering, internal linking, validation, and a nine-page publication roadmap.
Routing & rendering
apps/marketing/src/app/compare/[slug]/page.tsx
New Next.js dynamic route: fetches comparison page by slug, renders MDX (remark-gfm), exports generateStaticParams and generateMetadata, and uses CompareLayout + ComparisonJsonLd for SEO.
Layout component
apps/marketing/src/app/compare/[slug]/components/CompareLayout/CompareLayout.tsx, .../CompareLayout/index.ts
New CompareLayout React component and public re-export; renders hero (title/description/lastUpdated), styled prose container, decorative grid elements, and CTA footer.
MDX / MD rendering support
apps/marketing/package.json
Adds dependency remark-gfm to support GitHub-flavored MDX features (tables, task lists, etc.).
Styling
apps/marketing/src/app/globals.css
Adds table styling rules for .prose tables (full-width tables, header/body cell styles, spacing, borders).
Content data layer & utils
apps/marketing/src/lib/compare.ts, apps/marketing/src/lib/compare-utils.ts
New content loader and helpers: ComparisonPage type, getComparisonPages, getComparisonPage, getAllComparisonSlugs, extractCompareToc, and formatCompareDate; parses MDX frontmatter and content into normalized objects.
JSON‑LD & exports
apps/marketing/src/components/JsonLd/JsonLd.tsx, .../JsonLd/index.ts
Adds ComparisonJsonLd component + props interface and re-exports it for SEO structured data (Article schema with optional image and modifiedTime).
Sitemap integration
apps/marketing/src/app/sitemap.ts
Includes comparison pages in sitemap generation (URL: /compare/{slug}, lastModified, monthly changefreq, priority 0.7).

Sequence Diagram

sequenceDiagram
    participant User
    participant NextRouter as Next.js Router
    participant CompareLib as compare.ts
    participant MDXParser as MDX (+remark-gfm)
    participant Components as React Components
    participant Browser

    User->>NextRouter: GET /compare/:slug
    NextRouter->>CompareLib: getComparisonPage(slug)
    CompareLib-->>NextRouter: ComparisonPage { frontmatter, content, url }
    NextRouter->>MDXParser: render MDX content (remark-gfm)
    MDXParser-->>NextRouter: React nodes
    NextRouter->>Components: render ComparisonJsonLd + CompareLayout + mdxComponents
    Components-->>Browser: HTML + JSON‑LD + styled content
    Browser->>Browser: display page with SEO metadata
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰
I hopped through content, pages in my paws,
Four matchups planted in neat little rows,
Tables gleam, JSON‑LD hums for crawlers' applause,
A stitched-up route where comparison wind blows,
Nibble the CTA and onward it goes.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(marketing): add SEO comparison pages' clearly and concisely describes the main change: adding SEO-focused comparison pages to the marketing app.
Description check ✅ Passed The description is comprehensive and covers all template sections with clear information about summary, new files, modified files, and test plan with passing results.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch research-competitors-and-plan-seo-comparison-pages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@apps/marketing/docs/SEO_COMPARISON_PAGES_PLAN.md`:
- Around line 218-268: The markdownlint MD040 warning is triggered by unlabeled
fenced code blocks in SEO_COMPARISON_PAGES_PLAN.md; fix it by adding a language
identifier (e.g., text) to the opening fences of each template/code-tree block —
replace the three opening "```" fences that precede "1. Hero:..." (1v1
template), "1. Hero: 'Best [Category]...'" (Category Roundup template), and the
"apps/marketing/" directory tree block with "```text" so each fenced block
begins with ```text and keeps the existing closing ``` fences unchanged.

In `@apps/marketing/src/lib/compare.ts`:
- Around line 47-48: The catch block currently swallows frontmatter parse
errors; update the catch to capture the error (e.g., catch (err)) and log it
using the prefixed pattern (for example
console.error(`[compare/parseFrontmatter] Failed to parse frontmatter for
${filePath || id || source}:`, err)) so errors are visible, then continue to
return null if that’s the intended fallback; modify the catch around the
frontmatter parsing code in compare.ts accordingly.
- Around line 70-74: The getComparisonPage function builds filePath from slug
without validation, allowing path traversal; validate the slug before using it
(e.g., enforce an allowlist regex like only alphanumeric, dashes/underscores, no
path separators or '..') or sanitize by resolving the path (use
path.resolve(path.join(COMPARE_DIR, `${slug}.mdx`)) and then assert the resolved
path startsWith the resolved COMPARE_DIR) and return undefined (or throw) if
validation fails; update getComparisonPage to perform this check before calling
fs.existsSync and reading the file.
🧹 Nitpick comments (7)
apps/marketing/content/compare/superset-vs-opencode.mdx (1)

23-31: Consider time‑stamping volatile metrics.
Line 26–31 includes pricing and GitHub star counts that can drift; adding “as of Feb 2, 2026” or avoiding exact figures can reduce staleness.

apps/marketing/src/lib/compare-utils.ts (1)

6-17: Document why optional fields can be absent.
lastUpdated? and image? are optional but lack justification; a short JSDoc keeps intent clear and aligns with the interface guideline.

Suggested update
 export interface ComparisonPage {
 	slug: string;
 	url: string;
 	title: string;
 	description: string;
 	date: string;
-	lastUpdated?: string;
+	/** ISO date of the most recent substantive update; omitted if never updated. */
+	lastUpdated?: string;
 	type: "1v1" | "roundup" | "tutorial";
 	competitors: string[];
 	keywords: string[];
-	image?: string;
+	/** Optional OG/social image URL when available. */
+	image?: string;
 	content: string;
 }

As per coding guidelines: Make dependencies required in interfaces unless truly optional; document why if optional.

apps/marketing/src/lib/compare.ts (1)

13-15: Type frontmatter to avoid implicit any.
gray-matter returns data: any; add a typed frontmatter interface and use the generic to keep type safety.

Suggested update
 import { slugify, type TocItem } from "./blog-utils";
 import type { ComparisonPage } from "./compare-utils";

 export { type ComparisonPage, formatCompareDate } from "./compare-utils";

 const COMPARE_DIR = path.join(process.cwd(), "content/compare");

+interface CompareFrontmatter {
+	title?: string;
+	description?: string;
+	date?: string | Date;
+	lastUpdated?: string | Date;
+	type?: ComparisonPage["type"];
+	competitors?: string[];
+	keywords?: string[];
+	image?: string;
+}
+
 function parseFrontmatter(filePath: string): ComparisonPage | null {
 	try {
 		const fileContent = fs.readFileSync(filePath, "utf-8");
-		const { data, content } = matter(fileContent);
+		const { data, content } = matter<CompareFrontmatter>(fileContent);

As per coding guidelines: Avoid any type unless necessary.

apps/marketing/content/compare/superset-vs-cursor.mdx (1)

22-29: Consider time‑stamping model/pricing details.
Line 25–29 lists specific models and pricing tiers that can change; adding “as of Feb 2, 2026” or softening the specificity can reduce future drift.

apps/marketing/src/app/sitemap.ts (1)

61-67: Extract the comparison priority into a named constant.

Line 66 introduces 0.7 as a magic number; pulling it to a module-level constant improves clarity and reuse.

As per coding guidelines: Avoid magic numbers by extracting them to named constants at module top.

♻️ Proposed change
+const COMPARISON_PAGE_PRIORITY = 0.7;
+
 export default function sitemap(): MetadataRoute.Sitemap {
 	const baseUrl = COMPANY.MARKETING_URL;
@@
 	const comparisonPages: MetadataRoute.Sitemap = getComparisonPages().map(
 		(page) => ({
 			url: `${baseUrl}/compare/${page.slug}`,
 			lastModified: new Date(page.lastUpdated || page.date),
 			changeFrequency: "monthly" as const,
-			priority: 0.7,
+			priority: COMPARISON_PAGE_PRIORITY,
 		}),
 	);
apps/marketing/src/app/compare/[slug]/components/CompareLayout/CompareLayout.tsx (1)

20-24: Extract grid offset magic numbers to constants.

Lines 22-24 hardcode 384/383 in the gradient string; using named constants makes the layout intent clearer and easier to tweak.

As per coding guidelines: Avoid magic numbers by extracting them to named constants at module top.

♻️ Proposed change
+const GRID_LINE_OFFSET = 384;
+const GRID_LINE_OFFSET_INNER = GRID_LINE_OFFSET - 1;
+const GRID_BACKGROUND = `
+	linear-gradient(
+		to right,
+		transparent 0%,
+		transparent calc(50% - ${GRID_LINE_OFFSET}px),
+		rgba(255,255,255,0.06) calc(50% - ${GRID_LINE_OFFSET}px),
+		rgba(255,255,255,0.06) calc(50% - ${GRID_LINE_OFFSET_INNER}px),
+		transparent calc(50% - ${GRID_LINE_OFFSET_INNER}px),
+		transparent calc(50% + ${GRID_LINE_OFFSET_INNER}px),
+		rgba(255,255,255,0.06) calc(50% + ${GRID_LINE_OFFSET_INNER}px),
+		rgba(255,255,255,0.06) calc(50% + ${GRID_LINE_OFFSET}px),
+		transparent calc(50% + ${GRID_LINE_OFFSET}px)
+	)
+`;
+
 export function CompareLayout({ page, children }: CompareLayoutProps) {
 	const formattedDate = formatCompareDate(page.lastUpdated ?? page.date);
@@
 			<div
 				className="absolute inset-0 pointer-events-none"
 				style={{
-					backgroundImage: `
-						linear-gradient(to right, transparent 0%, transparent calc(50% - 384px), rgba(255,255,255,0.06) calc(50% - 384px), rgba(255,255,255,0.06) calc(50% - 383px), transparent calc(50% - 383px), transparent calc(50% + 383px), rgba(255,255,255,0.06) calc(50% + 383px), rgba(255,255,255,0.06) calc(50% + 384px), transparent calc(50% + 384px))
-					`,
+					backgroundImage: GRID_BACKGROUND,
 				}}
 			/>
apps/marketing/src/components/JsonLd/JsonLd.tsx (1)

105-112: Document why optional JSON-LD props are optional.

modifiedTime and image are optional but not documented. A short rationale keeps the interface self-explanatory.

As per coding guidelines: Make dependencies required in interfaces unless truly optional; document why if optional.

♻️ Proposed change
 interface ComparisonJsonLdProps {
 	title: string;
 	description: string;
 	publishedTime: string;
-	modifiedTime?: string;
+	/** Optional; falls back to publishedTime when not provided. */
+	modifiedTime?: string;
 	url: string;
-	image?: string;
+	/** Optional; include only when a canonical image exists. */
+	image?: string;
 }

Comment on lines +218 to +268
### 1v1 Comparison Template
```
1. Hero: "[Tool A] vs [Tool B]" + one-sentence summary
2. TL;DR comparison table (5-7 key dimensions)
3. What is [Tool A]? (1-2 paragraphs)
4. What is [Tool B]? (1-2 paragraphs)
5. Detailed comparison sections (3-5 sections):
- Agent approach / AI capabilities
- Developer experience & workflow
- Pricing & plans
- Privacy & security
- Best for (use cases)
6. When to use [Tool A] vs [Tool B] (decision framework)
7. Can you use both? (complementary angle)
8. Verdict / Recommendation
9. FAQ section (3-5 questions — good for featured snippets)
10. CTA: Try Superset
```

### Category Roundup Template
```
1. Hero: "Best [Category] in 2026" + one-sentence summary
2. Quick comparison table (all tools, 5-7 dimensions)
3. Tool-by-tool breakdown (each with pros/cons/pricing/best for)
4. How to choose: decision framework
5. The orchestration approach (positions Superset)
6. FAQ section
7. CTA: Try Superset
```

---

## Implementation Plan

### Route Structure

Pages live under `/compare/[slug]` in the marketing app:

```
apps/marketing/
├── content/
│ └── compare/ # NEW: MDX content files
│ ├── superset-vs-warp.mdx
│ ├── superset-vs-cursor.mdx
│ ├── best-ai-coding-agent-tools.mdx
│ ├── superset-vs-devin.mdx
│ ├── multiple-claude-code-agents-parallel.mdx
│ ├── superset-vs-github-copilot.mdx
│ ├── best-terminal-for-ai-coding.mdx
│ ├── superset-vs-conductor.mdx
│ └── superset-vs-openai-codex.mdx
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add language identifiers to fenced code blocks.

markdownlint MD040 flags the template and tree fences—add a language hint (e.g., text) to silence the warning.

✍️ Proposed change
-```
+```text
 1. Hero: "[Tool A] vs [Tool B]" + one-sentence summary
@@
-```
+```

-```
+```text
 1. Hero: "Best [Category] in 2026" + one-sentence summary
@@
-```
+```

-```
+```text
 apps/marketing/
 ├── content/
@@
-```
+```
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 219-219: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 238-238: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 256-256: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In `@apps/marketing/docs/SEO_COMPARISON_PAGES_PLAN.md` around lines 218 - 268, The
markdownlint MD040 warning is triggered by unlabeled fenced code blocks in
SEO_COMPARISON_PAGES_PLAN.md; fix it by adding a language identifier (e.g.,
text) to the opening fences of each template/code-tree block — replace the three
opening "```" fences that precede "1. Hero:..." (1v1 template), "1. Hero: 'Best
[Category]...'" (Category Roundup template), and the "apps/marketing/" directory
tree block with "```text" so each fenced block begins with ```text and keeps the
existing closing ``` fences unchanged.

Comment on lines +47 to +48
} catch {
return null;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t swallow frontmatter parse errors.
The catch block returns null without context, which hides content issues during builds and runtime.

Suggested update
-	} catch {
-		return null;
-	}
+	} catch (error) {
+		console.error("[compare/parseFrontmatter] Failed to parse comparison frontmatter", {
+			filePath,
+			error,
+		});
+		return null;
+	}

As per coding guidelines: Never swallow errors silently; at minimum log them with context; Use prefixed console logging with pattern [domain/operation] message for all logging.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch {
return null;
} catch (error) {
console.error("[compare/parseFrontmatter] Failed to parse comparison frontmatter", {
filePath,
error,
});
return null;
}
🤖 Prompt for AI Agents
In `@apps/marketing/src/lib/compare.ts` around lines 47 - 48, The catch block
currently swallows frontmatter parse errors; update the catch to capture the
error (e.g., catch (err)) and log it using the prefixed pattern (for example
console.error(`[compare/parseFrontmatter] Failed to parse frontmatter for
${filePath || id || source}:`, err)) so errors are visible, then continue to
return null if that’s the intended fallback; modify the catch around the
frontmatter parsing code in compare.ts accordingly.

Comment on lines +70 to +74
export function getComparisonPage(slug: string): ComparisonPage | undefined {
const filePath = path.join(COMPARE_DIR, `${slug}.mdx`);

if (!fs.existsSync(filePath)) {
return undefined;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate slug before building the file path.
slug is used directly in path.join; if it contains path separators or .., it can read outside content/compare. Add a strict allowlist or resolved-path check.

Suggested update
 const COMPARE_DIR = path.join(process.cwd(), "content/compare");
+const SAFE_SLUG = /^[a-z0-9-]+$/i;

 export function getComparisonPage(slug: string): ComparisonPage | undefined {
+	if (!SAFE_SLUG.test(slug)) {
+		return undefined;
+	}
 	const filePath = path.join(COMPARE_DIR, `${slug}.mdx`);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function getComparisonPage(slug: string): ComparisonPage | undefined {
const filePath = path.join(COMPARE_DIR, `${slug}.mdx`);
if (!fs.existsSync(filePath)) {
return undefined;
const SAFE_SLUG = /^[a-z0-9-]+$/i;
export function getComparisonPage(slug: string): ComparisonPage | undefined {
if (!SAFE_SLUG.test(slug)) {
return undefined;
}
const filePath = path.join(COMPARE_DIR, `${slug}.mdx`);
if (!fs.existsSync(filePath)) {
return undefined;
🤖 Prompt for AI Agents
In `@apps/marketing/src/lib/compare.ts` around lines 70 - 74, The
getComparisonPage function builds filePath from slug without validation,
allowing path traversal; validate the slug before using it (e.g., enforce an
allowlist regex like only alphanumeric, dashes/underscores, no path separators
or '..') or sanitize by resolving the path (use
path.resolve(path.join(COMPARE_DIR, `${slug}.mdx`)) and then assert the resolved
path startsWith the resolved COMPARE_DIR) and return undefined (or throw) if
validation fails; update getComparisonPage to perform this check before calling
fs.existsSync and reading the file.

…ctor, and Warp

- Add /compare/[slug] dynamic route with MDX rendering, JSON-LD, and sitemap integration
- Add remark-gfm for markdown table support in MDX
- Add prose table styles to globals.css
- Trim comparison content to ~800 words each with accurate pricing ($20/seat/mo Pro tier)
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/marketing/content/compare/superset-vs-cursor.mdx`:
- Line 25: Update the table row that currently lists "Claude 4.5 Sonnet" and
"GPT-5" under the Cursor column: replace "Claude 4.5 Sonnet" with the confirmed
name "Claude 4 Sonnet", remove or replace the unverified "GPT-5" entry (either
list the confirmed "gpt-4.1" / "standard models" or a note like "model
availability may vary"), and keep "Gemini 2.5 Pro" as-is; edit the table cell in
the line containing "Agent-agnostic — works with Claude Code..." so the Cursor
models reflect only confirmed names.

In `@apps/marketing/docs/SEO_COMPARISON_PAGES_PLAN.md`:
- Line 151: Update the target keywords line so the GitHub brand is capitalized
correctly: change the keyword string "github copilot alternative" to "GitHub
copilot alternative" (and scan the document for other occurrences of "github" in
the target keywords or prose to replace with "GitHub" for consistent
capitalization).

| | **Superset** | **Cursor** |
|---|---|---|
| **Category** | Agent orchestration terminal | AI code editor (VS Code fork) |
| **AI approach** | Agent-agnostic — works with Claude Code, Codex, Aider, or any CLI agent | Built-in models (GPT-5, Claude 4.5 Sonnet, Gemini 2.5 Pro) proxied through Cursor servers |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n apps/marketing/content/compare/superset-vs-cursor.mdx | head -50

Repository: superset-sh/superset

Length of output: 2975


🌐 Web query:

Cursor IDE 2026 supported AI models GPT-5 Claude Gemini

💡 Result:

Cursor IDE (Feb 2026): support for GPT / Claude / Gemini

  • Claude (Anthropic): Supported. Cursor’s model guides explicitly recommend and reference Claude 4 Sonnet and Claude 4 Opus. [1] Cursor also states you can use all Claude models available via the Anthropic API when you add your own API key. [2]
  • Gemini (Google): Supported. Cursor’s model guides explicitly reference Gemini 2.5 Pro (and note Max Mode relevance for Gemini 2.5 Flash/Pro). [1][3] Cursor also supports Gemini models via the Google AI API when you add your own API key. [2]
  • GPT-5 (OpenAI): Not confirmed in Cursor’s official docs (from the sources above). Cursor’s docs do confirm OpenAI model support generally (e.g., gpt-4.1 is referenced), but for custom OpenAI API keys Cursor notes it supports “standard, non-reasoning chat models only” and that the model picker will show which OpenAI models are available—so GPT-5 availability depends on what Cursor exposes in-app and whether GPT-5 qualifies under that constraint. [1][2]

Practical check: In Cursor, open Cursor Settings → Models (or the model dropdown) and see whether GPT-5 appears; that’s the definitive answer for your installation/account. [2]

Sources:
[1] Cursor docs – Selecting models (mentions claude-4-sonnet, claude-4-opus, gemini-2.5-pro, gpt-4.1) (docs.cursor.com)
[2] Cursor docs – API Keys (supported providers; OpenAI “standard, non-reasoning chat models only”; Anthropic/Google support) (docs.cursor.com)
[3] Cursor docs – Models (Max Mode relevance for Gemini 2.5 Flash/Pro; frontier models note) (docs.cursor.com)

Citations:


Correct model names in the Cursor comparison.

Line 25 contains inaccurate model names. Per Cursor's official documentation:

  • "Claude 4.5 Sonnet" should be "Claude 4 Sonnet" (official docs reference Claude 4 Sonnet and Claude 4 Opus, not 4.5)
  • "GPT-5" is not confirmed in Cursor's official documentation (docs reference gpt-4.1 and standard models only; GPT-5 availability is unverified)
  • "Gemini 2.5 Pro" is correct ✓

Update the table entry to reflect only confirmed models available through Cursor servers, or note that model availability may vary.

🤖 Prompt for AI Agents
In `@apps/marketing/content/compare/superset-vs-cursor.mdx` at line 25, Update the
table row that currently lists "Claude 4.5 Sonnet" and "GPT-5" under the Cursor
column: replace "Claude 4.5 Sonnet" with the confirmed name "Claude 4 Sonnet",
remove or replace the unverified "GPT-5" entry (either list the confirmed
"gpt-4.1" / "standard models" or a note like "model availability may vary"), and
keep "Gemini 2.5 Pro" as-is; edit the table cell in the line containing
"Agent-agnostic — works with Claude Code..." so the Cursor models reflect only
confirmed names.

- **Why**: This targets Claude Code's active user base directly. High purchase intent — these users already use coding agents and want to do more.

#### Page 6: Superset vs GitHub Copilot
- **Target keywords**: "superset vs copilot", "github copilot alternative", "copilot alternative for coding agents"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Capitalize "GitHub" consistently.

The target keyword uses lowercase "github" but should be "GitHub" for brand consistency in the prose.

-- **Target keywords**: "superset vs copilot", "github copilot alternative", "copilot alternative for coding agents"
+- **Target keywords**: "superset vs copilot", "GitHub Copilot alternative", "copilot alternative for coding agents"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Target keywords**: "superset vs copilot", "github copilot alternative", "copilot alternative for coding agents"
- **Target keywords**: "superset vs copilot", "GitHub Copilot alternative", "copilot alternative for coding agents"
🧰 Tools
🪛 LanguageTool

[uncategorized] ~151-~151: The official name of this software platform is spelled with a capital “H”.
Context: ...get keywords**: "superset vs copilot", "github copilot alternative", "copilot alternat...

(GITHUB)

🤖 Prompt for AI Agents
In `@apps/marketing/docs/SEO_COMPARISON_PAGES_PLAN.md` at line 151, Update the
target keywords line so the GitHub brand is capitalized correctly: change the
keyword string "github copilot alternative" to "GitHub copilot alternative" (and
scan the document for other occurrences of "github" in the target keywords or
prose to replace with "GitHub" for consistent capitalization).

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 3, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch
  • ✅ Electric Fly.io app

Thank you for your contribution! 🎉

@saddlepaddle saddlepaddle merged commit 33fb94f into main Feb 3, 2026
13 checks passed
@Kitenite Kitenite deleted the research-competitors-and-plan-seo-comparison-pages branch February 7, 2026 02:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant