Skip to main content

Overview

BrowserTest SDK provides comprehensive usage tracking to help you monitor API consumption, manage quotas, and optimize costs.

Getting Usage Information

Current Usage

const usage = await bt.getUsage();
console.log('Current usage:', usage);

Usage Response Structure

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

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

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

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

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

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

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

  1. Regular Checks: Monitor usage regularly, especially before large operations
  2. Alert Thresholds: Set up alerts at 80% and 95% usage levels
  3. Cost Tracking: Estimate costs based on current usage patterns
  4. Plan Optimization: Upgrade or downgrade plans based on usage patterns

Efficient Usage

// 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

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) + '%');
}