engineering

Creando una Interfaz de Reseñas Personalizada con la API de Reviewlee

Sarah Chen
4 min de lectura
Editor de código mostrando un componente de reseña personalizado construido con la API de Reviewlee

El problema con los "Widgets"

La mayoría de las plataformas de reseñas tratan tu sitio web como una valla publicitaria para su marca. Te dan un <iframe> rígido o un widget de JavaScript pesado que:

  1. Reduce tu puntuación de Lighthouse con scripts de terceros.
  2. Choca con tu sistema de diseño (fuentes incorrectas, colores incorrectos).
  3. Actúa como un caballo de Troya para dirigir el tráfico de vuelta a su plataforma, no a la tuya.

En Reviewlee, creemos que las reseñas son infraestructura. Proporcionamos la base de datos, los formularios de recolección y el motor de verificación, pero cómo muestras esos datos debería depender de ti.

¿Por qué elegir "Headless"?

Al usar la API de Reviewlee ("Reseñas Headless"), obtienes:

  • Cero Desplazamiento de Diseño (Layout Shift): Renderiza reseñas en el servidor (SSR/RSC) para una visualización instantánea.
  • Marca Perfecta: Usa tus propias clases de CSS/Tailwind.
  • Supremacía SEO: Las reseñas son parte de tu HTML, no inyectadas por JS después de la carga.

Construyamos un componente de reseña personalizado usando Next.js 16 y Tailwind CSS.

Prerrequisitos

  • Una cuenta de Reviewlee (Gratis o Pro).
  • Tu clave API pública (se encuentra en Configuración > API).
  • Un proyecto Next.js (aunque esto funciona con Remix, Astro, etc.).

Paso 1: Obtener Reseñas (Lado del Servidor)

En Next.js App Router, obtenemos datos directamente en nuestro Componente de Servidor. Esto asegura que los motores de búsqueda vean las reseñas inmediatamente.

// lib/api.ts
import { notFound } from "next/navigation";

export interface Review {
  id: string;
  rating: number;
  title: string;
  body: string;
  author_name: string;
  verified: boolean;
  created_at: string;
}

export async function getReviews(formId: string) {
  const res = await fetch(
    `https://api.reviewlee.com/api/v1/reviews?formId=${formId}&status=published`,
    {
      headers: {
        // Usa tu clave pública si obtienes desde el cliente,
        // o clave secreta si usas proxy/obtienes desde el servidor.
        Authorization: `Bearer ${process.env.REVIEWLEE_API_KEY}`,
      },
      next: { revalidate: 3600 }, // Caché por 1 hora
    }
  );

  if (!res.ok) {
    if (res.status === 404) return [];
    throw new Error("Error al obtener las reseñas");
  }

  const data = await res.json();
  return data.reviews as Review[];
}

Paso 2: El Componente de Tarjeta de Reseña

Ahora, construyamos la interfaz de usuario. Usaremos lucide-react para las estrellas y Tailwind para el estilo.

// components/review-card.tsx
import { Star, CheckCircle2 } from "lucide-react";
import { cn } from "@/lib/utils";
import type { Review } from "@/lib/api";

export function ReviewCard({ review }: { review: Review }) {
  return (
    <div className="p-6 rounded-xl bg-card border border-border shadow-sm">
      {/* Encabezado: Autor y Fecha */}
      <div className="flex items-center justify-between mb-4">
        <div className="flex items-center gap-2">
          <span className="font-semibold text-foreground">{review.author_name}</span>
          {review.verified && (
            <span className="flex items-center gap-1 text-xs font-medium text-emerald-600 bg-emerald-50 px-2 py-0.5 rounded-full">
              <CheckCircle2 className="w-3 h-3" />
              Cliente Verificado
            </span>
          )}
        </div>
        <time className="text-sm text-muted-foreground">
          {new Date(review.created_at).toLocaleDateString("es-ES", {
            year: "numeric",
            month: "short",
            day: "numeric",
          })}
        </time>
      </div>

      {/* Clasificación */}
      <div className="flex gap-0.5 mb-3" aria-label={`${review.rating} de 5 estrellas`}>
        {[1, 2, 3, 4, 5].map((star) => (
          <Star
            key={star}
            className={cn(
              "w-4 h-4",
              star <= review.rating 
                ? "fill-amber-400 text-amber-400" 
                : "fill-muted text-muted"
            )}
          />
        ))}
      </div>

      {/* Contenido */}
      <h3 className="font-bold text-lg mb-2">{review.title}</h3>
      <p className="text-muted-foreground leading-relaxed">{review.body}</p>
    </div>
  );
}

Paso 3: Integración y JSON-LD

Finalmente, intégralo en tu página y agrega los Datos Estructurados cruciales para Google.

// app/reviews/page.tsx
import { getReviews } from "@/lib/api";
import { ReviewCard } from "@/components/review-card";

export const metadata = {
  title: "Reseñas de Clientes",
  description: "Mira lo que nuestros clientes tienen que decir.",
};

export default async function ReviewsPage() {
  const reviews = await getReviews("tu-id-de-formulario");
  const averageRating = 
    reviews.reduce((acc, r) => acc + r.rating, 0) / reviews.length;

  // Datos de fragmentos enriquecidos de Google
  const jsonLd = {
    "@context": "https://schema.org",
    "@type": "Product",
    name: "Plataforma SaaS Acme",
    aggregateRating: {
      "@type": "AggregateRating",
      ratingValue: averageRating.toFixed(1),
      reviewCount: reviews.length,
    },
  };

  return (
    <section className="container py-12">
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      
      <h1 className="text-4xl font-extrabold tracking-tight mb-8">
        Amado por más de {reviews.length} desarrolladores
      </h1>
      
      <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
        {reviews.map((review) => (
          <ReviewCard key={review.id} review={review} />
        ))}
      </div>
    </section>
  );
}

Conclusión

Al tomar el control de la interfaz de usuario, aseguras que tus reseñas generen confianza para ti, no para la plataforma de reseñas.

Este enfoque es:

  • Más rápido: Sin JS pesado de terceros.
  • Más limpio: Coincide perfectamente con tu marca.
  • Más inteligente: Todo el crédito de SEO va a tu dominio.

¿Listo para construir? Obtén tu clave API desde el Panel de Control y comienza a enviar código.

apitutorialdevelopercustom-uireactnextjs

¿Listo para ser dueño de tus reseñas?

Comienza a recopilar reseñas verificadas con propiedad total de datos. Sin bloqueos, sin tarifas ocultas.

Iniciar prueba gratuita de 14 días