See llms.txt for all machine-readable content.

Back to Templates

Score competitor price changes with Apify, Sheets, DeepSeek, ElevenLabs, and Telegram

Competitor pricing pages move quietly, usually on a Tuesday, and you find out weeks later. This workflow crawls the pages on your watchlist every morning, compares each one with yesterday's snapshot, scores how big the move is, and only sends a voice note when the change actually matters. Small edits get a one line text, and quiet days stay quiet.

Last updated: November 2026.

Quick Overview

The watchlist lives in a Google Sheets tab, so adding a competitor is a new row, not a workflow edit. Apify crawls the active URLs with three retries per call, and a failed crawl is logged and reported instead of silently skipping a day. Each page is reduced to a text hash plus its price tokens, then a scoring step compares the numbers with the last run. Major moves go through a DeepSeek agent, a quality check that rejects prices the crawl never saw, ElevenLabs text to speech and a Telegram voice note. Every alert is written to an alert_log tab with its Telegram message id, and a Monday digest rolls up the week.

How it works

  1. A cron trigger fires at 08:00, reads the pricing_snapshots tab and builds a lookup of the previous hash and price tokens per competitor.
  2. The competitor_watchlist tab is read, inactive rows and non https URLs are dropped, duplicates are removed and the Apify request body is built from what is left. An empty list sends a Telegram notice and stops.
  3. The Apify Website Content Crawler runs with a spend cap, and the dataset is read back. Both nodes retry three times, and a final error goes to run_log plus a Telegram alert.
  4. Each page is normalized, hashed and labeled changed, unchanged or first run, then appended to pricing_snapshots.
  5. Score Change Severity compares the numbers in today's price tokens with the previous ones. A move of 10 percent or more, or a different number of price tiers, is major. Other text changes are minor.
  6. A Switch routes major moves to the agent, minor moves to a short Telegram text and quiet runs to a no-op.
  7. The agent returns a headline, summary and 60 to 90 word narration. Check Brief Quality verifies the headline, the narration length and that every quoted price exists in the crawl. Failures send the raw change table as text instead of a voice note.
  8. Approved briefs go to ElevenLabs, and the mp3 is posted to Telegram with the headline as caption.
  9. Whichever message was sent, a log row with severity, channel, headline, Telegram message id and delivery status is appended to alert_log.
  10. Every Monday at 09:00 a second lane reads alert_log, counts the last seven days by severity and channel, lists the major moves and flags any delivery without a message id.

Setup

  1. Connect your Apify account and confirm the Website Content Crawler actor is on your plan.
  2. Add an OpenAI-compatible credential on Pricing Model. The template points at a DeepSeek endpoint, and any chat model that returns JSON works.
  3. In one Google Sheets file create competitor_watchlist (competitor, pricing_url, active), pricing_snapshots, alert_log and run_log, then select that file in every Sheets node.
  4. Add an ElevenLabs credential and pick the voice on Speak Pricing Brief.
  5. Add a Telegram credential and replace the placeholder chat id 123456789 in all Telegram nodes.
  6. Run the workflow once to store the baseline, then run it again after a page edit to see a scored change come through.

Quick Answers

Why was the first run silent?
The first run has nothing to compare against, so every page is stored as a baseline. Scoring and alerts start on the next run.

What counts as a major change?
A numeric price move of 10 percent or more, or a page that now lists a different number of prices. Change MAJOR_PCT in the scoring node to tune it.

What happens if the model invents a price?
The quality check looks for every currency amount in the narration inside the crawled text. If one is missing, the voice note is skipped and you get the raw change table instead.

How do I know alerts actually arrived?
Each alert row in alert_log carries the Telegram message id and a sent or unconfirmed status, and the Monday digest counts the unconfirmed ones.

Additional info

Built with n8n. Need an assessment on your business? Feel free to reach out at https://khmuhtadin.com/consultation/