cdpfleet Sign up free

cdpfleet / Monitoring

For price, stock and uptime watching

Check the page the way a visitor sees it.

Load the page in a real browser, read the price, the stock line or the button that must be there, and compare it with last time. Sessions are billed per second, so a check costs seconds, not an hour of a server.

  • ~15 sbilled for a two-snapshot watch (case 50)
  • 120free browser-minutes a day on Community
  • per secondbilling

Or let cdpfleet run the checks: Monitors

No program or scheduler of your own: a monitor loads the page in a real browser on a schedule, compares what it shows with last time and tells you what changed.

  • A schedule: every 15 minutes or more on shared plans (5 on dedicated), up to weekly — or a cron expression in UTC.
  • What counts as a change: the page's Markdown, text or HTML — the whole page or one element (selector), with remove for banners and ignore regular expressions for dates and counters; whitespace is normalised first.
  • Told how you like: a signed monitor.change webhook with the diff, an email, and 30 days of history; three failed checks in a row send one monitor.error.
  • Billed per check: each check is one function call — a few seconds of a thread. Paid plans, up to 100 monitors per thread.
  • Changes as they happen: a watch job stays on a page and streams its XHR and fetch calls, WebSocket messages and changes to an element over SSE and webhooks — for prices, scores or order books that move every second.

Pay for the reading, not the waiting

  • Short sessions: launch, read, close. Two snapshots of a watch that took more than two minutes billed about 15 seconds of browser time; keeping one browser open in between would have billed every second (case 50).
  • Small watches fit the free plan: Community has 2 threads with 60 browser-minutes each a day and a proxy included. Sessions last up to 15 minutes, which is plenty for a check (Community plan).
  • Run it from your scheduler: cron, a CI schedule or a queue starts the same program; keep the last snapshot in a file or a database row. For many URLs, read them in one session per round, or in parallel sessions up to your threads (case 10).
  • Cap every check: overall_timeout ends a stuck check on time, so a hung page can't burn minutes (overall_timeout).
// One check: read the fields, compare, alert only on what changed.
const page = await browser.newPage();
await page.goto(url, { waitUntil: 'domcontentloaded' });
const now = {
  price: await page.locator('.price_color').first().innerText(),
  stock: (await page.locator('.availability').first().innerText()).trim(),
};
const changed = Object.keys(now).filter((k) => now[k] !== last[k]);
if (changed.length) await alert(changed.map((k) => `${k}: ${last[k]} → ${now[k]}`));
await browser.close(); // ends the session and its billing

What to compare

  • Fields, not pages: comparing whole pages flags every rotating ad and timestamp. Read the price, the stock text or the element you care about and diff those (case 50).
  • Validate at the source: parse each price to a number and fail the run when a field is missing, so a layout change shows up on day one instead of as silent nonsense (case 28).
  • Visual checks: a screenshot of one element is a fraction of a full-page one and makes a steady baseline; PDFs work on the Chromium-based browsers (case 29).
  • Prices by country: a country-pinned residential exit shows the price that market sees (geo testing).

When a check fails

  • Watch the video: headful sessions are recorded by default. A failed scrape was explained by its recording — the browser was on the last page, not facing a broken selector (case 41, recordings).
  • Back off when a site pushes back: honour Retry-After and move to another exit; the crawler that retried at once was challenged (case 53).
  • At your thread cap: a launch gets 429 threads_exceeded; the SDKs wait and retry for you (case 76).

Long-running watches

  • Keep one browser for hours on dedicated threads with keep_alive: your monitor can restart and reconnect to the same browser; pages and storage in its default context are still there (keep_alive, dedicated threads).
  • Logged-in pages: keep the login in a persistent profile on a paid plan instead of signing in on every check.