diff --git a/apps/site/src/lib/seo.ts b/apps/site/src/lib/seo.ts index 7891cbe2a..0232bed67 100644 --- a/apps/site/src/lib/seo.ts +++ b/apps/site/src/lib/seo.ts @@ -172,15 +172,20 @@ export function freeSoftwareSchema({ }; } -/** The pricing page: coss.com with its self-serve plans. */ +/** + * The pricing page: coss.com with its self-serve plans. Not a schema.org `Product`: Google reads + * one as a shop's merchant listing, and refuses it for having no image. + */ export function pricingSchema(description: string) { return { "@context": "https://schema.org", - "@type": "Product", + "@type": "SoftwareApplication", name: SITE_NAME, description, url: abs("/pricing"), - brand: { "@id": ORGANIZATION_ID }, + applicationCategory: "DeveloperApplication", + operatingSystem: "Any (HTTPS API)", + provider: { "@id": ORGANIZATION_ID }, offers: offers(), }; } diff --git a/apps/site/test/seo.test.ts b/apps/site/test/seo.test.ts index 138dab5da..ea1d938d5 100644 --- a/apps/site/test/seo.test.ts +++ b/apps/site/test/seo.test.ts @@ -14,7 +14,7 @@ import { withoutNestedFolders } from "../src/lib/docs-tree"; import { ALL_PRODUCT_LINKS, FOOTER_COLUMNS } from "../src/lib/nav"; import { singleOperationProps } from "../src/lib/openapi-single-operation"; import { rateTables } from "../src/lib/pricing"; -import { metaDescription } from "../src/lib/seo"; +import { metaDescription, pricingSchema } from "../src/lib/seo"; import { markdownResponse, PRODUCTS, SITE_DESCRIPTION } from "../src/lib/site"; import { FREE_TOOLS } from "../src/lib/tools"; @@ -273,3 +273,7 @@ describe("changelog", () => { for (const entry of CHANGELOG) expect(markdown).toContain(entry.title); }); }); + +test("the pricing page isn't a merchant listing, which Google refuses without an image", () => { + expect(pricingSchema("Plans.")["@type"]).toBe("SoftwareApplication"); +});