SDKNode.jsTypeScript
Node.js SDK
The official Node.js/TypeScript SDK for AlterLab. Zero dependencies, fully typed, modern async API.
Node.js 18+Full TypeScriptNative FetchZero DependenciesESM + CJS
Installation
npm install alterlabyarn add alterlabpnpm add alterlabQuick Start
import { AlterLab } from 'alterlab';
// Initialize client
const client = new AlterLab({ apiKey: 'sk_live_...' });
// Scrape a website
const result = await client.scrape('https://example.com');
console.log(result.text); // Extracted text
console.log(result.json); // Structured JSON
console.log(result.billing.costDollars); // Cost in USD
console.log(result.billing.tierUsed); // Which tier succeededClient Options
import { AlterLab } from 'alterlab';
// Basic initialization
const client = new AlterLab({ apiKey: 'sk_live_...' });
// With all options
const client = new AlterLab({
apiKey: 'sk_live_...', // Required (or set ALTERLAB_API_KEY env var)
baseUrl: 'https://alterlab.io', // Custom API endpoint
timeout: 120000, // Request timeout in ms
maxRetries: 3, // Auto-retry on failures
retryDelay: 1000, // Initial retry delay in ms
});
// From environment variable
// Set ALTERLAB_API_KEY=sk_live_...
const client = new AlterLab(); // Reads from env| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | env var | Your AlterLab API key |
baseUrl | string | alterlab.io | API base URL |
timeout | number | 120000 | Request timeout in ms |
maxRetries | number | 3 | Max retries on failure |
retryDelay | number | 1000 | Initial retry delay in ms |
Scraping Methods
client.scrape(url, options?)
Main scraping method with auto mode detection.
const result = await client.scrape('https://example.com', {
// Mode
mode: 'auto', // 'auto' | 'html' | 'js' | 'pdf' | 'ocr'
// JavaScript options
waitFor: '#content', // CSS selector to wait for
screenshot: true, // Capture screenshot
// Advanced options
advanced: {
renderJs: true,
waitCondition: 'networkidle',
mobile: false,
viewportWidth: 1920,
viewportHeight: 1080,
},
// Output options
formats: ['text', 'json', 'markdown'],
// Caching
cache: true,
cacheTtl: 3600, // 1 hour
// Cost controls
costControls: {
maxTier: 3,
prefer: 'cost',
failFast: true,
},
});client.scrapeHtml(url, options?)
HTML-only mode (fastest, cheapest).
const result = await client.scrapeHtml('https://example.com');
console.log(result.html);
console.log(result.billing.tierName); // 'curl' or 'http'client.scrapeJs(url, options?)
JavaScript rendering with Playwright.
const result = await client.scrapeJs('https://spa-app.com', {
screenshot: true,
waitFor: '.loaded',
});
console.log(result.text);
console.log(result.screenshotUrl);client.scrapePdf(url) / client.scrapeOcr(url)
Extract text from PDFs and images.
// PDF extraction
const pdfResult = await client.scrapePdf('https://example.com/doc.pdf');
console.log(pdfResult.text);
// OCR for images
const ocrResult = await client.scrapeOcr('https://example.com/image.png', {
language: 'eng',
});
console.log(ocrResult.text);Structured Extraction
// Extract specific fields with JSON Schema
const result = await client.scrape('https://store.com/product/123', {
extractionSchema: {
type: 'object',
properties: {
name: { type: 'string' },
price: { type: 'number' },
inStock: { type: 'boolean' },
reviews: {
type: 'array',
items: { type: 'string' }
}
}
}
});
console.log(result.json);
// { name: "Product", price: 29.99, inStock: true, reviews: [...] }// Use a pre-built extraction profile
const result = await client.scrape('https://store.com/product/123', {
extractionProfile: 'product'
});
console.log(result.json);
// { name, price, description, images, availability, ... }
// Available profiles: 'product', 'article', 'job_posting', 'contact'// Extract using natural language prompt
const result = await client.scrape('https://news.example.com/article', {
extractionPrompt: 'Extract the article title, author, date, and main content'
});
console.log(result.json);Cost Controls
import { AlterLab } from 'alterlab';
const client = new AlterLab({ apiKey: 'sk_live_...' });
// Limit to cheap tiers only
const result = await client.scrape('https://example.com', {
costControls: {
maxTier: 2, // Don't go above HTTP tier
prefer: 'cost', // Optimize for lowest cost
failFast: true, // Error instead of escalating
maxCostDollars: 0.001 // Cap cost at $0.001
}
});
// Estimate cost before scraping
const estimate = await client.estimateCost('https://linkedin.com');
console.log(`Estimated: $${estimate.estimatedCostDollars.toFixed(4)}`);
console.log(`Confidence: ${estimate.confidence}`);
console.log(`Likely tier: ${estimate.tierName}`);💰 BYOP Discount: Get 20% off by using your own proxy integration
const result = await client.scrape('https://example.com', {
advanced: {
useOwnProxy: true,
proxyCountry: 'US' // Optional geo targeting
}
});
if (result.billing.byopApplied) {
console.log(`Saved ${result.billing.byopDiscountPercent}%!`);
}Async Jobs
import { AlterLab } from 'alterlab';
const client = new AlterLab({ apiKey: 'sk_live_...' });
// Start an async job (returns immediately)
const jobId = await client.scrapeAsync('https://example.com', {
mode: 'js',
advanced: { screenshot: true }
});
console.log(`Job started: ${jobId}`);
// Option 1: Poll manually
const status = await client.getJobStatus(jobId);
console.log(`Status: ${status.status}`);
console.log(`Progress: ${status.progress}%`);
// Option 2: Wait for completion (blocking)
const result = await client.waitForJob(jobId, {
pollInterval: 2000, // Check every 2 seconds
timeout: 300000 // 5 minute timeout
});
console.log(result.text);Error Handling
import {
AlterLab,
AuthenticationError,
InsufficientCreditsError,
RateLimitError,
ScrapeError,
TimeoutError,
ValidationError,
} from 'alterlab';
const client = new AlterLab({ apiKey: 'sk_live_...' });
try {
const result = await client.scrape('https://example.com');
console.log(result.text);
} catch (error) {
if (error instanceof AuthenticationError) {
console.log('Invalid API key');
} else if (error instanceof InsufficientCreditsError) {
console.log(`Balance: $${error.balanceDollars}`);
console.log('Please top up your balance');
} else if (error instanceof RateLimitError) {
console.log(`Rate limited. Retry after ${error.retryAfter}s`);
} else if (error instanceof ValidationError) {
console.log(`Invalid request: ${error.message}`);
} else if (error instanceof ScrapeError) {
console.log(`Scraping failed: ${error.message}`);
} else if (error instanceof TimeoutError) {
console.log('Request timed out');
}
}| Exception | HTTP Code | Description |
|---|---|---|
AuthenticationError | 401 | Invalid or missing API key |
InsufficientCreditsError | 402 | Insufficient balance |
RateLimitError | 429 | Too many requests |
ValidationError | 400 | Invalid request parameters |
ScrapeError | 422 | Scraping failed |
TimeoutError | - | Request timed out |
TypeScript
The SDK is written in TypeScript and exports all types. Your IDE will provide full autocomplete and type checking.
import {
AlterLab,
AlterLabConfig,
ScrapeResult,
ScrapeOptions,
BillingDetails,
CostControls,
AdvancedOptions,
UsageStats,
CostEstimate,
JobStatus,
} from 'alterlab';
// All types are exported
const options: ScrapeOptions = {
mode: 'js',
screenshot: true,
costControls: {
maxTier: 3,
prefer: 'cost',
},
};
const result: ScrapeResult = await client.scrape('https://example.com', options);
// Full autocomplete for all fields
const billing: BillingDetails = result.billing;
console.log(billing.costDollars);
console.log(billing.tierName);
console.log(billing.escalationPath);API Reference
Full Documentation
For complete API reference including all types and methods, see the GitHub repository.
ScrapeResult
interface ScrapeResult {
requestId: string;
url: string;
finalUrl: string;
statusCode: number;
text: string;
html: string;
json: Record<string, unknown> | null;
markdownContent: string | null;
title: string | null;
author: string | null;
screenshotUrl: string | null;
pdfUrl: string | null;
cached: boolean;
responseTimeMs: number;
sizeBytes: number;
billing: BillingDetails;
}BillingDetails
interface BillingDetails {
tierUsed: number; // 1-5
tierName: TierName; // 'curl' | 'http' | 'stealth' | 'browser' | 'captcha'
costMicrocents: number; // 1,000,000 = $1
costDollars: number;
byopApplied: boolean;
byopDiscountPercent: number;
escalationPath: TierEscalation[];
}