@inputless/react
v1.0.6
Published
React integration components and hooks for Inputless Analytics
Maintainers
Readme
@inputless/react
React integration for Inputless Analytics - Comprehensive behavioral analytics for React applications.
Purpose
Provides React hooks, context providers, and pre-built components for easy integration of Inputless Analytics into React applications. This package enables automatic event tracking, pattern analysis, and real-time insights with minimal code changes.
Features
- React Hooks:
useInputlessTracker(),useInputlessInsights(),useInputlessContext(),useTrackedEvent() - Context Provider:
<InputlessProvider>for app-wide analytics configuration - Pre-built Tracked Components: Button, Input, Link, Form, Image with automatic tracking
- Document Components: Upload and view documents with AI-powered insights
- SSR Support: Server-side rendering compatible (Next.js, Remix, etc.)
- Type-Safe: Full TypeScript support with comprehensive type definitions
- PII Protection: Automatic protection of personally identifiable information
- Real-time Insights: Access patterns, anomalies, and behavioral insights
Installation
npm install @inputless/react @inputless/tracker @inputless/context @inputless/eventsOr with yarn:
yarn add @inputless/react @inputless/tracker @inputless/context @inputless/eventsDependencies
@inputless/tracker- Core tracking functionality@inputless/context- Pattern analysis and context engine@inputless/events- Event type definitionsreact^18.2.0 - React hooks support
Quick Start
1. Wrap Your App with InputlessProvider (Local Only - No API Endpoint)
import { InputlessProvider } from '@inputless/react';
import type { TrackerConfig } from '@inputless/tracker';
function App() {
// Local-only configuration (no API endpoint)
const config: TrackerConfig = {
enabledCategories: { ui: true, form: true },
debug: true,
// No apiEndpoint - all processing is local
};
return (
<InputlessProvider
config={config}
autoPageView={true}
autoTrack={true}
debug={true}
>
<YourApp />
</InputlessProvider>
);
}2. Use Pre-built Tracked Components
import { TrackedButton, TrackedInput, TrackedLink } from '@inputless/react';
function LoginForm() {
return (
<form>
<TrackedInput
id="email-input" // Required
type="email"
placeholder="Email"
label="Email Address" // Optional
/>
<TrackedButton
id="submit-button" // Required
type="submit"
label="Sign In" // Optional
>
Sign In
</TrackedButton>
<TrackedLink
id="forgot-password-link" // Required
href="/forgot-password" // Required
label="Forgot Password" // Optional
>
Forgot Password?
</TrackedLink>
</form>
);
}3. Access Tracker Directly
import { useInputlessTracker } from '@inputless/react';
function CustomComponent() {
const tracker = useInputlessTracker();
const handleCustomAction = () => {
// Track custom events
tracker.trackCustom('biz.purchase', {
productId: 'prod-123',
amount: 99.99,
currency: 'USD',
});
};
return <button onClick={handleCustomAction}>Buy Now</button>;
}Usage Examples
Example 1: Basic Local Setup
import React from 'react';
import { InputlessProvider, TrackedButton } from '@inputless/react';
import type { TrackerConfig } from '@inputless/tracker';
// Local-only configuration
const config: TrackerConfig = {
enabledCategories: { ui: true, form: true },
debug: true,
// No apiEndpoint - all processing is local
};
function App() {
return (
<InputlessProvider
config={config}
autoPageView={true}
autoTrack={true}
debug={false}
ssr={false}
>
<Dashboard />
</InputlessProvider>
);
}
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<TrackedButton
id="cta-button"
label="Get Started"
>
Get Started
</TrackedButton>
</div>
);
}Example 2: Advanced Local Configuration with Custom Instances
import { InputlessProvider } from '@inputless/react';
import { InputlessTracker } from '@inputless/tracker';
import { ContextEngine } from '@inputless/context';
import type { TrackerConfig } from '@inputless/tracker';
function App() {
// Create custom tracker instance (local only)
const tracker = new InputlessTracker({
enabledCategories: { ui: true, form: true, performance: true },
batchSize: 20,
flushInterval: 3000,
debug: true,
// No apiEndpoint - all processing is local
});
// Create custom context engine
const contextEngine = new ContextEngine({
patterns: {
temporal: true,
spatial: true,
sequence: true,
frequency: true,
behavioral: true,
minConfidence: 0.7,
},
anomaly: {
enabled: true,
threshold: 0.8,
method: 'hybrid',
},
debug: true,
});
// Start instances
tracker.start();
contextEngine.start();
// Local-only config
const config: TrackerConfig = {
enabledCategories: { ui: true, form: true },
debug: true,
};
return (
<InputlessProvider
config={config}
tracker={tracker}
contextEngine={contextEngine}
autoTrack={true}
autoPageView={true}
debug={process.env.NODE_ENV === 'development'}
ssr={false}
>
<YourApp />
</InputlessProvider>
);
}Using Hooks
useInputlessTracker
import { useInputlessTracker, useInputlessTrackerOptional } from '@inputless/react';
function ProductCard({ productId }: { productId: string }) {
// Throws error if used outside InputlessProvider
const tracker = useInputlessTracker();
const handleView = () => {
tracker.trackCustom('product.view', {
productId,
category: 'electronics',
});
};
const handleAddToCart = () => {
const element = document.getElementById(`add-to-cart-${productId}`);
if (element) {
tracker.trackClick(element, {
productId,
action: 'add_to_cart',
});
}
};
return (
<div onMouseEnter={handleView}>
<h3>Product {productId}</h3>
<button id={`add-to-cart-${productId}`} onClick={handleAddToCart}>
Add to Cart
</button>
</div>
);
}
// Optional tracker hook
function OptionalTrackingComponent() {
// Returns null if tracker not available (doesn't throw)
const tracker = useInputlessTrackerOptional();
const handleClick = () => {
if (tracker) {
tracker.trackClick(document.getElementById('button')!);
}
};
return <button id="button" onClick={handleClick}>Click</button>;
}useInputlessInsights
import { useInputlessInsights } from '@inputless/react';
import type { UseInputlessInsightsOptions } from '@inputless/react';
function AnalyticsDashboard() {
const { patterns, anomalies, insights, loading, error, refetch } =
useInputlessInsights({
autoRefresh: true,
refreshInterval: 5000,
sessionId: undefined,
});
if (loading) return <div>Loading insights...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h2>Analytics Dashboard</h2>
<section>
<h3>Detected Patterns ({patterns.length})</h3>
<ul>
{patterns.map((pattern, index) => (
<li key={index}>
<strong>{pattern.type}:</strong> Confidence: {pattern.confidence}
</li>
))}
</ul>
</section>
<section>
<h3>Anomalies ({anomalies.length})</h3>
<ul>
{anomalies
.filter((a) => a.isAnomaly)
.map((anomaly, index) => (
<li key={index}>
Score: {anomaly.score} - {anomaly.reason}
</li>
))}
</ul>
</section>
<section>
<h3>Insights ({insights.length})</h3>
<ul>
{insights.map((insight, index) => (
<li key={index}>
<strong>{insight.type}:</strong> {insight.message}
</li>
))}
</ul>
</section>
<button onClick={() => refetch()}>Refresh Insights</button>
</div>
);
}useInputlessContext
import { useInputlessContext, useInputlessContextOptional } from '@inputless/react';
function DebugPanel() {
const { tracker, contextEngine, config, autoTrack, debug } =
useInputlessContext();
return (
<div>
<h3>Debug Information</h3>
<p>Session ID: {tracker?.getSessionId()}</p>
<p>Auto Track: {autoTrack ? 'Enabled' : 'Disabled'}</p>
<p>Debug Mode: {debug ? 'On' : 'Off'}</p>
<p>Context Engine: {contextEngine ? 'Initialized' : 'Not initialized'}</p>
</div>
);
}
// Optional context hook
function OptionalContextComponent() {
// Returns null if context not available (doesn't throw)
const context = useInputlessContextOptional();
if (!context) {
return <div>Not within InputlessProvider</div>;
}
return (
<div>
<p>Tracker: {context.tracker ? 'Available' : 'Not available'}</p>
<p>Debug: {context.debug ? 'On' : 'Off'}</p>
</div>
);
}useTrackedEvent
import { useTrackedEvent } from '@inputless/react';
import type { BaseEvent } from '@inputless/events';
function CustomEventTracker() {
const trackEvent = useTrackedEvent({
disableTracking: false,
onTrack: (event: BaseEvent) => {
console.log('Custom tracking:', event);
},
});
const handlePurchase = (productId: string, amount: number) => {
// Function signature: (event: Partial<BaseEvent>) => void
trackEvent({
type: 'biz.purchase',
data: {
productId,
amount,
currency: 'USD',
},
});
};
const handleFormSubmit = (formData: Record<string, unknown>) => {
trackEvent({
type: 'form.submit',
data: {
formId: 'checkout-form',
fields: Object.keys(formData),
// Don't include actual values (PII protection)
},
});
};
return (
<div>
<button onClick={() => handlePurchase('prod-123', 99.99)}>
Purchase
</button>
</div>
);
}Tracked Components
TrackedButton
import { TrackedButton } from '@inputless/react';
import type { BaseEvent } from '@inputless/events';
function CallToAction() {
return (
<TrackedButton
id="signup-button"
label="Sign Up Button"
onClick={() => console.log('Clicked')}
trackingMetadata={{
campaign: 'homepage',
position: 'hero',
}}
disableTracking={false}
onTrack={(event: BaseEvent) => {
console.log('Tracked:', event);
}}
>
Sign Up Now
</TrackedButton>
);
}TrackedInput
import { TrackedInput } from '@inputless/react';
import type { BaseEvent } from '@inputless/events';
function SearchBar() {
return (
<TrackedInput
id="search-input"
type="search"
placeholder="Search..."
label="Search Input"
trackingMetadata={{
section: 'header',
}}
disableTracking={false}
onTrack={(event: BaseEvent) => {
console.log('Input tracked:', event);
}}
/>
);
}Note: TrackedInput automatically protects PII - only input length is tracked, not the actual value.
TrackedLink
import { TrackedLink } from '@inputless/react';
import type { BaseEvent } from '@inputless/events';
function Navigation() {
return (
<nav>
<TrackedLink
id="home-link"
href="/"
label="Home"
trackingMetadata={{ navSection: 'main' }}
disableTracking={false}
onTrack={(event: BaseEvent) => {
console.log('Link tracked:', event);
}}
>
Home
</TrackedLink>
<TrackedLink
id="about-link"
href="/about"
label="About"
trackingMetadata={{ navSection: 'main' }}
>
About
</TrackedLink>
</nav>
);
}TrackedForm
import { TrackedForm, TrackedInput, TrackedButton } from '@inputless/react';
import type { BaseEvent } from '@inputless/events';
function ContactForm() {
return (
<TrackedForm
id="contact-form"
formId="contact"
label="Contact Form"
trackingMetadata={{}}
disableTracking={false}
onTrack={(event: BaseEvent) => {
console.log('Form tracked:', event);
}}
onSubmit={(e) => {
e.preventDefault();
// Handle form submission
}}
>
<TrackedInput
id="name-input"
type="text"
placeholder="Name"
label="Name"
/>
<TrackedInput
id="email-input"
type="email"
placeholder="Email"
label="Email"
/>
<TrackedButton id="submit-button" type="submit" label="Submit">
Submit
</TrackedButton>
</TrackedForm>
);
}TrackedImage
import { TrackedImage } from '@inputless/react';
import type { BaseEvent } from '@inputless/events';
function ProductGallery() {
return (
<div>
<TrackedImage
id="product-image-1"
src="/images/product-1.jpg"
alt="Product 1"
label="Product Image 1"
trackingMetadata={{
productId: 'prod-123',
galleryPosition: 1,
}}
disableTracking={false}
onTrack={(event: BaseEvent) => {
console.log('Image tracked:', event);
}}
/>
</div>
);
}Document Components
DocumentUploader
import { DocumentUploader } from '@inputless/react';
function DocumentUpload() {
const handleUpload = async (files: File[]) => {
for (const file of files) {
// Upload file to your server
const formData = new FormData();
formData.append('file', file);
const response = await fetch('/api/documents', {
method: 'POST',
body: formData,
});
const { documentId } = await response.json();
console.log('Uploaded:', documentId);
}
};
return (
<DocumentUploader
onUpload={handleUpload}
acceptedTypes={['.pdf', '.docx', '.txt']}
maxFileSize={10 * 1024 * 1024} // 10MB
multiple={true}
showProgress={true}
/>
);
}DocumentViewer
import { DocumentViewer } from '@inputless/react';
function DocumentDetails({ documentId }: { documentId: string }) {
const fetchDocument = async (id: string) => {
const response = await fetch(`/api/documents/${id}`);
return response.json();
};
return (
<DocumentViewer
documentId={documentId}
fetchDocument={fetchDocument}
showEntities={true}
showTopics={true}
showAIInsights={true}
/>
);
}Example 3: SSR Support (Next.js Example - Local Only)
// app/layout.tsx (Next.js App Router)
import { InputlessProvider } from '@inputless/react';
import type { TrackerConfig } from '@inputless/tracker';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
// Local-only configuration (no API endpoint)
const config: TrackerConfig = {
enabledCategories: { ui: true, form: true },
debug: process.env.NODE_ENV === 'development',
};
return (
<html lang="en">
<body>
<InputlessProvider
config={config}
ssr={typeof window === 'undefined'}
autoPageView={true}
autoTrack={true}
debug={process.env.NODE_ENV === 'development'}
>
{children}
</InputlessProvider>
</body>
</html>
);
}Disabling Tracking
import { TrackedButton } from '@inputless/react';
function ConditionalTracking({ enableTracking }: { enableTracking: boolean }) {
return (
<TrackedButton
id="button"
disableTracking={!enableTracking}
onClick={() => console.log('Clicked')}
>
Click Me
</TrackedButton>
);
}Custom Tracking Callbacks
import { TrackedButton } from '@inputless/react';
import type { BaseEvent } from '@inputless/events';
function CustomTracking() {
const handleTrack = (event: BaseEvent) => {
// Custom tracking logic
console.log('Event tracked:', event);
// Send to additional analytics service
if (window.gtag) {
window.gtag('event', event.type, event.data);
}
};
return (
<TrackedButton
id="button"
onTrack={handleTrack}
onClick={() => console.log('Clicked')}
>
Click Me
</TrackedButton>
);
}API Reference
InputlessProvider Props
interface InputlessProviderProps {
config: TrackerConfig; // Required - Tracker configuration
children: React.ReactNode; // Required - Child components
autoPageView?: boolean; // Optional, default: true
autoTrack?: boolean; // Optional, default: true
tracker?: InputlessTracker; // Optional - Custom tracker instance
contextEngine?: ContextEngine; // Optional - Custom context engine
debug?: boolean; // Optional, default: false
ssr?: boolean; // Optional, default: false - Enable SSR mode
}Hooks
useInputlessTracker()
Returns the tracker instance. Throws error if used outside provider.
const tracker: InputlessTracker = useInputlessTracker();useInputlessTrackerOptional()
Returns the tracker instance or null if not available.
const tracker: InputlessTracker | null = useInputlessTrackerOptional();useInputlessInsights(options?)
Returns insights, patterns, and anomalies.
interface UseInputlessInsightsOptions {
sessionId?: string; // Optional - Session ID (defaults to current session)
autoRefresh?: boolean; // Optional - Enable auto-refresh
refreshInterval?: number; // Optional - Refresh interval in milliseconds
}
const {
patterns: Pattern[],
anomalies: AnomalyScore[],
insights: Insight[],
loading: boolean,
error: Error | null,
refetch: () => Promise<void>,
} = useInputlessInsights(options?);useInputlessContext()
Returns the full context value.
const {
tracker: InputlessTracker | null,
contextEngine: ContextEngine | null,
config: TrackerConfig,
autoTrack: boolean,
debug: boolean,
} = useInputlessContext();useInputlessContextOptional()
Returns the context value or null if not available.
const context: InputlessContextValue | null = useInputlessContextOptional();useTrackedEvent(options?)
Returns a function to track custom events.
interface UseTrackedEventOptions {
disableTracking?: boolean; // Optional - Disable automatic tracking
onTrack?: (event: BaseEvent) => void; // Optional - Custom tracking callback
}
const trackEvent = useTrackedEvent(options?);
// Function signature: (event: Partial<BaseEvent>) => void
trackEvent({
type: 'biz.purchase',
data: {
productId: 'prod-123',
amount: 99.99,
},
});Component Props
All tracked components accept standard HTML props plus:
interface BaseTrackedProps {
id: string; // Required for tracking (varies by component)
label?: string; // Optional - Element label for tracking
trackingMetadata?: Record<string, unknown>; // Optional - Additional metadata
disableTracking?: boolean; // Optional - Disable automatic tracking
onTrack?: (event: BaseEvent) => void; // Optional - Custom tracking callback
}
// Extends React.ButtonHTMLAttributes<HTMLButtonElement> + BaseTrackedProps
interface TrackedButtonProps extends BaseTrackedProps {
id: string; // Required
}
// Extends React.InputHTMLAttributes<HTMLInputElement> + BaseTrackedProps
interface TrackedInputProps extends BaseTrackedProps {
id: string; // Required
}
// Extends React.AnchorHTMLAttributes<HTMLAnchorElement> + BaseTrackedProps
interface TrackedLinkProps extends BaseTrackedProps {
id: string; // Required
href: string; // Required
}
// Extends React.FormHTMLAttributes<HTMLFormElement> + BaseTrackedProps
interface TrackedFormProps extends BaseTrackedProps {
id: string; // Required
formId?: string; // Optional
}
// Extends React.ImgHTMLAttributes<HTMLImageElement> + BaseTrackedProps
interface TrackedImageProps extends BaseTrackedProps {
id: string; // Required
}TypeScript Support
Full TypeScript support with comprehensive type definitions:
import type {
InputlessProviderProps,
TrackedButtonProps,
TrackedInputProps,
TrackedLinkProps,
TrackedFormProps,
TrackedImageProps,
UseInputlessInsightsResult,
} from '@inputless/react';Best Practices
Always provide
idprop: All tracked components require anidfor proper tracking.Use descriptive labels: Provide
labelprop for better analytics insights.Protect PII: Never track personally identifiable information. TrackedInput automatically protects input values.
Batch tracking: The tracker automatically batches events for optimal performance.
SSR compatibility: Use
ssr={true}prop in server-side rendering environments.Conditional tracking: Use
disableTrackingprop to conditionally disable tracking.Custom metadata: Use
trackingMetadataprop to add context-specific data.
Examples
See the examples directory for complete working examples:
- Basic setup
- Next.js integration
- E-commerce tracking
- Form analytics
- Document processing
Troubleshooting
Tracker not initializing
Ensure you're wrapping your app with InputlessProvider:
<InputlessProvider config={config}>
<App />
</InputlessProvider>Events not being tracked
- Check that
autoTrackis enabled (default: true) - Verify
disableTrackingis not set totrue - Check browser console for errors
- Enable
debug={true}for detailed logging
SSR issues
Use the ssr prop in server-side environments:
<InputlessProvider config={config} ssr={true}>
<App />
</InputlessProvider>Module Structure
@inputless/react/
├── InputlessProvider.tsx # Context provider
├── hooks/
│ ├── useInputlessTracker.ts # Tracker hook
│ ├── useInputlessInsights.ts # Insights hook
│ ├── useInputlessContext.ts # Context hook
│ └── useTrackedEvent.ts # Event tracking hook
├── components/
│ ├── TrackedButton.tsx # Button component
│ ├── TrackedInput.tsx # Input component
│ ├── TrackedLink.tsx # Link component
│ ├── TrackedForm.tsx # Form component
│ └── TrackedImage.tsx # Image component
├── DocumentUploader.tsx # Document uploader
├── DocumentViewer.tsx # Document viewer
└── utils/
├── ssrUtils.ts # SSR utilities
├── trackingUtils.ts # Tracking utilities
└── componentUtils.ts # Component utilitiesDistribution
npm package: @inputless/react
Version: 1.0.0+
Registry: npm
License
MIT
Support
For issues, questions, or contributions, please visit:
