@quickpipe/analytics-sdk
v1.0.0
Published
JavaScript/TypeScript SDK for sending analytics events to QuickPipe
Maintainers
Readme
QuickPipe Analytics API & SDK
Complete analytics tracking and PQL (Product Qualified Lead) scoring platform for SaaS applications.
📖 Interactive Documentation - Full docs with playgrounds, API reference, and SDK guides
QuickPipe provides two integration methods:
| Method | Best For | Languages | |--------|----------|-----------| | REST API | Direct HTTP calls, any language, server-side control | Any (cURL, Python, Ruby, Go, Java, etc.) | | SDK | Simplified integration, automatic batching, type safety | JavaScript/TypeScript, Python |
Core capabilities:
- Track events - Log user actions like sign-ups, feature usage, payments
- Score leads - Calculate a 0-100 PQL score to identify conversion-ready users
- Identify users - Associate events with user profiles and traits
Documentation
| Resource | Description | |----------|-------------| | Interactive Docs | Customer documentation with live playgrounds | | Getting Started | Overview and quick start | | API Reference | REST API endpoints and authentication | | SDK Documentation | JavaScript/TypeScript SDK reference | | API Playground | Test API endpoints in browser | | SDK Playground | Test SDK in browser | | PQL Calculator | Interactive scoring tool |
Table of Contents
- Quick Start
- Part 1: REST API
- Part 2: SDK Installation
- Part 3: Analytics Tracking
- Part 4: PQL Scoring
- SDK Reference
- Examples
Quick Start
Quick Start: REST API
No SDK required - just HTTP calls:
# Set your API key
export QUICKPIPE_API_KEY="qp_live_your_key_here"
# Track an event
curl -X POST https://api.quickpipe.ai/events/track \
-H "Authorization: Bearer $QUICKPIPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-123",
"event": "feature_used",
"properties": {
"feature": "dashboard",
"eventTypes": "feature_used"
}
}'
# Identify a user
curl -X POST https://api.quickpipe.ai/users/identify \
-H "Authorization: Bearer $QUICKPIPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-123",
"traits": {
"email": "[email protected]",
"name": "Jane Doe",
"company": "Acme Inc"
}
}'
# Calculate PQL score
curl -X POST https://api.quickpipe.ai/pql/calculate \
-H "Authorization: Bearer $QUICKPIPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-123",
"behavioral": { "featureUsageCount": 25, "sessionCount": 12 },
"firmographic": { "companySize": 150, "hasPaymentMethod": true }
}'Quick Start: SDK
For JavaScript/TypeScript or Python applications with built-in batching and type safety:
import { createAnalytics, createPQLScorer, STANDARD_EVENTS } from '@quickpipe/analytics-sdk';
// 1. Track a user event
const analytics = createAnalytics({ apiKey: 'your-api-key' });
analytics.identify('user-123', { email: '[email protected]' });
analytics.track(STANDARD_EVENTS.FEATURE_USED, { eventTypes: 'search' });
// 2. Score a lead
const scorer = createPQLScorer();
const result = scorer.calculate({
behavioral: { featureUsageCount: 25, sessionCount: 12 },
engagement: { emailOpenRate: 0.45, lastActiveAt: new Date() },
firmographic: { companySize: 150, hasPaymentMethod: true }
});
console.log(result.total); // 73
console.log(result.category); // 'warm'
console.log(result.recommendations); // ['Add to nurture sequence', ...]Part 1: REST API
The QuickPipe REST API allows you to integrate analytics and PQL scoring from any programming language or platform. All you need is the ability to make HTTP requests.
Base URL: https://api.quickpipe.ai
Authentication
All API requests require authentication using your API key in the Authorization header:
Authorization: Bearer qp_live_your_key_hereAPI Key Types:
| Key Prefix | Environment | Usage |
|------------|-------------|-------|
| qp_live_ | Production | Live customer data |
| qp_test_ | Sandbox | Testing and development |
Track Events (API)
Endpoint: POST /events/track
Record a user action or event.
curl -X POST https://api.quickpipe.ai/events/track \
-H "Authorization: Bearer $QUICKPIPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-123",
"event": "feature_used",
"properties": {
"eventTypes": "feature_used",
"feature": "advanced_search",
"applicationId": "app-456"
},
"timestamp": "2024-01-15T10:30:00Z"
}'Request Body:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| userId | string | Yes | Unique user identifier |
| event | string | Yes | Event name (use standard events) |
| properties | object | No | Event metadata |
| properties.eventTypes | string | Recommended | Event category for scoring |
| timestamp | string | No | ISO 8601 timestamp (defaults to now) |
Response:
{
"success": true,
"eventId": "evt_abc123",
"timestamp": "2024-01-15T10:30:00.000Z"
}Identify Users (API)
Endpoint: POST /users/identify
Create or update a user profile with traits.
curl -X POST https://api.quickpipe.ai/users/identify \
-H "Authorization: Bearer $QUICKPIPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-123",
"traits": {
"email": "[email protected]",
"name": "Jane Doe",
"company": "Acme Inc",
"plan": "professional",
"signupDate": "2024-01-01"
}
}'Request Body:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| userId | string | Yes | Unique user identifier |
| traits | object | No | User properties to store |
| traits.email | string | Recommended | User email address |
| traits.name | string | No | User display name |
| traits.company | string | No | Company name |
| traits.* | any | No | Custom user properties |
Response:
{
"success": true,
"userId": "user-123",
"created": false,
"updated": true
}Calculate PQL Score (API)
Endpoint: POST /pql/calculate
Calculate a PQL score for a user based on their data.
curl -X POST https://api.quickpipe.ai/pql/calculate \
-H "Authorization: Bearer $QUICKPIPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-123",
"behavioral": {
"featureUsageCount": 25,
"sessionCount": 12,
"avgSessionDuration": 480,
"keyFeaturesUsed": ["dashboard", "reports", "api"]
},
"engagement": {
"emailOpenRate": 0.45,
"lastActiveAt": "2024-01-15T10:30:00Z"
},
"firmographic": {
"companySize": 150,
"industry": "technology",
"hasPaymentMethod": true,
"isOnTrial": true,
"trialDaysRemaining": 3
}
}'Response:
{
"total": 82,
"category": "hot",
"breakdown": {
"behavioral": { "subtotal": 78, "weighted": 31.2 },
"engagement": { "subtotal": 85, "weighted": 25.5 },
"firmographic": { "subtotal": 84, "weighted": 25.2 }
},
"topFactors": [
{ "name": "trialUrgency", "contribution": 18 },
{ "name": "keyFeatureAdoption", "contribution": 15 }
],
"recommendations": [
"🔥 Schedule sales call immediately",
"Trial ending soon - offer extension or discount"
],
"calculatedAt": "2024-01-15T10:30:00.000Z"
}API Error Handling
All errors return a consistent format:
{
"error": {
"code": "INVALID_REQUEST",
"message": "userId is required",
"details": { "field": "userId" }
}
}Error Codes:
| Code | HTTP Status | Description |
|------|-------------|-------------|
| UNAUTHORIZED | 401 | Invalid or missing API key |
| INVALID_REQUEST | 400 | Malformed request body |
| NOT_FOUND | 404 | User or resource not found |
| RATE_LIMITED | 429 | Too many requests |
| INTERNAL_ERROR | 500 | Server error |
Rate Limits:
| Plan | Requests/minute | Events/day | |------|-----------------|------------| | Free | 60 | 10,000 | | Starter | 300 | 100,000 | | Professional | 1,000 | 1,000,000 | | Enterprise | Custom | Unlimited |
Part 2: SDK Installation
JavaScript/TypeScript SDK
npm install @quickpipe/analytics-sdkOr with Yarn/pnpm:
yarn add @quickpipe/analytics-sdk
pnpm add @quickpipe/analytics-sdkPython SDK
pip install quickpipe-analyticsOr with Poetry:
poetry add quickpipe-analyticsPart 3: Analytics Tracking
Track user actions to build a behavioral profile for scoring.
Setup
import { createAnalytics } from '@quickpipe/analytics-sdk';
const analytics = createAnalytics({
apiKey: 'qp_test_quickpipe_demo', // Required
endpoint: 'http://localhost:8000', // Optional, this is the default
flushInterval: 5000, // Optional: batch flush interval (ms)
flushAt: 10, // Optional: flush after N events
debug: false, // Optional: enable console logs
strictEvents: true // Optional: throw on invalid events
});Environment variables (alternative to config):
QUICKPIPE_ANALYTICS_API_KEY- Your API keyQUICKPIPE_ANALYTICS_ENDPOINT- Custom endpoint
Identify Users
Link events to a specific user:
// Basic
analytics.identify('user-123');
// With traits (stored and attached to events)
analytics.identify('user-123', {
email: '[email protected]',
name: 'Jane Doe',
applicationId: 'app-456'
});For anonymous users before sign-up:
analytics.setAnonymousId('anon-abc');Track Events
import { STANDARD_EVENTS } from '@quickpipe/analytics-sdk';
// Using standard event names (recommended)
analytics.track(STANDARD_EVENTS.SIGN_UP, {
eventTypes: 'sign_up',
applicationId: 'app-456'
});
// Track a feature being used
analytics.track(STANDARD_EVENTS.FEATURE_USED, {
eventTypes: 'search',
feature: 'advanced_search',
applicationId: 'app-456'
});
// Track a payment
analytics.track(STANDARD_EVENTS.PAYMENT_SUCCEEDED, {
eventTypes: 'payment',
amount: 99.00,
currency: 'USD'
});
// Force send immediately (otherwise batched)
await analytics.flush();Standard Events & Weights
Each event has a weight (0-10) that contributes to PQL scoring. Higher weight = stronger buying signal.
User Lifecycle
| Event | Weight | Constant |
|-------|--------|----------|
| Sign Up | 4 | SIGN_UP |
| Sign In | 3 | SIGN_IN |
| Sign Out | 1 | SIGN_OUT |
| Account Created | 5 | ACCOUNT_CREATED |
| Account Deleted | 0 | ACCOUNT_DELETED |
| Password Reset | 2 | PASSWORD_RESET |
| Password Changed | 2 | PASSWORD_CHANGED |
| Email Verified | 5 | EMAIL_VERIFIED |
| Invite Sent | 7 | INVITE_SENT |
| Invite Accepted | 8 | INVITE_ACCEPTED |
| Invite Declined | 0 | INVITE_DECLINED |
Payment & Billing
| Event | Weight | Constant |
|-------|--------|----------|
| Payment Succeeded | 10 | PAYMENT_SUCCEEDED |
| Payment Failed | 0 | PAYMENT_FAILED |
| Subscription Started | 9 | SUBSCRIPTION_STARTED |
| Subscription Cancelled | 0 | SUBSCRIPTION_CANCELLED |
| Subscription Changed | 5 | SUBSCRIPTION_CHANGED |
| Subscription Renewed | 8 | SUBSCRIPTION_RENEWED |
| Subscription Upgraded | 9 | SUBSCRIPTION_UPGRADED |
| Subscription Downgraded | 2 | SUBSCRIPTION_DOWNGRADED |
| Trial Started | 6 | TRIAL_STARTED |
| Trial Ended | 3 | TRIAL_ENDED |
| Invoice Created | 4 | INVOICE_CREATED |
| Invoice Paid | 7 | INVOICE_PAID |
| Refund Issued | 0 | REFUND_ISSUED |
Engagement & Product Usage
| Event | Weight | Constant |
|-------|--------|----------|
| Page View | 2 | PAGE_VIEW |
| Feature Used | 6 | FEATURE_USED |
| Search Performed | 4 | SEARCH_PERFORMED |
| Document Viewed | 4 | DOCUMENT_VIEWED |
| Document Created | 7 | DOCUMENT_CREATED |
| Document Updated | 6 | DOCUMENT_UPDATED |
| Document Deleted | 2 | DOCUMENT_DELETED |
| Export Started | 5 | EXPORT_STARTED |
| Export Completed | 7 | EXPORT_COMPLETED |
| Import Started | 5 | IMPORT_STARTED |
| Import Completed | 7 | IMPORT_COMPLETED |
Email & Communication
| Event | Weight | Constant |
|-------|--------|----------|
| Email Sent | 3 | EMAIL_SENT |
| Email Opened | 4 | EMAIL_OPENED |
| Email Clicked | 5 | EMAIL_CLICKED |
| Email Bounced | 0 | EMAIL_BOUNCED |
| Email Delivered | 3 | EMAIL_DELIVERED |
| Email Unsubscribed | 0 | EMAIL_UNSUBSCRIBED |
Integrations
| Event | Weight | Constant |
|-------|--------|----------|
| Integration Connected | 8 | INTEGRATION_CONNECTED |
| Integration Disconnected | 0 | INTEGRATION_DISCONNECTED |
| API Called | 6 | API_CALLED |
Workspace & Team
| Event | Weight | Constant |
|-------|--------|----------|
| Workspace Created | 6 | WORKSPACE_CREATED |
| Workspace Deleted | 0 | WORKSPACE_DELETED |
| Member Added | 8 | MEMBER_ADDED |
| Member Removed | 2 | MEMBER_REMOVED |
| Role Changed | 4 | ROLE_CHANGED |
Support
| Event | Weight | Constant |
|-------|--------|----------|
| Support Ticket Created | 3 | SUPPORT_TICKET_CREATED |
| Support Ticket Resolved | 5 | SUPPORT_TICKET_RESOLVED |
| Feedback Submitted | 6 | FEEDBACK_SUBMITTED |
Errors & System
| Event | Weight | Constant |
|-------|--------|----------|
| Error Occurred | 0 | ERROR_OCCURRED |
Using Weights in Code
import { STANDARD_EVENTS, EVENT_WEIGHTS, getEventWeight } from '@quickpipe/analytics-sdk';
// Get weight for an event
const weight = getEventWeight('PAYMENT_SUCCEEDED'); // 10
// Access weights directly
const inviteWeight = EVENT_WEIGHTS.INVITE_ACCEPTED; // 8Part 4: PQL Scoring
What is PQL?
PQL (Product Qualified Lead) answers one question: "Is this user likely to convert?"
Unlike traditional marketing-qualified leads (MQL) based on form fills and downloads, PQL uses actual product behavior to predict conversion.
Traditional MQL: "Downloaded whitepaper" → Maybe interested?
PQL: "Used 5 features, logged in 12 times, trial ending in 3 days" → YES, call them!Quick Example
import { createPQLScorer } from '@quickpipe/analytics-sdk';
const scorer = createPQLScorer();
const result = scorer.calculate({
userId: 'user-123',
behavioral: {
featureUsageCount: 25, // Used features 25 times
sessionCount: 12, // Logged in 12 times
avgSessionDuration: 480, // 8 minutes per session
keyFeaturesUsed: ['dashboard', 'reports', 'api'],
activationStepsCompleted: 4,
totalActivationSteps: 5
},
engagement: {
emailOpenRate: 0.45, // Opens 45% of emails
clickThroughRate: 0.08, // Clicks 8% of links
lastActiveAt: new Date(), // Active today
supportTicketsCreated: 1
},
firmographic: {
companySize: 150, // 150 employees
industry: 'technology',
hasPaymentMethod: true, // Credit card on file!
isOnTrial: true,
trialDaysRemaining: 3, // Trial ending soon!
planType: 'professional'
}
});
console.log(result);
// {
// total: 82,
// category: 'hot',
// recommendations: ['🔥 Schedule sales call immediately', ...],
// ...
// }Understanding the Score
Score Categories
| Score | Category | Meaning | What to do | |-------|----------|---------|------------| | 80-100 | 🔥 Hot | Ready to buy | Call immediately | | 50-79 | 🟡 Warm | Interested, needs nurturing | Email campaign | | 20-49 | 🔵 Cold | Low engagement | Educational content | | 0-19 | ⚪ Unqualified | Not a fit | Monitor passively |
The Three Pillars
The score combines three categories of signals:
┌─────────────────────────────────────────────────────────────────┐
│ FINAL SCORE (0-100) │
├───────────────────┬───────────────────┬─────────────────────────┤
│ BEHAVIORAL │ ENGAGEMENT │ FIRMOGRAPHIC │
│ (40%) │ (30%) │ (30%) │
├───────────────────┼───────────────────┼─────────────────────────┤
│ What they DO │ How they RESPOND │ WHO they are │
│ • Feature usage │ • Email opens │ • Company size │
│ • Session count │ • Click rate │ • Industry fit │
│ • Time in app │ • Recency │ • Payment method │
│ • Key features │ • Support tickets │ • Trial status │
│ • Onboarding │ • Docs viewed │ • Plan type │
└───────────────────┴───────────────────┴─────────────────────────┘How the Math Works
- Each signal gets a raw score (0-100)
- Multiply by signal weight within its category
- Sum to get category subtotal
- Multiply by category distribution (40/30/30)
- Add all categories = final score
Example:
Feature usage: 83 × 0.20 (weight) = 16.6
Session count: 60 × 0.15 = 9.0
...
Behavioral subtotal = 65
Behavioral contribution = 65 × 0.40 (distribution) = 26
Engagement contribution = 55 × 0.30 = 16.5
Firmographic contribution = 70 × 0.30 = 21
FINAL SCORE = 26 + 16.5 + 21 = 63.5 → "warm"Input Data
Behavioral Data
interface BehavioralData {
featureUsageCount?: number; // Total feature interactions (0-30+ → 0-100)
sessionCount?: number; // Login sessions (0-20+ → 0-100)
avgSessionDuration?: number; // Seconds per session (0-600+ → 0-100)
keyFeaturesUsed?: string[]; // Your "aha moment" features
totalKeyFeatures?: number; // How many key features exist (default: 5)
activationStepsCompleted?: number;
totalActivationSteps?: number; // Default: 5
}What counts as a "key feature"? Features that correlate with conversion. Examples:
dashboard- Saw the main valueinvite_teammate- Team adoption signalconnect_integration- Deep product usageexport_report- Getting real value
Engagement Data
interface EngagementData {
emailOpenRate?: number; // 0.0-1.0 (e.g., 0.45 = 45%)
clickThroughRate?: number; // 0.0-1.0 (e.g., 0.05 = 5%)
lastActiveAt?: Date | string; // When they last logged in
supportTicketsCreated?: number; // 0-2 is good, 5+ is concerning
helpDocsViewed?: number;
contentEngagements?: number; // Webinars, blog posts, etc.
}Important: lastActiveAt is crucial! A user who hasn't logged in for 2 weeks is going cold fast.
Firmographic Data
interface FirmographicData {
companySize?: number; // Employee count
industry?: string; // e.g., 'technology', 'healthcare'
targetIndustries?: string[]; // Override default target industries
hasPaymentMethod?: boolean; // Credit card on file = strong signal!
isOnTrial?: boolean;
trialDaysRemaining?: number; // Lower = more urgent
planType?: 'free' | 'starter' | 'professional' | 'enterprise';
}Company size scoring (default, mid-market focus):
- 0-9 employees: 30%
- 10-49: 60%
- 50-500: 100% ← Sweet spot
- 501-2000: 80%
- 2000+: 60%
Score Output
interface PQLResult {
total: number; // 0-100 score
category: 'hot' | 'warm' | 'cold' | 'unqualified';
breakdown: {
behavioral: { subtotal, weighted, featureUsage, sessionCount, ... },
engagement: { subtotal, weighted, emailOpenRate, recency, ... },
firmographic: { subtotal, weighted, companySize, industry, ... }
};
topFactors: [ // What's driving the score
{ name: 'keyFeatureAdoption', contribution: 28 },
{ name: 'recency', contribution: 24 },
...
];
recommendations: string[]; // Suggested actions
calculatedAt: string; // ISO timestamp
}Customizing Weights
Pre-built Weight Profiles
import {
createPQLScorer,
DEFAULT_WEIGHTS, // Balanced (40% behavioral, 30% engagement, 30% firmographic)
FREEMIUM_WEIGHTS, // For freemium/PLG products
ENTERPRISE_WEIGHTS // For enterprise sales
} from '@quickpipe/analytics-sdk';
// For enterprise sales (firmographic matters more)
const enterpriseScorer = createPQLScorer({
weights: ENTERPRISE_WEIGHTS,
categoryDistribution: [0.3, 0.25, 0.45] // Less behavioral, more firmographic
});Custom Weights
const scorer = createPQLScorer({
weights: {
behavioral: {
featureUsage: 25, // These must sum to 100
sessionCount: 20,
sessionDuration: 15,
keyFeatureAdoption: 25,
activationCompletion: 15
},
engagement: {
emailOpenRate: 10,
clickThroughRate: 15,
recency: 35, // Make recency more important
supportInteractions: 20,
contentEngagement: 20
},
firmographic: {
companySize: 30, // Focus on company fit
industry: 25,
paymentMethod: 20,
trialStatus: 15,
planType: 10
}
},
thresholds: {
hot: 85, // Raise the bar for "hot"
warm: 55,
cold: 25
},
categoryDistribution: [0.35, 0.35, 0.30] // Must sum to 1.0
});SDK Reference
Analytics SDK Methods
createAnalytics(config?)
Creates an analytics instance.
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| apiKey | string | Required | Your QuickPipe API key |
| endpoint | string | https://api.quickpipe.ai | API endpoint |
| flushInterval | number | 5000 | Batch send interval (ms) |
| flushAt | number | 10 | Flush after N events |
| debug | boolean | false | Enable console logs |
| strictEvents | boolean | true | Throw on invalid event names |
analytics.identify(userId, traits?)
Associates subsequent events with a user.
| Parameter | Type | Description |
|-----------|------|-------------|
| userId | string | Unique user identifier |
| traits | object | Optional user properties: email, name, applicationId, plus custom |
analytics.track(event, properties)
Records an event.
| Parameter | Type | Description |
|-----------|------|-------------|
| event | string | Event name from STANDARD_EVENTS |
| properties.eventTypes | string \| string[] | Event type(s) |
| properties.email | string | Optional email |
| properties.applicationId | string | Optional app ID |
| properties.date | string | ISO timestamp (defaults to now) |
| properties.* | any | Custom properties |
analytics.setAnonymousId(id)
Sets an anonymous ID for unauthenticated users.
analytics.flush(): Promise<void>
Immediately sends all queued events.
analytics.reset()
Clears user identity and event queue.
PQL Scorer Methods
createPQLScorer(config?)
Creates a scorer instance.
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| weights | PQLWeights | DEFAULT_WEIGHTS | Signal weights |
| thresholds | object | {hot:80, warm:50, cold:20} | Category boundaries |
| customWeight | number | 0.1 | Multiplier for custom signals |
| categoryDistribution | [n,n,n] | [0.4, 0.3, 0.3] | [behavioral, engagement, firmographic] |
scorer.calculate(input): PQLResult
Calculates the PQL score.
Input:
| Field | Type | Description |
|-------|------|-------------|
| userId | string | User identifier |
| email | string | User email |
| behavioral | BehavioralData | Product usage signals |
| engagement | EngagementData | Communication signals |
| firmographic | FirmographicData | Company/account signals |
| custom | Record<string, number> | Custom signals (0-100 each) |
Output (PQLResult):
| Field | Type | Description |
|-------|------|-------------|
| total | number | Score 0-100 |
| category | 'hot' \| 'warm' \| 'cold' \| 'unqualified' | Score category |
| breakdown | object | Detailed scores per dimension |
| topFactors | Array<{name, contribution}> | Top scoring factors |
| recommendations | string[] | Suggested actions |
| calculatedAt | string | ISO timestamp |
Weight Constants
| Constant | Use Case |
|----------|----------|
| DEFAULT_WEIGHTS | Balanced scoring (most common) |
| FREEMIUM_WEIGHTS | PLG/freemium products - weights product usage higher |
| ENTERPRISE_WEIGHTS | Enterprise sales - weights firmographic higher |
Examples
Real-World: Identifying Hot Leads
import { createPQLScorer } from '@quickpipe/analytics-sdk';
const scorer = createPQLScorer();
// Fetch your users from database
const users = await db.users.findMany();
const hotLeads = users
.map(user => ({
user,
score: scorer.calculate({
behavioral: {
featureUsageCount: user.eventCount,
sessionCount: user.sessionCount,
keyFeaturesUsed: user.featuresUsed
},
engagement: {
lastActiveAt: user.lastSeenAt,
emailOpenRate: user.emailStats?.openRate
},
firmographic: {
companySize: user.company?.size,
hasPaymentMethod: user.hasPaymentMethod,
isOnTrial: user.trialEndsAt > new Date(),
trialDaysRemaining: daysUntil(user.trialEndsAt)
}
})
}))
.filter(({ score }) => score.category === 'hot')
.sort((a, b) => b.score.total - a.score.total);
// These users should be contacted by sales
for (const { user, score } of hotLeads) {
console.log(`${user.email}: ${score.total} - ${score.recommendations[0]}`);
}Tracking + Scoring Together
import { createAnalytics, createPQLScorer, STANDARD_EVENTS } from '@quickpipe/analytics-sdk';
const analytics = createAnalytics({ apiKey: process.env.API_KEY });
const scorer = createPQLScorer();
// When a user performs an action
async function onFeatureUsed(userId: string, feature: string) {
// Track the event
analytics.identify(userId);
analytics.track(STANDARD_EVENTS.FEATURE_USED, {
eventTypes: 'feature_used',
feature
});
// Re-calculate score (you'd fetch real data from your DB)
const userData = await getUserData(userId);
const score = scorer.calculate(userData);
// If they crossed into "hot", notify sales
if (score.category === 'hot') {
analytics.track(STANDARD_EVENTS.PQL_THRESHOLD_REACHED, {
eventTypes: 'pql_hot',
score: score.total
});
await notifySalesTeam(userId, score);
}
}Daily Lead Scoring Job
import { createPQLScorer, STANDARD_EVENTS } from '@quickpipe/analytics-sdk';
const scorer = createPQLScorer();
async function dailyLeadScoringJob() {
const users = await db.users.findMany({ where: { isActive: true } });
const results = {
hot: [] as string[],
warm: [] as string[],
cold: [] as string[],
unqualified: [] as string[]
};
for (const user of users) {
const score = scorer.calculate({
behavioral: await getBehavioralData(user.id),
engagement: await getEngagementData(user.id),
firmographic: await getFirmographicData(user.id)
});
// Store score
await db.pqlScores.upsert({
where: { userId: user.id },
create: { userId: user.id, score: score.total, category: score.category },
update: { score: score.total, category: score.category, updatedAt: new Date() }
});
results[score.category].push(user.email);
}
console.log(`Scoring complete:
Hot: ${results.hot.length}
Warm: ${results.warm.length}
Cold: ${results.cold.length}
Unqualified: ${results.unqualified.length}
`);
// Send hot leads to sales team
if (results.hot.length > 0) {
await sendToSalesforce(results.hot);
}
}Python SDK
For Python applications (Django, Flask, FastAPI), use the Python SDK:
pip install quickpipe-analyticsimport os
from quickpipe import QuickPipeClient, PQLScorer, StandardEvents
# Initialize
client = QuickPipeClient(
api_key=os.environ['QUICKPIPE_API_KEY'],
endpoint='https://api.quickpipe.ai'
)
# Identify user
client.identify('user-123', {
'email': '[email protected]',
'name': 'Jane Doe'
})
# Track events
client.track('user-123', StandardEvents.FEATURE_USED, {
'feature': 'dashboard'
})
# Calculate PQL score
scorer = PQLScorer()
result = scorer.calculate({
'behavioral': {'featureUsageCount': 25, 'sessionCount': 12},
'firmographic': {'companySize': 150, 'hasPaymentMethod': True}
})
print(result['total']) # 73
print(result['category']) # 'warm'Project Structure
sdk/
├── docs/
│ ├── index.html # Interactive documentation
│ ├── logo.png
│ └── favicon.png
├── src/
│ ├── client.ts # Analytics client
│ ├── events.ts # Standard events
│ ├── pql.ts # PQL scorer
│ ├── types.ts # TypeScript types
│ └── index.ts # Main exports
├── examples/ # Example code
├── package.json
├── tsconfig.json
├── README.md
└── index.mdLicense
MIT
Internal: Developer Implementation Guide
⚠️ This section is for QuickPipe developers setting up the platform, NOT for customers using the SDK.
Architecture Overview
QuickPipe follows a simple data flow:
1. SDK (Input) → Tracks user events in customer's frontend/backend
2. API (Processing) → Receives, validates, and stores events
3. Database → Persists events and user data
4. PQL Scoring → Calculates lead scores from aggregated dataDatabase Setup (PostgreSQL)
-- Users table
CREATE TABLE users (
id VARCHAR(255) PRIMARY KEY,
email VARCHAR(255),
name VARCHAR(255),
company VARCHAR(255),
traits JSONB DEFAULT '{}',
pql_score INTEGER DEFAULT 0,
pql_category VARCHAR(20) DEFAULT 'unqualified',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Events table
CREATE TABLE events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id VARCHAR(255) REFERENCES users(id),
event_name VARCHAR(255) NOT NULL,
properties JSONB DEFAULT '{}',
timestamp TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_user_events ON events(user_id, timestamp);
-- PQL Scores history
CREATE TABLE pql_scores (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id VARCHAR(255) REFERENCES users(id),
score INTEGER NOT NULL,
category VARCHAR(20) NOT NULL,
breakdown JSONB NOT NULL,
calculated_at TIMESTAMP DEFAULT NOW()
);Backend API Setup (Node.js/Express)
import express from 'express';
import { createPQLScorer } from '@quickpipe/analytics-sdk';
import { Pool } from 'pg';
const app = express();
const db = new Pool({ connectionString: process.env.DATABASE_URL });
const scorer = createPQLScorer();
app.use(express.json());
// Track event endpoint
app.post('/api/events/track', async (req, res) => {
const { event, userId, properties } = req.body;
await db.query(
'INSERT INTO events (user_id, event_name, properties) VALUES ($1, $2, $3)',
[userId, event, properties]
);
res.json({ success: true, eventId: crypto.randomUUID() });
});
// Calculate PQL score endpoint
app.post('/api/pql/score', async (req, res) => {
const { userId } = req.body;
const userData = await getUserMetrics(userId);
const result = scorer.calculate(userData);
await db.query(
'UPDATE users SET pql_score = $1, pql_category = $2 WHERE id = $3',
[result.total, result.category, userId]
);
res.json(result);
});
app.listen(3000);Backend API Setup (Python/FastAPI)
from fastapi import FastAPI
from quickpipe import PQLScorer
import databases
import os
app = FastAPI()
db = databases.Database(os.environ['DATABASE_URL'])
scorer = PQLScorer()
@app.post("/api/events/track")
async def track_event(event: str, user_id: str, properties: dict = {}):
await db.execute(
"INSERT INTO events (user_id, event_name, properties) VALUES (:uid, :event, :props)",
{"uid": user_id, "event": event, "props": properties}
)
return {"success": True}
@app.post("/api/pql/score")
async def calculate_score(user_id: str):
metrics = await get_user_metrics(user_id)
result = scorer.calculate(metrics)
await db.execute(
"UPDATE users SET pql_score = :score, pql_category = :cat WHERE id = :uid",
{"score": result["total"], "cat": result["category"], "uid": user_id}
)
return resultEnvironment Variables
# .env
DATABASE_URL=postgresql://user:password@localhost:5432/quickpipe
QUICKPIPE_API_KEY=qp_live_xxx
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx # Optional: for hot lead alertsDeployment Checklist
- [ ] Set up PostgreSQL database
- [ ] Run database migrations (see SQL above)
- [ ] Configure environment variables
- [ ] Deploy API server (Node.js or Python)
- [ ] Generate API keys for customers
- [ ] Set up cron job for daily PQL scoring
- [ ] Configure Slack/CRM webhooks for hot lead alerts
