0

I'm working on a Vue.js application where I need to dynamically set Open Graph (OG) meta tags based on data fetched from an API. The OG tags are necessary for social media sharing (e.g., Facebook, WhatsApp). The issue I'm facing is that the meta tags, particularly og:image, are set before the API call completes, resulting in an empty image URL initially. When the page is shared, the meta tags with the empty image URL are used, instead of the updated ones.

Here is my current code:

<template>
  <div v-if="dataFetched">
    <div class="m-5 md:mx-28">
//template code continues here



//vue main script
<script setup>
import { ref, onMounted, watch, computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useSeoMeta } from '@vueuse/head';

import DetailHeader from "~/components/listing-detail/DetailHeader.vue";
import DetailPictures from "~/components/listing-detail/DetailPictures.vue";
import DetailOverview from "~/components/listing-detail/DetailOverview.vue";
import DetailProperty from "~/components/listing-detail/DetailProperty.vue";
import DetailMap from "~/components/listing-detail/DetailMap.vue";
import DetailLocation from "~/components/listing-detail/DetailLocation.vue";
import DetailNearby from "~/components/listing-detail/DetailNearby.vue";
import DetailCalculator from "~/components/listing-detail/DetailCalculator.vue";

const axios = useNuxtApp().$axios;

defineProps({ id: String });

// Initialize data
const dataItem = ref([]);
const currentItem = ref(null);
const nearby_places = ref([]);
const dataFetched = ref(false);

const route = useRoute();
const router = useRouter();

const { nametitle } = route.params;
const nametitleValues = nametitle.split('-').map(value => value.replace(/-/g, ' '));
const title = nametitleValues.join(' ') + ' | A-plus Property Consultants';
const ogTitle = title;
const description = 'Discover ' + title + ', available on A-plus Property Consultants. Explore this property today!';
const ogDescription = description;
const ogImageUrl = ref('');
const currentUrl = 'https://aplus2.vercel.app' + route.fullPath;
const ogImageWidth = ref(32);
const ogImageHeight = ref(32);

const fetchData = async () => {
  let url = `${apiEndpoint}?propertySEF=${nametitle}`;
  try {
    const response = await axios.get(url);
    dataItem.value = response.data.listing;
    currentItem.value = response.data.listing;

    if (dataItem.value[0]?.property_nearby_place) {
      nearby_places.value = JSON.parse(dataItem.value[0].property_nearby_place);
    }

    if (dataItem.value[0]?.photo?.[0]?.photo_file) {
      ogImageUrl.value = `https://staging.aplussharing.com/storage/uploads/property/${dataItem.value[0].photo[0].photo_file}`;
    }
    
    dataFetched.value = true;
  } catch (error) {
    router.push({ name: "404" });
  }
};

onMounted(() => {
        fetchData();

    });

watch(dataFetched, (newValue) => {
  if (newValue) {
    useSeoMeta({
      title,
      ogTitle,
      description,
      ogDescription,
      ogImage: ogImageUrl.value,
      ogUrl: currentUrl,
      ogImageWidth: ogImageWidth.value,
      ogImageHeight: ogImageHeight.value,
      ogType: 'website',
    });
  }
},{immediate:true});
</script>



Problem: The OG meta tags, particularly og:image, are rendered before the API call completes, resulting in an empty og:image URL. When sharing the page on social media, the initial (empty) meta tags are used.

Goal: I want to block the rendering of meta tags until the API call completes and the og:image URL is available. How can I ensure that the meta tags are only set after the data has been fetched?

Any help or suggestions would be greatly appreciated!

1 Answer 1

0

See if this works for you. View source code(Ctrl + U) to check if the meta value is filled with data from API. To work with SEO, make sure you are running on SSR mode.

<template>
  <div>
    <div class="m-5 md:mx-28">
      template code continues here
    </div>
  </div>
</template>

//vue main script
<script setup>
const { data, pending, error, refresh } = await useFetch('https://jsonplaceholder.typicode.com/posts/1', {
  method: "GET"
})

useServerSeoMeta({
  title: () => data.value.title || "any default value",
  description: () => data.value.description || "any default description value",
  ogUrl: () => data.value.ogUrl || "any default ogUrl value",
  ogTitle: () => data.value.ogTitle || "any default ogTitle value",
  ogDescription: () => data.value.ogDescription || "any default ogDescription value",
  ogImage: () => data.value.ogImage || "any default ogImage value",
  ogType: () => data.value.ogType || "any default ogType value",
  ogLocale: () => data.value.ogLocale || "any default ogLocale value",
  twitterCard: () => data.value.twitterCard || "any default twitterCard value",
  twitterTitle: () => data.value.twitterTitle || "any default twitterTitle value",
  twitterDescription: () => data.value.twitterDescription || "any default twitterDescription value",
  twitterImage: () => data.value.twitterImage || "any default twitterImage value",
})

</script>

Not the answer you're looking for? Browse other questions tagged or ask your own question.