Playground Sign in Start free
Price monitoring · e-commerce

Track every SKU, every variant, every geo.

Competitor prices, stock, ratings, promo flags, across thousands of retailers, refreshed nightly, validated against a stable schema. Built so your merch team can ship pricing rules, not babysit scrapers.

80k
SKUs / night, typical
12
geos, one schema
99.5%
extraction success
4 hrs
time-to-first-price
What you actually need

The hard parts, already solved.

Cloak-busting infra

Retailer anti-bot layers blow up most scrapers. Our 5-tier proxy fallback + headed Chromium quietly steps through them, so you never see a CAPTCHA.

Geo-priced pages

Same product URL shows different prices in DE / FR / JP. We route via clean residential IPs in each region, so your geo-pricing intel is actually accurate.

Schema-drift alerts

When a target redesigns and a field disappears, we alert before your dashboards break. Most fixes ship inside 4 hours, behind the API.

Compliant by default

Robots.txt respected, request rates polite, headers honest. Plus full audit logs of every request, which matters for regulated procurement teams.

The pipeline

3 steps. One pipeline.

01
Discover
Feed us a sitemap, category URL, or a list of product URLs. SERP can also discover new SKUs by brand name + retailer.
02
Validate
Schema check + outlier detection (a $19 lamp jumping to $1,900 triggers a recheck before it lands in your warehouse).
03
Deliver
Push results to S3, BigQuery, Snowflake, or any webhook. Dedup keys + content hashes built in, so no double-counting on retries.
full pipeline · 30 lines
// nightly-prices.ts
import { Ujeebu } from "ujeebu";
import { writeRows } from "./bq";

const uj = new Ujeebu(process.env.UJEEBU_KEY);

const SITES = [
  "https://shop-a.com/sitemap-products.xml",
  "https://shop-b.com/sitemap.xml",
  "https://shop-c.de/sitemap.xml",
];

for (const sitemap of SITES) {
  const urls = await uj.sitemap(sitemap);

  const rows = await Promise.all(
    urls.map(url => uj.scrape({
      url, extract_rules: { price: ".price", title: "h1" },
      proxy_type: "premium",
    }))
  );

  await writeRows(
    rows.filter(r => r.data?.price?.value),
    { dataset: "prices", table: "nightly" }
  );
}

Built for commerce. Stress-tested by 3,000+ teams.

Start free