@pulsora/revenue
v1.0.0
Published
Privacy-first revenue tracking for Pulsora analytics - Server-side package
Maintainers
Readme
@pulsora/revenue
Privacy-first revenue tracking for Pulsora Analytics. Track revenue, subscriptions, and MRR with full attribution to customer journeys.
⚠️ Server-Side Only: This package is designed for server-side use to keep your API token secure.
Installation
npm install @pulsora/revenueQuick Start
import { Revenue } from '@pulsora/revenue';
const revenue = new Revenue({
apiToken: 'your-api-token',
});
// Track a revenue event
await revenue.track({
visitor_fingerprint: 'fp_from_payment_metadata',
session_id: 'session_from_payment_metadata',
customer_id: 'cus_123',
amount: 99.99,
currency: 'USD',
transaction_id: 'tx_abc123',
payment_processor: 'stripe',
event_type: 'purchase',
});Configuration
Revenue Options
interface RevenueConfig {
apiToken: string; // Required: Your Pulsora API token
endpoint?: string; // Optional: API endpoint (default: https://api.pulsora.co/api/ingest)
debug?: boolean; // Optional: Enable debug logging (default: false)
maxRetries?: number; // Optional: Max retry attempts (default: 3)
retryBackoff?: number; // Optional: Initial retry delay in ms (default: 1000)
}Revenue Tracking
Basic Revenue Event
await revenue.track({
visitor_fingerprint: 'fp_123', // From payment metadata
session_id: 'session_456', // From payment metadata
customer_id: 'cus_789', // Your customer ID
amount: 99.99,
currency: 'USD',
transaction_id: 'tx_abc123',
payment_processor: 'stripe',
event_type: 'purchase',
});Subscription Revenue
await revenue.track({
visitor_fingerprint: 'fp_123',
session_id: 'session_456',
customer_id: 'cus_789',
amount: 29.99,
currency: 'USD',
transaction_id: 'tx_def456',
payment_processor: 'stripe',
event_type: 'subscription',
customer_subscription_id: 'sub_123',
mrr_impact: 29.99,
is_recurring: true,
metadata: {
plan: 'pro',
interval: 'monthly',
},
});Event Types
purchase: One-time purchasesubscription: New subscriptionrenewal: Subscription renewalupgrade: Subscription upgradedowngrade: Subscription downgradechurn: Subscription cancellationrefund: Refund issued
Payment Processor Integration
To track revenue with attribution, you need to pass visitor_fingerprint and session_id from your frontend to your payment processor.
Stripe Example
Frontend (collect fingerprint & session)
import { Pulsora } from '@pulsora/core';
const pulsora = new Pulsora({
apiToken: 'your-public-token',
});
pulsora.init();
// When creating checkout session
const fingerprint = await pulsora.getVisitorFingerprint();
const sessionId = pulsora.getSessionId();
// Pass to your backend
const response = await fetch('/api/create-checkout', {
method: 'POST',
body: JSON.stringify({
priceId: 'price_123',
visitor_fingerprint: fingerprint,
session_id: sessionId,
}),
});Backend (create Stripe session with metadata)
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
app.post('/api/create-checkout', async (req, res) => {
const { priceId, visitor_fingerprint, session_id } = req.body;
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [{ price: priceId, quantity: 1 }],
mode: 'payment',
success_url: 'https://yoursite.com/success',
cancel_url: 'https://yoursite.com/cancel',
metadata: {
visitor_fingerprint,
session_id,
},
});
res.json({ sessionId: session.id });
});Webhook (track revenue)
import { Revenue } from '@pulsora/revenue';
import Stripe from 'stripe';
const revenue = new Revenue({
apiToken: process.env.PULSORA_API_TOKEN,
});
app.post('/webhooks/stripe', async (req, res) => {
const event = req.body;
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
await revenue.track({
visitor_fingerprint: session.metadata.visitor_fingerprint,
session_id: session.metadata.session_id,
customer_id: session.customer,
amount: session.amount_total / 100, // Convert cents to dollars
currency: session.currency.toUpperCase(),
transaction_id: session.id,
payment_processor: 'stripe',
event_type: 'purchase',
});
}
res.json({ received: true });
});Paddle Example
// Frontend: Pass metadata through Paddle
Paddle.Checkout.open({
items: [{ priceId: 'pri_123', quantity: 1 }],
customData: {
visitor_fingerprint: await pulsora.getVisitorFingerprint(),
session_id: pulsora.getSessionId(),
},
});
// Webhook: Track revenue
app.post('/webhooks/paddle', async (req, res) => {
const event = req.body;
if (event.event_type === 'transaction.completed') {
await revenue.track({
visitor_fingerprint: event.data.custom_data.visitor_fingerprint,
session_id: event.data.custom_data.session_id,
customer_id: event.data.customer_id,
amount: parseFloat(event.data.details.totals.total),
currency: event.data.currency_code,
transaction_id: event.data.id,
payment_processor: 'paddle',
event_type: 'purchase',
});
}
res.json({ success: true });
});Attribution
Revenue events are automatically attributed to the visitor's journey:
- First Touch: The initial source that brought the visitor (Google, Facebook, etc.)
- Last Touch: The most recent source before conversion
- UTM Parameters: Campaign tracking from pageviews
This happens automatically on the Pulsora backend using the visitor_fingerprint and session_id.
API Reference
Revenue Class
Constructor
new Revenue(config: RevenueConfig)Creates a new Revenue tracker instance.
Methods
track(data: RevenueData): Promise<void>
Track a revenue event.
Required fields:
visitor_fingerprint: Browser fingerprint from frontendsession_id: Session ID from frontendcustomer_id: Your unique customer identifieramount: Revenue amount (positive number)transaction_id: Unique transaction identifier
Optional fields:
currency: Currency code (default: 'USD')payment_processor: Payment processor name (e.g., 'stripe', 'paddle')event_type: Type of revenue eventcustomer_subscription_id: Subscription ID (for subscriptions)mrr_impact: MRR impact for subscription eventsis_recurring: Whether this is a recurring paymentmetadata: Additional metadata object
Error Handling
The package includes automatic retry logic for network failures and rate limiting.
try {
await revenue.track({
// ... revenue data
});
} catch (error) {
console.error('Failed to track revenue:', error);
// Handle error (e.g., log to your error tracking service)
}Security
⚠️ Never use this package in the browser!
Using this package in the browser exposes your API token and creates serious security risks. Always use it server-side in:
- Node.js applications
- Serverless functions (AWS Lambda, Vercel, Netlify)
- Backend APIs (Express, Fastify, etc.)
- Webhook handlers
Customer Privacy
The package is GDPR compliant:
- Customer IDs are hashed on Pulsora's backend before storage
- No PII is stored in plaintext
- Attribution is privacy-preserving using fingerprints
Debug Mode
Enable debug mode to see detailed logging:
const revenue = new Revenue({
apiToken: 'your-api-token',
debug: true,
});TypeScript Support
Full TypeScript support with type definitions included.
import { Revenue, RevenueData, RevenueConfig } from '@pulsora/revenue';Bundle Size
- ESM: ~3KB (uncompressed)
- Gzipped: ~1.5KB
License
MIT
Support
- Documentation: https://pulsora.co/docs
- Issues: https://github.com/pulsora/pulsora/issues
- Email: [email protected]
