Skip to main content

Overview

Error tracking automatically captures JavaScript errors, unhandled promise rejections, and React component errors. This helps you identify and fix issues quickly, improving application stability and user experience.

Quick Start

1

Enable Error Tracking

Set enableErrorTracking: true in your analytics configuration:
import { AnalyticsProvider } from "mentiq-sdk";

function App() {
  return (
    <AnalyticsProvider
      config={{
        apiKey: "your-api-key",
        projectId: "your-project-id",
        enableErrorTracking: true,
      }}
    >
      <YourApp />
    </AnalyticsProvider>
  );
}
2

Automatic Error Capture

Once enabled, the SDK automatically captures:
  • JavaScript runtime errors
  • Unhandled promise rejections
  • React component errors (when using ErrorBoundary)
  • Network errors (optional)
3

View in Dashboard

Access error reports in your MentiQ dashboard to:
  • See error frequency and trends
  • View stack traces and context
  • Identify affected users
  • Track error resolution

Automatic Error Tracking

When enabled, the SDK automatically captures errors:

JavaScript Errors

From src/analytics.ts:321-365, the SDK listens for global error events:
private setupErrorTracking(): void {
  if (typeof window === "undefined") return;

  const trackJavaScriptError = (event: ErrorEvent) => {
    const errorData: ErrorData = {
      message: event.message,
      stack: event.error?.stack,
      filename: event.filename,
      lineno: event.lineno,
      colno: event.colno,
      type: "javascript",
    };

    const analyticsEvent = createEvent("error", "javascript_error", {
      error: errorData,
    });
    this.enqueueEvent(analyticsEvent);
  };

  const trackUnhandledRejection = (event: PromiseRejectionEvent) => {
    const errorData: ErrorData = {
      message: event.reason?.message || String(event.reason),
      stack: event.reason?.stack,
      type: "unhandledrejection",
    };

    const analyticsEvent = createEvent("error", "unhandled_rejection", {
      error: errorData,
    });
    this.enqueueEvent(analyticsEvent);
  };

  window.addEventListener("error", trackJavaScriptError);
  window.addEventListener("unhandledrejection", trackUnhandledRejection);
}

Error Data Structure

interface ErrorData {
  message: string;          // Error message
  stack?: string;           // Stack trace
  filename?: string;        // File where error occurred
  lineno?: number;          // Line number
  colno?: number;           // Column number
  type: "javascript" | "unhandledrejection" | "network" | "custom";
}

Manual Error Tracking

Using the Hook

import { useErrorTracking } from "mentiq-sdk";

function MyComponent() {
  const { trackJavaScriptError, trackCustomError } = useErrorTracking();

  const handleOperation = async () => {
    try {
      await riskyOperation();
    } catch (error) {
      trackJavaScriptError(error, {
        context: "user-operation",
        userId: currentUser.id,
      });
    }
  };

  const handleValidation = () => {
    if (!isValid) {
      trackCustomError("Validation failed", {
        field: "email",
        value: email,
      });
    }
  };

  return (
    <button onClick={handleOperation}>Perform Operation</button>
  );
}

Using Analytics Instance

import { useAnalytics } from "mentiq-sdk";

function DataFetcher() {
  const { trackCustomError } = useAnalytics();

  useEffect(() => {
    fetchData()
      .catch(error => {
        trackCustomError(error, {
          context: "data-fetch",
          endpoint: "/api/users",
          timestamp: new Date().toISOString(),
        });
      });
  }, []);

  return <div>Loading...</div>;
}

React Error Boundaries

Use the AnalyticsErrorBoundary component to catch React component errors:
import { AnalyticsErrorBoundary } from "mentiq-sdk";

function App() {
  return (
    <AnalyticsErrorBoundary 
      fallback={<ErrorFallback />}
    >
      <YourApp />
    </AnalyticsErrorBoundary>
  );
}

function ErrorFallback() {
  return (
    <div>
      <h1>Something went wrong</h1>
      <p>We've been notified and are working on a fix.</p>
    </div>
  );
}

Granular Error Boundaries

Wrap specific components for better error isolation:
function Dashboard() {
  return (
    <div>
      <AnalyticsErrorBoundary fallback={<WidgetError />}>
        <CriticalWidget />
      </AnalyticsErrorBoundary>
      
      <AnalyticsErrorBoundary fallback={<ChartError />}>
        <AnalyticsChart />
      </AnalyticsErrorBoundary>
    </div>
  );
}

Use Cases

Track API Errors

function useAPI() {
  const { trackCustomError } = useAnalytics();

  const fetchData = async (endpoint: string) => {
    try {
      const response = await fetch(endpoint);
      
      if (!response.ok) {
        trackCustomError(`API Error: ${response.status}`, {
          endpoint,
          status: response.status,
          statusText: response.statusText,
        });
        throw new Error(`HTTP ${response.status}`);
      }
      
      return await response.json();
    } catch (error) {
      trackCustomError(error, {
        context: "api-fetch",
        endpoint,
      });
      throw error;
    }
  };

  return { fetchData };
}

Track Form Validation Errors

function ContactForm() {
  const { trackCustomError } = useAnalytics();

  const handleSubmit = (data: FormData) => {
    const errors = validateForm(data);
    
    if (errors.length > 0) {
      trackCustomError("Form validation failed", {
        formName: "contact-form",
        errors: errors.map(e => e.field).join(", "),
        errorCount: errors.length,
      });
      
      setFormErrors(errors);
      return;
    }
    
    submitForm(data);
  };

  return <form onSubmit={handleSubmit}>...</form>;
}

Track Authentication Errors

function LoginPage() {
  const { trackCustomError } = useAnalytics();

  const handleLogin = async (email: string, password: string) => {
    try {
      await signIn(email, password);
    } catch (error) {
      trackCustomError(error, {
        context: "authentication",
        action: "login",
        email_domain: email.split("@")[1], // Don't log full email
      });
      
      setError("Invalid credentials");
    }
  };

  return <LoginForm onSubmit={handleLogin} />;
}

Track Third-Party Integration Errors

function StripeCheckout() {
  const { trackCustomError } = useAnalytics();

  const handlePayment = async (paymentMethod: string) => {
    try {
      const result = await stripe.confirmPayment(paymentMethod);
      
      if (result.error) {
        trackCustomError("Stripe payment failed", {
          errorCode: result.error.code,
          errorType: result.error.type,
          amount: paymentAmount,
        });
      }
    } catch (error) {
      trackCustomError(error, {
        context: "stripe-integration",
        paymentMethod,
      });
    }
  };

  return <PaymentForm onSubmit={handlePayment} />;
}

Error Context & Enrichment

Add contextual information to errors for better debugging:
function ProductPage({ productId }) {
  const { trackCustomError } = useAnalytics();
  const { user } = useAuth();

  const handleAddToCart = async () => {
    try {
      await addToCart(productId);
    } catch (error) {
      trackCustomError(error, {
        // Context about the operation
        context: "add-to-cart",
        
        // Product info
        productId,
        
        // User info (avoid PII)
        userId: user?.id,
        userPlan: user?.plan,
        
        // Device/browser info (automatically captured)
        timestamp: new Date().toISOString(),
        
        // Custom metadata
        cartItemCount: cart.items.length,
      });
    }
  };

  return <AddToCartButton onClick={handleAddToCart} />;
}

Error Sampling

For high-volume applications, sample errors to reduce noise:
function useSmartErrorTracking() {
  const { trackCustomError } = useAnalytics();

  const trackError = (error: Error, properties?: EventProperties) => {
    // Sample 10% of common errors, track all critical errors
    const isCritical = properties?.severity === "critical";
    const shouldTrack = isCritical || Math.random() < 0.1;

    if (shouldTrack) {
      trackCustomError(error, properties);
    }
  };

  return { trackError };
}

Error Grouping

Group similar errors for better insights:
function trackGroupedError(error: Error, group: string) {
  const { trackCustomError } = useAnalytics();

  trackCustomError(error, {
    errorGroup: group,        // Group related errors
    errorHash: hashError(error), // Unique identifier for deduplication
  });
}

// Usage
try {
  await fetchUserData();
} catch (error) {
  trackGroupedError(error, "data-loading-errors");
}

Privacy Considerations

Be careful not to log sensitive information in error messages:
  • Avoid logging passwords, tokens, or API keys
  • Redact PII (personally identifiable information)
  • Sanitize user input before logging
  • Don’t log full credit card numbers

Safe Error Logging

function safeErrorTracking(error: Error, context: any) {
  const { trackCustomError } = useAnalytics();

  // Sanitize context to remove sensitive data
  const sanitizedContext = {
    ...context,
    password: undefined,
    token: undefined,
    creditCard: context.creditCard ? 
      `****${context.creditCard.slice(-4)}` : undefined,
    email: context.email ? 
      context.email.split("@")[1] : undefined, // Only log domain
  };

  trackCustomError(error, sanitizedContext);
}

Error Hook API

From src/hooks.ts:117-172, the useErrorTracking hook provides:
const { 
  trackJavaScriptError, 
  trackCustomError 
} = useErrorTracking();

// Track JavaScript Error objects
trackJavaScriptError(error: Error, properties?: EventProperties)

// Track custom error messages
trackCustomError(message: string, properties?: EventProperties)
The hook also auto-tracks global errors:
useEffect(() => {
  const handleError = (event: ErrorEvent) => {
    trackJavaScriptError(event.error, {
      filename: event.filename,
      lineno: event.lineno,
      colno: event.colno,
    });
  };

  const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
    trackCustomError(`Unhandled Promise Rejection: ${event.reason}`, {
      type: "unhandledrejection",
    });
  };

  window.addEventListener("error", handleError);
  window.addEventListener("unhandledrejection", handleUnhandledRejection);

  return () => {
    window.removeEventListener("error", handleError);
    window.removeEventListener("unhandledrejection", handleUnhandledRejection);
  };
}, []);

Best Practices

Error Tracking Tips:
  • Always include context (what the user was doing)
  • Add user and session identifiers for debugging
  • Group related errors for better insights
  • Set severity levels (critical, warning, info)
  • Don’t log sensitive user data
  • Sample high-frequency errors to avoid noise
  • Monitor error trends, not just counts

Troubleshooting

Errors Not Being Captured

  1. Verify enableErrorTracking: true in config
  2. Check browser console for SDK errors (enable debug: true)
  3. Ensure error occurs after SDK initialization

Missing Stack Traces

Stack traces may be missing for:
  • Cross-origin errors (CORS)
  • Minified code without source maps
  • Some browser privacy settings
Enable source maps in production for better stack traces.

Duplicate Errors

If seeing duplicate errors:
  • Check for multiple error listeners
  • Ensure only one AnalyticsProvider exists
  • Verify error boundary isn’t re-mounting

Build docs developers (and LLMs) love