Skip to content
Get started

Competitor Pricing Monitor

Extract structured pricing from multiple competitor pages in parallel. Shows how to use /extract/json with a consistent schema across a list of URLs.

Pull current pricing from a list of competitor URLs and normalize it into a consistent schema. Useful for agents that make decisions based on market positioning, or pipelines that track pricing drift over time. Using nocache: true ensures you’re always fetching live data, not a cached snapshot.

import Tabstack from "@tabstack/sdk";
const client = new Tabstack();
const competitors = [
"https://competitor-a.com/pricing",
"https://competitor-b.com/pricing",
"https://competitor-c.com/pricing",
];
type Plan = {
name: string;
price_usd: number | null;
billing_cycle: "monthly" | "annual" | "one-time" | "unknown";
has_free_tier: boolean;
};
const pricingSchema = {
type: "object",
properties: {
plans: {
type: "array",
items: {
type: "object",
properties: {
name: { type: "string" },
price_usd: {
type: ["number", "null"],
description: "Monthly price in USD. Null if custom or contact-only.",
},
billing_cycle: {
type: "string",
enum: ["monthly", "annual", "one-time", "unknown"],
},
has_free_tier: { type: "boolean" },
},
required: ["name", "price_usd", "billing_cycle", "has_free_tier"],
},
},
},
required: ["plans"],
};
async function monitorPricing() {
const results = await Promise.all(
competitors.map(async (url) => {
try {
// The SDK returns `Record<string, unknown>` for extract.json -- cast
// to the shape declared by your schema so downstream code is typed.
const data = (await client.extract.json({
url,
json_schema: pricingSchema,
effort: "standard",
nocache: true,
})) as { plans?: Plan[] };
return { url, plans: data.plans ?? [] };
} catch (err) {
console.error(`Failed to extract ${url}:`, err);
return { url, plans: null, error: String(err) };
}
})
);
console.log(JSON.stringify(results, null, 2));
}
monitorPricing();
  • Consistent schema across URLs. The same json_schema is applied to every competitor page. Tabstack normalizes the output regardless of how each site structures its pricing table.
  • Nullable prices for custom plans. Setting price_usd to ["number", "null"] handles “Contact us” or enterprise tiers without breaking the schema contract.
  • Parallel extraction. The TypeScript version uses Promise.all to fetch all URLs concurrently. The Python version runs sequentially — wrap with asyncio or a thread pool if latency matters.
  • No cached data. nocache: true forces a fresh fetch on every run. Drop it if you’re running this frequently and the underlying pages update slowly.
Terminal window
npm install @tabstack/sdk

Set your API key before running:

Terminal window
export TABSTACK_API_KEY=your_api_key