Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/web-roo-code/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from "@/components/homepage"
import { EXTERNAL_LINKS } from "@/lib/constants"
import { ArrowRight } from "lucide-react"
import { StructuredData } from "@/components/structured-data"

// Invalidate cache when a request comes in, at most once every hour.
export const revalidate = 3600
Expand All @@ -23,6 +24,7 @@ export default async function Home() {

return (
<>
<StructuredData />
Copy link

Choose a reason for hiding this comment

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

P3: Optional: If you want JSON-LD on all routes, consider rendering StructuredData in the root layout instead of the home page to avoid duplication and ensure consistency.

<section className="relative flex h-[calc(125vh-theme(spacing.12))] items-center overflow-hidden md:h-[calc(80svh-theme(spacing.12))]">
<AnimatedBackground />
<div className="container relative flex items-center h-full z-10 mx-auto px-4 sm:px-6 lg:px-8">
Expand Down
27 changes: 27 additions & 0 deletions apps/web-roo-code/src/components/structured-data.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getStructuredData } from "@/lib/structured-data"

/**
* StructuredData Component
*
* Renders JSON-LD structured data in the document head for SEO.
* This component should only be used once per page, typically in the root layout.
Copy link

Choose a reason for hiding this comment

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

P3: The usage note suggests root layout; this PR uses it on the homepage. Adjust wording to reduce confusion.

Suggested change
* This component should only be used once per page, typically in the root layout.
* Use once per page. For sitewide JSON-LD, include it in the root layout; for page-specific JSON-LD, include it in that page component.

*
* The structured data includes:
* - Organization information (brand, logo, social profiles)
* - WebSite metadata (site name for Google Search)
* - SoftwareApplication details (VS Code extension)
*
* @see https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data
*/
export function StructuredData() {
const structuredData = getStructuredData()

return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(structuredData),
}}
/>
)
}
2 changes: 1 addition & 1 deletion apps/web-roo-code/src/lib/seo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://roocode.com"
export const SEO = {
url: SITE_URL,
name: "Roo Code",
title: "Roo Code – Your AI-Powered Dev Team in VS Code and Beyond",
title: "Roo Code – The AI dev team that gets things done",
description:
"Roo Code puts an entire AI dev team right in your editor, outpacing closed tools with deep project-wide context, multi-step agentic coding, and unmatched developer-centric flexibility.",
locale: "en_US",
Expand Down
127 changes: 127 additions & 0 deletions apps/web-roo-code/src/lib/structured-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { SEO } from "./seo"
import { EXTERNAL_LINKS } from "./constants"

/**
* Type definitions for Schema.org structured data
*/
interface ImageObject {
"@type": "ImageObject"
url: string
width: number
height: number
}

interface Organization {
"@type": "Organization"
"@id": string
name: string
url: string
logo: ImageObject
alternateName: string[]
sameAs: string[]
}

interface WebSite {
"@type": "WebSite"
"@id": string
url: string
name: string
alternateName: string[]
publisher: { "@id": string }
}

interface SoftwareApplication {
"@type": "SoftwareApplication"
"@id": string
name: string
applicationCategory: string
operatingSystem: string
url: string
downloadUrl: string
offers: {
"@type": "Offer"
price: string
priceCurrency: string
}
isAccessibleForFree: boolean
publisher: { "@id": string }
}

interface StructuredDataGraph {
"@context": "https://schema.org"
"@graph": [Organization, WebSite, SoftwareApplication]
}

/**
* Generates the complete JSON-LD structured data for SEO
*
* This includes:
* - Organization schema (brand identity, logo, social profiles)
* - WebSite schema (site name for Google Search)
* - SoftwareApplication schema (VS Code extension metadata)
*
* @returns Complete structured data object ready for JSON-LD injection
*/
export function getStructuredData(): StructuredDataGraph {
// Organization ID - used to link all entities
const orgId = `${SEO.url}#org`
Copy link

Choose a reason for hiding this comment

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

P2: Ensure consistent @id with a single slash before the fragment and avoid double slashes if SEO.url ends with '/'.

Suggested change
const orgId = `${SEO.url}#org`
const orgId = `${SEO.url.replace(/\/$/, '')}/#org`


const organization: Organization = {
"@type": "Organization",
"@id": orgId,
name: SEO.name,
url: SEO.url,
logo: {
"@type": "ImageObject",
url: `${SEO.url}/android-chrome-512x512.png`,
width: 512,
height: 512,
},
alternateName: ["RooCode", "Roo Code AI"],
sameAs: [
EXTERNAL_LINKS.GITHUB,
EXTERNAL_LINKS.MARKETPLACE,
EXTERNAL_LINKS.X,
EXTERNAL_LINKS.LINKEDIN,
EXTERNAL_LINKS.REDDIT,
EXTERNAL_LINKS.DISCORD,
EXTERNAL_LINKS.YOUTUBE,
],
}

const website: WebSite = {
"@type": "WebSite",
"@id": `${SEO.url}#website`,
Copy link

Choose a reason for hiding this comment

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

P2: Normalize WebSite @id similar to org.

Suggested change
"@id": `${SEO.url}#website`,
"@id": `${SEO.url.replace(/\/$/, '')}/#website`,

url: SEO.url,
name: SEO.name,
alternateName: ["RooCode"],
publisher: { "@id": orgId },
}

const softwareApplication: SoftwareApplication = {
"@type": "SoftwareApplication",
"@id": `${SEO.url}#vscode-extension`,
Copy link

Choose a reason for hiding this comment

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

P2: Normalize SoftwareApplication @id similar to org.

Suggested change
"@id": `${SEO.url}#vscode-extension`,
"@id": `${SEO.url.replace(/\/$/, '')}/#vscode-extension`,

name: "Roo Code (VS Code extension)",
applicationCategory: "DeveloperApplication",
operatingSystem: "Windows, macOS, Linux",
url: SEO.url,
downloadUrl: EXTERNAL_LINKS.MARKETPLACE,
offers: {
"@type": "Offer",
price: "0",
priceCurrency: "USD",
},
isAccessibleForFree: true,
publisher: { "@id": orgId },
}

return {
"@context": "https://schema.org",
"@graph": [organization, website, softwareApplication],
}
}

/**
* Type export for use in components
*/
export type { StructuredDataGraph }
2 changes: 1 addition & 1 deletion src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"type": "git",
"url": "https://github.com/RooCodeInc/Roo-Code"
},
"homepage": "https://github.com/RooCodeInc/Roo-Code",
"homepage": "https://roocode.com",
"categories": [
"AI",
"Chat",
Expand Down