Blog

Monitor Competitor Pricing With 3 Lines of Code

Track competitor prices across any e-commerce site with just 3 lines of code. Unbrowse discovers the internal pricing APIs automatically — no scrapers, no selectors, no maintenance.

Lewis Tham
April 3, 2026

Monitor Competitor Pricing With 3 Lines of Code

Competitive pricing intelligence is a billion-dollar industry. Companies like Prisync, Competera, and Intelligence Node charge thousands per month to monitor competitor prices. Most of them run armies of web scrapers that break constantly.

You can build the same thing in 3 lines of code.

The 3-Line Solution

import { Unbrowse } from "@unbrowse/sdk";
const unbrowse = new Unbrowse();
const price = await unbrowse.resolve({ intent: "get current price", url: "https://competitor.com/product/123" });

That is not a simplified example. That is the complete working code. Unbrowse discovers the shadow API behind any product page and returns structured pricing data — no scraper configuration, no CSS selectors, no browser instances.

Why This Works

Every e-commerce site fetches product data from internal APIs. When you visit a product page, the browser does not parse HTML to display the price — it calls an API endpoint that returns JSON with the price, availability, variants, and more.

These shadow APIs are more stable than the HTML. While a site might redesign their product page every quarter, the underlying API rarely changes because their mobile apps, internal tools, and CDN layers all depend on it.

Unbrowse discovers these APIs by observing real browsing traffic, reverse-engineers the contract (URL template, parameters, auth patterns), and publishes the route to a shared marketplace. Once discovered, any agent can call the API directly.

Building a Full Competitor Monitor

The 3-line version gets you a single price check. Here is how to build a production competitor monitoring system:

import { Unbrowse } from "@unbrowse/sdk";
import { writeFileSync, readFileSync, existsSync } from "fs";

const unbrowse = new Unbrowse();

const competitors = {
  "Widget Pro": [
    { retailer: "Amazon", url: "https://www.amazon.com/dp/B0EXAMPLE1" },
    { retailer: "Walmart", url: "https://www.walmart.com/ip/widget-pro/12345" },
    { retailer: "Target", url: "https://www.target.com/p/widget-pro/-/A-12345" },
  ],
  "Widget Lite": [
    { retailer: "Amazon", url: "https://www.amazon.com/dp/B0EXAMPLE2" },
    { retailer: "Best Buy", url: "https://www.bestbuy.com/site/widget-lite/6789.p" },
  ],
};

const HISTORY_FILE = "./competitor-prices.json";

function loadHistory() {
  return existsSync(HISTORY_FILE)
    ? JSON.parse(readFileSync(HISTORY_FILE, "utf-8"))
    : {};
}

function saveHistory(history) {
  writeFileSync(HISTORY_FILE, JSON.stringify(history, null, 2));
}

async function monitor() {
  const history = loadHistory();
  const timestamp = new Date().toISOString();

  for (const [product, sources] of Object.entries(competitors)) {
    if (!history[product]) history[product] = [];

    const prices = await Promise.all(
      sources.map(async (s) => {
        const result = await unbrowse.resolve({
          intent: `get current price and availability for ${product}`,
          url: s.url,
        });
        return {
          retailer: s.retailer,
          price: result.data?.price,
          available: result.data?.inStock ?? result.data?.available,
        };
      })
    );

    history[product].push({ timestamp, prices });

    // Save after each product (incremental progress)
    saveHistory(history);

    // Log any price changes
    const previous = history[product][history[product].length - 2];
    if (previous) {
      for (const current of prices) {
        const prev = previous.prices.find((p) => p.retailer === current.retailer);
        if (prev && prev.price !== current.price) {
          console.log(
            `PRICE CHANGE: ${product} at ${current.retailer}: $${prev.price} -> $${current.price}`
          );
        }
      }
    }
  }

  return history;
}

await monitor();

Key design decisions in this code:

  • Parallel per product: All retailers for a single product are checked simultaneously
  • Incremental saves: History is saved after each product, so interrupted runs do not lose data
  • Change detection: Compares current prices against the last recorded check
  • Availability tracking: Captures stock status alongside price

Detecting Price Patterns

With historical data accumulating, you can detect pricing patterns that give you a competitive edge:

function analyzePricing(history, product) {
  const entries = history[product] || [];
  if (entries.length < 2) return null;

  const analysis = {};

  for (const retailer of new Set(entries.flatMap((e) => e.prices.map((p) => p.retailer)))) {
    const retailerPrices = entries
      .map((e) => {
        const match = e.prices.find((p) => p.retailer === retailer);
        return match ? { timestamp: e.timestamp, price: match.price } : null;
      })
      .filter(Boolean)
      .filter((p) => p.price != null);

    if (retailerPrices.length < 2) continue;

    const prices = retailerPrices.map((p) => p.price);
    analysis[retailer] = {
      current: prices[prices.length - 1],
      min: Math.min(...prices),
      max: Math.max(...prices),
      average: prices.reduce((a, b) => a + b, 0) / prices.length,
      trend: prices[prices.length - 1] > prices[0] ? "increasing" : "decreasing",
      volatility: (Math.max(...prices) - Math.min(...prices)) / Math.min(...prices),
      dataPoints: prices.length,
    };
  }

  return analysis;
}

This tells you which retailers are the most volatile (opportunity for arbitrage), which trend upward (buy now signals), and which consistently undercut others.

Alerting on Competitive Moves

Set up real-time alerts when competitors change prices:

async function checkAndAlert() {
  const history = loadHistory();

  for (const [product, sources] of Object.entries(competitors)) {
    const prices = await Promise.all(
      sources.map(async (s) => {
        const result = await unbrowse.resolve({
          intent: `get current price`,
          url: s.url,
        });
        return { retailer: s.retailer, price: result.data?.price };
      })
    );

    const previousEntry = history[product]?.[history[product].length - 1];
    if (!previousEntry) continue;

    for (const current of prices) {
      const prev = previousEntry.prices.find((p) => p.retailer === current.retailer);
      if (!prev || !current.price || !prev.price) continue;

      const change = ((current.price - prev.price) / prev.price) * 100;

      if (Math.abs(change) >= 5) {
        console.log(
          `SIGNIFICANT CHANGE: ${product} at ${current.retailer} ` +
          `moved ${change > 0 ? "up" : "down"} ${Math.abs(change).toFixed(1)}% ` +
          `($${prev.price} -> $${current.price})`
        );
      }
    }
  }
}

Scaling to Hundreds of Products

For larger product catalogs, batch your monitoring with rate awareness:

async function batchMonitor(products, batchSize = 10) {
  const history = loadHistory();
  const allProducts = Object.entries(products);

  for (let i = 0; i < allProducts.length; i += batchSize) {
    const batch = allProducts.slice(i, i + batchSize);

    await Promise.all(
      batch.map(async ([product, sources]) => {
        if (!history[product]) history[product] = [];

        const prices = await Promise.all(
          sources.map(async (s) => {
            const result = await unbrowse.resolve({
              intent: `get current price`,
              url: s.url,
            });
            return { retailer: s.retailer, price: result.data?.price };
          })
        );

        history[product].push({
          timestamp: new Date().toISOString(),
          prices,
        });
      })
    );

    // Save after each batch
    saveHistory(history);
    console.log(`Batch ${Math.floor(i / batchSize) + 1} complete (${i + batch.length}/${allProducts.length} products)`);
  }
}

Comparison With Existing Solutions

Feature Prisync/Competera Custom Scrapers Unbrowse
Setup time Days-weeks Days Minutes
Monthly cost $500-5000+ Hosting + maintenance Free (marketplace earnings offset)
Products tracked Plan-limited Unlimited Unlimited
Maintenance Managed Constant Zero
Data freshness Hourly-daily Depends On-demand
Code required None (SaaS) Hundreds of lines 3 lines per product
Custom analysis Limited Full control Full control

The Marketplace Advantage

When your monitoring agent discovers a retailer's pricing API, that route gets published to the Unbrowse marketplace. Other agents that need pricing from the same retailer use your route instantly — and you earn x402 micropayments for every hit.

The first agent to index a major retailer's pricing API earns 2x the standard rate. If you monitor 50 competitors across 10 retailers, you are building a portfolio of high-value routes that generate passive income as more agents come online.

Getting Started

git clone --single-branch --depth 1 https://github.com/unbrowse-ai/unbrowse.git ~/unbrowse
cd ~/unbrowse && ./setup --host off

Or install the SDK:

npm install @unbrowse/sdk

Start with your top 3 competitors. Add their product URLs to the monitor. Run it once to discover the routes, then schedule it hourly. You will have better competitive intelligence than most enterprise pricing tools — in 3 lines of code.