React SDK
React SDK for event tracking, error monitoring, and logging in React applications. Built on top of logstyx-js-core, the React SDK provides React-specific features including an ErrorBoundary component and a Trackable component for declarative event tracking.
Installation
npm install github:devatlogstyx/logstyx-js-react#releaseQuick Start
import useLogstyx from 'logstyx-js-react';
function App() {
const logger = useLogstyx({
projectId: 'your_project_id',
endpoint: 'https://your-domain.com/api/v1/logs',
captureUncaught: true,
captureUnhandledRejections: true
});
const { ErrorBoundary, Trackable } = logger;
return (
<ErrorBoundary logger={logger}>
<div>
<Trackable
event="click"
context={{ page: 'home' }}
data={{ action: 'cta-click' }}>
<button>Get Started</button>
</Trackable>
</div>
</ErrorBoundary>
);
}Origin Configuration Required
Make sure to add your domain to the allowed origins in your Logstyx dashboard under Project Settings → Security.
Configuration
useLogstyx(options)
Initializes the Logstyx SDK and returns the logger instance with React components.
Required Options
projectId (string)
Your Logstyx project identifier.
projectId: 'proj_abc123xyz'endpoint (string)
Your Logstyx API endpoint.
endpoint: 'https://logs.yourcompany.com/api/v1/logs'Optional Options
captureUncaught (boolean)
Automatically capture uncaught JavaScript exceptions.
Default: false
captureUncaught: truecaptureUnhandledRejections (boolean)
Automatically capture unhandled Promise rejections.
Default: false
captureUnhandledRejections: truepersistentSession (boolean)
Automatically add sessionId on context that persist over the visiting session.
Default: false
persistentSession: trueErrorBoundary Component
React component that catches errors in child components and logs them to Logstyx. Prevents your entire app from crashing when an error occurs.
Basic Usage
import useLogstyx from 'logstyx-js-react';
function App() {
const logger = useLogstyx({
projectId: 'proj_abc123',
endpoint: 'https://logs.example.com/api/v1/logs'
});
const { ErrorBoundary } = logger;
return (
<ErrorBoundary logger={logger}>
<YourApp />
</ErrorBoundary>
);
}With Custom Fallback UI
function CustomFallbackUI({ error, errorInfo }) {
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h2>Oops! Something went wrong.</h2>
<p>{error?.message || 'An unknown error occurred'}</p>
<details style={{ marginTop: '20px' }}>
<summary>Click for technical details</summary>
<pre style={{ textAlign: 'left', overflow: 'auto' }}>
{errorInfo?.componentStack}
</pre>
</details>
<button onClick={() => window.location.reload()}>
Reload Page
</button>
</div>
);
}
function App() {
const logger = useLogstyx({ projectId: 'proj_abc123' });
const { ErrorBoundary } = logger;
return (
<ErrorBoundary logger={logger} fallbackUI={CustomFallbackUI}>
<YourApp />
</ErrorBoundary>
);
}Multiple Error Boundaries
Use multiple ErrorBoundary components to isolate errors to specific parts of your app:
function App() {
const logger = useLogstyx({ projectId: 'proj_abc123' });
const { ErrorBoundary } = logger;
return (
<div>
<Header />
<ErrorBoundary logger={logger}>
<Sidebar />
</ErrorBoundary>
<ErrorBoundary logger={logger}>
<MainContent />
</ErrorBoundary>
<ErrorBoundary logger={logger}>
<Footer />
</ErrorBoundary>
</div>
);
}Props
| Prop | Type | Required | Description |
|---|---|---|---|
logger | object | Yes | The logger instance from useLogstyx() |
fallbackUI | component | No | Custom error UI component |
children | node | Yes | Child components to protect |
FallbackUI Props:
| Prop | Type | Description |
|---|---|---|
error | Error | The error that was caught |
errorInfo | object | React error info with componentStack |
Trackable Component
Declarative component for tracking user interactions without writing event handlers.
Basic Usage
import useLogstyx from 'logstyx-js-react';
function MyComponent() {
const logger = useLogstyx({ projectId: 'proj_abc123' });
const { Trackable } = logger;
return (
<Trackable event="click" data={{ action: 'button_click' }}>
<button>Click Me</button>
</Trackable>
);
}With Context
Add persistent context that applies to all events:
<Trackable
event="click"
context={{ page: 'pricing', section: 'hero' }}
data={{ plan: 'pro', action: 'signup' }}>
<button>Start Free Trial</button>
</Trackable>Multiple Events
Track multiple events on a single element:
<Trackable
event="focus blur change"
context={{ field: 'email' }}
data={{ formType: 'newsletter' }}>
<input type="email" placeholder="Enter your email" />
</Trackable>Custom Log Level
<Trackable
event="click"
level="warning"
data={{ action: 'delete_draft' }}>
<button>Delete Draft</button>
</Trackable>Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
event | string | Yes | - | Space-separated DOM events (e.g., "click", "submit", "click submit") |
context | object | No | {} | Context metadata |
data | object | No | {} | Event-specific data |
level | string | No | "info" | Log level: "info", "warning", "error", "critical" |
children | node | Yes | - | Single child element |
Single Child Required
Trackable must have exactly one child element. Use a wrapper <div> if you need to track multiple elements.
Manual Logging
Use the logger instance directly for manual logging:
Log Levels
function MyComponent() {
const logger = useLogstyx({ projectId: 'proj_abc123' });
const handleAction = async () => {
try {
logger.info({ message: 'Action started', userId: '123' });
const result = await performAction();
logger.info({
message: 'Action completed',
result: result.status
});
} catch (error) {
logger.error({
message: 'Action failed',
error: error.message
});
}
};
return <button onClick={handleAction}>Perform Action</button>;
}Available Methods
// Info level
logger.info({ message: 'User logged in', userId: '123' });
// Warning level
logger.warning({ message: 'API rate limit approaching' });
// Error level
logger.error({ message: 'Payment failed', error: err.message });
// Critical level
logger.critical({ message: 'Database connection lost' });
// Custom level
logger.send('custom', { message: 'Custom event' });Context Management
Set and clear context for multiple logs:
function UserProfile({ user }) {
const logger = useLogstyx({ projectId: 'proj_abc123' });
useEffect(() => {
// Set context when component mounts
logger.setContext({
userId: user.id,
userRole: user.role,
page: 'profile'
});
// Clear context when component unmounts
return () => logger.clearContext();
}, [user.id]);
const handleUpdate = () => {
// This log will include the context
logger.info({ message: 'Profile updated' });
};
return <button onClick={handleUpdate}>Update Profile</button>;
}Complete Examples
E-commerce Tracking
import useLogstyx from 'logstyx-js-react';
function ProductPage({ product }) {
const logger = useLogstyx({
projectId: 'proj_abc123',
endpoint: 'https://logs.example.com/api/v1/logs'
});
const { Trackable } = logger;
return (
<div>
<h1>{product.name}</h1>
<Trackable
event="click"
context={{ page: 'product', productId: product.id }}
data={{ action: 'add_to_cart', price: product.price }}>
<button>Add to Cart</button>
</Trackable>
<Trackable
event="click"
context={{ page: 'product', productId: product.id }}
data={{ action: 'buy_now', price: product.price }}
level="info">
<button>Buy Now</button>
</Trackable>
<Trackable
event="click"
context={{ page: 'product', productId: product.id }}
data={{ action: 'view_details' }}>
<a href={`/products/${product.id}/details`}>
View Details
</a>
</Trackable>
</div>
);
}Form Tracking
function SignupForm() {
const logger = useLogstyx({ projectId: 'proj_abc123' });
const { Trackable } = logger;
const handleSubmit = async (e) => {
e.preventDefault();
logger.info({
message: 'Signup form submitted',
referrer: document.referrer
});
try {
await submitSignup(formData);
logger.info({ message: 'Signup successful' });
} catch (error) {
logger.error({
message: 'Signup failed',
error: error.message
});
}
};
return (
<form onSubmit={handleSubmit}>
<Trackable
event="focus blur"
context={{ field: 'email', form: 'signup' }}>
<input type="email" name="email" required />
</Trackable>
<Trackable
event="focus blur"
context={{ field: 'password', form: 'signup' }}>
<input type="password" name="password" required />
</Trackable>
<button type="submit">Sign Up</button>
</form>
);
}Feature Usage Tracking
function Dashboard() {
const logger = useLogstyx({ projectId: 'proj_abc123' });
const { Trackable } = logger;
useEffect(() => {
logger.setContext({
page: 'dashboard',
userId: currentUser.id
});
return () => logger.clearContext();
}, []);
return (
<div>
<Trackable
event="click"
data={{ feature: 'export', format: 'csv' }}>
<button>Export CSV</button>
</Trackable>
<Trackable
event="click"
data={{ feature: 'filter', filterType: 'date' }}>
<button>Filter by Date</button>
</Trackable>
<Trackable
event="click"
data={{ feature: 'refresh' }}>
<button>Refresh Data</button>
</Trackable>
</div>
);
}Error Handling with ErrorBoundary
import useLogstyx from 'logstyx-js-react';
function ErrorFallback({ error, errorInfo }) {
return (
<div className="error-container">
<h1>Something went wrong</h1>
<p>We've been notified and are working on it.</p>
<details>
<summary>Error details</summary>
<p><strong>Error:</strong> {error?.message}</p>
<pre>{errorInfo?.componentStack}</pre>
</details>
<button onClick={() => window.location.reload()}>
Reload Page
</button>
</div>
);
}
function App() {
const logger = useLogstyx({
projectId: 'proj_abc123',
endpoint: 'https://logs.example.com/api/v1/logs',
captureUncaught: true,
captureUnhandledRejections: true,
persistentSession:true
});
const { ErrorBoundary } = logger;
return (
<ErrorBoundary logger={logger} fallbackUI={ErrorFallback}>
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Router>
</ErrorBoundary>
);
}Best Practices
1. Initialize Once at App Root
// ✅ Good: Initialize at app root
function App() {
const logger = useLogstyx({ projectId: 'proj_abc123' });
const { ErrorBoundary } = logger;
return (
<ErrorBoundary logger={logger}>
<Router>
<Routes>...</Routes>
</Router>
</ErrorBoundary>
);
}
// ❌ Avoid: Re-initializing in every component
function MyComponent() {
const logger = useLogstyx({ projectId: 'proj_abc123' }); // Don't do this
// ...
}2. Use Context for Related Events
// ✅ Good: Set context once
useEffect(() => {
logger.setContext({ page: 'checkout', userId: user.id });
return () => logger.clearContext();
}, []);
logger.info({ message: 'Step 1 completed' });
logger.info({ message: 'Step 2 completed' });
// ❌ Avoid: Repeating context
logger.info({ message: 'Step 1', page: 'checkout', userId: user.id });
logger.info({ message: 'Step 2', page: 'checkout', userId: user.id });3. Trackable for Simple Interactions
// ✅ Good: Use Trackable for simple clicks
<Trackable event="click" data={{ action: 'download' }}>
<button>Download</button>
</Trackable>
// ✅ Good: Use manual logging for complex logic
const handleComplexAction = async () => {
logger.info({ message: 'Action started' });
try {
const result = await complexOperation();
logger.info({ message: 'Action completed', result });
} catch (error) {
logger.error({ message: 'Action failed', error: error.message });
}
};4. Strategic ErrorBoundary Placement
// ✅ Good: Multiple boundaries for isolation
function App() {
return (
<div>
<Header />
<ErrorBoundary logger={logger}>
<Sidebar />
</ErrorBoundary>
<ErrorBoundary logger={logger}>
<MainContent /> {/* Error here won't crash Sidebar */}
</ErrorBoundary>
</div>
);
}5. Enable Error Capture in Production
const logger = useLogstyx({
projectId: process.env.REACT_APP_LOGSTYX_PROJECT_ID,
endpoint: process.env.REACT_APP_LOGSTYX_ENDPOINT,
captureUncaught: process.env.NODE_ENV === 'production',
captureUnhandledRejections: process.env.NODE_ENV === 'production'
persistentSession:true,
});6. Structured Data for Better Insights
// ❌ Avoid: Plain strings
logger.info('User clicked button');
// ✅ Better: Structured data
logger.info({
message: 'User interaction',
action: 'button_click',
buttonId: 'cta-signup',
page: 'landing',
timestamp: Date.now()
});Troubleshooting
Trackable Component Not Working
Issue: Events aren't being tracked
Solution: Ensure Trackable has exactly one child:
// ❌ Wrong: Multiple children
<Trackable event="click">
<button>Button 1</button>
<button>Button 2</button>
</Trackable>
// ✅ Correct: Single child
<Trackable event="click">
<div>
<button>Button 1</button>
<button>Button 2</button>
</div>
</Trackable>ErrorBoundary Not Catching Errors
Issue: Errors aren't being caught
Solution: ErrorBoundary only catches errors in child components, not in:
- Event handlers (use try-catch)
- Asynchronous code (use try-catch)
- Server-side rendering
- Errors in ErrorBoundary itself
// ❌ Won't be caught by ErrorBoundary
<button onClick={() => {
throw new Error('Click error');
}}>
Click
</button>
// ✅ Will be caught
<button onClick={() => {
try {
riskyOperation();
} catch (error) {
logger.error({ message: 'Error', error: error.message });
}
}}>
Click
</button>Context Not Persisting
Issue: Context is lost between logs
Solution: Make sure to set context before logging:
// Set context
logger.setContext({ userId: '123' });
// Context will be included in this log
logger.info({ message: 'Action' });
// Clear when done
logger.clearContext();Origin Errors
Issue: Getting CORS or origin errors
Solution: Add your domain to allowed origins in Logstyx dashboard:
- Go to Project Detail Page
- Click Settings
- Add your domain to allowed origins
- Include both development (
http://localhost:3000) and production domains
Integration with React Router
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import useLogstyx from 'logstyx-js-react';
function App() {
const logger = useLogstyx({ projectId: 'proj_abc123' });
const { ErrorBoundary } = logger;
const location = useLocation();
// Log page views
useEffect(() => {
logger.info({
message: 'Page view',
path: location.pathname,
search: location.search
});
}, [location]);
return (
<ErrorBoundary logger={logger}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</ErrorBoundary>
);
}