New to Kestra?
Use blueprints to kickstart your first workflows.
Orchestrate a nightly Puppeteer scrape of competitor pricing pages with Kestra. Diff against a KV Store snapshot and alert Slack only when a price actually changes.
Most SaaS and e-commerce pricing pages render their price tables with client-side JavaScript, so a plain HTTP GET and a regex or HTML parser sees an empty shell instead of a number. This blueprint drives an actual headless Chrome browser with Puppeteer, a Node.js library with no equivalent in Kestra's built-in HTTP or scripting tasks, to load each competitor's pricing page the way a real visitor would, wait for the price element to render, then read it straight off the DOM. It stores the scraped snapshot in Kestra's KV Store, diffs it against the previous run, and only pings Slack when a price actually moved, so the channel stays quiet on the nights nothing changed.
read_previous_snapshot (io.kestra.plugin.core.kv.Get) reads the competitor_pricing_snapshot key. errorOnMissing: false lets the first run fall through to an empty list.scrape_pricing_pages (io.kestra.plugin.scripts.node.Script) runs on the ghcr.io/puppeteer/puppeteer container image, which ships Chrome preinstalled so Puppeteer never has to download a browser at runtime. beforeCommands installs the puppeteer and @kestra-io/libs npm packages, inputFiles stages the competitors input as competitors.json, and the inline script launches one browser instance, visits each competitor page in turn with page.goto and page.waitForSelector, reads the price with page.$eval, and reports the whole array back to Kestra with Kestra.outputs({ pricesJson: ... }).detect_price_changes (io.kestra.plugin.scripts.node.Script) stages both the previous and current snapshots as inputFiles, compares them by competitor name, and outputs a changeCount and a human-readable changesSummary.alert_on_price_change (io.kestra.plugin.core.flow.If) only fires notify_price_change (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) when changeCount is greater than zero.update_snapshot (io.kestra.plugin.core.kv.Set) writes today's prices back to the KV Store as the baseline for tomorrow's diff.nightly Schedule trigger runs at 6 AM, and an errors block posts a separate Slack alert if the scrape or diff step fails, which usually means a competitor changed their page layout and a selector needs updating.A scheduled script can call Puppeteer, but it typically has no durable state between runs, no structured retry when a single competitor's page times out, and no alerting path that distinguishes "a price changed" from "the scrape itself broke". Kestra adds the KV Store for the snapshot, a Schedule trigger you can pause without touching code, an If task that keeps notifications quiet unless something actually changed, and an errors block that alerts on scrape failures separately from price-change alerts, so the two Slack messages never get confused.
ghcr.io/puppeteer/puppeteer Docker image (or an equivalent image with Chrome and its runtime dependencies preinstalled).SLACK_WEBHOOK_URL: Slack incoming webhook URL used for both price-change and failure alerts.SLACK_WEBHOOK_URL secret to your Kestra namespace.competitors input with your real competitor URLs and the CSS selector for each one's price element.nightly trigger and let it run; watch the KV Store's competitor_pricing_snapshot key advance each night.io.kestra.plugin.jdbc.postgresql.Query task after update_snapshot to log every scrape into a history table for trend charts, not just the latest snapshot.page.screenshot() per competitor as visual proof alongside the extracted price, and store it via outputFiles.Schedule trigger for a Flow trigger so the scrape runs on demand right before a pricing committee meeting.