
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
featurely-error-tracker
Advanced tools
Advanced error tracking SDK for Featurely with breadcrumbs, device info, and complete context
Advanced error tracking SDK for Featurely with automatic breadcrumb tracking, device information, network conditions, and complete context for error reproduction.
✨ Automatic Error Tracking - Catches unhandled errors and promise rejections
🍞 Breadcrumb Tracking - Records the last 50 user actions before errors
📱 Device & Browser Info - Captures device type, OS, browser, and screen resolution
🌐 Network Conditions - Tracks connection type and quality
🎯 User Context - Associates errors with specific users
🔔 Toast Notifications - Optional visual error alerts with customizable styles and positions
⚛️ React Integration - Error Boundary helper included
📊 Severity Levels - Categorize errors by importance
🔒 TypeScript - Fully typed for better DX
npm install featurely-error-tracker
or
yarn add featurely-error-tracker
or
pnpm add featurely-error-tracker
Get your API key from Featurely Dashboard Settings:
errors:write permissionft_live_xxx or ft_test_xxx)import { ErrorTracker } from "featurely-error-tracker";
const tracker = new ErrorTracker({
apiKey: "ft_live_your_api_key_here",
environment: "production",
appVersion: "1.0.0",
});
// Install automatic tracking
tracker.install();
Errors will now be automatically tracked and reported to Featurely with full context.
Want visual feedback when errors occur? Enable toast notifications:
const tracker = new ErrorTracker({
apiKey: "ft_live_your_api_key_here",
environment: "production",
appVersion: "1.0.0",
toast: {
enabled: true,
position: "top-right", // Choose position
duration: 5000, // Auto-dismiss after 5 seconds
showOnAutoCapture: true, // Show toasts for caught errors
},
});
tracker.install();
// Manually show toasts anytime
tracker.showToast({
message: "Operation completed successfully!",
style: "success",
});
import { ErrorTracker } from "featurely-error-tracker";
const tracker = new ErrorTracker({
apiKey: "ft_live_your_api_key",
environment: "production",
appVersion: "1.0.0",
});
tracker.install();
import { ErrorTracker, ErrorTrackerConfig } from "featurely-error-tracker";
const config: ErrorTrackerConfig = {
apiKey: process.env.FEATURELY_API_KEY!,
environment: process.env.NODE_ENV as "development" | "staging" | "production",
appVersion: "1.0.0",
releaseId: process.env.GIT_COMMIT_SHA,
maxBreadcrumbs: 50,
enabled: process.env.NODE_ENV === "production",
onError: (error) => {
console.error("Featurely SDK error:", error);
},
};
const tracker = new ErrorTracker(config);
tracker.install();
try {
await riskyOperation();
} catch (error) {
await tracker.reportError(error, "high", {
userId: currentUser.id,
action: "risky_operation",
});
}
// After user login
tracker.setUser(user.id, user.email);
// Clear user context on logout
tracker.setUser();
tracker.addBreadcrumb({
type: "custom",
message: "User clicked checkout button",
category: "navigation",
level: "info",
data: {
cartTotal: 99.99,
itemCount: 3,
},
});
import { trackOperation } from "featurely-error-tracker";
const result = await trackOperation(
tracker,
async () => {
return await fetchUserData();
},
{ action: "fetch_user_data" }
);
import { Component, ErrorInfo, ReactNode } from 'react';
import { ErrorTracker, ErrorBoundaryTracker } from 'featurely-error-tracker';
const tracker = new ErrorTracker({
apiKey: 'ft_live_your_api_key',
environment: 'production',
appVersion: '1.0.0'
});
const boundaryTracker = new ErrorBoundaryTracker(tracker);
interface Props {
children: ReactNode;
}
interface State {
hasError: boolean;
}
class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
boundaryTracker.captureError(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
import ErrorBoundary from './components/ErrorBoundary';
function App() {
return (
<ErrorBoundary>
<YourApp />
</ErrorBoundary>
);
}
Create app/providers.tsx:
'use client';
import { useEffect } from 'react';
import { ErrorTracker } from 'featurely-error-tracker';
let tracker: ErrorTracker | null = null;
export function ErrorTrackingProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
if (!tracker) {
tracker = new ErrorTracker({
apiKey: process.env.NEXT_PUBLIC_FEATURELY_API_KEY!,
environment: process.env.NODE_ENV as 'production' | 'development',
appVersion: '1.0.0'
});
tracker.install();
}
return () => {
tracker?.uninstall();
};
}, []);
return <>{children}</>;
}
Use in app/layout.tsx:
import { ErrorTrackingProvider } from './providers';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<ErrorTrackingProvider>
{children}
</ErrorTrackingProvider>
</body>
</html>
);
}
Create pages/_app.tsx:
import { ErrorTracker } from 'featurely-error-tracker';
import type { AppProps } from 'next/app';
import { useEffect } from 'react';
const tracker = new ErrorTracker({
apiKey: process.env.NEXT_PUBLIC_FEATURELY_API_KEY!,
environment: process.env.NODE_ENV as 'production' | 'development',
appVersion: '1.0.0'
});
function MyApp({ Component, pageProps }: AppProps) {
useEffect(() => {
tracker.install();
return () => tracker.uninstall();
}, []);
return <Component {...pageProps} />;
}
export default MyApp;
ErrorTrackerMain class for error tracking.
interface ErrorTrackerConfig {
apiKey: string; // Required: Your Featurely API key
apiUrl?: string; // Optional: Custom API endpoint
environment?: string; // Optional: 'development' | 'staging' | 'production'
appVersion?: string; // Optional: Your app version
releaseId?: string; // Optional: Git commit SHA or release ID
maxBreadcrumbs?: number; // Optional: Max breadcrumbs to keep (default: 50)
enabled?: boolean; // Optional: Enable/disable tracking (default: true)
validateApiKey?: boolean; // Optional: Validate API key format (default: true)
onError?: (error: Error) => void; // Optional: Callback for SDK errors
toast?: {
// Optional: Toast notification configuration
enabled?: boolean; // Enable toast notifications (default: false)
position?: ToastPosition; // Default position: 'top-right'
duration?: number; // Auto-dismiss duration in ms (default: 5000)
showOnAutoCapture?: boolean; // Show toasts for auto-captured errors (default: true)
};
}
install(): voidInstalls automatic error tracking. This will track:
tracker.install();
uninstall(): voidRemoves all tracking and restores original functions.
tracker.uninstall();
reportError(error, severity?, context?): Promise<void>Manually report an error.
await tracker.reportError(new Error("Something went wrong"), "high", {
userId: "123",
action: "checkout",
});
Parameters:
error: Error - The error object to reportseverity?: 'low' | 'medium' | 'high' | 'critical' - Severity level (default: 'medium')context?: Record<string, unknown> - Additional context dataaddBreadcrumb(data): voidManually add a breadcrumb.
tracker.addBreadcrumb({
type: "custom",
message: "User performed action",
category: "user-action",
level: "info",
data: { key: "value" },
});
Breadcrumb Types:
navigation - Page navigationclick - User clicksinput - Form inputshttp - HTTP requestsconsole - Console messagescustom - Custom eventssetUser(userId?, userEmail?): voidSet user context for error attribution.
tracker.setUser("user_123", "user@example.com");
getSessionId(): stringGet the current session ID.
const sessionId = tracker.getSessionId();
isTrackerInstalled(): booleanCheck if automatic tracking is installed.
if (tracker.isTrackerInstalled()) {
console.log("Tracking is active");
}
showToast(options): voidDisplay a toast notification with customizable style and position.
Note: Toast notifications must be enabled in the config (toast.enabled: true).
// Show error toast
tracker.showToast({
message: "Failed to save data",
style: "error",
position: "top-right",
duration: 5000,
closable: true,
});
// Show success toast
tracker.showToast({
message: "Data saved successfully!",
style: "success",
position: "top-center",
duration: 3000,
});
// Show warning that stays until manually closed
tracker.showToast({
message: "Please review your changes",
style: "warning",
duration: 0, // 0 = no auto-dismiss
});
Toast Options:
interface ToastOptions {
message: string; // Toast message to display
style?: ToastStyle; // 'error' | 'warning' | 'success' | 'info' (default: 'error')
position?: ToastPosition; // Position on screen (default: from config)
duration?: number; // Auto-dismiss in ms, 0 to disable (default: 5000)
closable?: boolean; // Show close button (default: true)
}
type ToastPosition =
| "top-left"
| "top-center"
| "top-right"
| "bottom-left"
| "bottom-center"
| "bottom-right";
type ToastStyle = "error" | "warning" | "success" | "info";
Toast Styles:
error - Red gradient backgroundwarning - Orange gradient backgroundsuccess - Green gradient backgroundinfo - Blue gradient backgroundExample with Auto-Capture:
const tracker = new ErrorTracker({
apiKey: "ft_live_xxx",
toast: {
enabled: true,
position: "top-right",
duration: 5000,
showOnAutoCapture: true, // Auto-show toasts for caught errors
},
});
tracker.install();
// Now any unhandled error will automatically show a toast notification
// You can also manually trigger toasts:
try {
await riskyOperation();
} catch (error) {
await tracker.reportError(error, "high");
tracker.showToast({
message: "Operation failed. Please try again.",
style: "error",
});
}
trackOperation<T>(tracker, operation, context?): Promise<T>Utility function to wrap async operations with automatic error tracking.
import { trackOperation } from "featurely-error-tracker";
const data = await trackOperation(tracker, async () => await fetchData(), {
action: "fetch_data",
});
ErrorBoundaryTrackerHelper class for React Error Boundaries.
import { ErrorBoundaryTracker } from 'featurely-error-tracker';
const boundaryTracker = new ErrorBoundaryTracker(tracker);
// In your Error Boundary:
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
boundaryTracker.captureError(error, errorInfo);
}
try {
const tracker = new ErrorTracker({
apiKey: "", // ❌ Invalid
});
} catch (error) {
console.error(error.message);
// "API key is required. Get your API key from: https://featurely.no/dashboard/settings"
}
try {
const tracker = new ErrorTracker({
apiKey: "invalid_key", // ❌ Wrong format
});
} catch (error) {
console.error(error.message);
// "Invalid API key format. Expected format: ft_live_xxx or ft_test_xxx"
}
const tracker = new ErrorTracker({
apiKey: "custom_key",
validateApiKey: false, // ✅ Skip validation
});
Store your API key in environment variables:
# .env.local
NEXT_PUBLIC_FEATURELY_API_KEY=ft_live_your_api_key_here
Then use it:
const tracker = new ErrorTracker({
apiKey: process.env.NEXT_PUBLIC_FEATURELY_API_KEY!,
environment: process.env.NODE_ENV as "production" | "development",
});
Initialize the tracker as early as possible in your application lifecycle.
// ✅ Good: Initialize in app entry point
// src/index.tsx or app/layout.tsx
Never hardcode API keys in your source code.
// ❌ Bad
const tracker = new ErrorTracker({ apiKey: "ft_live_123..." });
// ✅ Good
const tracker = new ErrorTracker({ apiKey: process.env.FEATURELY_API_KEY });
Avoid sending development errors to production.
const tracker = new ErrorTracker({
apiKey: process.env.FEATURELY_API_KEY!,
enabled: process.env.NODE_ENV === "production",
});
Always set user context after login for better error attribution.
// After successful login
tracker.setUser(user.id, user.email);
// After logout
tracker.setUser();
Add custom breadcrumbs for critical user actions.
tracker.addBreadcrumb({
type: "custom",
message: "User initiated payment",
category: "payment",
level: "info",
data: { amount: 99.99, currency: "USD" },
});
console.log(tracker.isTrackerInstalled()); // Should be true
console.log(process.env.FEATURELY_API_KEY); // Should start with ft_live_ or ft_test_
If your site uses a Content-Security-Policy header, you must allow connections to https://www.featurely.no. Without this, error reports will be silently dropped.
Add to your connect-src directive:
connect-src 'self' https://www.featurely.no;
Next.js example (next.config.js):
const cspHeader = `
connect-src 'self' https://www.featurely.no;
`.trim();
If CSP is blocking the SDK, you will see this in the browser console:
[ErrorTracker] ⚠️ Network error — this may be caused by a Content-Security-Policy.
Add "https://www.featurely.no" to your connect-src directive.
The SDK logs actionable console errors for common auth issues:
| Situation | Console message |
|---|---|
| Invalid or expired API key (401) | Link to API Keys settings page with instructions to create a new key |
API key lacks errors:write permission (403) | Instructions to update the key's permissions in the dashboard |
Reduce the number of breadcrumbs:
const tracker = new ErrorTracker({
apiKey: "ft_live_xxx",
maxBreadcrumbs: 20, // Default is 50
});
Make sure you have TypeScript installed:
npm install --save-dev typescript
This package is written in TypeScript and includes full type definitions.
import {
ErrorTracker,
ErrorTrackerConfig,
BreadcrumbData,
DeviceInfo,
NetworkInfo,
AppContext,
InvalidApiKeyError,
ConfigurationError,
} from "featurely-error-tracker";
Complete example files are available in the examples/ directory:
basic.example.js - Basic JavaScript usagereact.example.tsx - React with Error Boundarynextjs.example.tsx - Next.js (App Router + Pages Router)MIT © Featurely
Contributions are welcome! Please feel free to submit a Pull Request.
Made with ❤️ by Featurely
FAQs
Advanced error tracking SDK for Featurely with breadcrumbs, device info, and complete context
We found that featurely-error-tracker demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.