How to access pathname
in generateMetadata
?
#50189
Replies: 27 comments 34 replies
-
If it's a dynamic URL param you can get it from the |
Beta Was this translation helpful? Give feedback.
-
Facing the same issue :( If anyone has an idea |
Beta Was this translation helpful? Give feedback.
-
I thought about just reading the name of the current file like so:
Have not tried it yet though ;) But I think this should be officially supported by NextJS |
Beta Was this translation helpful? Give feedback.
-
Looking around I found a way using headers api.
|
Beta Was this translation helpful? Give feedback.
-
Thank you @jmacbhc ! Furthermore, here's a snippet that turns nested routes to a nicely looking title: export async function generateMetadata({ params }: Props): Promise<Metadata> {
const headersList = headers();
const pathname = headersList.get("x-invoke-path") || "DefaultTitle";
const pathSegments = pathname.split("/").filter((segment) => segment !== ""); // Split pathname into segments and remove empty segments
const titleSegments = pathSegments.map(
(segment) => segment.charAt(0).toUpperCase() + segment.slice(1) // Capitalize the first letter of each segment
);
const title = titleSegments.join(" › "); // Join segments with a separator
return { title };
} // Example: "/home/profile" turns to "Home › Profile" Edit: This solution does not work in a Vercel deployment. |
Beta Was this translation helpful? Give feedback.
-
Here is what I'm using for now:
import { NextResponse, type NextRequest } from "next/server";
export function middleware(request: NextRequest) {
request.headers.set("x-url", request.url);
return NextResponse.next();
}
import type { Metadata } from "next";
import { headers } from "next/headers";
export async function generateMetadata(): Promise<Metadata> {
const url = new URL(headers().get("x-url")!);
console.log(url.pathname);
return {};
} |
Beta Was this translation helpful? Give feedback.
-
Working in Next 14 middleware.ts
layout.ts
|
Beta Was this translation helpful? Give feedback.
-
The answers in this thread work but will make the route dynamically rendered instead of statically, because of calling headers(). As per Next.js Documentation on https://nextjs.org/docs/app/api-reference/functions/headers
I don't think this the best solution. |
Beta Was this translation helpful? Give feedback.
-
You also really need |
Beta Was this translation helpful? Give feedback.
-
This have to be joke about developer UX 😢 |
Beta Was this translation helpful? Give feedback.
-
After some consideration, I'm reopening this as the current solution is not giving access to |
Beta Was this translation helpful? Give feedback.
-
This is not your case, but I'd like to point out that: If you were trying to access the It looks like this: export const metadata = {
metadataBase: new URL('https://acme.com'),
alternates: {
canonical: '/',
languages: {
'en-US': '/en-US',
'de-DE': '/de-DE',
},
},
openGraph: {
images: '/og-image.png',
},
} |
Beta Was this translation helpful? Give feedback.
-
This should be part of the official documentation |
Beta Was this translation helpful? Give feedback.
-
+1, this is a significant issue with any website trying to manage titles properly. We need access to the URL and path name in |
Beta Was this translation helpful? Give feedback.
-
I need this too to set the right language alternatives. I am using
but for page
but I have no idea about the right way to access the pathname |
Beta Was this translation helpful? Give feedback.
-
I'm seeking a method to automatically populate the |
Beta Was this translation helpful? Give feedback.
-
After digging a little bit in generateMetadata params it seems there is an "unsafe" way to do that without opting out from cache. /**
* Get the pathname from the metadata state
* This dives into async storage of promise state to get the pathname
*
* This is much more performant that using headers() from next as this doesn't opt out from the cache
* @param state
*/
export const getPathnameFromMetadataState = (state: any): string | undefined => {
const res = Object.getOwnPropertySymbols(state || {})
.map(p => state[p])
.find(state => state?.hasOwnProperty?.("urlPathname"))
return res?.urlPathname.replace(/\?.+/, "")
} export async function generateMetadata(_: any, state: any): Promise<Metadata> {
const metaByPath = await fetchMetadataByPath()
const pathname = getPathnameFromMetadataState(state) ?? ""
const { title, description } = metaByPath[pathname] || {}
return {
title,
description,
}
} Pretty ugly, but it gets the job done 🤷♂️ |
Beta Was this translation helpful? Give feedback.
-
Adding another approach in case it helps someone. :-) If you are receiving params, and it happens to be a catchall segment, this might work for you: Folders:
Then you might be able to do this: export async function generateMetadata(params: {
params: { product: [...parts: string[]] };
}): Promise<Metadata> {
const {
params: {
product: [slug, id]
}
} = params;
// reconstitute URL from product, slug and id
const url = `${DOMAIN_FROM_SOMEWHRE}/products/${slug}/${id}`;
}```
|
Beta Was this translation helpful? Give feedback.
-
Is there a solution for this that doesn't involve making requests or getting headers? |
Beta Was this translation helpful? Give feedback.
-
According to this comment by @delbaoliveira , the reason why this is not possible currently is that Next.js restricts access to "request-time" data included in the Request object because it wants to have visibility over where this data is being accessed, and turn these access points to SSR instead of building them statically on build-time, and it does this by providing This goal is not affected by what we're trying to do here.What we need here is a way to identify the current route on build-time in |
Beta Was this translation helpful? Give feedback.
-
It is possible to access to it from page.tsx (and not layout) through the middleware :
|
Beta Was this translation helpful? Give feedback.
-
I have figured out a way to generate dynamic // app/layout.tsx
export const metadata: Metadata = {
metadataBase: new URL("https://yourwebsite.com"),
alternates: {
canonical: "./", // note this is ./, not / !!!
},
}; The value of <link rel="canonical" href="https://yourwebsite.com/foo/bar/baz"> The behavior should be documented. |
Beta Was this translation helpful? Give feedback.
-
For more information that explain why there is no official support for this check this: #43704 (comment) |
Beta Was this translation helpful? Give feedback.
-
I found out that using "./" in the URL property of Just set Example (generateMetadata):
Tested in Next.js v15. Note for i18n users:When using i18n the |
Beta Was this translation helpful? Give feedback.
-
in my case:
export async function generateMetadata(
_: Promise<{ locale: string }>,
parent: ResolvingMetadata,
): Promise<Metadata> {
const { alternates } = await parent;
// Format the current URL: ./[locale]/...
console.log(alternates?.canonical?.url) // current URL => pathname
} |
Beta Was this translation helpful? Give feedback.
-
Another interesting solution by @alfonsusac is to use Parallel Routes as a way to get Next into giving access to pathnames in Here's how to do it:
export async function generateMetadata(props: {
params: Promise<{ slug: string[] }>;
}) {
const {slug} = await props.params; // slug contains the full pathname as array
return {
title: "/" + slug.join("/"),
description: "Generated by create next app",
};
} Now on build-time, Next will try to get all the pages of the application, then generate their metadata tags as if they are dynamic pages, even if they aren't. Here's alfonsusac's PoC for this. I haven't tested it extensively, please comment here if you find edge cases where it breaks. Now while this solution works, I'm not going to mark it as answer since it's also a hacky solution that suprisingly works. But I still stand by my opinion that getting pathname is generateMetadata() should be supported, see my previous comment for details. |
Beta Was this translation helpful? Give feedback.
-
I'm looking for a way to dynamically generate
<title>
based on the currentpathname
.For example,
/store
would becometitle: 'Store'
ingenerateMetadata()
.This would also allow for a nested
pathname
to turn into a nestedtitle
, for example/store/hoodies/dark-hoodie
could turn intotitle: 'Store - Hoodies - Dark Hoodie'
.Is there a way to do this currently in Next 13?
Beta Was this translation helpful? Give feedback.
All reactions