Weekly competitor pricing tracker logged to Google Sheets
Every Monday at 9am, scrape competitor pricing pages, diff them against last week, and append a clean change log to a Google Sheet.
Build a code workflow that tracks competitor pricing on a weekly cadence and logs every change to a Google Sheet.
Trigger: cron, every Monday at 9am in the user's local timezone.
Setup inputs: (1) a list of competitor pricing page URLs, each with a short competitor name label, (2) a Google Sheets spreadsheet ID and the tab name to write to.
Step 1 — Scrape each competitor pricing page. Iterate over the configured URLs and call Firecrawl's Scrape URL operation for each one. Use the JSON extraction format with a structured schema that pulls an array of plans, where each plan has: plan_name (string), price_amount (number), price_currency (string, default USD), billing_period (string, one of monthly, annual, one-time, contact-sales). Pass a short natural-language prompt alongside the schema so Firecrawl knows to extract the standard pricing tiers and skip add-ons and enterprise contact rows. Collect the results into a single array shaped as { competitor, url, scraped_at, plans: [...] }.
Step 2 — Load the previous week's snapshot from Google Sheets. Call the Get Values operation on the configured spreadsheet and tab, reading the full data range. The sheet's columns are: run_date, competitor, plan_name, price_amount, price_currency, billing_period, change. Use the most recent run_date in the sheet as the prior snapshot to diff against.
Step 3 — Run the diff in a Daytona sandbox. Call Create Sandbox to provision a fresh Python sandbox. Then call Run Code in Sandbox with a Python script that takes the current scrape array and the prior snapshot as inputs and produces, for each (competitor, plan_name) pair, a normalized row with a change column set to one of: new (plan didn't exist last week), price_up (same plan, higher price), price_down (same plan, lower price), unchanged (same plan, same price), removed (plan existed last week but is missing this week). Match plans by (competitor, plan_name) case-insensitively. Output the result as a JSON array of rows. After the script returns, call Delete Sandbox to clean up — every run should leave zero sandboxes behind.
Step 4 — Append the new snapshot to Google Sheets. Call the Append Values operation to add one row per plan from the diff output. Each row is: today's date, competitor, plan_name, price_amount, price_currency, billing_period, change. Use USER_ENTERED so dates and numbers render correctly.
Error handling: if Firecrawl fails to extract from a single URL, log an error row for that competitor with change set to 'scrape_failed' but still process the others. If the Daytona sandbox creation or code execution fails, attempt Delete Sandbox in a cleanup step regardless so we never leak sandboxes.
This is a deterministic pipeline. Every step has fixed inputs and outputs, no judgement calls or LLM reasoning required inside the workflow itself.
Additional information
What does this prompt do?
- Visits every competitor pricing page you list and pulls the plan names and prices from each one.
- Compares this week's prices against last week's snapshot in your Google Sheet and tags each plan as new, price up, price down, unchanged, or removed.
- Appends a fresh, dated snapshot to your sheet so you keep a permanent week-by-week history of every competitor's pricing.
- Runs every Monday at 9am with no manual checking. You just open the sheet.
What do I need to use this?
- A Firecrawl account for the website scraping.
- A Daytona account to run the weekly diff in an isolated sandbox.
- A Google account with a Google Sheet you want to log pricing into.
- The list of competitor pricing page URLs you want to track.
How can I customize it?
- Change when it runs. Daily, every Friday, twice a week. Pick whatever cadence matches how often your market moves.
- Add or remove competitor URLs without touching the rest of the workflow.
- Adjust which fields you log. The default is plan name, price, currency, and billing period, but you can pull seat tiers, feature lists, or any other field that lives on the pricing page.
Frequently asked questions
Do I need to know how to code to use this?
What if a competitor changes the layout of their pricing page?
Will this work for pricing pages that require a login?
Where does the historical data live?
How is this different from a simple scraper that just logs prices?
Stop manually checking competitor pricing pages.
Connect Firecrawl, Daytona, and Google Sheets once, and Geni logs every pricing change for you every Monday morning.