When a competitor drops the price on a product you both sell, you often find out late: when that week's sales come in lower than expected, or when someone finally updates the spreadsheet of competitor prices by hand. Manual checks work for a handful of products, but for hundreds of products checked daily, you need automation.
A script of your own can fetch the product pages, but you still have to pull the price, currency, and stock status out of each retailer's page, and update that code whenever a retailer changes its layout. A single day's price also tells you little on its own. To know whether a drop is a one-day promo or a lasting cut, you need a price history for each product.
The Monitor competitor prices with Apify template combines Apify's E-commerce Scraping Tool with n8n, Postgres or Supabase, and an AI agent. It collects competitor prices every morning, builds a historical baseline, and sends repricing recommendations to Slack.
You don't need to build a scraper or write the workflow from scratch. Import the template, configure your database, add your product URLs, and connect your credentials.
What the template does #
Every morning at 6 am, the workflow runs through five stages and a health check.
1. Collect prices with E-commerce Scraping Tool
The Select Pages to Monitor node holds your list of competitor product URLs and your Slack channel. It's the only node you need to edit.
The workflow sends the whole list to E-commerce Scraping Tool in a single run. The Actor handles proxies, anti-bot protection, and per-retailer extraction. It returns structured product data, including prices, product names, brands, availability, and URLs. Because retailers don't always report these fields in the same format, the next step standardizes the data before storing it.
The Apify node has a $1 spending cap per run (maxTotalChargeUsd) to help control scraping costs. You can increase the cap if you're monitoring a larger product list.
2. Clean up the data
Retailers don't format product data the same way. The Normalize Product Data step fixes the three differences that would quietly corrupt your price history:
- Prices are read without assuming a country format, so
1.299,99and$1,299.99both come out as the right number. - Currency is stored as an ISO code (USD, CAD, EUR) rather than an ambiguous symbol, making it clear which currency each price uses.
- Stock has three states: in stock, out of stock, and not reported. A page that doesn't show availability isn't treated as sold out.
3. Build the price history
Each product gets one row per day in a price_history table in your Postgres or Supabase database. If you run the workflow twice on the same day, it updates that day's row instead of adding a duplicate.
The table also keeps the full Actor output for each product. If you later want to track something new, such as ratings, you can add a column and fill it from data you've already collected.
4. Detect the moves that matter
This is what separates the template from a simple price comparison. A database view compares today's price with each product's own history and flags a product only when:
- the price is 5% or more above or below its 30-day average
- the price sets a new 90-day low or high
- the product goes out of stock or comes back in stock
It reports changes, not states. If a rival cuts a price and holds it for two weeks, you hear about it once, on the day it happened.
It also stays silent for the first 14 days. A product needs at least 14 days of data before the workflow flags it, because a baseline of one or two days is noise. No alerts in the first two weeks means the workflow is working as intended.
5. Turn moves into a recommendation
Everything that moved goes to the Repricing Analysis Agent in one batch. Because detection already happened in the database, the agent's job is to explain the move, not to decide whether it counts. Its instructions tell it to:
- lead with the decision (consider matching, or hold), then give the reason
- use only the numbers it receives and never invent figures
- avoid stating margins or exact prices to set, because it doesn't know your costs
- say how strong the pattern is, and point out when the product has less than 30 days of history
- treat an out-of-stock rival as a supply signal, a reason to hold rather than follow the price down
- call out a new 90-day low as the strongest signal
- keep it short: one paragraph per product, and a summary if more than three products moved
The agent also treats product names and other scraped text strictly as data. If a product title contains text that reads like an instruction, the agent ignores it and says the name looked manipulated.
Here's the kind of message that lands in Slack:
Consider matching on the Calvin Klein Men's Heavyweight Short Puffer at amazon.com. It is at $81.86, 25.4% below its 30-day average of $109.72, and it is a new 90-day low, which is the strongest signal in this report. The record covers 11 days, which is under 30, so treat the pattern as provisional.
Health check: know when data stops coming in
A broken product page and a quiet market look the same if you only report price changes. A second branch compares the URLs you asked for with the products that came back. If any URL returned nothing, or returned a product without a price, it posts a separate warning to Slack listing them. When everything comes back, it stays quiet.
How to set up the template #
Before you start, you'll need:
- n8n, either n8n Cloud or self-hosted
- an Apify account . The free plan includes $5 of usage a month, which covers roughly 15 to 27 products checked daily, depending on the retailers.
- Postgres 15 or later, or a Supabase project. Version 15 is the minimum because the template's database views need it.
- an OpenAI API key. The template uses gpt-5-mini, and you can swap in Anthropic, Google, or a local model.
- a Slack workspace with a channel for the alerts
Step 1. Import the template
Open the template page and click Use for free to copy it into your n8n instance. If you have the workflow as a JSON file, use Import from File in n8n instead.
Step 2. Add the Apify node
The template uses the Apify node, which n8n lists as a verified community node. On n8n Cloud, search for Apify on the canvas.
Your instance owner needs to have verified community nodes turned on. On self-hosted n8n, install @apify/n8n-nodes-apify under Settings > Community nodes.
Step 3. Create the database tables
The SQL is in the red sticky note titled Run this SQL first, on the right side of the canvas. Copy everything between the ``` sql line and the closing ```.
-
Supabase: openSQL Editor in your project, paste the SQL, and clickRun .
-
Other Postgres: run it in your usual database tool, logged in as the user n8n will connect with.
It creates a pricing schema with the price_history table and the two views the workflow reads. Row-level security is on with no access rules, so only the database user that owns the table can read or write it, and Supabase never exposes it through its public API. If you skip this step, the first run fails with relation "pricing.price_history" does not exist.
Step 4. Connect your accounts
The workflow uses four accounts across six nodes. You create each credential once and then select it in every node that needs it. To create one, open the node, click the Credential dropdown, and choose Create new credential.
Apify
Used in Run Apify Scraper.
-
In Apify Console , go toSettings >API & Integrations and copy your API token.
-
In n8n, choose Apify API , paste the token, and clickSave .
On n8n Cloud, you can choose Apify OAuth2 API instead and click Connect my account to sign in with your Apify account, with no token to copy.
Postgres or Supabase
Used in Save Daily Snapshot to DB and Detect Price Changes.
On Supabase, click Connect at the top of your project and choose Session pooler. Use the pooler rather than the direct connection, because Supabase's direct connection works only over IPv6, which many n8n setups can't reach. Copy these values into the n8n Postgres credential:
- Host: the pooler host, for example
aws-0-eu-central-1.pooler.supabase.com - Database:
postgres - User:
postgres.your-project-ref, exactly as Supabase shows it - Password: your database password, not your Supabase login. If you don't have it, reset it underProject Settings >Database .
- Port:
5432 - **SSL:**Require
Leave Ignore SSL Issues and SSH Tunnel off and click Save. n8n tests the connection when you save. Then open Detect Price Changes and select the same credential.
This user is the same one that ran the SQL in step 3, which matters: the table has row-level security with no access rules, so only the user that owns it can read or write it. On other Postgres servers, enter your own host, database name, and port, and log in as the user that ran the SQL.
OpenAI
Used in Chat Model.
-
Open the API keys page on the OpenAI platform and clickCreate new secret key .
-
In n8n, choose OpenAI , paste the key intoAPI Key , and clickSave . LeaveOrganization ID blank unless you belong to more than one OpenAI organization.
OpenAI bills API usage separately from ChatGPT subscriptions, so add credit to your API account before the first run. On n8n Cloud, if the credential field offers Use Gateway credits, you can use that instead of your own key.
Slack
Used in Send Slack Alert and Send Slack Warning.
The template connects to Slack with OAuth2. Create your alerts channel before you start.
- n8n Cloud: chooseSlack OAuth2 API , clickConnect my account , and approve access in the window that opens.
- Self-hosted n8n: you need your own Slack app first. Copy theOAuth Callback URL from the n8n credential. Atapi.slack.com/apps , chooseCreate New App >From a manifest and paste the OAuth2 manifest from then8n Slack credential docs , with your callback URL in it. Install the app to your workspace, which needs a Slack admin. Then copy the app'sClient ID andClient Secret into n8n and connect.
Select the same credential in Send Slack Warning. If the first alert fails with a not_in_channel error, type /invite @ followed by the app's name in your alerts channel and run the workflow again.
Step 5. Add your products and a name of the Slack channel
Open Select Pages to Monitor. It's a Code node, but the only part you change is the list at the top:
const WATCH = [
'https://www.amazon.com/dp/REPLACE_ME',
'https://www.walmart.com/ip/REPLACE_ME/000000000',
];
const SLACK_CHANNEL = '#pricing-alerts';
Replace the two example URLs with competitor product pages. Put each URL in single quotes with a comma after it, one per line, and add as many lines as you need. Then change #pricing-alerts to your channel name. Leave the rest of the node as it is.
Use direct product URLs, not search results. Search results change from day to day, so they can't build a price history for one product. For products with sizes or colors, link to the exact variant you compete with.
Step 6. Match the spending cap to your list
Run Apify Scraper stops each run at $1 of usage (maxTotalChargeUsd) or 300 seconds (Timeout), whichever comes first. $1 covers at least 90 products at free-plan prices. For a longer list, raise the cap, and raise the timeout if runs stop before they finish. Products a run didn't reach show up in the Slack collection warning, so you'll know if the limits are too low.
Step 7. Check the timezone
The schedule runs at 6 am in your n8n instance's timezone, which may not be yours. Check it under Settings, or change the hour in the Every Morning at 6am node.
Step 8. Test it
Click Execute workflow to run it once, then check three things:
pricing.price_historyhas one row per product. In Supabase, openTable Editor and switch to thepricingschema.- Slack has no repricing alert yet. That's expected, because alerts start after 14 days of history.
- If any URL returned nothing or no price, a collection warning appears in your Slack channel. Fix or replace those URLs.
Step 9. Turn it on
Activate the workflow so it runs every morning. After two weeks, the first repricing alerts can arrive.
Ways to adapt it #
- Change the thresholds. The 5% band, the 90-day range, and the 14-day waiting period all live in one SQL view. Change them there, and the agent's alerts follow.
- Send alerts somewhere else. Replace the Slack node with email, Google Sheets, or a webhook.
- Watch a whole category. Run E-commerce Scraping Tool in keyword mode once to collect product URLs, then paste the ones you want into the watchlist.
- Compare like with like. Use E-commerce Product Matching Tool to find each competitor's equivalent of your products before you add their URLs, so you don't compare your product with something merely similar.
- Check prices from your AI assistant. ConnectApify MCP server to Claude, Cursor, or another MCP client, and run E-commerce Scraping Tool on demand when you need a price outside the daily schedule.
Conclusion #
The template handles the part that's hard to keep up by hand: a price for every product on your list each morning, and a short Slack note when one of them moves outside its usual range. Pick the products where a competitor's price cut would hurt you most, and when the first alerts arrive, read them with your own margins in front of you. If the 5% threshold turns out too noisy or too quiet for your category, it's one number in one SQL view.
FAQ #
Why didn't I get any alerts in the first two weeks?
The workflow needs at least 14 days of price history for a product before it flags changes. Until then, it collects data and stays quiet. The health check still warns you if a URL stops returning data.
Which retailers does it work with?
E-commerce Scraping Tool supports major retailers and marketplaces, including Amazon, Walmart, Target, eBay, Best Buy, Home Depot, IKEA, Tesco, Mercado Libre, and Idealo. Check the Actor's page for the current list.
Does the AI agent change my prices?
No. It recommends a response and explains why. A person reads the alert and decides what to do.
Can I use a different AI model?
Yes. Swap the Chat Model node for any chat model n8n supports and add that provider's credentials.
Can I store the history in Google Sheets instead of a database?
Not without changes. The template detects price moves with SQL views, so it needs Postgres or Supabase as shipped.