# Flight Price Tracker: Fare Drop Alerts (Memory) (`sillage-data/flight-price-watch`) Actor

Flight price tracker with memory: watch routes by airport code and get a fare drop alert when the price falls, hits a new low or goes under your target. One decision per route and date, a ready-to-send alert line, 0.005 USD per check.

- **URL**: https://apify.com/sillage-data/flight-price-watch.md
- **Developed by:** [Sillage Data](https://apify.com/sillage-data) (community)
- **Categories:** Travel, Automation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Flight Price Watch

**A flight price tracker that remembers.** Other flight scrapers hand you a list of fares and leave the comparing to you. Flight Price Watch keeps the last price of every route you watch, checks again on your schedule, and tells you only what changed: a fare drop, a new lowest price, a price under your target, or Google rating prices as low. Each alert comes with a ready-to-send sentence for Slack, Telegram or email.

Try it in one click: the default input watches Brussels to Lisbon 45 days from today. Run it twice and the second run compares with the first. Price: 0.005 USD per route check and 0.02 USD per alert, no subscription.

```text
BRU-LIS on 10 Dec 2026: 88 EUR (-12% vs last check (100 EUR), lowest price seen so far, under your target of 90 EUR, Google rates prices as low)
```

### What you get for each route and date

```json
{
  "route": "BRU-LIS",
  "departureDate": "2026-12-10",
  "status": "alert",
  "cheapestPrice": 88,
  "currency": "EUR",
  "cheapestAirlines": ["Brussels Airlines"],
  "cheapestStops": 0,
  "cheapestDurationMinutes": 175,
  "googleVerdict": "low",
  "typicalPriceRange": [95, 230],
  "previousPrice": 100,
  "changePercent": -12.0,
  "lowestSeenPrice": 88,
  "alerts": ["BELOW_TARGET", "DROP", "NEW_LOW", "VERDICT_LOW"],
  "alertText": "BRU-LIS on 10 Dec 2026: 88 EUR (-12% vs last check ...)",
  "googleFlightsUrl": "https://www.google.com/travel/flights/search?tfs=...",
  "quality": {"itinerariesSeen": 8, "verdictParsed": true, "trusted": true}
}
```

`status` is one of `baseline` (first check, nothing to compare yet), `unchanged`, `changed`, `alert`, or `unverified` (the page could not be trusted: not charged, memory untouched).

### Why not just run another flight scraper?

| | Typical flight scraper | Flight Price Watch |
|---|---|---|
| Memory between runs | You build it (sheet, database, n8n) | Built in, one memory per watch name |
| Output | Hundreds of rows per search | One decision per route and date |
| Alert sentence | You write it | Ready to send |
| Bad or partial page | Often charged | Marked `unverified`, never charged, never compared |
| "Cheapest" check | Trust the first list | Our cheapest must equal the "from" price the page shows itself |

### How it works

1. Add your routes as airport codes (`BRU-LIS`, `JFK-LAX`), a date (`2026-12-10` or `+45d`) and, if you want, a target price.
2. Schedule the Actor daily in Apify (Schedules) with the same watch name.
3. Add a webhook or an integration on "Run succeeded" and filter dataset items where `status` is `alert`.
4. Receive the `alertText` in Slack, Telegram, email, Google Sheets or your agent.

The first run is a baseline. Alerts start from the second run.

### Pricing

Pay per event, no subscription:

| Event | Price | When |
|---|---|---|
| Route check | 0.005 USD | One route and date read and verified |
| Alert | 0.02 USD | A check that produced at least one alert |

Unverified pages cost nothing. Example: 10 routes checked every day for a month = 300 checks = 1.50 USD, plus 0.02 USD for each alert. You can cap any run with the maximum cost per run setting; the Actor stops cleanly when the cap is reached.

### Input

| Field | What it does |
|---|---|
| `routes` | Up to 20 routes like `BRU-LIS` |
| `departure` | Fixed date `2026-12-10` or rolling `+45d` |
| `windowDays` | Also check the next N days (1 to 14) |
| `returnAfterNights` | 0 for one way, N for a round trip back N nights later |
| `targetPrice` | Optional alert threshold in your currency |
| `dropPercent` | Minimum drop since the last check for a DROP alert (default 5) |
| `alertOn` | Which alert types you want |
| `adults`, `cabin`, `nonstopOnly` | Search options |
| `currency`, `country`, `language` | Price currency, market and page language |
| `watchName` | Name of the memory; same name = same history |
| `resetMemory` | Forget the history for this watch name |
| `maxChecks` | Cost guard per run (default 30, max 100) |

### Integrations

Use Apify Schedules for daily runs, webhooks for alerts, and the Apify integrations for Make, n8n, Zapier, Slack and Google Sheets. Call it from code with the Apify API clients for JavaScript and Python, or from an AI agent through the Apify MCP server.

### Questions and answers

#### What is the best way to get a Google Flights price alert automatically?

Run Flight Price Watch on a daily Apify schedule with your routes and a target price. It stores the last price and the lowest price seen, and returns an alert line only when the fare drops, hits a new low, goes under your target, or Google rates prices as low.

#### Is there a Google Flights API for price tracking?

Google does not offer a public Google Flights API. Flight Price Watch reads the public search page for each route and date and returns structured JSON, with memory between runs, through the Apify API.

#### How does it know the price is the real cheapest?

Every page lists the cheapest fare it shows ("from" price). The Actor only trusts a check when its cheapest itinerary equals that number. Otherwise the check is `unverified`, not charged, and not stored, so it cannot create a false drop alert.

#### What does the Google price verdict mean?

Google compares the current cheapest fare with a typical range for the route. Below the range is `low`, inside is `typical`, above is `high`. The range is in `typicalPriceRange`.

#### Why did I get a baseline and no alert?

The first check of a route and date has nothing to compare with. Run it again (or schedule it) with the same `watchName`.

#### Can I track a round trip?

Yes. Set `returnAfterNights`, for example 7 for a one-week trip. The price is the round-trip fare shown on the page.

#### What are the limits?

It returns the cheapest fare and the few top itineraries the page shows, not every flight. It does not book, does not return booking links, and does not cover multi-city trips. Up to 100 checks per run, one request at a time.

#### Is it legal to use?

It reads public price pages, without login and without account cookies, at a slow pace (one request at a time, a few seconds apart). It does not solve captchas or bypass blocks: if a page is blocked, the run stops and nothing is charged. Google's terms restrict automated access to its services, and Google's robots.txt disallows the flight search path. You are responsible for how you use the data; this is not legal advice. If Apify or Google asks, the Actor will be withdrawn. Flight Price Watch is not affiliated with Google.

### Safeguards

- Public price data only: no personal data, no accounts, no reviews, no booking.
- No captcha solving, no fake tokens, no fingerprint spoofing.
- One request at a time, at least 2 seconds apart, a hard cap on checks per run.
- A blocked page stops the run; unverified pages are free and never update the memory.

### Support

Found a problem or need a field? Open an issue in the Issues tab. We answer every question within 6 hours.

# Actor input Schema

## `routes` (type: `array`):

One route per line, as two 3-letter airport codes: BRU-LIS, JFK-LAX, LHR-BCN. Up to 20 routes.

## `departure` (type: `string`):

A date like 2026-12-10, or a relative value like +45d (45 days from the day the run starts). Use a fixed date for trip alerts; +45d gives a rolling watch.

## `windowDays` (type: `integer`):

1 checks only the departure date. 7 checks it and the 6 following days (one check per day, each charged).

## `returnAfterNights` (type: `integer`):

0 for a one-way fare. 7 for a round trip that comes back 7 nights later.

## `targetPrice` (type: `integer`):

Optional. Alert when the cheapest fare goes at or under this amount (in the currency below).

## `dropPercent` (type: `integer`):

Alert when the price falls at least this many percent since the last check.

## `alertOn` (type: `array`):

Which decisions create an alert (and the alert charge). BELOW_TARGET, DROP, NEW_LOW, VERDICT_LOW.

## `adults` (type: `integer`):

Number of adult passengers (1 to 9).

## `cabin` (type: `string`):

Cabin class.

## `nonstopOnly` (type: `boolean`):

Only consider direct flights.

## `currency` (type: `string`):

3-letter currency code, for example EUR, USD, GBP.

## `country` (type: `string`):

2-letter country code of the market used for prices (US, BE, GB...). Keep it the same between runs so prices stay comparable.

## `language` (type: `string`):

Language of the search page, for example en-US.

## `watchName` (type: `string`):

The memory used to compare with past runs. Use a different name for each separate watch list. Same name = same memory.

## `resetMemory` (type: `boolean`):

Forget past prices for this watch name and start again with a baseline.

## `maxChecks` (type: `integer`):

Cost guard: the run never does more checks than this (routes x days).

## `proxyConfiguration` (type: `object`):

Apify datacenter proxy is the default and was reliable in tests. Residential works too but adds about 0.002 USD of traffic per check.

## Actor input object example

```json
{
  "routes": [
    "BRU-LIS"
  ],
  "departure": "+45d",
  "windowDays": 1,
  "returnAfterNights": 0,
  "dropPercent": 5,
  "alertOn": [
    "BELOW_TARGET",
    "DROP",
    "NEW_LOW",
    "VERDICT_LOW"
  ],
  "adults": 1,
  "cabin": "economy",
  "nonstopOnly": false,
  "currency": "EUR",
  "country": "US",
  "language": "en-US",
  "watchName": "default",
  "resetMemory": false,
  "maxChecks": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `checks` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "routes": [
        "BRU-LIS"
    ],
    "departure": "+45d",
    "windowDays": 1,
    "returnAfterNights": 0,
    "dropPercent": 5,
    "alertOn": [
        "BELOW_TARGET",
        "DROP",
        "NEW_LOW",
        "VERDICT_LOW"
    ],
    "adults": 1,
    "cabin": "economy",
    "nonstopOnly": false,
    "currency": "EUR",
    "country": "US",
    "language": "en-US",
    "watchName": "default",
    "resetMemory": false,
    "maxChecks": 3,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("sillage-data/flight-price-watch").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "routes": ["BRU-LIS"],
    "departure": "+45d",
    "windowDays": 1,
    "returnAfterNights": 0,
    "dropPercent": 5,
    "alertOn": [
        "BELOW_TARGET",
        "DROP",
        "NEW_LOW",
        "VERDICT_LOW",
    ],
    "adults": 1,
    "cabin": "economy",
    "nonstopOnly": False,
    "currency": "EUR",
    "country": "US",
    "language": "en-US",
    "watchName": "default",
    "resetMemory": False,
    "maxChecks": 3,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("sillage-data/flight-price-watch").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "routes": [
    "BRU-LIS"
  ],
  "departure": "+45d",
  "windowDays": 1,
  "returnAfterNights": 0,
  "dropPercent": 5,
  "alertOn": [
    "BELOW_TARGET",
    "DROP",
    "NEW_LOW",
    "VERDICT_LOW"
  ],
  "adults": 1,
  "cabin": "economy",
  "nonstopOnly": false,
  "currency": "EUR",
  "country": "US",
  "language": "en-US",
  "watchName": "default",
  "resetMemory": false,
  "maxChecks": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call sillage-data/flight-price-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sillage-data/flight-price-watch"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/lcNsSeMYs8hwFrvyU/builds/O6cI31lOQvAQ8G5eZ/openapi.json
