# Track Amazon prices with Python

> A small Python script that checks Amazon prices every day, saves them to a CSV file and tells you when a product drops below your target price.

- URL: https://everydata.io/guides/track-amazon-prices-with-python
- Updated: 2026-09-30
- Publisher: everydata.io (https://everydata.io)

Prices on Amazon change all the time, and nobody wants to open the same product page every morning. In this guide you build a small script that does it for you: it looks up the current price of the products you care about, writes every check into a spreadsheet-friendly file, and tells you when a price falls below the amount you are willing to pay.

You do not have to deal with the Amazon page itself. everydata.io loads the live product page for you and sends back clean data – title, price, currency, availability – so the script stays short and does not break when Amazon changes its layout.

## What you will have at the end

- A script that checks a list of Amazon products and appends each price to prices.csv.
- A message when a price drops or reaches your target.
- A daily schedule, so it runs without you.

## What you need

- Python 3.10 or newer and the `requests` package (`pip install requests`).
- A free everydata.io API key – [create one here](https://everydata.io/login).
- The ASIN of each product: the 10-character code after `/dp/` in the Amazon address.

## 1. Keep your API key out of the code

Sign in, copy your key from the dashboard and put it into an environment variable. The script reads it from there, so the key never ends up in a file you might share.

`terminal`:

```shell
export EVERYDATA_API_KEY="ds_your_key"
```

## 2. Look up one product

Start with a single request so you can see what comes back. The product-by-ASIN endpoint takes the ASIN and the marketplace (`com` for amazon.com, `de` for amazon.de and so on).

`first_request.py`:

```python
import os

import requests

API = "https://api.everydata.io"
KEY = os.environ["EVERYDATA_API_KEY"]

resp = requests.get(
    f"{API}/amz/amazon-lookup-product-by-asin",
    params={"asin": "B07ZPKN6YR", "domainCode": "com"},
    headers={"x-api-key": KEY},
    timeout=60,
)
resp.raise_for_status()
product = resp.json()

print(product["productTitle"])
print(product["price"], product["currency"], "-", product["warehouseAvailability"])
```

The answer is JSON. Every response starts with `responseStatus` and `responseMessage`, followed by the product. This is a shortened version of the documented example:

Example response of `GET /amz/amazon-lookup-product-by-asin`:

```json
{
  "responseStatus": "PRODUCT_FOUND_RESPONSE",
  "responseMessage": "Product successfully found!",
  "productTitle": "Apple iPhone 11, 64GB, Black - Unlocked (Renewed)",
  "productRating": "4.2 out of 5 stars",
  "countReview": 60024,
  "asin": "B07ZPKN6YR",
  "warehouseAvailability": "This item cannot be shipped to your selected delivery location. Please choose a different delivery location.",
  "retailPrice": 0,
  "price": 0,
  "currency": "USD"
}
```

> Look at `price` in this example: it is `0`. That happens when the page shows no buyable price – here because the item could not be shipped to the delivery location. Your script should treat `0` as “no price right now”, not as a free product.

## 3. Check a list of products and save every result

Now turn the single request into a small tracker. `WATCHLIST` holds the products and the price you are waiting for. Each run looks up every product once, appends a row to `prices.csv` and compares the new price with the last one it saved.

`track.py`:

```python
"""Check the price of a few Amazon products and append each check to prices.csv."""
import csv
import os
import re
import time
from datetime import datetime, timezone
from pathlib import Path

import requests

API = "https://api.everydata.io"
KEY = os.environ["EVERYDATA_API_KEY"]
CSV_FILE = Path("prices.csv")
DOMAIN = "com"  # amazon.com – use "de", "co.uk", "fr" … for other marketplaces

# ASIN -> the price at which you want to hear about it
WATCHLIST = {
    "B07ZPKN6YR": 30.00,
}


def api_get(path: str, params: dict) -> dict:
    """GET an everydata.io endpoint. Waits when rate limited (429) and retries a failed page load (5xx) once."""
    retried = False
    for _ in range(4):
        resp = requests.get(f"{API}{path}", params=params, headers={"x-api-key": KEY}, timeout=60)
        if resp.status_code == 429:
            # Too many requests at once. The answer says how long to wait: "... Try again in 12 seconds."
            wait = re.search(r"in (\d+) seconds", resp.text)
            time.sleep(int(wait.group(1)) + 1 if wait else 60)
            continue
        if resp.status_code >= 500 and not retried:
            retried = True  # 5xx answers are not counted against your quota
            time.sleep(10)
            continue
        resp.raise_for_status()  # 4xx (wrong key, quota used up, bad parameter) or a second 5xx
        return resp.json()
    raise RuntimeError("still rate limited after several waits – try again later")


def last_price(asin: str) -> float | None:
    """The most recent price we saved for this ASIN, if any."""
    if not CSV_FILE.exists():
        return None
    with CSV_FILE.open(newline="") as f:
        rows = [r for r in csv.DictReader(f) if r["asin"] == asin and r["price"]]
    return float(rows[-1]["price"]) if rows else None


def main() -> None:
    previous = {asin: last_price(asin) for asin in WATCHLIST}
    now = datetime.now(timezone.utc).isoformat(timespec="seconds")
    new_file = not CSV_FILE.exists()

    with CSV_FILE.open("a", newline="") as f:
        writer = csv.writer(f)
        if new_file:
            writer.writerow(["checked_at", "asin", "title", "price", "retail_price", "currency", "availability"])

        for asin, target in WATCHLIST.items():
            try:
                p = api_get("/amz/amazon-lookup-product-by-asin", {"asin": asin, "domainCode": DOMAIN})
            except (requests.RequestException, RuntimeError) as exc:
                print(f"{asin}: could not check this time ({exc}) – the next run tries again")
                continue  # one failed product does not stop the others
            price = p.get("price") or None  # 0 means the page showed no price
            writer.writerow([
                now, asin, p.get("productTitle"), price or "", p.get("retailPrice") or "",
                p.get("currency") or "", p.get("warehouseAvailability") or "",
            ])

            if price is None:
                print(f"{asin}: no price on the page ({p.get('warehouseAvailability')})")
            elif price <= target:
                print(f"{asin}: {price} {p.get('currency')} – at or below your target of {target}")
            elif previous[asin] is not None and price < previous[asin]:
                print(f"{asin}: dropped from {previous[asin]} to {price} {p.get('currency')}")


if __name__ == "__main__":
    main()
```

Run it with `python3 track.py`. The first run creates the file; later runs add one row per product. You can open `prices.csv` in any spreadsheet program to draw a price chart.

`api_get` handles the two answers you will meet sooner or later. If a page cannot be loaded, the API answers with a 5xx status such as 502 or 503; those answers are not counted against your quota, so the script waits a few seconds and tries once more. If you send too many requests at once, the answer is 429 and says how many seconds to wait – the script waits that long and continues. A product that still fails is reported and skipped, and the next run picks it up again.

## 4. Decide how you want to be told

The script prints a line in three cases: the page shows no price, the price is at or below your target, or it dropped since the last check. Printing is enough when you read the log. If you would rather get a message, replace the three `print` calls with whatever you already use – an email via Python's `smtplib`, a chat webhook or a push service.

## 5. Run it every day

On a Mac or Linux machine that is switched on, cron is the simplest scheduler. This line runs the tracker every morning at 7:00 and keeps a log:

`crontab`:

```shell
# Every day at 07:00 – edit with: crontab -e
0 7 * * * cd /home/you/price-tracker && EVERYDATA_API_KEY=ds_your_key /usr/bin/python3 track.py >> track.log 2>&1
```

On Windows, the Task Scheduler does the same job. Any small server or a scheduled CI job works too.

Every product check is one request. As an example: three products checked once a day are about 90 requests a month, which fits into the free plan of 100 requests. For more products or more checks per day, see [pricing](https://everydata.io/pricing).

## 6. Optional: read the price history everydata.io already has

Every product lookup made through everydata.io also stores the price it saw. The price-history endpoint returns those observations for the last `days` days. It only knows about products someone has looked up before, so for a product nobody has checked yet the list is empty – your own CSV file stays the reliable record.

`history.py`:

```python
resp = requests.get(
    f"{API}/amz/amazon-price-history",
    params={"asin": "B07ZPKN6YR", "domainCode": "com", "days": 90},
    headers={"x-api-key": KEY},
    timeout=60,
)
data = resp.json()
print(data["count"], "observations")
for point in data["history"]:
    print(point["observedAt"], point["price"], point["inStock"])
```

Example response of `GET /amz/amazon-price-history`:

```json
{
  "responseStatus": "PRODUCT_FOUND_RESPONSE",
  "responseMessage": "Product successfully found!",
  "asin": "B07ZPKN6YR",
  "domainCode": "com",
  "days": 90,
  "currency": "USD",
  "count": 2,
  "history": [
    {
      "observedAt": "2026-09-18T10:12:00Z",
      "price": 39.99,
      "retailPrice": 49.99,
      "inStock": true
    },
    {
      "observedAt": "2026-09-19T09:40:00Z",
      "price": 34.99,
      "retailPrice": 49.99,
      "inStock": true
    }
  ]
}
```

## Endpoints used in this guide

- `GET /amz/amazon-lookup-product-by-asin`
- `GET /amz/amazon-price-history`

## More

- [All platforms](https://everydata.io/apis) · [Pricing](https://everydata.io/pricing) · [API reference](https://everydata.io/docs) · [Getting started](https://everydata.io/docs/getting-started) · [MCP server](https://everydata.io/docs/mcp) · [Status](https://everydata.io/status)
- Machine-readable: [llms.txt](https://everydata.io/llms.txt), [llms-full.txt](https://everydata.io/llms-full.txt), [OpenAPI](https://api.everydata.io/openapi.json)
