Overview
BrowserTest SDK provides comprehensive usage tracking to help you monitor API consumption, manage quotas, and optimize costs.Getting Usage Information
Current Usage
Copy
const usage = await bt.getUsage();
console.log('Current usage:', usage);
Usage Response Structure
Copy
interface QuotaInfo {
plan: string;
usage: {
screenshot: {
used: number;
limit: number;
remaining: number;
};
agentic: {
used: number;
limit: number;
remaining: number;
};
total: {
screenshot: number;
agentic: number;
};
};
}
Plan Information
Available Plans
- Starter: 1,000 screenshots/month, 100 agentic tests/month
- Pro: 10,000 screenshots/month, 500 agentic tests/month
- Enterprise: Custom limits
Checking Your Plan
Copy
const usage = await bt.getUsage();
console.log('Current plan:', usage.plan);
switch (usage.plan) {
case 'free':
console.log('Free plan - upgrade for higher limits');
break;
case 'starter':
console.log('Starter plan - good for small projects');
break;
case 'pro':
console.log('Pro plan - suitable for most businesses');
break;
case 'enterprise':
console.log('Enterprise plan - custom limits');
break;
}
Usage Monitoring
Real-Time Usage Tracking
Copy
class UsageTracker {
constructor(bt) {
this.bt = bt;
this.usageHistory = [];
this.alerts = [];
}
async trackUsage(operation) {
const before = await this.bt.getUsage();
const startTime = Date.now();
try {
const result = await operation();
const after = await this.bt.getUsage();
const duration = Date.now() - startTime;
const usageDelta = {
screenshots: after.usage.screenshot.used - before.usage.screenshot.used,
tests: after.usage.agentic.used - before.usage.agentic.used
};
this.usageHistory.push({
timestamp: new Date().toISOString(),
operation: operation.name || 'anonymous',
duration,
usage: usageDelta,
success: true
});
this.checkAlerts(after);
return result;
} catch (error) {
const after = await this.bt.getUsage();
this.usageHistory.push({
timestamp: new Date().toISOString(),
operation: operation.name || 'anonymous',
duration: Date.now() - startTime,
usage: { screenshots: 0, tests: 0 }, // Error might still count
success: false,
error: error.message
});
throw error;
}
}
checkAlerts(usage) {
const screenshotPercent = (usage.usage.screenshot.used / usage.usage.screenshot.limit) * 100;
const testPercent = (usage.usage.agentic.used / usage.usage.agentic.limit) * 100;
if (screenshotPercent > 90) {
this.alerts.push({
type: 'screenshot_quota',
message: `Screenshot usage at ${screenshotPercent.toFixed(1)}%`,
timestamp: new Date().toISOString()
});
}
if (testPercent > 90) {
this.alerts.push({
type: 'test_quota',
message: `Test usage at ${testPercent.toFixed(1)}%`,
timestamp: new Date().toISOString()
});
}
if (usage.usage.screenshot.remaining < 10) {
this.alerts.push({
type: 'low_screenshot_quota',
message: `Only ${usage.usage.screenshot.remaining} screenshots remaining`,
timestamp: new Date().toISOString()
});
}
if (usage.usage.agentic.remaining < 5) {
this.alerts.push({
type: 'low_test_quota',
message: `Only ${usage.usage.agentic.remaining} tests remaining`,
timestamp: new Date().toISOString()
});
}
}
getUsageReport() {
const latest = this.usageHistory[this.usageHistory.length - 1];
const totalUsage = this.usageHistory.reduce(
(acc, entry) => ({
screenshots: acc.screenshots + entry.usage.screenshots,
tests: acc.tests + entry.usage.tests
}),
{ screenshots: 0, tests: 0 }
);
return {
current: latest,
total: totalUsage,
history: this.usageHistory.slice(-10), // Last 10 operations
alerts: this.alerts.slice(-5) // Last 5 alerts
};
}
}
// Usage
const tracker = new UsageTracker(bt);
await tracker.trackUsage(async () => {
return bt.screenshot.take({ url: 'https://example.com' });
});
console.log('Usage report:', tracker.getUsageReport());
Usage Dashboard
Copy
class UsageDashboard {
constructor(bt) {
this.bt = bt;
this.interval = null;
}
startMonitoring(intervalMs = 60000) { // Check every minute
this.interval = setInterval(async () => {
await this.displayDashboard();
}, intervalMs);
}
stopMonitoring() {
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
}
}
async displayDashboard() {
try {
const usage = await this.bt.getUsage();
console.clear();
console.log('=== BrowserTest Usage Dashboard ===');
console.log(`Plan: ${usage.plan}`);
console.log('');
console.log('📸 Screenshots:');
console.log(` Used: ${usage.usage.screenshot.used}`);
console.log(` Limit: ${usage.usage.screenshot.limit}`);
console.log(` Remaining: ${usage.usage.screenshot.remaining}`);
console.log(` Usage: ${((usage.usage.screenshot.used / usage.usage.screenshot.limit) * 100).toFixed(1)}%`);
console.log('');
console.log('🤖 Agentic Tests:');
console.log(` Used: ${usage.usage.agentic.used}`);
console.log(` Limit: ${usage.usage.agentic.limit}`);
console.log(` Remaining: ${usage.usage.agentic.remaining}`);
console.log(` Usage: ${((usage.usage.agentic.used / usage.usage.agentic.limit) * 100).toFixed(1)}%`);
console.log('');
this.displayWarnings(usage);
} catch (error) {
console.error('Failed to fetch usage:', error.message);
}
}
displayWarnings(usage) {
const warnings = [];
const screenshotPercent = (usage.usage.screenshot.used / usage.usage.screenshot.limit) * 100;
const testPercent = (usage.usage.agentic.used / usage.usage.agentic.limit) * 100;
if (screenshotPercent > 90) {
warnings.push(`⚠️ Screenshot usage at ${screenshotPercent.toFixed(1)}%`);
}
if (testPercent > 90) {
warnings.push(`⚠️ Test usage at ${testPercent.toFixed(1)}%`);
}
if (usage.usage.screenshot.remaining < 10) {
warnings.push(`🚨 Only ${usage.usage.screenshot.remaining} screenshots remaining`);
}
if (usage.usage.agentic.remaining < 5) {
warnings.push(`🚨 Only ${usage.usage.agentic.remaining} tests remaining`);
}
if (warnings.length > 0) {
console.log('Warnings:');
warnings.forEach(warning => console.log(` ${warning}`));
console.log('');
}
const resetDate = new Date();
resetDate.setMonth(resetDate.getMonth() + 1, 1); // Next month
console.log(`Next reset: ${resetDate.toLocaleDateString()}`);
}
}
// Usage
const dashboard = new UsageDashboard(bt);
dashboard.startMonitoring(30000); // Update every 30 seconds
// Stop after 5 minutes for demo
setTimeout(() => {
dashboard.stopMonitoring();
console.log('Monitoring stopped');
}, 300000);
Cost Estimation
Usage-Based Cost Calculation
Copy
class CostEstimator {
constructor() {
// Example pricing (adjust based on actual pricing)
this.pricing = {
free: { screenshots: 0, tests: 0 },
starter: { screenshots: 0.01, tests: 0.10 }, // $0.01 per screenshot, $0.10 per test
pro: { screenshots: 0.005, tests: 0.05 },
enterprise: { screenshots: 0.002, tests: 0.02 }
};
}
estimateMonthlyCost(plan, usage) {
const planPricing = this.pricing[plan] || this.pricing.starter;
const screenshotCost = usage.screenshot * planPricing.screenshots;
const testCost = usage.agentic * planPricing.tests;
const totalCost = screenshotCost + testCost;
return {
plan,
breakdown: {
screenshots: {
count: usage.screenshot,
rate: planPricing.screenshots,
cost: screenshotCost
},
tests: {
count: usage.agentic,
rate: planPricing.tests,
cost: testCost
}
},
totalCost,
formatted: `$${totalCost.toFixed(2)}`
};
}
recommendPlan(currentUsage) {
const plans = Object.keys(this.pricing);
const recommendations = plans.map(plan => ({
plan,
...this.estimateMonthlyCost(plan, currentUsage)
}));
return recommendations.sort((a, b) => a.totalCost - b.totalCost)[0];
}
}
// Usage
const estimator = new CostEstimator();
const usage = await bt.getUsage();
const costEstimate = estimator.estimateMonthlyCost(usage.plan, {
screenshot: usage.usage.screenshot.used,
agentic: usage.usage.agentic.used
});
console.log('Current monthly cost estimate:', costEstimate.formatted);
console.log('Breakdown:', costEstimate.breakdown);
const recommendation = estimator.recommendPlan({
screenshot: usage.usage.screenshot.used,
agentic: usage.usage.agentic.used
});
console.log('Recommended plan:', recommendation.plan, 'at', recommendation.formatted);
Quota Management
Quota Warnings
Copy
class QuotaManager {
constructor(bt) {
this.bt = bt;
this.warningThresholds = {
screenshots: 0.8, // 80%
tests: 0.8
};
this.criticalThresholds = {
screenshots: 0.95, // 95%
tests: 0.95
};
}
async checkQuotas() {
const usage = await this.bt.getUsage();
const warnings = [];
const critical = [];
const screenshotPercent = usage.usage.screenshot.used / usage.usage.screenshot.limit;
const testPercent = usage.usage.agentic.used / usage.usage.agentic.limit;
if (screenshotPercent >= this.criticalThresholds.screenshots) {
critical.push(`Screenshots: ${usage.usage.screenshot.remaining} remaining`);
} else if (screenshotPercent >= this.warningThresholds.screenshots) {
warnings.push(`Screenshots: ${(screenshotPercent * 100).toFixed(1)}% used`);
}
if (testPercent >= this.criticalThresholds.tests) {
critical.push(`Tests: ${usage.usage.agentic.remaining} remaining`);
} else if (testPercent >= this.warningThresholds.tests) {
warnings.push(`Tests: ${(testPercent * 100).toFixed(1)}% used`);
}
return {
warnings,
critical,
usage,
isNearLimit: warnings.length > 0,
isAtLimit: critical.length > 0
};
}
async shouldThrottle(operation) {
const status = await this.checkQuotas();
// Throttle if critically low on quota
return status.isAtLimit;
}
async executeWithQuotaCheck(operation, operationType) {
const shouldThrottle = await this.shouldThrottle(operationType);
if (shouldThrottle) {
throw new Error(`Operation throttled due to low ${operationType} quota`);
}
return operation();
}
}
// Usage
const quotaManager = new QuotaManager(bt);
try {
await quotaManager.executeWithQuotaCheck(
() => bt.screenshot.take({ url: 'https://example.com' }),
'screenshots'
);
} catch (error) {
if (error.message.includes('throttled')) {
console.log('Operation throttled - quota limit reached');
// Handle throttling: queue operation, upgrade plan, etc.
} else {
throw error;
}
}
Usage Analytics
Historical Usage Tracking
Copy
class UsageAnalytics {
constructor(bt) {
this.bt = bt;
this.history = [];
this.maxHistorySize = 1000;
}
async recordUsage() {
const usage = await this.bt.getUsage();
const record = {
timestamp: new Date().toISOString(),
...usage
};
this.history.push(record);
// Keep only recent records
if (this.history.length > this.maxHistorySize) {
this.history = this.history.slice(-this.maxHistorySize);
}
return record;
}
getUsageTrends(days = 7) {
const cutoff = new Date();
cutoff.setDate(cutoff.getDate() - days);
const recent = this.history.filter(record =>
new Date(record.timestamp) >= cutoff
);
if (recent.length < 2) return null;
const first = recent[0];
const last = recent[recent.length - 1];
const screenshotIncrease = last.usage.screenshot.used - first.usage.screenshot.used;
const testIncrease = last.usage.agentic.used - first.usage.agentic.used;
const daysDiff = (new Date(last.timestamp) - new Date(first.timestamp)) / (1000 * 60 * 60 * 24);
return {
period: `${days} days`,
screenshotPerDay: screenshotIncrease / daysDiff,
testPerDay: testIncrease / daysDiff,
totalIncrease: {
screenshots: screenshotIncrease,
tests: testIncrease
}
};
}
predictUsage(days = 30) {
const trends = this.getUsageTrends(7); // Use 7-day trend
if (!trends) return null;
const current = this.history[this.history.length - 1];
const predicted = {
screenshots: current.usage.screenshot.used + (trends.screenshotPerDay * days),
tests: current.usage.agentic.used + (trends.testPerDay * days)
};
const screenshotLimitExceeded = predicted.screenshots > current.usage.screenshot.limit;
const testLimitExceeded = predicted.tests > current.usage.agentic.limit;
return {
predicted,
limits: {
screenshots: current.usage.screenshot.limit,
tests: current.usage.agentic.limit
},
willExceed: {
screenshots: screenshotLimitExceeded,
tests: testLimitExceeded,
any: screenshotLimitExceeded || testLimitExceeded
},
daysToLimit: {
screenshots: screenshotLimitExceeded ?
Math.floor((current.usage.screenshot.limit - current.usage.screenshot.used) / trends.screenshotPerDay) : null,
tests: testLimitExceeded ?
Math.floor((current.usage.agentic.limit - current.usage.agentic.used) / trends.testPerDay) : null
}
};
}
}
// Usage
const analytics = new UsageAnalytics(bt);
// Record usage periodically
setInterval(() => analytics.recordUsage(), 3600000); // Every hour
// Get insights
const trends = analytics.getUsageTrends(7);
console.log('7-day trends:', trends);
const prediction = analytics.predictUsage(30);
if (prediction?.willExceed.any) {
console.log('⚠️ Predicted to exceed limits in 30 days');
if (prediction.daysToLimit.screenshots) {
console.log(`Screenshots limit in ${prediction.daysToLimit.screenshots} days`);
}
if (prediction.daysToLimit.tests) {
console.log(`Tests limit in ${prediction.daysToLimit.tests} days`);
}
}
Best Practices
Monitoring Strategy
- Regular Checks: Monitor usage regularly, especially before large operations
- Alert Thresholds: Set up alerts at 80% and 95% usage levels
- Cost Tracking: Estimate costs based on current usage patterns
- Plan Optimization: Upgrade or downgrade plans based on usage patterns
Efficient Usage
Copy
// Batch operations to minimize API calls
const urls = ['https://site1.com', 'https://site2.com', 'https://site3.com'];
const batchResults = await bt.screenshot.takeBatch({
urls,
fullPage: true
});
// Reuse results when possible
const screenshotCache = new Map();
async function getScreenshot(url, options = {}) {
const key = `${url}:${JSON.stringify(options)}`;
if (!screenshotCache.has(key)) {
const result = await bt.screenshot.take({ url, ...options });
screenshotCache.set(key, result);
}
return screenshotCache.get(key);
}
// Monitor usage impact
async function monitoredOperation(operation, description) {
const before = await bt.getUsage();
const result = await operation();
const after = await bt.getUsage();
const cost = {
screenshots: after.usage.screenshot.used - before.usage.screenshot.used,
tests: after.usage.agentic.used - before.usage.agentic.used
};
console.log(`${description} used: ${cost.screenshots} screenshots, ${cost.tests} tests`);
return result;
}
Budget Management
Copy
class BudgetManager {
constructor(bt, budget) {
this.bt = bt;
this.monthlyBudget = budget;
this.costPerScreenshot = 0.01; // Adjust based on plan
this.costPerTest = 0.10;
}
async checkBudget() {
const usage = await bt.getUsage();
const currentCost = (usage.usage.screenshot.used * this.costPerScreenshot) +
(usage.usage.agentic.used * this.costPerTest);
const remainingBudget = this.monthlyBudget - currentCost;
const percentUsed = (currentCost / this.monthlyBudget) * 100;
return {
currentCost,
remainingBudget,
percentUsed,
isOverBudget: currentCost > this.monthlyBudget,
projectedEndOfMonth: this.projectEndOfMonthCost(usage)
};
}
projectEndOfMonthCost(usage) {
// Simple projection based on current daily usage
const now = new Date();
const daysInMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate();
const daysRemaining = daysInMonth - now.getDate();
// Assume current daily rate continues
const dailyRate = (usage.usage.screenshot.used + usage.usage.agentic.used) / now.getDate();
const projectedUsage = dailyRate * daysInMonth;
const projectedCost = (usage.usage.screenshot.used * this.costPerScreenshot) +
(usage.usage.agentic.used * this.costPerTest);
return {
projectedCost,
willExceed: projectedCost > this.monthlyBudget,
dailyRate,
daysRemaining
};
}
}
// Usage
const budget = new BudgetManager(bt, 100); // $100 monthly budget
const status = await budget.checkBudget();
if (status.isOverBudget) {
console.log('🚨 Over budget! Current cost:', status.currentCost);
} else if (status.percentUsed > 80) {
console.log('⚠️ Budget used:', status.percentUsed.toFixed(1) + '%');
}
