Skip to content

Commit ba97896

Browse files
ankur-archclaude
andcommitted
seo: make Google show "Prisma" as the site name, not "Prisma ORM"
Searching for "prisma" returned the prisma.io homepage titled "Prisma ORM". That string appears nowhere in the homepage's metadata β€” Google was rewriting the title link, because the title it was given, "Agent Infrastructure for TypeScript", contains no brand at all. When a title doesn't identify the site, Google substitutes other signals, chiefly inbound anchor text, and nearly everything linking to prisma.io calls it "Prisma ORM". Three things were feeding the rewrite: - The homepage title carried no brand, and page titles across the site were inconsistent about it β€” some ended in "| Prisma", most had nothing. - Docs and blog each declared their own schema.org WebSite entity ("Prisma Documentation", "Prisma Blog") alongside the canonical one in apps/site, so the domain offered Google three competing candidates for its site name. - Docs and blog emitted no og:site_name, leaving apps/site as the only section of the domain asserting the brand. So: - Homepage title is now brand-first, "Prisma | Agent Infrastructure for TypeScript", per Google's guidance for homepages. - createPageMetadata appends "| Prisma" to any title that doesn't already contain it, which brands the ~30 pages that lacked it while leaving "Prisma ORM | Type-Safe ORM..." and friends untouched. - Docs and blog no longer declare WebSite entities. Docs is a CollectionPage and the blog is a Blog, both isPartOf the one WebSite in apps/site. The docs node dropped its SearchAction along the way; that drove the sitelinks search box, which Google has retired. - Docs and blog set og:site_name to "Prisma", matching apps/site. Verified by rendering all three apps: the homepage titles as "Prisma | Agent Infrastructure for TypeScript", /terms as "Terms of Service | Prisma", /orm unchanged, and docs/blog emit a single WebSite plus og:site_name "Prisma". Note that this only removes our own conflicting signals. Google recrawls and re-evaluates the site name on its own schedule, so the SERP change will lag the deploy by days to weeks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent b6806c8 commit ba97896

13 files changed

Lines changed: 58 additions & 18 deletions

File tree

β€Žapps/blog/src/app/(blog)/[slug]/page.tsxβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ export async function generateMetadata({
333333
canonical: withBlogBasePath(page.url),
334334
},
335335
openGraph: {
336+
siteName: "Prisma",
336337
title,
337338
description,
338339
url: withBlogBasePath(page.url),

β€Žapps/blog/src/app/(blog)/author/[slug]/page.tsxβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ export async function generateMetadata({
143143
description,
144144
alternates: { canonical: withBlogBasePath(`/author/${profile.slug}`) },
145145
openGraph: {
146+
siteName: "Prisma",
146147
type: "website",
147148
title,
148149
description,

β€Žapps/blog/src/app/(blog)/page.tsxβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export async function generateMetadata(): Promise<Metadata> {
3333
canonical: withBlogBasePath("/"),
3434
},
3535
openGraph: {
36+
siteName: "Prisma",
3637
type: "website",
3738
title: BLOG_HOME_TITLE,
3839
description: BLOG_HOME_DESCRIPTION,

β€Žapps/blog/src/app/(blog)/series/[key]/page.tsxβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ export async function generateMetadata({
143143
description,
144144
alternates: { canonical: withBlogBasePath(`/series/${key}`) },
145145
openGraph: {
146+
siteName: "Prisma",
146147
type: "website",
147148
title,
148149
description,

β€Žapps/blog/src/app/(blog)/series/page.tsxβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export async function generateMetadata(): Promise<Metadata> {
1919
description: PAGE_DESCRIPTION,
2020
alternates: { canonical: withBlogBasePath("/series") },
2121
openGraph: {
22+
siteName: "Prisma",
2223
type: "website",
2324
title,
2425
description: PAGE_DESCRIPTION,

β€Žapps/blog/src/lib/structured-data.tsβ€Ž

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,17 @@ export function createBlogStructuredData() {
2626
],
2727
},
2828
{
29-
"@type": "WebSite",
30-
"@id": `${blogUrl}#website`,
29+
// The blog is a section of prisma.io, not a site of its own. It used to
30+
// declare its own WebSite, which competed with the canonical one in
31+
// apps/site for the site name Google shows.
32+
"@type": "Blog",
33+
"@id": `${blogUrl}#blog`,
3134
name: "Prisma Blog",
3235
url: blogUrl,
3336
description: BLOG_HOME_DESCRIPTION,
37+
isPartOf: {
38+
"@id": `${baseUrl}#website`,
39+
},
3440
publisher: {
3541
"@id": `${baseUrl}#organization`,
3642
},

β€Žapps/docs/src/app/(docs)/(default)/[[...slug]]/page.tsxβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export async function generateMetadata({
126126
canonical: withDocsBasePath(page.url),
127127
},
128128
openGraph: {
129+
siteName: "Prisma",
129130
title,
130131
description,
131132
url: withDocsBasePath(page.url),

β€Žapps/docs/src/app/layout.tsxβ€Ž

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,20 @@ export default function Layout({ children }: { children: ReactNode }) {
6666
<script
6767
type="application/ld+json"
6868
dangerouslySetInnerHTML={{
69+
// Docs is a section of prisma.io, not a site of its own. Declaring
70+
// a second WebSite here gave Google a competing candidate for the
71+
// site name, so this points at the canonical one in apps/site
72+
// instead. (The SearchAction it used to carry drove the sitelinks
73+
// search box, which Google retired.)
6974
__html: JSON.stringify({
7075
"@context": "https://schema.org",
71-
"@type": "WebSite",
76+
"@type": "CollectionPage",
7277
name: "Prisma Documentation",
7378
url: "https://www.prisma.io/docs",
74-
potentialAction: {
75-
"@type": "SearchAction",
76-
target: {
77-
"@type": "EntryPoint",
78-
urlTemplate: "https://www.prisma.io/docs?q={search_term_string}",
79-
},
80-
"query-input": "required name=search_term_string",
81-
},
79+
// @ids must match the nodes apps/site emits verbatim, which build
80+
// off an origin with no trailing slash.
81+
isPartOf: { "@id": "https://www.prisma.io#website" },
82+
publisher: { "@id": "https://www.prisma.io#organization" },
8283
}),
8384
}}
8485
/>

β€Žapps/site/src/app/(index)/page.tsxβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ export const metadata = createPageMetadata({
218218

219219
const homeStructuredData = createCollectionPageStructuredData({
220220
path: "/",
221-
name: "Agent Infrastructure for TypeScript",
221+
name: SITE_HOME_TITLE,
222222
description: SITE_HOME_DESCRIPTION,
223223
items: [
224224
{

β€Žapps/site/src/app/not-found.tsxβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { NotFoundTracker } from "@/components/not-found-tracker";
33
import type { Metadata } from "next";
44

55
export const metadata: Metadata = {
6-
title: "404 - Page Not Found",
6+
title: "404 - Page Not Found | Prisma",
77
description: "The page you were looking for could not be found.",
88
};
99

0 commit comments

Comments
Β (0)