[▲ Vercel Community](/) · [Categories](/categories) · [Latest](/latest) · [Top](/top) · [Live](/live)

[Help](/c/help/9)

# Dynmic Metadata from API Appears Inside <body> Instead of <head> (App)

167 views · 5 likes · 11 posts


Akash Electron (@akash-electron) · 2025-11-20

I am using **Next.js App Router** (`app/`) with **dynamic routes** and generating metadata based on API responses.
However, my metadata **does NOT appear in the SSR `<head>`** when I check “View Page Source”.
Instead, metadata is **either missing**, or appears **inside the `<body>`** after hydration.

## **Project Context**

* Route: `/app/(propertyPages)/(SeoPages)/[...slugs]/page.tsx`
* Metadata is generated using `generateMetadata()`
* Metadata depends on API calls (example: `getPageBySlugOne`, `validateSlugsOne`, etc.)
* I am using:

```
export const revalidate = 86400; // ISR 24h
export const dynamicParams = true; // Enable on-demand generation
```

* API functions run inside `generateMetadata()`

## **The Problem**

Even though metadata is returned correctly from `generateMetadata`, it **does not show** inside `<head>` in SSR HTML.

###  What I actually see in “View Page Source”:

* Only global metadata from `layout.tsx`
* NO title
* NO meta description
* NOTHING from `generateMetadata()`

###  Instead, Next.js injects metadata **after hydration** inside the `<body>`

This is the HTML output I uploaded:
(uploaded exact file here: **`random.txt`**)

All metadata is missing from `<head>` in the raw server HTML.

### How can I force metadata to be rendered **server-side inside `<head>`** even when it comes from an API?

### 3. Does ISR + dynamicParams still make `generateMetadata()` behave dynamically?

### 4. Do I need to use `cache()`, `dynamic = "force-static"`, or `{ next: { revalidate }}` inside fetch() to fix this?


Akash Electron (@akash-electron) · 2025-11-20

@harpreet-3932 @amyegan 
I hope you can help me out with this issue 🙏


Akash Electron (@akash-electron) · 2025-11-20

@pawlean @harpreet-3932 @emil-christensen


Amy Egan (@amyegan) · 2025-11-20 · ♥ 1

The Next.js team have said that this is intentional when [streaming metadata](https://nextjs.org/docs/app/api-reference/functions/generate-metadata#streaming-metadata) is involved

https://github.com/vercel/next.js/issues/79313#issuecomment-2892288965

> whenever metadata resolution would potentially block rendering the page, we instead defer it and stream it into the page body. Browsers are still able to interpret the `title` tag properly regardless of where it's rendered in the DOM

I hope that helps!


farzigalib (@farzigalib) · 2025-11-21 · ♥ 2

Recently I worked on same scenario, check out the below code in your page.tsx


```javascript
/app/(propertyPages)/(SeoPages)/[...slugs]/page.tsx



interface PageProps {

  params: Promise<{ slug: string }>;

}



export async function generateMetadata({

params,

}: PageProps): Promise<Metadata> {

const { slug } = await params;


const workPreview = await getWorkPreviewAPI({ type: 'slug', id: slug });


if (!workPreview.success) {

return {};

  }


const {

metaTitle,

metaDescription,

metaKeywords,

metaOGImg,

metaAltText,

bannerImage,

  } = workPreview.blogData;



return {

title: metaTitle,

description: metaDescription,

keywords: metaKeywords,

openGraph: {

title: metaTitle,

description: metaDescription,

images: {

url: getImageUrl(metaOGImg ?? bannerImage),

alt: metaAltText ?? '',

      },

    },

twitter: {

title: metaTitle,

description: metaDescription,

images: {

url: getImageUrl(metaOGImg ?? bannerImage),

alt: metaAltText ?? '',

      },

card: 'summary_large_image',

    },

  };

}
```



On local you might be not get expected result but if make it like it will work as expected.


Pauline P. Narvas (@pawlean) · 2025-11-21 · ♥ 1

@farzigalib Thanks for sharing what worked for you :slight_smile:


Akash Electron (@akash-electron) · 2025-11-21

thanks for replying , but i am doiing the same


farzigalib (@farzigalib) · 2025-11-21

I would help you if you provide more context of you code, specially layout.tsx and \[…slug\]/page.tsx


farzigalib (@farzigalib) · 2025-11-21

I implemented the same in one of my project you can check it [here](https://www.systango.com/case-studies/3t)

So basically /case-studies/\[slug\] is dynamic and every page have it own metadata


Akash Electron (@akash-electron) · 2025-11-22

actually problem is in only this url , else dynamic route are woring fine as expectd


farzigalib (@farzigalib) · 2025-11-24 · ♥ 1

Create layout.tsx for `(SeoPages)` & `(propertyPages)` and then it will work. Try once.