← All posts

Flight Price Tracker: How to Build Travel Price Monitoring

Quick answer: To build a flight price tracker or travel price monitoring system, start with official airline and OTA APIs wherever they exist, because their terms of service usually restrict automated scraping of live fares. Where a public price page is fair game, fetch it on a schedule, parse the fare, store a time series, and alert when the price drops below a threshold or your rolling average. Never evade authentication or bot protection to collect pricing.

Travel prices move constantly. The same seat can swing 30% in a week, and hotel rates shift by day of week and lead time. That volatility is exactly why monitoring is useful, and exactly why you should build it carefully. This post walks through a compliant approach, a working code sketch, and an honest note on where the legal lines sit.

Start With Official APIs, Not Scraping

Before you write a single line of a scraper, check whether the data is available through a sanctioned channel. Airlines and online travel agencies frequently prohibit automated collection of live fares in their terms of service, and they invest heavily in bot detection precisely because pricing is competitive intelligence.

Sanctioned options that exist in the industry:

Source type What it gives you Access model
Airline developer APIs Direct fares and availability Registration, often partner approval
GDS providers Broad multi-carrier fares Commercial contract
Aggregator affiliate APIs Search results across carriers Affiliate or partner key
Hotel platform APIs Room rates and availability Registration, sometimes revenue share

If an official API covers your route or property set, use it. It is more stable than scraping, it will not break when a page redesigns, and it keeps you inside the terms you agreed to.

When a Public Page Is Fair Game

Some travel price data lives on genuinely public pages that do not require login and do not prohibit reading in their terms: a published hotel rack rate, a public deals board, a fare calendar that renders without authentication. For those, monitoring is reasonable as long as you are gentle about it.

The pattern is the same one you would use for any competitor pricing monitor: fetch, parse, store, compare, alert. The travel-specific wrinkle is that prices are keyed by date and often need JavaScript to render.

Here is a fetch using the link.sc API, which renders the page and returns clean content so you are not maintaining a headless browser fleet:

import requests

API = "https://api.link.sc/v1/fetch"
HEADERS = {"x-api-key": "lsc_your_key", "Content-Type": "application/json"}

def fetch_price_page(url):
    r = requests.post(API, headers=HEADERS, json={
        "url": url,
        "format": "markdown",
        "render_js": True,
        "wait_for": ".price"   # wait until the price element is present
    })
    r.raise_for_status()
    return r.json()["content"]

Parse the Fare and Store a Time Series

A single price is noise. A history is signal. Store every reading with a timestamp so you can compute trends and know what "cheap" actually means for this route.

import re, sqlite3
from datetime import datetime, timezone

db = sqlite3.connect("fares.db")
db.execute("""CREATE TABLE IF NOT EXISTS fares (
    route TEXT, depart_date TEXT, price REAL, currency TEXT, seen_at TEXT
)""")

def parse_price(markdown):
    m = re.search(r'[$€£]\s?([\d,]+(?:\.\d{2})?)', markdown)
    return float(m.group(1).replace(",", "")) if m else None

def record(route, depart_date, price, currency="USD"):
    db.execute(
        "INSERT INTO fares VALUES (?,?,?,?,?)",
        (route, depart_date, price, currency,
         datetime.now(timezone.utc).isoformat())
    )
    db.commit()

For hotels, the shape is identical: key on property plus check-in date instead of route plus departure date.

Alert on a Real Drop, Not a Blip

The naive version alerts every time the price changes, which trains you to ignore it. A useful tracker alerts on a meaningful drop relative to recent history.

def should_alert(route, depart_date, current, threshold_pct=10):
    rows = db.execute(
        "SELECT price FROM fares WHERE route=? AND depart_date=? "
        "ORDER BY seen_at DESC LIMIT 10",
        (route, depart_date)
    ).fetchall()
    if len(rows) < 3:
        return False
    prices = [r[0] for r in rows]
    recent_avg = sum(prices) / len(prices)
    drop = (recent_avg - current) / recent_avg * 100
    return drop >= threshold_pct

Two things make alerts trustworthy:

  1. Require history. Do not alert until you have several readings, or the first low reading looks like a drop when it is just your baseline.
  2. Compare to a rolling average, not the single previous value. Prices jitter; you want the trend.

Wire the alert to email, Slack, or a webhook. Include the route, the date, the old average, the new price, and a direct booking link so the recipient can act before the fare moves again.

Scheduling and Rate Limits

Fares update often, but you do not need to poll every minute. A reasonable cadence:

Data Suggested interval
Active fare you are watching to book Every 1 to 3 hours
Broad route monitoring A few times per day
Hotel rates for a future trip Once or twice per day

Polling harder than this rarely catches drops you would otherwise miss, and it multiplies both your API credits and the load you put on the source. link.sc's free tier of 500 credits a month at link.sc/pricing is enough to watch a small set of routes at a sensible cadence.

The Honest Ethics and ToS Note

This is the part people skip, so read it. Collecting travel prices sits in a genuinely contested legal and ethical area.

  • Terms of service matter. Many airlines and OTAs explicitly forbid automated fare collection. If a site's terms prohibit it, do not do it, even if the page is technically reachable.
  • Do not evade protections. Solving CAPTCHAs, rotating identities to dodge bans, or bypassing bot detection to reach fares crosses from monitoring into circumvention. Stay out of that.
  • Public and unauthenticated only. If it needs a login or is behind a paywall, it is off limits without permission.
  • Be a good citizen. Reasonable intervals, honest user agents, respect for robots.txt.

For the broader framework, our guide to ethical web scraping and compliance covers how to evaluate a source before you monitor it. When in doubt, prefer the official API, or contact the provider about a data partnership. A slower, sanctioned data source beats a fast one that gets your account and IPs banned.

Putting It Together

A solid travel price monitor is mostly discipline: official API first, public pages only when terms allow, gentle scheduling, a stored history, and alerts that fire on real drops. The fetch layer is the least interesting part once you offload rendering and parsing to an API, which frees you to focus on the logic that actually decides when a fare is worth booking.


Want to prototype a travel price monitor without babysitting browsers and proxies? Start free on link.sc and fetch clean price data with one API call.