# How to build a competitive pricing agent in n8n with Apify

> Source: <https://blog.apify.com/competitive-pricing-agent/>
> Published: 2026-11-02 10:00:00+00:00

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](https://n8n.io/workflows/19750-monitor-competitor-price-shifts-with-apify-postgres-openai-and-slack/) 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](https://apify.com/apify/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,99` and`$1,299.99` both 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](https://console.apify.com/sign-up) . 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](https://n8n.io/workflows/19750-monitor-competitor-price-shifts-with-apify-postgres-openai-and-slack/) 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:** open**SQL Editor** in your project, paste the SQL, and click**Run** .

- **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**.

1. In [Apify Console](https://console.apify.com/settings/integrations) , go to**Settings** >**API & Integrations** and copy your API token.

1. In n8n, choose **Apify API** , paste the token, and click**Save** .

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 under**Project 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**.

1. Open the [API keys page](https://platform.openai.com/api-keys) on the OpenAI platform and click**Create new secret key** .

1. In n8n, choose **OpenAI** , paste the key into**API Key** , and click**Save** . Leave**Organization 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:** choose**Slack OAuth2 API** , click**Connect my account** , and approve access in the window that opens.
- **Self-hosted n8n:** you need your own Slack app first. Copy the**OAuth Callback URL** from the n8n credential. At[api.slack.com/apps](https://api.slack.com/apps) , choose**Create New App** >**From a manifest** and paste the OAuth2 manifest from the[n8n Slack credential docs](https://docs.n8n.io/integrations/builtin/credentials/slack/) , with your callback URL in it. Install the app to your workspace, which needs a Slack admin. Then copy the app's**Client ID** and**Client 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:

``` js
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_history` has one row per product. In Supabase, open**Table Editor** and switch to the`pricing` schema.
- 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.** Connect[Apify MCP server](https://mcp.apify.com) 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](https://apify.com/apify/e-commerce-scraping-tool) 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.
