0

I'm working on a Nuxt 3 project, and I've encountered an issue where Google search results display my page title as undefined, even though the title appears correctly in the HTML tags. Below is the relevant code from my project:

Undefined title in google serp

Search console

Undefined title in search console

app.vue

<script lang="ts" setup>
const config = useRuntimeConfig();
const route = useRoute();

const i18nHead = useLocaleHead({
  addDirAttribute: true,
  identifierAttribute: "id",
  addSeoAttributes: true,
});

declare const window: any;

onMounted(() => {
  if (window.tidioChatApi) {
    window.tidioChatApi.on("ready", onTidioChatApiReady);
  } else {
    document.addEventListener("tidioChat-ready", onTidioChatApiReady);
  }
});

const onTidioChatApiReady = () => {
  window.tidioChatApi.open();
};

const { t, locale } = useI18n();

const title = computed(() =>
  (route.meta.title
    ? t(route.meta.title as string, { appName: config.public.appName })
    : undefined) as any,
);
const description = computed(() =>
  route.meta.description ? t(route.meta.description as string) : undefined,
);

useHead({
  title,
  link: () => [
    ...(i18nHead.value.link || []),
    { rel: "icon", type: "image/x-icon", href: "/favicon.ico" },
  ],
  meta: () => [
    ...(i18nHead.value.meta || []),
    { name: "description", content: description.value },
    { property: "og:title", content: title.value },
    { property: "og:description", content: description.value },
    { property: "og:site_name", content: config.public.appName as string },
    { property: "og:image", content: config.public.frontendUrl + "/images/meta_image.webp" },
    { property: "og:type", content: "website" },
    { name: "twitter:card", content: "summary_large_image" },
    { name: "twitter:title", content: title.value },
    { name: "twitter:description", content: description.value },
    { name: "twitter:image", content: config.public.frontendUrl + "/images/meta_image.webp" },
  ],
  htmlAttrs: {
    lang: () => i18nHead.value.htmlAttrs.lang,
    dir: () => i18nHead.value.htmlAttrs.dir,
  },
});
</script>

<template>
  <div>
    <NuxtLoadingIndicator color="repeating-linear-gradient(to right,#6e20e1 0%,#8045fd 50%,#6e20e1 100%)" :height="3" />
    <NuxtLayout>
      <NuxtPage />
    </NuxtLayout>
    <CookieControl v-if="locale === 'es'" locale="es" />
    <CookieControl v-else locale="en" />
    <UNotifications :ui="{ strategy: 'override' }" />
  </div>
</template>

layouts/guest-layout.vue

<script lang="ts" setup>
const sanctumClient = useSanctumClient();
const { data: products } = useAsyncData<Product[]>(
  "products",
  () =>
    sanctumClient("/products", {
      headers: {
        "Accept-Language": useNuxtApp().$i18n.localeProperties.value.code,
      },
    }),
  {
    lazy: true,
  },
);
</script>
<template>
  <div class="bg-white dark:bg-gray-900 min-h-screen">
    <TheMenu />
    <UMain>
      <slot />
    </UMain>
    <ProModal v-if="products" :products="products" />
    <TheFooter />
  </div>
</template>

pages/index.vue

<script lang="ts" setup>
definePageMeta({
  title: "landing.summarizer.title",
  description: "landing.summarizer.description",
  layout: "guest-layout",
});

const { t } = useI18n();
const localePath = useLocalePath();
const { isAuthenticated } = useSanctumAuth();

const faq = [
  {
    label: t("landing.summarizer.faq.1.label"),
    content: t("landing.summarizer.faq.1.content"),
  },
  {
    label: t("landing.summarizer.faq.2.label"),
    content: t("landing.summarizer.faq.2.content"),
  },
  // ...more FAQ items
];
</script>

<template>
  <div>
<ULandingHero
      :ui="{
        wrapper: 'py-4 sm:py-8 md:py-8',
        container: 'gap-4 sm:gap-y-4',
        description: 'mt-2 text-base',
      }"
      :title="$t('landing.summarizer.hero.title')"
      :description="$t('landing.summarizer.hero.description')"
    >
      <SummariesGuestSummarizer />
    </ULandingHero>

    <ULandingSection
      style="
        background: linear-gradient(
          180deg,
          #f8f4ff 0%,
          rgba(255, 255, 255, 0) 100%
        );
      "
      :ui="{
        wrapper: 'pt-16 sm:pt-20 pb-0 sm:pb-0',
      }"
    >
    <!-- More content... -->
  </div>
</template>

Despite setting the title in the definePageMeta and using useHead, Google search results display the title as undefined.

Steps I've Taken to Debug:

  • Verified that route.meta.title is set and not undefined.
  • Checked the translation keys (landing.summarizer.title) in my i18n files.
  • Ensured that title and description are correctly computed and not returning undefined.
  • Added logging to confirm that the route.meta.title and translation are as expected.
  • Ensured the useHead hook is being executed correctly.
  • Checked the generated server-side HTML to verify the title tag.

Additional Information:

  • Using Nuxt 3 with TypeScript.
  • Implementing internationalization (i18n) for dynamic title and description.
  • Has anyone encountered a similar issue or can provide guidance on resolving this? Any help would be appreciated.
2
  • I think you should try "title: title.value" inside the useHead Commented Jul 7 at 6:37
  • I'm looking also that, thank you, i'll try Commented Jul 8 at 16:23

0