studios-sdk
v0.1.0
Published
Official Studios tracking SDK for JavaScript & React
Maintainers
Readme
Studios SDK
Official JavaScript & React SDK for Studios - prevent SaaS churn with intelligent tracking.
Installation
npm install studios-sdk
# or
yarn add studios-sdk
# or
pnpm add studios-sdkQuick Start
JavaScript/TypeScript
import Studios from 'studios-sdk';
const studios = Studios.init({ appId: 'YOUR_APP_ID' });
// Identify users
await studios.identify('user_123', {
email: '[email protected]',
name: 'Sarah Chen',
plan: 'pro',
mrr: 4900, // in cents
});
// Track events
studios.track('user_123', 'feature_used', {
feature: 'exports'
});
// Track support tickets
studios.supportTicket('user_123', {
status: 'open',
subject: 'How do I export data?'
});React
import { StudiosProvider, useTrack } from 'studios-sdk/react';
function App() {
return (
<StudiosProvider config={{ appId: 'YOUR_APP_ID' }}>
<Dashboard />
</StudiosProvider>
);
}
function Dashboard() {
const track = useTrack();
const handleExport = () => {
track(user.id, 'export_clicked', { format: 'csv' });
};
return <button onClick={handleExport}>Export</button>;
}Features
- ✅ TypeScript support with full type definitions
- ✅ Browser + Node.js (universal)
- ✅ React hooks for easy integration
- ✅ Auto-batching (10 events or 5 seconds)
- ✅ Automatic retries with exponential backoff
- ✅ Zero dependencies
- ✅ <5kb gzipped
API Reference
Studios.init(config)
Initialize the Studios SDK.
Parameters:
appId(string, required) - Your Studios app IDendpoint(string, optional) - API endpoint (defaults to production)batchSize(number, optional) - Events per batch (default: 10)batchInterval(number, optional) - Batch interval in ms (default: 5000)retryAttempts(number, optional) - Retry attempts (default: 1)debug(boolean, optional) - Enable debug logging (default: false)
Example:
const studios = Studios.init({
appId: 'app_xxxxxxxx',
debug: process.env.NODE_ENV === 'development'
});studios.identify(userId, traits)
Identify a user and their attributes. Call this when a user signs up or their attributes change.
Parameters:
userId(string, required) - User identifiertraits.email(string, required) - User emailtraits.name(string, optional) - User nametraits.company(string, optional) - Company nametraits.plan(string, optional) - Subscription plantraits.mrr(number, optional) - Monthly recurring revenue in centstraits.ltv(number, optional) - Lifetime value in centstraits.signupDate(number, optional) - Signup date (unix timestamp in ms)traits.properties(object, optional) - Custom properties
Example:
await studios.identify('user_123', {
email: '[email protected]',
name: 'Sarah Chen',
company: 'Acme Corp',
plan: 'pro',
mrr: 9900, // $99.00 in cents
signupDate: Date.now()
});studios.track(userId, event, properties?)
Track a user event. Events are automatically batched and sent every 10 events or 5 seconds.
Parameters:
userId(string, required) - User identifierevent(string, required) - Event name (use snake_case)properties(object, optional) - Event properties
Example:
studios.track('user_123', 'feature_used', {
feature: 'exports',
format: 'csv',
rows: 1000
});
studios.track('user_123', 'project_created', {
name: 'My Project',
template: 'blank'
});Recommended Events:
user_signed_up- New user registrationtrial_started- Trial activationsubscription_started- Paid conversionsubscription_upgraded- Plan upgradesubscription_canceled- Cancellationfeature_used- Core feature usageexport_*/import_*- Data operationsintegration_connected- Third-party integrationsrate_limit_hit- Usage limits reachedpayment_failed- Payment issues
studios.supportTicket(userId, options)
Track a support ticket to detect support silence patterns.
Parameters:
userId(string, required) - User identifieroptions.status(string, required) - Ticket status: 'open' | 'pending' | 'resolved' | 'closed'options.ticketId(string, optional) - External ticket IDoptions.subject(string, optional) - Ticket subject
Example:
// When ticket is created
await studios.supportTicket('user_123', {
status: 'open',
ticketId: 'TICKET-456',
subject: 'How do I export data?'
});
// When ticket is resolved
await studios.supportTicket('user_123', {
status: 'resolved',
ticketId: 'TICKET-456'
});studios.flush()
Manually flush the event queue. Usually not needed as auto-batching handles this.
Example:
await studios.flush(); // Send all queued events immediatelyReact Hooks
<StudiosProvider>
Wrap your app with this provider to enable hooks.
Props:
config(StudiosConfig, required) - SDK configuration
Example:
import { StudiosProvider } from 'studios-sdk/react';
export default function RootLayout({ children }) {
return (
<html>
<body>
<StudiosProvider config={{
appId: process.env.NEXT_PUBLIC_STUDIOS_APP_ID!,
debug: process.env.NODE_ENV === 'development'
}}>
{children}
</StudiosProvider>
</body>
</html>
);
}useStudios()
Access the Studios client in any component within StudiosProvider.
Returns: Studios instance
Example:
import { useStudios } from 'studios-sdk/react';
function SignupForm() {
const studios = useStudios();
const handleSignup = async (email, name) => {
const userId = await createUser(email, name);
await studios.identify(userId, {
email,
name,
plan: 'trial',
signupDate: Date.now()
});
};
return <form onSubmit={handleSignup}>...</form>;
}useTrack()
Convenience hook for tracking events with automatic memoization.
Returns: (userId: string, event: string, properties?: object) => void
Example:
import { useTrack } from 'studios-sdk/react';
function Dashboard({ user }) {
const track = useTrack();
const handleExport = async () => {
track(user.id, 'export_started', { format: 'csv' });
const data = await exportData();
track(user.id, 'export_completed', {
format: 'csv',
rows: data.length
});
};
return <button onClick={handleExport}>Export</button>;
}Integration Guide
Next.js App Router
1. Add environment variable:
Create .env.local:
NEXT_PUBLIC_STUDIOS_APP_ID=app_xxxxxxxx2. Wrap your app with StudiosProvider:
app/layout.tsx:
import { StudiosProvider } from 'studios-sdk/react';
export default function RootLayout({ children }) {
return (
<html>
<body>
<StudiosProvider config={{
appId: process.env.NEXT_PUBLIC_STUDIOS_APP_ID!
}}>
{children}
</StudiosProvider>
</body>
</html>
);
}3. Track events in components:
'use client';
import { useStudios, useTrack } from 'studios-sdk/react';
export default function Page() {
const track = useTrack();
return <button onClick={() => track(user.id, 'button_clicked')}>
Click Me
</button>;
}Node.js Backend
import Studios from 'studios-sdk';
const studios = Studios.init({
appId: process.env.STUDIOS_APP_ID!
});
// In your API routes
app.post('/api/signup', async (req, res) => {
const { email, name } = req.body;
const userId = await createUser(email, name);
await studios.identify(userId, {
email,
name,
plan: 'trial',
signupDate: Date.now()
});
res.json({ success: true });
});
// Flush on shutdown
process.on('SIGTERM', async () => {
await studios.flush();
process.exit(0);
});Browser (Vanilla JS)
<script type="module">
import Studios from 'https://unpkg.com/studios-sdk/dist/index.mjs';
const studios = Studios.init({ appId: 'YOUR_APP_ID' });
studios.track('user_123', 'page_viewed', {
path: window.location.pathname
});
</script>Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| appId | string | required | Your Studios app ID |
| endpoint | string | https://grand-condor-228.convex.cloud | API endpoint |
| batchSize | number | 10 | Events per batch |
| batchInterval | number | 5000 | Batch interval in ms |
| retryAttempts | number | 1 | Retry attempts on failure |
| debug | boolean | false | Enable debug logging |
Batching Behavior
Events are automatically batched to reduce API calls:
- Events are queued in memory
- Batch is sent when 10 events are queued OR 5 seconds elapse
- Use
flush()to send immediately (e.g., on page unload)
// Batch will flush after 10 events or 5 seconds
studios.track('user_1', 'event_1');
studios.track('user_1', 'event_2');
// ... 8 more events triggers immediate flush
// Or flush manually
window.addEventListener('beforeunload', () => {
studios.flush();
});Error Handling
The SDK gracefully handles errors and won't crash your app:
// Errors are logged but don't throw
studios.track('user_1', 'event'); // Won't crash on network error
// For critical operations, use try/catch
try {
await studios.identify(userId, { email });
} catch (error) {
console.error('Failed to identify user:', error);
// Handle error (e.g., retry logic, fallback)
}TypeScript Support
Full TypeScript definitions are included:
import Studios, { StudiosConfig, IdentifyTraits } from 'studios-sdk';
const config: StudiosConfig = {
appId: 'app_xxx',
debug: true
};
const traits: IdentifyTraits = {
email: '[email protected]',
plan: 'pro',
mrr: 9900
};
const studios = Studios.init(config);
await studios.identify('user_123', traits);Examples
See the examples/ directory for complete examples:
browser.html- Vanilla JavaScript in browsernext-app.tsx- Next.js App Router integrationnode.ts- Node.js backend integration
License
MIT
Support
- Documentation: [Link to docs]
- Issues: [GitHub Issues]
- Email: [email protected]
