Skip to content

Commit 1e6394c

Browse files
vfanucciclaude
andauthored
seo: add SoftwareApplication schema on homepage, enterprise, pricing, features (#4821)
* seo: add SoftwareApplication schema on homepage, enterprise, pricing, features Adds a reusable SchemaSoftwareApplication.astro component and injects it on the four highest-traffic product pages. Gives AI agents and search crawlers a machine-parseable description of Kestra as a software product, including category, license, supported platforms, and offers per tier. Identified as priority 1 in the Agents Taskforce Pillar 1 audit. * fix(schema): address @id collision and stale softwareVersion (Piyush review) - Make SchemaSoftwareApplication @id parameterizable via prop (default remains #software for the home page). - Enterprise page now declares a distinct entity @id=#enterprise-edition with isVariantOf -> #software, so JSON-LD parsers no longer see four contradictory definitions sharing the same @id. - Remove the component from /pricing (already covered by the page-level Product+Offer pricingSchema) and /features (no unique entity to declare). - Drop the hardcoded "softwareVersion": "1.0" — stale value that drifts from the real Kestra release. Field is optional and best omitted. - Tighten operatingSystem to actual OSes (Linux, macOS, Windows). Docker and Kubernetes are deployment targets, not operating systems. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(schema): replace broken Product schema on /pricing with SchemaSoftwareApplication; add to /features The previous decision to leave the existing Product+Offer block on /pricing was based on the assumption it already covered the page. Google Rich Results Test shows otherwise: the Product schema triggers Merchant Listing validation rules (image, priceValidUntil, hasMerchantReturnPolicy, shippingDetails), producing 6 errors — none of which apply to a SaaS pricing page. - /pricing: drop the inline pricingSchema (3x Product) and emit the canonical #software entity via SchemaSoftwareApplication. The component's built-in offers array already declares all three tiers (Open Source, Cloud, Enterprise), so no information is lost and Google validates cleanly under SoftwareApplication rules. - /features: add SchemaSoftwareApplication so the page is no longer schema-silent (was only emitting BreadcrumbList + Organization). - Component: bump default description from "1200+ plugins" to "1400+ plugins" to match the live homepage copy. Completes the original PR scope (homepage + enterprise + pricing + features) and eliminates the Merchant Listing validation errors. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 468c8b8 commit 1e6394c

5 files changed

Lines changed: 93 additions & 65 deletions

File tree

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
interface Props {
3+
id?: string
4+
name?: string
5+
description?: string
6+
url?: string
7+
isVariantOf?: string
8+
}
9+
10+
const { id, name, description, url, isVariantOf } = Astro.props
11+
12+
const canonicalUrl =
13+
url ?? new URL(Astro.url.pathname, Astro.site ?? "https://kestra.io").toString().replace(/\/$/, "")
14+
15+
const schema: Record<string, unknown> = {
16+
"@context": "https://schema.org",
17+
"@type": "SoftwareApplication",
18+
"@id": id ?? "https://kestra.io/#software",
19+
"name": name ?? "Kestra",
20+
"url": canonicalUrl,
21+
"description":
22+
description ??
23+
"Open-source workflow orchestration platform for data pipelines, infrastructure automation, and AI workflows. YAML-native, language-agnostic, 1400+ plugins.",
24+
"applicationCategory": "DeveloperApplication",
25+
"applicationSubCategory": "Workflow Orchestration",
26+
"operatingSystem": "Linux, macOS, Windows",
27+
"downloadUrl": "https://github.com/kestra-io/kestra",
28+
"author": { "@id": "https://kestra.io/#organization" },
29+
"publisher": { "@id": "https://kestra.io/#organization" },
30+
"license": "https://www.apache.org/licenses/LICENSE-2.0",
31+
"offers": [
32+
{
33+
"@type": "Offer",
34+
"name": "Kestra Open Source",
35+
"price": "0",
36+
"priceCurrency": "USD",
37+
"availability": "https://schema.org/InStock",
38+
"url": "https://github.com/kestra-io/kestra",
39+
},
40+
{
41+
"@type": "Offer",
42+
"name": "Kestra Cloud",
43+
"priceSpecification": {
44+
"@type": "UnitPriceSpecification",
45+
"priceType": "https://schema.org/InvoicePrice",
46+
"description": "Pay only for what you use",
47+
},
48+
"availability": "https://schema.org/InStock",
49+
"url": "https://kestra.io/pricing",
50+
},
51+
{
52+
"@type": "Offer",
53+
"name": "Kestra Enterprise Edition",
54+
"priceSpecification": {
55+
"@type": "UnitPriceSpecification",
56+
"priceType": "https://schema.org/InvoicePrice",
57+
"description": "Annual subscription — contact sales",
58+
},
59+
"availability": "https://schema.org/InStock",
60+
"url": "https://kestra.io/demo",
61+
},
62+
],
63+
}
64+
65+
if (isVariantOf) {
66+
schema.isVariantOf = { "@id": isVariantOf }
67+
}
68+
---
69+
70+
<script type="application/ld+json" set:html={JSON.stringify(schema)} />

src/pages/enterprise/index.astro

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
import Layout from "~/components/layout.astro"
3+
import SchemaSoftwareApplication from "~/components/common/SchemaSoftwareApplication.astro"
34
45
import Hero from "~/components/enterprise/Hero.vue"
56
import SeeHow from "~/components/common/SeeHow.astro"
@@ -39,6 +40,15 @@ const STATS = [
3940
---
4041

4142
<Layout {title} {description} headerTheme="lightText">
43+
<Fragment slot="head">
44+
<SchemaSoftwareApplication
45+
id="https://kestra.io/#enterprise-edition"
46+
name="Kestra Enterprise Edition"
47+
description="Kestra Enterprise is a workflow orchestration platform for engineering teams running mission-critical operations at scale. Built-in governance, enterprise security, SSO, RBAC, audit logs, and horizontal scalability. Self-hosted or managed."
48+
url="https://kestra.io/enterprise"
49+
isVariantOf="https://kestra.io/#software"
50+
/>
51+
</Fragment>
4252
<Hero client:load />
4353
<div class="enterprise">
4454
<ScrollSpy client:load />

src/pages/features/index.astro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
import Faq from "~/components/common/Faq.vue"
33
import Layout from "~/components/layout.astro"
4+
import SchemaSoftwareApplication from "~/components/common/SchemaSoftwareApplication.astro"
45
import Run from "~/components/features/core/Run.astro"
56
import Stacked from "~/components/common/Stacked.astro"
67
import Intro from "~/components/features/core/Intro.astro"
@@ -49,6 +50,9 @@ const items = [
4950
---
5051

5152
<Layout {title} {description} headerTheme="lightText">
53+
<Fragment slot="head">
54+
<SchemaSoftwareApplication url="https://kestra.io/features" />
55+
</Fragment>
5256
<div class="core">
5357
<Intro />
5458
<Simple />

src/pages/index.astro

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
import Layout from "~/components/layout.astro"
3+
import SchemaSoftwareApplication from "~/components/common/SchemaSoftwareApplication.astro"
34
import Hero from "~/components/home/Hero.astro"
45
import Comparison from "~/components/home/Comparison.astro"
56
import Stacked from "~/components/common/Stacked.astro"
@@ -16,6 +17,11 @@ const totalPlugins = await fetchTotalPluginsCount()
1617
---
1718

1819
<Layout headerTheme="darkHeader">
20+
<Fragment slot="head">
21+
<SchemaSoftwareApplication
22+
url="https://kestra.io"
23+
/>
24+
</Fragment>
1925
<div class="home-page">
2026
<Hero />
2127
<Comparison />

src/pages/pricing/index.astro

Lines changed: 3 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
import Layout from "~/components/layout.astro"
3+
import SchemaSoftwareApplication from "~/components/common/SchemaSoftwareApplication.astro"
34
import Header from "~/components/price/Header.astro"
45
import HostSwitcher from "~/components/price/HostSwitcher.astro"
56
import PriceGrid from "~/components/price/PriceGrid.astro"
@@ -10,74 +11,11 @@ import PriceQuote from "~/components/price/PriceQuote.vue"
1011
const title = "Kestra Pricing: Open Source, Cloud & Enterprise Plans"
1112
const description =
1213
"Choose the right plan for your needs. Start with the Open Source version and scale with the Enterprise Edition of Kestra."
13-
14-
const pricingSchema = {
15-
"@context": "https://schema.org",
16-
"@graph": [
17-
{
18-
"@type": "Product",
19-
"@id": "https://kestra.io/pricing#open-source",
20-
"name": "Kestra Open Source",
21-
"url": "https://kestra.io/pricing",
22-
"description":
23-
"Self-hosted orchestration platform with 1,400+ plugins, unlimited flows and executions, AI Copilot, event-driven scheduling, and multi-cloud deployment.",
24-
"brand": { "@id": "https://kestra.io/#organization" },
25-
"offers": {
26-
"@type": "Offer",
27-
"price": "0",
28-
"priceCurrency": "USD",
29-
"availability": "https://schema.org/InStock",
30-
"url": "https://github.com/kestra-io/kestra",
31-
},
32-
},
33-
{
34-
"@type": "Product",
35-
"@id": "https://kestra.io/pricing#cloud",
36-
"name": "Kestra Cloud",
37-
"url": "https://kestra.io/pricing",
38-
"description":
39-
"Fully managed Kestra platform with automatic scaling, built-in security, enterprise plugins, SOC2 compliance, and pay-as-you-scale pricing.",
40-
"brand": { "@id": "https://kestra.io/#organization" },
41-
"offers": {
42-
"@type": "Offer",
43-
"priceSpecification": {
44-
"@type": "UnitPriceSpecification",
45-
"priceType": "https://schema.org/InvoicePrice",
46-
"description": "Pay only for what you use",
47-
},
48-
"availability": "https://schema.org/InStock",
49-
"url": "https://kestra.io/pricing",
50-
},
51-
},
52-
{
53-
"@type": "Product",
54-
"@id": "https://kestra.io/pricing#enterprise",
55-
"name": "Kestra Enterprise Edition",
56-
"url": "https://kestra.io/pricing",
57-
"description":
58-
"Enterprise-grade orchestration with SSO, LDAP/SCIM, custom RBAC, audit logs, worker groups, multi-tenant support, AI Copilot with any LLM, and enterprise SLA.",
59-
"brand": { "@id": "https://kestra.io/#organization" },
60-
"offers": {
61-
"@type": "Offer",
62-
"priceSpecification": {
63-
"@type": "UnitPriceSpecification",
64-
"priceType": "https://schema.org/InvoicePrice",
65-
"description": "Annual subscription — contact sales",
66-
},
67-
"availability": "https://schema.org/InStock",
68-
"url": "https://kestra.io/demo",
69-
},
70-
},
71-
],
72-
}
7314
---
7415

7516
<Layout {title} {description}>
7617
<Fragment slot="head">
77-
<script
78-
type="application/ld+json"
79-
set:html={JSON.stringify(pricingSchema)}
80-
/>
18+
<SchemaSoftwareApplication url="https://kestra.io/pricing" />
8119
</Fragment>
8220
<div class="cont">
8321
<Header>
@@ -94,4 +32,4 @@ const pricingSchema = {
9432
.cont {
9533
overflow: clip;
9634
}
97-
</style>
35+
</style>

0 commit comments

Comments
 (0)