npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@vibereview/react

v3.1.9

Published

React SDK for VibeReview - Simple, type-safe feedback widgets

Downloads

2,289

Readme

@vibereview/react

Simple, type-safe React SDK for VibeReview - Add beautiful feedback widgets to your React app in minutes.

npm version TypeScript


🎯 Why VibeReview?

The Problem: Your landing page doesn't convert. Visitors don't trust you. No social proof = no sales.

The Solution: Collect feedback in your app. Display the best reviews on your landing page. Watch conversions skyrocket.

await review("feature-id"); // Collect feedback in your app
<Carousel />; // Display best reviews on landing page

What you get:

  • 🚀 Boost Conversions - Professional review widgets on your landing page
  • ⭐️ Social Proof - Real user testimonials that build instant trust
  • 🎨 Ultra-Customizable - ScoreBadge, Carousel, Wall of Love, Fomo notifications
  • 💬 Smart Collection - Beautiful feedback widgets inside your app
  • 📊 Best Reviews First - Automatic filtering to show only top-rated feedback
  • 📱 Professional Design - Matches your brand, mobile-ready

What you DON'T need:

  • ❌ No manual testimonial collection
  • ❌ No design work for review widgets
  • ❌ No coding complex layouts
  • ❌ No fake reviews
  • ❌ No third-party review platforms


📋 Table of Contents


💡 How it Works

User Action  →  Your Code  →  Feedback Widget  →  Your Dashboard  →  Landing Page Widget
   👆              👨‍💻            ⭐️ ⭐️ ⭐️              📊                    💰

Example:

  1. User clicks "Export PDF"
  2. You call review('export-pdf')
  3. Beautiful rating widget slides in
  4. User rates 5 stars ⭐️⭐️⭐️⭐️⭐️ and writes "So fast!"
  5. You see it instantly in your dashboard
  6. You display the best reviews on your landing page to convert more visitors

That's the entire flow. No complexity. No setup. Just feedback that converts into sales.

🎥 Video Testimonials: If your trigger has video capture enabled, the video recording widget only appears when users give 4 or 5 stars. This ensures you collect video testimonials from happy customers only, maximizing conversion impact on your landing page.


✨ Features

  • 🚀 Landing Page Widgets - Ready-to-use social proof components (ScoreBadge, Carousel, Wall of Love, Fomo)
  • 💰 Conversion Focused - Automatically display best reviews to maximize trust and sales
  • 🎨 Ultra-Customizable - Professional design that matches your brand
  • ⚡️ Lightweight - Minimal wrapper around the VibeReview JavaScript SDK
  • 🎯 Type-Safe - Full TypeScript support with excellent autocomplete
  • 🪝 React Hooks - Modern React API with useVibeReview()
  • 🔄 Trigger Versioning - A/B test different widget configurations
  • 📊 Promise-Based - Modern async/await API that always resolves
  • 🌍 i18n Support - Built-in multilingual support (EN, FR, ES, DE, PT)
  • Mobile-Ready - Responsive design out of the box

📦 Installation

Prerequisites:

  • React 16.8+ (Hooks support required)
  • A VibeReview account (free signup)
  • A project created in the dashboard
  • Your projectId and apiKey (available in the dashboard)
npm install @vibereview/react

or with yarn:

yarn add @vibereview/react

or with pnpm:

pnpm add @vibereview/react

🚀 Quick Start

1. Wrap your app with the Provider

Add this at the root of your React app (get your keys from dashboard).

For Next.js:

// app/layout.tsx
import { VibeReviewProvider } from "@vibereview/react";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <VibeReviewProvider
          projectId="proj_abc123" // 👈 Your project ID
          apiKey="vbr_xyz789" // 👈 Your API key
          mode="development" // 👈 Use 'production' when deploying
        >
          {children}
        </VibeReviewProvider>
      </body>
    </html>
  );
}

For Standard React (Vite / CRA):

// src/App.tsx
import { VibeReviewProvider } from "@vibereview/react";

export default function App() {
  return (
    <VibeReviewProvider
      projectId="proj_abc123"
      apiKey="vbr_xyz789"
      mode="development"
    >
      <YourApp />
    </VibeReviewProvider>
  );
}

💡 Tip: Use mode="development" while testing locally to see debug logs. Switch to mode="production" (or omit it) when deploying.

2. Create a trigger in your dashboard

Go to your dashboard and create a trigger with:

  • Trigger ID: export-pdf (this is the unique identifier you'll use in your code)
  • Type: Rating, Survey, or Text feedback
  • Question: "How was the PDF export?"

3. Ask for feedback anywhere

import { useVibeReview } from "@vibereview/react";

function ExportButton() {
  const { review } = useVibeReview();

  const handleExport = async () => {
    await exportDocument(); // Your export logic

    // ✨ This is where the magic happens
    // Use the trigger ID you created in the dashboard
    await review("export-pdf"); // Beautiful widget appears!
  };

  return <button onClick={handleExport}>📄 Export PDF</button>;
}

That's it! 🎉 Users click → Widget appears → Best reviews show on landing page → Visitors convert.

No design needed. No forms to build. No database setup. Just one line that drives sales.

💡 Important: The string you pass to review() (like 'export-pdf') is the Trigger ID you created in your dashboard. It's a unique identifier that tells VibeReview which feedback widget to show.

📖 Usage Examples

⚡️ The Simplest Example (Copy & Paste Ready)

import { useVibeReview } from "@vibereview/react";

function FeedbackButton() {
  const { review } = useVibeReview();

  return (
    <button onClick={() => review("my-feature")}>💬 What do you think?</button>
  );
}

That's it! One line, one function. When users click, they see a beautiful rating widget. Best reviews → Landing page → More conversions.

Note: Make sure you created a trigger with ID 'my-feature' in your dashboard first!


🎯 Real Example: After a Purchase

function CheckoutSuccess() {
  const { review } = useVibeReview();

  // Ask for feedback right after checkout
  useEffect(() => {
    review("checkout-experience");
  }, []);

  return (
    <div>
      <h1>✅ Order Confirmed!</h1>
      <p>Your order #12345 is on its way</p>
    </div>
  );
}

What happens: User completes a purchase → Rating widget appears → Best reviews show on landing page → Future visitors trust you more → Higher conversions.


🚀 Real Example: Feature Launch

function NewExportFeature() {
  const { review } = useVibeReview();
  const [exported, setExported] = useState(false);

  const handleExport = async () => {
    // Do the export
    await exportToPDF();
    setExported(true);

    // Ask: "How was it?"
    const result = await review("pdf-export");

    if (result.completed && result.rating?.rating >= 4) {
      // User loves it! Show this review on landing page
      console.log("Great review - will boost conversions!");
    }
  };

  return <button onClick={handleExport}>📄 Export to PDF</button>;
}

What happens: User tries new feature → Rates 5 stars ⭐️⭐️⭐️⭐️⭐️ → Review appears on landing page → New visitors see social proof → More sign-ups.


💡 Real Example: Smart Retry (User Dismissed)

function SmartFeedback() {
  const { review } = useVibeReview();

  const askForFeedback = async () => {
    const result = await review("onboarding");

    if (result.completed) {
      // ✅ Got full feedback!
      console.log("Rating:", result.rating);
      console.log("Comments:", result.feedback);
      // Best reviews will appear on landing page automatically
    } else if (result.dismissed) {
      // ⏭️ User closed it - maybe ask later
      setTimeout(() => askForFeedback(), 24 * 60 * 60 * 1000); // Try again tomorrow
    }
  };

  return <button onClick={askForFeedback}>Start Tour</button>;
}

What happens: User not ready now? No problem. Ask again later. Every positive review = more conversions on your landing page.


🌍 Real Example: Multi-Language App

function LanguageMenu() {
  const { setLocale } = useVibeReview();

  return (
    <div>
      <button onClick={() => setLocale("en")}>🇬🇧 English</button>
      <button onClick={() => setLocale("fr")}>🇫🇷 Français</button>
      <button onClick={() => setLocale("es")}>🇪🇸 Español</button>
    </div>
  );
}

What happens: User picks their language → Feedback widgets automatically appear in that language. Zero translation work for you.


User Authentication

function ExportButton() {
  const { login, review } = useVibeReview();
  const [user] = useState({ id: "user_123" }); // Your auth system

  // Login user when component mounts
  useEffect(() => {
    if (user?.id) {
      login(user.id, {
        name: user.name,
        email: user.email,
        photoUrl: user.avatarUrl, // Shows on landing page social proof widgets
      });
    }
  }, [user, login]);

  const handleExport = async () => {
    // 1. Do the actual export
    await exportToPDF();

    // 2. Then ask for feedback
    await review("export-pdf");

    // 3. Best reviews automatically appear on landing page 🚀
  };

  return <button onClick={handleExport}>📄 Export PDF</button>;
}

🎨 Social Proof Components for Landing Pages

Once you collect feedback, display it on your landing page to boost conversions. All components are clickable and redirect to your public reviews page (SEO-friendly).

Available Components

import {
  ScoreBadge,
  AvatarStack,
  Carousel,
  WallOfLove,
  Fomo,
} from "@vibereview/react";

Complete Landing Page Example

import { useEffect, useState } from "react";
import {
  useVibeReview,
  ScoreBadge,
  AvatarStack,
  Carousel,
  WallOfLove,
  Fomo,
} from "@vibereview/react";
import type { ProjectInfo } from "@vibereview/react";

export function LandingPage() {
  const { getProjectInfo } = useVibeReview();
  const [info, setInfo] = useState<ProjectInfo | null>(null);

  useEffect(() => {
    getProjectInfo().then(setInfo);
  }, [getProjectInfo]);

  return (
    <main>
      {/* Hero Section: Show social proof immediately */}
      <section className="hero">
        <h1>The best tool for X</h1>
        <p>Trusted by thousands of users</p>
        <AvatarStack /> {/* Shows user avatars with ratings */}
      </section>
      {/* Testimonials Section: Only show if we have text reviews */}
      {info && info.stats.textCount > 0 && (
        <section className="testimonials">
          <h2>What our users say</h2>
          <Carousel /> {/* Sliding carousel of reviews */}
        </section>
      )}
      {/* Wall of Love: Only show if we have enough reviews */}
      {info && info.stats.count > 5 && (
        <section className="reviews">
          <h2>All Reviews</h2>
          <WallOfLove /> {/* Masonry/Grid layout */}
        </section>
      )}
      {/* Footer: Trust badge */}
      <footer>
        <ScoreBadge /> {/* Compact rating badge */}
      </footer>
      {/* Global: Real-time notifications */}
      <Fomo /> {/* "John just rated 5 stars" popup */}
    </main>
  );
}

Component Details

<ScoreBadge />

A compact trust badge showing your average rating and review count.

  • Best for: Header, Footer, Sidebar
  • Usage: <ScoreBadge />

<AvatarStack />

A row of user avatars with star rating. High-converting social proof.

  • Best for: Hero section, Pricing page, Sign-up forms
  • Usage: <AvatarStack />

<Carousel />

A sliding carousel of your best reviews.

  • Best for: Testimonials section, Homepage
  • Usage:
    <Carousel
      variant="card" // 'default' | 'card' | 'minimal'
      autoPlay={true}
      className="my-10" // Optional: Add margin/padding
    />

<WallOfLove />

A masonry or grid layout displaying many reviews at once.

  • Best for: Dedicated reviews page, Bottom of landing page
  • Usage: <WallOfLove />
  • Advanced Options:
    <WallOfLove
      variant="masonry" // 'masonry' | 'grid' | 'compact'
      contentFilter="all" // 'all' | 'text' | 'video'
      videoMode="inline" // 'modal' | 'inline'
      limit={12}
      theme="light"
      className="max-w-6xl mx-auto" // Optional container style
    />

Content Filtering:

  • contentFilter: 'all' - Show both text and video reviews (default)
  • contentFilter: 'text' - Show only text reviews
  • contentFilter: 'video' - Show only video testimonials

Video Modes:

  • videoMode: 'modal' - Click thumbnail to open video in modal (default)
  • videoMode: 'inline' - Play video directly in the card with custom controls

<Fomo />

A small notification popup showing recent reviews in real-time.

  • Best for: Global layout (appears in bottom corner)
  • Usage:
    <Fomo position="bottom-left" variant="rating-only" displayDuration={4000} />

💡 Pro Tip: All components are 100% customizable in your dashboard. Change colors, fonts, layouts, and more - no coding required. They automatically update when new reviews come in.


🎯 JavaScript Usage (No TypeScript)

The package works perfectly with plain JavaScript and still provides autocomplete!

// JavaScript (with autocomplete!)
import { VibeReviewProvider, useVibeReview } from "@vibereview/react";

function App() {
  return (
    <VibeReviewProvider projectId="proj_xxx" apiKey="vbr_xxx">
      <MyApp />
    </VibeReviewProvider>
  );
}

function MyButton() {
  const { review } = useVibeReview();

  const handleClick = async () => {
    // 'my-trigger' is the Trigger ID from your dashboard
    const result = await review("my-trigger");
    if (result.completed) {
      console.log("Done!");
    }
  };

  return <button onClick={handleClick}>Click me</button>;
}

⚙️ Configuration

Provider Props

| Prop | Type | Default | Description | | ----------- | ------------------------------- | -------------- | ---------------------------------------------------------------- | | projectId | string | required | Your VibeReview project ID | | apiKey | string | required | Your VibeReview API key | | mode | 'development' \| 'production' | 'production' | Environment mode. Use 'development' for debug logs and testing | | onReady | () => void | - | Called when SDK is loaded and ready | | onError | (error: Error) => void | - | Called if SDK fails to load |


🔄 Trigger Versioning

VibeReview supports versioning for triggers, allowing you to A/B test different widget configurations without breaking existing implementations.

Why Trigger Versions?

  • Test Changes Safely - Try new questions/options without affecting live users
  • Gradual Rollout - Roll out changes to a subset of users first
  • Rollback Support - Quickly revert to a previous version if needed
  • Version History - Track what changed and when

Usage

const { review } = useVibeReview();

// Show latest version (default)
await review("export-pdf");

// Show specific version by name (semantic versioning format)
await review("export-pdf", { version: "2.0.0" });

// Show specific version by number
await review("export-pdf", { version: { number: 2 } });

// Show specific version by explicit name
await review("export-pdf", { version: { name: "2.1.0" } });

// With callbacks AND version
await review("export-pdf", {
  onSubmit: () => console.log("Done!"),
  version: "2.0.0",
});

Version Syntax

| Syntax | Description | Example | | -------------------------------- | ------------------------------------- | ---------------------------------------- | | No version | Always use most recent version | Default behavior | | { version: '2.0.0' } | String = version name (semver format) | '1.0.0', '2.0.0', '2.1.0' | | { version: { number: 2 } } | Specific version number | { number: 1 }, { number: 2 } | | { version: { name: '2.1.0' } } | Explicit version name (semver format) | { name: '1.0.0' }, { name: '2.1.0' } |


🪝 Hook API

useVibeReview()

Returns an object with the following methods:

isReady: boolean

Whether the SDK is loaded and ready to use.

const { isReady } = useVibeReview();

return (
  <button disabled={!isReady} onClick={() => review("feedback")}>
    {isReady ? "Give Feedback" : "Loading..."}
  </button>
);

login(userId, userInfo?)

Login a user to track their feedback across sessions.

Parameters:

  • userId (string) - Unique user identifier
  • userInfo (object, optional) - User metadata
    • name (string) - User's display name
    • email (string) - User's email
    • photoUrl (string) - URL to user's avatar (shows on landing page widgets)
login("user_123", {
  name: "John Doe",
  email: "[email protected]",
  photoUrl: "https://example.com/avatar.jpg",
});

logout()

Logout the current user and clear their session.

logout();

review(triggerId, options?): Promise

Display a feedback widget and get the result. The Promise always resolves - it never rejects (except for SDK initialization errors). Check result.completed to see if the user finished the flow.

Parameters:

  • triggerId (string) - The Trigger ID from your dashboard (e.g., 'export-pdf', 'checkout-flow')
  • options (object, optional) - Callbacks and/or version options
    • onRate(data) - Called when user submits a rating
    • onFeedback(data) - Called when user submits feedback
    • onVideoSubmit(data) - Called when user submits a video
    • onSubmit(data) - Called when entire flow completes
    • onDismiss() - Called when user closes the widget
    • version (string | object) - Trigger version
      • String: 'latest', 'v1', 'v2' (treated as version name)
      • Object: { number: 2 } or { name: 'v2' }

Returns: Promise

  • completed (boolean) - True if the entire flow was completed
  • dismissed (boolean, optional) - True if user closed the widget
  • error (string, optional) - Error message if something went wrong
  • alreadySubmitted (boolean, optional) - True if user already gave feedback
  • allVersionsSeen (boolean, optional) - True if user has seen all versions
  • rating (RatingData, optional) - Rating data if user gave a rating
  • feedback (FeedbackData, optional) - Feedback data if user gave feedback
  • triggerId (string, optional) - The trigger ID
  • type ('rating' | 'feedback', optional) - Widget type shown

Examples:

// Simple async/await (use your trigger ID from dashboard)
const result = await review("export-pdf");
if (result.completed) {
  console.log("Got rating:", result.rating);
  console.log("Got feedback:", result.feedback);
}

// Handle different states
const result = await review("checkout-flow");
if (result.completed) {
  router.push("/thank-you");
} else if (result.dismissed) {
  // User closed it, but we might have partial data
  console.log("Partial rating:", result.rating);
  scheduleRetry("checkout-flow");
} else if (result.error) {
  showError(result.error);
} else if (result.alreadySubmitted) {
  showMessage("Thanks for your previous feedback!");
}

// With callbacks (still supported)
const result = await review("onboarding-survey", {
  onRate: (data) => {
    if (data.rating >= 4) {
      // User is happy!
    }
  },
  onSubmit: () => {
    // Flow completed
  },
});

// With version
const result = await review("feature-x", { version: "v2" });

// With callbacks AND version (same object!)
const result = await review("feature-x", {
  onSubmit: () => console.log("Done!"),
  version: "v2",
});

setLocale(locale)

Set the UI language for the feedback widgets.

Parameters:

  • locale (string) - Language code: 'en', 'fr', 'es', 'de', 'pt'
setLocale("fr"); // Switch to French
setLocale("es"); // Switch to Spanish

getLocale(): string

Get the current UI language.

Returns: string - Current locale code

const currentLang = getLocale(); // 'en'

getAvailableLocales(): string[]

Get list of available languages.

Returns: string[] - Array of locale codes

const languages = getAvailableLocales();
// ['en', 'fr', 'es', 'de', 'pt']

setTheme(theme)

Set the UI theme for the feedback widgets.

Parameters:

  • theme ('light' | 'dark' | 'auto') - Theme mode
    • 'light' - Force light mode
    • 'dark' - Force dark mode
    • 'auto' - Follow system preference (default)
setTheme("dark"); // Force dark mode
setTheme("light"); // Force light mode
setTheme("auto"); // Auto-detect from system

getTheme(): string

Get the current UI theme.

Returns: 'light' | 'dark' | 'auto' - Current theme setting

const currentTheme = getTheme(); // 'auto'

getProjectInfo(): Promise<ProjectInfo>

Get information about the project, including statistics and testimonials. Useful for conditionally rendering widgets based on available data.

Returns: Promise<ProjectInfo>

const info = await getProjectInfo();
console.log(info.stats.textCount); // Number of text reviews

📘 TypeScript Support

Full TypeScript support with excellent autocomplete:

import type {
  RatingData,
  FeedbackData,
  VideoData,
  SubmitData,
  ReviewResult,
  UserRating,
  UserFeedback,
  AverageRatingData,
  VibeReviewCallbacks,
} from "@vibereview/react";

const handleRate = (data: RatingData) => {
  // data.rating is typed as number (1-5)
  // data.triggerKey is typed as string
  // data.timestamp is typed as number | undefined
};

const handleFeedback = (data: FeedbackData) => {
  // data.type is typed as 'text' | 'survey-single' | 'survey-multiple' | 'video'
  // data.response is typed as string | string[]
  // data.triggerKey is typed as string
};

const handleVideo = (data: VideoData) => {
  // data.videoUrl is typed as string
  // data.videoThumbnailUrl is typed as string
};

const handleReview = async () => {
  const result: ReviewResult = await review("checkout");
  // result.completed is typed as boolean
  // result.dismissed is typed as boolean | undefined
  // result.rating is typed as RatingData | undefined
};

All Available Types

// Promise result type
interface ReviewResult {
  completed: boolean; // True if entire flow completed
  dismissed?: boolean; // True if user closed widget
  error?: string; // Error message if something went wrong
  alreadySubmitted?: boolean; // True if already gave feedback
  allVersionsSeen?: boolean; // True if seen all versions
  rating?: RatingData; // Rating data if given
  feedback?: FeedbackData; // Feedback data if given
  triggerId?: string; // Trigger identifier
  type?: "rating" | "feedback"; // Widget type shown
}

// Callback data types
interface RatingData {
  rating: number; // 1-5 stars
  triggerKey: string; // Trigger identifier
  timestamp?: number; // When rated
}

interface FeedbackData {
  type: "text" | "survey-single" | "survey-multiple" | "video";
  response: string | string[]; // Text or selected option IDs
  triggerKey: string;
  timestamp?: number;
}

interface VideoData {
  videoUrl: string;
  videoPath: string;
  videoThumbnailUrl: string;
  trigger?: any;
}

interface SubmitData {
  triggerKey: string;
  timestamp?: number;
  videoUrl?: string;
  videoThumbnailUrl?: string;
}

// API response types
interface UserRating {
  rating: number; // 1-5 stars
  createdAt?: string; // ISO date string
}

interface UserFeedback {
  type: "text" | "survey-single" | "survey-multiple";
  response: string | SurveyOption[]; // May be enriched with labels
  rating?: number; // If rating was also given
  createdAt?: string;
}

interface SurveyOption {
  id: string; // Option ID
  label: string; // Human-readable label
}

interface AverageRatingData {
  averageRating: number; // 0-5 (average)
  totalRatings: number; // Count of ratings
}

// User info type
interface UserInfo {
  name?: string;
  email?: string;
  photoUrl?: string;
}

🚀 Framework-Specific Examples

Next.js 13+ (App Router)

// app/layout.tsx
import { VibeReviewProvider } from "@vibereview/react";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <VibeReviewProvider projectId="..." apiKey="...">
          {children}
        </VibeReviewProvider>
      </body>
    </html>
  );
}

Next.js Pages Router

// pages/_app.tsx
import { VibeReviewProvider } from "@vibereview/react";

function MyApp({ Component, pageProps }) {
  return (
    <VibeReviewProvider projectId="..." apiKey="...">
      <Component {...pageProps} />
    </VibeReviewProvider>
  );
}

Vite + React

// main.tsx
import { VibeReviewProvider } from "@vibereview/react";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <VibeReviewProvider projectId="..." apiKey="...">
      <App />
    </VibeReviewProvider>
  </React.StrictMode>
);

🐛 Troubleshooting

"useVibeReview must be used within VibeReviewProvider"

Make sure your component is wrapped with <VibeReviewProvider>.

SDK not loading

Check the browser console for network errors. Ensure your domain is whitelisted in your VibeReview dashboard.

Video Recording not working

Video recording requires a secure context (HTTPS) or localhost. It will not work on insecure HTTP sites due to browser security restrictions on camera access.

TypeScript errors

Make sure you have @types/react installed:

npm install --save-dev @types/react

🐛 Troubleshooting

| Issue | Solution | |-------|----------| | useVibeReview must be used within VibeReviewProvider | Ensure your component is wrapped with <VibeReviewProvider> | | Widget not appearing | Verify the triggerId matches the one in your dashboard | | Video recording not working | Enable HTTPS or use localhost (camera requires secure context) | | TypeScript errors | Install @types/react and @types/react-dom | | No data showing | Wait a few minutes after first submission; check your dashboard | | Authentication issues | Ensure login() is called before review() for logged-in users | | Widget styling issues | Check for CSS conflicts in your app; use !important if needed |

💡 Best Practices

When to Ask for Feedback

  • After successful actions (export, download, purchase)
  • After feature usage (try new feature)
  • During natural pauses (end of onboarding, between tasks)
  • Avoid interrupting critical workflows

Trigger ID Naming Convention

// Good: Descriptive and consistent
review("export-pdf");
review("checkout-success");
review("onboarding-complete");

// Avoid: Vague names
review("feedback-1");
review("popup-3");

## 📄 License

Proprietary © VibeReview - All rights reserved

## 🔗 Links

- [Documentation](https://vibereview.co/docs)
- [Dashboard](https://vibereview.co/dashboard)
- [Support](mailto:[email protected])