I’m having an issue with generating meta tags for my Next.js blogging application. I am currently using Typescript and apollo-codegen to generate query hooks to fetch information from my Strapi backend. Because i’ve read on many other posts that dynamic meta tag information won’t show in the view page source if the information is client-side rendered, I made the change to use graphql-codegen-next-ssr (https://github.com/correttojs/graphql-codegen-apollo-next-ssr). All of my queries are now pre-rendered rendered.
[slug].tsx
const BlogDetails: PageGetBlogDetailComp = (props) => {
return props?.data ? (
<div className=" container mx-auto mb-8 bg-light-neutral px-10 dark:bg-dark-neutral">
<Head>
<title>
Apex Blogs | {props?.data?.blogs?.data[0]?.attributes?.title}
</title>
<meta
property="og:title"
content={props?.data?.blogs?.data[0].attributes?.title}
/>
<meta property="og:description" content="Open Graph Description" />
<meta property="og:type" content="video.movie" />
<meta
property="og:image"
content={
props?.data?.blogs?.data[0]?.attributes?.featureImage?.data
?.attributes?.url
}
/>
<meta
property="og:url"
content={`https://apex-blogs.vercel.app/blog/${props?.data?.blogs?.data[0]?.attributes?.slug}`}
/>
</Head>
//......
export const getStaticProps: GetServerSideProps = async ({ params, req }) => {
const res = await ssrGetBlogDetail.getServerPage(
{
variables: { slug: params?.slug?.toString() || "" },
},
{ req }
);
if (res.props.error) {
return {
notFound: true,
};
}
return res;
};
Despite this, I am still having no luck seeing my meta tags. I can’t even view tags I’ve added in my __app.ts in the page source. The meta tags only show up in inspect element. The only way I could see the meta tags in page source is if added them in the _document.ts file, but my tags need to be dynamic.
My goal is to have shareable blog posts. Please let me know if I need to add additional infomation.
5
2 Answers
I’ll share my solution. First, You don’t need to add Head
component in every page component.
because It won’t show in the source anyway.(In my case though.)
But If you place Head
component in the _app.js
component, It will appears in the source.
Let’s take advantage of this.
- Place
<Head>
component on_app.js
file like below.
And delete all the<Head>
component in other page components.
function MyApp({ Component, pageProps }: AppProps) {
const router = useRouter()
return (
<Suspense>
<Head>
<title>{pageProps?.title}</title>
<meta name="description" content={pageProps?.description}/>
<meta property="og:title" content={pageProps?.title} />
</Head>
<Component {...pageProps} />
</Suspense>
)
}
- And in the every page components, add
getInitialProps
function like below.
This is to send the contents forHead
component of _app.js. so when you change pages,_app.js
component will receivepageProps
from page component’sgetInitialProps
function.
//in Main page component..
import { NextPageContext } from 'next'
export default function Main(){
return <div>…</div>
}
Main.getInitialProps = async (ctx: NextPageContext) => {
return {
title: ’Title you wanna show’,
description: ’Desc you wanna show’
}
}
-
now if you
console.log(pageProps)
in the_app.js
, you will see
all the props you passed in current page components like below.
{ title: ’Title you wanna show’, description: ’Desc you wanna show’ }
-
Save all the codes and open source page by press
option + command + u
keys. then you will see all meta tags you’ve added.
Make sure you’re importing Head from the right place
import Head from 'next/head';
Here an example that are working
// on your ./pages/index(or any path here).tsx
import { GetServerSideProps } from "next";
import Head from "next/head";
const getSiteTitle = async () => {
return Promise.resolve({
siteTitle: "this is my website title",
});
};
export default function Index({ siteTitle = null }: HomeProps) {
return <Home siteTitle={siteTitle} />;
}
export const getServerSideProps: GetServerSideProps<HomeProps> = async () => {
let siteTitle = null;
const response = await getSiteTitle(); // any async promise here.
siteTitle = response.siteTitle;
if (!siteTitle) {
return {
notFound: true,
};
}
return {
props: { siteTitle }, // will be passed to the page component as props
};
};
// Home must be a component, you can save this file on src/templates or src/scenes to keep the react pattern.
export type HomeProps = {
siteTitle: string,
};
export const Home = ({ siteTitle }: HomeProps) => {
return (
<>
<Head>
<title>{siteTitle}</title>
</Head>
<div>
<h1>Hello World </h1>
</div>
</>
);
};
2
-
yes, I imported Head from the very top of my page, so I'm pretty sure it's in the right place. I can see my my meta tags in the inspect element tool but not in the page-source
– Roddy2HottySep 19, 2022 at 20:42
-
i think is by the way you're passing optional data to the component, make sure the page don't load until you have the data. And the <div> you're using above <Head> tag is a bad pratice, remove the div and instead, try to use <> </> fragments to wrapp your return (line-3 of your code)
– Lázaro SouzaSep 20, 2022 at 13:07
Make sure you're using next/head and not next/document, they both contain
Head
. Weird that even next/head inside app.tsx isn't rendering. Are you sure your component is rendering?Sep 19, 2022 at 23:47
Everything renders fine but the Head componenent. I've even tried to use the next-seo package with no luck. I've deleted the _document.ts file and cleared the cache, still had no luck
Sep 20, 2022 at 1:37
make sure your
getStaticPaths
is returning valid paths, and considerfallback: "blocking"
temporarily just to be 100% sure you are getting initial pages rendered. It's possible the pages are not generated and you load the fallback (with empty props) before quickly updating it with props that render your <Head>Sep 20, 2022 at 16:51
Is it only the meta tags that aren't showing in the page source? Can you show us the code for your
_app
file?Sep 27, 2022 at 18:39
facing the same issue
Oct 26, 2022 at 8:50