Price Monitor
Monitors competitor pricing pages and alerts on changes.
scrapeaistreamswitchemail
Source
/**
* Monitors competitor pricing pages and alerts on changes.
*/
schedule check_prices {
label: "Check Prices"
cron: "0 6 * * *"
timezone: "America/New_York"
}
workflow monitor_prices {
label: "Monitor Competitor Prices"
root {
type: code
label: "Start"
code: @ts {
return { checked_at: new Date().toISOString() }
}
outputSchema: @json {
{
"type": "object",
"properties": {
"checked_at": { "type": "string" }
}
}
}
}
node scrape_competitor {
type: scrape
label: "Scrape pricing page"
url: @ts { return "https://competitor.example.com/pricing" }
onlyMainContent: true
formats: ["markdown"]
}
node extract_prices {
type: ai
label: "Extract pricing data"
kind: object
model: "google/gemini-2.5-flash"
prompt: @ts {
return "Extract all pricing tiers and their prices from this pricing page content. Return structured data.\n\n" + JSON.stringify(context.nodes.scrape_competitor.output)
}
schema: @json {
{
"type": "object",
"required": ["tiers"],
"properties": {
"tiers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"monthly_price": { "type": "number" },
"annual_price": { "type": "number" },
"features": { "type": "array", "items": { "type": "string" } }
}
}
}
}
}
}
}
node check_history {
type: stream
label: "Get previous prices"
stream: price_history
version: v1
filter: @ts {
return {}
}
}
node store_result {
type: code
label: "Store prices"
code: @ts {
return {
checked_at: context.nodes.root.output.checked_at,
tiers: context.nodes.extract_prices.output.tiers,
tier_count: context.nodes.extract_prices.output.tiers.length
}
}
}
node compare {
type: code
label: "Compare with previous prices"
code: @ts {
const rows = context.nodes.check_history.output || []
const previous = rows.length > 0 && rows[0].tiers ? rows[0].tiers : null
const current = context.nodes.extract_prices.output.tiers
const key = function(tiers) {
return JSON.stringify((tiers || []).map(function(t) {
return { name: t.name, monthly_price: t.monthly_price, annual_price: t.annual_price }
}))
}
const changed = previous !== null && key(previous) !== key(current)
return {
changed: changed,
current_count: current.length,
previous_count: previous ? previous.length : 0,
current_tiers: current
}
}
}
node route_change {
type: switch
label: "Route on change"
cases: ["changed", "unchanged"]
router: @ts {
if (context.nodes.compare.output.changed) return "changed"
return "unchanged"
}
}
node alert_change {
type: email
label: "Alert on price change"
from: @ts { return "[email protected]" }
to: @ts { return "[email protected]" }
subject: @ts { return "Competitor pricing changed" }
text: @ts {
const cmp = context.nodes.compare.output
return "Competitor pricing changed.\n\nTiers now: " + cmp.current_count + " (was " + cmp.previous_count + ")\n\nCurrent tiers:\n" + JSON.stringify(cmp.current_tiers, null, 2)
}
}
node no_change {
type: code
label: "No change"
code: @ts {
return { changed: false }
}
}
flow {
root -> scrape_competitor
scrape_competitor -> extract_prices
root -> check_history
extract_prices -> store_result
extract_prices -> compare
check_history -> compare
compare -> route_change
route_change -["changed"]-> alert_change
route_change -["unchanged"]-> no_change
}
}
stream price_history {
label: "Price history"
workflow: monitor_prices
version: v1
versions: {
v1 {
schema: @json {
{
"type": "object",
"required": ["checked_at", "tier_count"],
"properties": {
"checked_at": { "type": "string" },
"tiers": { "type": "array" },
"tier_count": { "type": "number" }
}
}
}
condition: @ts { return context.output.store_result != null }
prepare: @ts { return context.output.store_result }
}
}
}
trigger on_price_check {
schedule:check_prices -> monitor_prices
enabled: true
}
Flow
Trigger to workflow
check_pricesschedule
monitor_prices
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Workflow nodes
CODE
Code Node
Start
SCRAPE
Scrape Node
Scrape pricing page
AI
AI Node
Extract pricing data
STREAM
Stream Node
Get previous prices
CODE
Code Node
Store prices
CODE
Code Node
Compare with previous prices
SWITCH
Switch Node
Route on change
EMAIL
Email Node
Alert on price change
CODE
Code Node
No change
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.