Como integrar Google Reviews en Nuxt 3
Cómo mostrar las reseñas de Google en tu sitio web desarrollado con Nuxt 3 y mejorar la confianza de tus visitantes.

Si tienes un proyecto de desarrollo web personalizado en Nuxt 3 y quieres dar un plus de confianza a tus visitantes, integrar reseñas de Google (Google Reviews) es una excelente opción. No solo sirve para mostrar la opinión de tus clientes satisfechos, sino que también ayuda a mejorar la credibilidad de tu marca y tu presencia online.
A continuación, te explico paso a paso cómo hacerlo.
¿Por qué Integrar Google Reviews en tu página web?
- Mayor confianza: Las reseñas positivas generan cercanía con los usuarios, animándolos a interactuar y contratar servicios de desarrollo web o diseño.
- Mejora de la reputación: Google valora mucho las interacciones reales, lo que puede favorecer tu posicionamiento en búsquedas locales o de tu sector.
- Aporte de valor: Mostrar testimonios de clientes reales ayuda a diferenciarte de la competencia y refuerza tu estrategia de marketing digital.
Configura tu proyecto en Nuxt 3
- Crea o abre tu proyecto Nuxt 3.
- Asegúrate de tener instalados los paquetes necesarios (Node.js, npm o Yarn).
- Ejecuta
npm install
(oyarn install
) para verificar que todos tus módulos estén al día.
npx nuxi init mi-proyecto cd mi-proyecto npm install
npm i tailwindcss npm i nuxt-swiper
modules: [ '@nuxtjs/tailwindcss', 'nuxt-swiper' ],
Paso 2: Obtén la Clave de API de Google Places
Para acceder a las reseñas de Google, necesitas una clave de API:
- Ve a la Google Cloud Platform.
- Crea un nuevo proyecto o selecciona uno existente.
- Navega a APIs y Servicios > Habilitar APIs y Servicios.
- Busca y habilita la Google Places API.
- En Credenciales, crea una clave de API.
- Restricción de API: Por seguridad, restringe el uso de la clave a la API de Places.
También necesitarás el id de lugar, que es el identificador que recibe las reseñas. Puedes buscar tu id en Places API.
Asegura Tus Claves de API
Para mantener la seguridad, es recomendable utilizar variables de entorno. Crea, si no lo tienes ya, un archivo .env
en la raíz de tu proyecto:
Nota: Asegúrate de reemplazar 'NUXT_PUBLIC_GOOGLE_MAP_API_KEY'
con tu clave de API real. Además, es recomendable almacenar las claves de API en variables de entorno para mayor seguridad.
NUXT_PUBLIC_GOOGLE_MAP_API_KEY=TU_CLAVE_API
Y añádelas a tu archivo nuxt.config para poder acceder a ellas desde cualquier componente:
runtimeConfig: { public: { googleMapsApiKey: process.env.NUXT_PUBLIC_GOOGLE_MAP_API_KEY, }, },
Crea un composable para obtener las reseñas
Para mantener tu proyecto web personalizado ordenado, lo ideal es centralizar las peticiones a Google en un endpoint dentro de tu proyecto Nuxt:
- En la carpeta
server/api/
, crea un archivo (por ejemplo,reviews.js
oreviews.ts
). - Importa las dependencias necesarias para realizar solicitudes HTTP.
- Haz una petición GET a la API de Google Places usando tu clave (API Key).
- Devuelve los datos que necesites (nombre del usuario, calificación, texto de la reseña, etc.).
// server/api/get-google-reviews.js import { getQuery } from 'h3'; export default defineEventHandler(async (event) => { const { placeId } = getQuery(event); if (!placeId) { return { error: 'El placeId es requerido.' }; } const config = useRuntimeConfig(); const apiKey = config.public.googleMapsApiKey; const apiUrl = `https://maps.googleapis.com/maps/api/place/details/json?place_id=${placeId}&fields=rating,user_ratings_total,reviews&language=es&key=${apiKey}`; try { const response = await fetch(apiUrl); const data = await response.json(); if (data?.result?.reviews && data.result.reviews.length > 0) { // Puedes filtrar las reseñas para mostrar, por ejemplo, sólo las de 4 y 5 estrellas: review.rating >= 4 // para mostrarlas todas review.rating >= 1 const filteredReviews = data.result.reviews .filter((review) => review.rating >= 1) .slice(-100); return { averageRating: data.result.rating, totalReviews: data.result.user_ratings_total, reviews: filteredReviews, }; } else { return { error: 'No se encontraron reseñas.' }; } } catch (err) { console.error('Error al llamar a la API de Google Places:', err); return { error: 'Error al obtener las reseñas' }; } });
Crea un componente para mostrar las reseñas
Crea un componente llamado GoogleReviews.vue
dentro de la carpeta components
. He añadido un svg para mostrar las 5 estrellas y un script que calcula el ancho que debe rellenarse.
<template> <div> <!-- <h2 class="text-2xl font-bold">Reseñas de Google</h2> --> <div class="flex flex-col lg:flex-row"> <div v-if="averageRating !== null && totalReviews !== null" class="my-4 w-full lg:w-1/6 flex flex-col items-center"> <div class="rating-text font-bold text-clamp-2xl"> <strong class=""> Excelente </strong> </div> <div class="stars pb-4 w-44" :data-stars="averageRating"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 172.4 33.6"> <g> <defs> <path id="SVGID_1" d="M17.8,1.1L23,11.5l11.6,1.7l-8.4,8.1l2,11.4l-10.3-5.4L7.5,32.7l2-11.4l-8.4-8.1l11.6-1.7L17.8,1.1z M52,1.1l5.2,10.4l11.6,1.7l-8.4,8.1l2,11.4L52,27.3l-10.3,5.4l2-11.4l-8.4-8.1l11.6-1.7L52,1.1z M86.2,1.1l5.2,10.4l11.6,1.7 l-8.4,8.1l2,11.4l-10.3-5.4l-10.3,5.4l2-11.4l-8.4-8.1L81,11.5L86.2,1.1z M120.4,1.1l5.2,10.4l11.6,1.7l-8.4,8.1l2,11.4l-10.3-5.4 L110,32.7l2-11.4l-8.4-8.1l11.6-1.7L120.4,1.1z M154.6,1.1l5.2,10.4l11.6,1.7l-8.4,8.1l2,11.4l-10.3-5.4l-10.3,5.4l2-11.4 l-8.4-8.1l11.6-1.7L154.6,1.1z" stroke="#F6BB09" /> </defs> <clipPath id="SVGID_2"> <use xlink:href="#SVGID_1" style="overflow:visible;" /> </clipPath> <rect class="bg-stars [clip-path:url(#SVGID_2)] fill-gold-1" x="0.7" y="0.1" :width="calculateWidth(averageRating)" height="33.5" fill="#F6BB09" /> <use xlink:href="#SVGID_1" style="overflow:visible;fill:none;stroke:#F6BB09;stroke-miterlimit:10;" /> </g> </svg> <p class="text-xs font-light mb-0 text-center">Valoración media: {{ averageRating }} / 5</p> </div> <span class="nowrap">En base a <strong>{{ totalReviews }} reseñas</strong></span> <img loading="lazy" src="~/assets/images/icons/google-logo.svg" alt="Logo Google" class="w-24" /> </div> <!-- Mostrar reseñas filtradas --> <div class="relative w-5/6"> <button class="swiper-button-prev absolute left-0 top-1/2 -translate-y-1/2 z-10"> ← </button> <button class="swiper-button-next absolute right-0 top-1/2 -translate-y-1/2 z-10"> → </button> <ClientOnly> <swiper-container class="mySwiper px-6 max-w-full list-none lg:px-6 min-h-96 flex flex-col lg:flex-row gap-6 w-full lg:w-5/6" v-if="reviews.length" ref="reviewsSlider" :init="false"> <swiper-slide v-for="(review, index) in reviews" :key="index" class="p-6 mt-2 mb-12 bg-white border border-gray-300 rounded-md w-full"> <div class="flex items-center gap-4 mb-4"> <img loading="lazy" :src="review.profile_photo_url" :alt="review.author_name" width="40" height="40" class="size-10 rounded-full"> <div class="w-full"> <p class="font-semibold mb-0">{{ review.author_name }}</p> <p class="text-xs font-light mb-0">{{ review.relative_time_description }}</p> </div> <img src="~/assets/images/icons/google-color-icon.svg" alt="Google" width="24" height="24" class="size-6" /> </div> <!-- <p class="text-sm">Calificación: {{ review.rating }} estrellas</p> --> <div class="stars pb-4 w-24" :data-stars="review.rating"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 172.4 33.6"> <g> <defs> <path id="SVGID_1" d="M17.8,1.1L23,11.5l11.6,1.7l-8.4,8.1l2,11.4l-10.3-5.4L7.5,32.7l2-11.4l-8.4-8.1l11.6-1.7L17.8,1.1z M52,1.1l5.2,10.4l11.6,1.7l-8.4,8.1l2,11.4L52,27.3l-10.3,5.4l2-11.4l-8.4-8.1l11.6-1.7L52,1.1z M86.2,1.1l5.2,10.4l11.6,1.7 l-8.4,8.1l2,11.4l-10.3-5.4l-10.3,5.4l2-11.4l-8.4-8.1L81,11.5L86.2,1.1z M120.4,1.1l5.2,10.4l11.6,1.7l-8.4,8.1l2,11.4l-10.3-5.4 L110,32.7l2-11.4l-8.4-8.1l11.6-1.7L120.4,1.1z M154.6,1.1l5.2,10.4l11.6,1.7l-8.4,8.1l2,11.4l-10.3-5.4l-10.3,5.4l2-11.4 l-8.4-8.1l11.6-1.7L154.6,1.1z" stroke="#F6BB09" /> </defs> <clipPath id="SVGID_2"> <use xlink:href="#SVGID_1" style="overflow:visible;" /> </clipPath> <rect class="bg-stars [clip-path:url(#SVGID_2)] fill-gold-1" x="0.7" y="0.1" :width="calculateWidth(review.rating)" height="33.5" fill="#F6BB09" /> <use xlink:href="#SVGID_1" style="overflow:visible;fill:none;stroke:#F6BB09;stroke-miterlimit:10;" /> </g> </svg> </div> <div class="text-wrapper"> <p class="italic text-sm">"{{ review.text }}"</p> </div> </swiper-slide> </swiper-container> </ClientOnly> </div> </div> </div> </template>
<script setup> import { ref, onMounted } from 'vue'; const placeId = 'TU_PLACE_ID_AQUÍ'; // Cargamos las reseñas y calificaciones en el servidor usando useAsyncData const { data, error } = await useAsyncData(async () => { return await $fetch(`/api/get-google-reviews?placeId=${placeId}`); }) const reviewsSlider = ref(null) const reviews = ref(data.value?.reviews || []) const averageRating = ref(data.value?.averageRating || null) const totalReviews = ref(data.value?.totalReviews || null) // Configuración de swiper slider useSwiper(reviewsSlider, { loop: true, autoHeight: true, slidesPerView: 1, spaceBetween: 30, navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, pagination: { clickable: true, }, autoplay: { delay: 5000, }, breakpoints: { '768': { slidesPerView: 2, spaceBetween: 40, }, '1280': { slidesPerView: 3, spaceBetween: 40, }, }, }); // Función para calcular el ancho basado en la valoración function calculateWidth(rating) { return `${(rating * 20) * 171.7 / 100}`; } </script>
<style scoped> .fill-gold-1 { @apply fill-[#F6BB09] } .swiper-button-prev, .swiper-button-next { @apply bg-white text-black shadow-md rounded-full p-2 w-10 h-10 flex items-center justify-center hover:bg-gray-100 transition; } </style>
Muestra las reseñas en tu frontend
- En el componente de tu página (por ejemplo,
pages/index.vue
), haz una llamada al endpoint que creaste. - Renderiza la lista de reseñas en un layout atractivo.
- Personaliza estilos y formato para que se adapte a tu diseño (colores, tipografía y estructura de tu sitio web personalizado).
<template> <div class="reviews-title"> Reseñas de nuestros clientes </div> <GoogleReviews /> </template> <script setup> import GoogleReviews from '~/components/GoogleReviews.vue' </script> <style scoped> .reviews-title { font-family: Arial, Helvetica, sans-serif; font-size: 3rem; padding: 2rem; } </style>
Ajusta el diseño y la experiencia de usuario
Para que la sección de reseñas luzca profesional y cohesionada, cuida aspectos como:
- Tipografías y colores: que respeten la identidad visual de tu marca.
- Distribución en pantalla: un layout tipo grid o carrusel puede hacer que las reseñas sean más atractivas.
- Llamadas a la acción: aprovecha para guiar a los usuarios hacia un formulario de contacto o hacia otros servicios que ofrezcas.
He subido el proyecto a github para que lo descargues si lo necesitas: Nuxt Google Reviews
Conclusión
Integrar Google Reviews en Nuxt 3 es un paso sencillo y muy poderoso para fortalecer la confianza en tus servicios de desarrollo web personalizado. Siguiendo estos pasos, conseguirás destacar tus reseñas de forma elegante y ordenada, potenciando tanto tu reputación online como la experiencia de tus usuarios.
¿Listo para dar el siguiente paso?
Aprovecha al máximo la credibilidad que aportan las reseñas de Google y haz que tu proyecto Nuxt 3 brille con luz propia. ¡Si tienes dudas o necesitas asesoría para tu próximo sitio web, no dudes en ponerte en contacto con nosotros!
Preguntas frecuentes
¿Por qué es importante integrar las reseñas de Google en mi sitio web?
Integrar las reseñas de Google en tu sitio web aumenta la confianza de los visitantes, mejora el SEO al proporcionar contenido relevante y actualizado, y te ayuda a destacar frente a la competencia al mostrar testimonios auténticos de tus clientes.
¿Qué beneficios SEO obtengo al mostrar reseñas de Google en mi sitio?
Ofrecer contenido generado por usuarios (UGC) y un mayor tiempo de permanencia puede favorecer el posicionamiento, además de mejorar la experiencia y la credibilidad ante buscadores.
¿Puede afectar la velocidad de carga de mi web la integración de Google Reviews?
Si está bien implementada (con un endpoint optimizado y/o caché), el impacto debería ser mínimo. Es importante asegurarse de no hacer demasiadas peticiones innecesarias a la API.