Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build the tracker as a small data pipeline: save a precise watch definition, start a live flight search, poll its results, store every observation, evaluate a clear alert rule, and refresh the selected itinerary before sending a booking link. This design handles flexible dates, changing inventory, duplicate fares and provider rate limits without pretending that an observed price is guaranteed at checkout.

What the tracker must do

A useful tracker does more than request a fare once. For each watch, it should:

  • Record origin and destination airports, travel dates or a flexible-date rule, passengers, cabin, stop limit, preferred carriers, market, locale, currency and notification channel.
  • Use a provider’s documented live-search workflow. Skyscanner’s Flights Live Prices API uses a /create request followed by /poll; its quick-start request includes market, locale, currency, query legs and adults.
  • Keep a time-stamped history of normalized itineraries and the original provider response.
  • Distinguish indicative or cached values from live offers.
  • Apply an understandable rule such as “alert below $450” or “alert when this itinerary falls 15% from my baseline.”
  • Suppress duplicate messages, enforce a cooldown, and refresh the fare immediately before a user follows a booking link.

Airline inventory can disappear between a search and checkout. Every notification should therefore show the observation time, currency, baggage assumptions and a reminder to verify the final price with the airline or agency.

Choose the data workflow before writing code

Live search versus indicative prices

Skyscanner says live prices are retrieved from airline and inventory partners each time a search request is received. Its indicative prices can be cached for up to four days and may differ from live results. Use indicative data to power an exploratory calendar or discover promising date combinations; run a live search before creating an alert and refresh again before handoff.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
Data type Good use What the user must see
Indicative or cached Scanning many flexible dates cheaply Label it “indicative,” include the observation time, and never present it as bookable.
Live search result Threshold evaluation and an initial alert Show provider timestamp, currency, itinerary and fare conditions.
Refreshed itinerary Final click-through or booking handoff Tell the user to recheck the total at checkout because inventory may have changed.

Provider selection criteria

Compare providers on freshness, airport and carrier coverage, flexible-date and multi-city support, stop limits, create/poll or synchronous behavior, refresh semantics, authentication, rate limits, latency, retention and commercial handoff. A provider’s “offer” may have a different meaning from an indicative result: Duffel describes an offer as a flight that can be purchased from an airline at a particular price. Keep that distinction in your own schema.

Design a watch and an observation schema

Store the query exactly as submitted so a later refresh can reproduce it. A relational database works well for a personal or team tracker.

Table Required columns Purpose
watches id, origin, destination, legs, date_rule, adults, children, infants, cabin, max_stops, carriers, market, locale, currency, channel, threshold, cooldown_minutes, active The user’s intent and alert policy.
search_runs id, watch_id, provider, provider_session, requested_at, completed_at, status, raw_request, raw_response Audit trail for create/poll sessions and debugging.
observations id, watch_id, itinerary_key, observed_at, provider, currency, total_price, stops, carriers, departure_at, return_at, baggage_text, raw_payload Historical prices used for comparisons and charts.
alerts id, watch_id, itinerary_key, observation_id, sent_at, rule_version Deduplication and cooldown enforcement.

Use decimal arithmetic for money, never binary floating point. Include currency with every amount. An itinerary key should be stable across polls: derive it from marketing or operating carriers, flight numbers, airports, departure and arrival timestamps, cabin and fare family. Do not key only on price; the same fare can move up and down.

Implement a polling worker in Python

The following service skeleton uses SQLite, an environment-configured API host, and the documented /create then /poll pattern. Set the host, authentication header and provider-specific payload fields according to the provider account you use; the worker itself is complete and keeps raw responses for inspection.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import json, os, sqlite3, time, hashlib
from datetime import datetime, timezone
from decimal import Decimal
import requests

API_BASE = os.environ["FLIGHT_API_BASE"].rstrip("/")
API_KEY = os.environ["FLIGHT_API_KEY"]
POLL_SECONDS = (2, 4, 8, 16, 30)
DB = os.getenv("FLIGHT_DB", "flights.sqlite3")


def utc_now():
    return datetime.now(timezone.utc).isoformat()


def db():
    c = sqlite3.connect(DB)
    c.row_factory = sqlite3.Row
    c.executescript("""
    create table if not exists watches (
      id integer primary key, origin text not null, destination text not null,
      departure text not null, return_date text, adults integer not null,
      market text not null, locale text not null, currency text not null,
      cabin text, max_stops integer, threshold numeric, cooldown_minutes integer default 1440,
      last_alert_at text, active integer default 1
    );
    create table if not exists observations (
      id integer primary key, watch_id integer, itinerary_key text, observed_at text,
      provider text, currency text, total_price numeric, raw_payload text
    );
    create table if not exists alerts (
      id integer primary key, watch_id integer, itinerary_key text,
      observation_id integer, sent_at text, unique(watch_id, itinerary_key, observation_id)
    );
    """)
    return c


def itinerary_key(item):
    # Adjust field paths to the provider's normalized itinerary response.
    stable = {
      "carrier": item.get("carrier"), "number": item.get("flight_number"),
      "from": item.get("origin"), "to": item.get("destination"),
      "depart": item.get("departure"), "arrive": item.get("arrival"),
      "cabin": item.get("cabin")
    }
    return hashlib.sha256(json.dumps(stable, sort_keys=True).encode()).hexdigest()


def create_session(w):
    payload = {
      "market": w["market"], "locale": w["locale"], "currency": w["currency"],
      "query_legs": [{"origin": w["origin"], "destination": w["destination"],
                      "date": w["departure"]}],
      "adults": w["adults"]
    }
    if w["return_date"]:
        payload["query_legs"].append({"origin": w["destination"],
          "destination": w["origin"], "date": w["return_date"]})
    headers = {"x-api-key": API_KEY, "content-type": "application/json"}
    r = requests.post(API_BASE + "/create", json=payload, headers=headers, timeout=30)
    r.raise_for_status()
    return r.json()


def poll_session(session_id):
    headers = {"x-api-key": API_KEY}
    for delay in POLL_SECONDS:
        r = requests.get(API_BASE + "/poll", params={"session_id": session_id},
                         headers=headers, timeout=30)
        if r.status_code == 202:
            time.sleep(delay); continue
        r.raise_for_status()
        data = r.json()
        if data.get("status") in ("complete", "completed") or data.get("itineraries"):
            return data
        time.sleep(delay)
    raise TimeoutError("provider did not complete the live search")


def save_and_alert(c, w, result):
    now = utc_now()
    for item in result.get("itineraries", []):
        key = itinerary_key(item)
        price = Decimal(str(item["price"]))
        cur = item.get("currency", w["currency"])
        cur_id = c.execute("insert into observations(watch_id,itinerary_key,observed_at,provider,currency,total_price,raw_payload) values(?,?,?,?,?,?,?)",
          (w["id"], key, now, "live-provider", cur, str(price), json.dumps(item))).lastrowid
        under_limit = w["threshold"] is not None and price <= Decimal(str(w["threshold"]))
        last = w["last_alert_at"]
        cooldown_ok = True
        if last:
            age = (datetime.fromisoformat(now) - datetime.fromisoformat(last)).total_seconds()/60
            cooldown_ok = age >= (w["cooldown_minutes"] or 1440)
        already = c.execute("select 1 from alerts where watch_id=? and itinerary_key=? and observation_id=?",
                            (w["id"], key, cur_id)).fetchone()
        if under_limit and cooldown_ok and not already:
            send_notification(w, item, price, cur, now)
            c.execute("insert into alerts(watch_id,itinerary_key,observation_id,sent_at) values(?,?,?,?)",
                      (w["id"], key, cur_id, now))
            c.execute("update watches set last_alert_at=? where id=?", (now, w["id"]))
    c.commit()


def send_notification(w, item, price, currency, observed_at):
    # Replace with email, push, SMS or webhook delivery.
    print(f"ALERT {w['origin']}-{w['destination']}: {price} {currency} at {observed_at}; {item}")


def run_watch(w):
    c = db()
    try:
        session = create_session(w)
        result = poll_session(session["session_id"])
        save_and_alert(c, w, result)
    finally:
        c.close()

if __name__ == "__main__":
    c = db()
    watches = c.execute("select * from watches where active=1").fetchall()
    c.close()
    for watch in watches:
        try: run_watch(watch)
        except Exception as exc: print(f"watch {watch['id']} failed: {exc}")

Run the worker from a scheduler such as cron, a systemd timer or a queue. Keep concurrency below the provider’s documented limit, and add jitter so all watches do not start at the same second. The example uses exponential backoff for incomplete polls; production code should also retry transient 429 and 5xx responses with a maximum attempt count, while failing fast on authentication and validation errors.

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.

Support flexible dates without misleading alerts

Represent flexibility as data rather than generating an untraceable set of searches. Examples include “any departure within ±3 days,” “weekends in October,” or “stay 7–10 nights.” Expand the rule into individual date pairs, attach the parent watch ID to every query, and record the exact dates returned. For a large calendar, start with indicative searches, rank the cheapest combinations, then run live searches only for the best candidates. An alert must name the actual departure and return dates; “from $X” is not actionable.

For multi-city trips, store an ordered list of legs instead of assuming a round trip. For one-way trips, omit the return leg. Validate that passenger counts, infant rules, cabin and carrier filters match the provider’s accepted values before creating a session.

Make alerts useful and quiet

Threshold rules

  • Absolute ceiling: notify when the total is at or below a currency-specific amount.
  • Percentage drop: compare with a baseline for the same itinerary, not the cheapest fare ever seen on another date.
  • New-route minimum: notify the first time a route appears below a limit, then suppress repeats.
  • Quiet-period change: alert only when a fare changes materially after a configured number of hours.

Deduplication and message contents

Use an itinerary signature plus a cooldown. Include origin, destination, exact dates, carrier, flight numbers when available, stops, total price, currency, baggage assumptions, observed time, expiration caveat and a deep link. Store the provider query and timestamp beside the link so support staff can reproduce the result.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Refresh before the booking handoff

Do not send a month-old result directly to a booking page. When a user clicks an alert, create a refresh-prices session for the selected itinerary, wait for completion, and display the refreshed total. If the itinerary disappears or the price changes, show both values and ask the user to choose another result. The final page should direct the user to verify taxes, baggage, seat fees, change rules and the amount charged by the airline or agency.

Run it reliably on a small host

A Raspberry Pi 5 is a practical Linux host for a hobby, home or small-office tracker. Raspberry Pi lists dual-band Wi-Fi, Gigabit Ethernet, USB-C power and an RTC connector, with production planned until at least January 2036. Use reliable storage, cooling and a backup-power plan as engineering safeguards. Keep API keys in environment variables or a secrets manager, restrict database permissions, back up the SQLite file, and rotate logs so raw responses do not fill the disk.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

Provider controls, cost and retention

  • Send market, locale and currency on every request; these fields affect both availability and displayed totals.
  • Respect documented quotas and usage guidelines. A scheduler that scans every possible date every minute can exhaust a quota without improving the user’s decision.
  • Cache your own normalized history, but never relabel an old observation as live.
  • Retain raw payloads long enough to debug parsing and alert disputes, then apply a deletion policy for personal data.
  • Track request count, latency, poll duration, 429 responses, empty-result rate and alert delivery failures.

There is no reliable universal savings percentage to promise. Airfare varies by market, date, inventory and currency, so measure your own alert-to-click and click-to-available rates instead.

Troubleshooting common failures

401 or 403 responses

Check that the key is present in the expected header, belongs to the correct environment and is allowed to call live search. Do not retry indefinitely; fix credentials first.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

400 validation errors

Log the sanitized request and validate IATA or provider entity IDs, ISO-style dates, passenger counts, market, locale and currency before calling /create. Flexible-date expansion often produces an invalid return date or unsupported cabin value.

429 rate limits

Reduce concurrent sessions, add exponential backoff with jitter, and schedule watches across the interval. A cache of recent indicative results can reduce exploratory calls, but a live refresh is still required before an alert handoff.

Poll timeout

Keep the provider session ID and poll response. Increase the maximum wait only within the provider’s documented session lifetime; otherwise mark the run incomplete and retry later rather than sending a false “no deals” message.

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft

Prices differ at checkout

Show whether the value was indicative or live, refresh immediately before handoff, and preserve currency, baggage and timestamp. Inventory changes are expected; do not overwrite history with the new value.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Duplicate alerts

Verify that your itinerary key excludes volatile fields such as price, enforce a cooldown, and put a unique constraint on the watch, itinerary and observation identifiers.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If you need screenshots of a fare dashboard, report or internal page rather than building browser automation, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets before capture; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP tools—take_screenshot, get_page_info and capture_pdf—work with Claude, Cursor and other MCP clients.

One GET request is enough (see the ScreenshotNeo API documentation):

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/flight-dashboard -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com/flight-dashboard"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com/flight-dashboard' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo includes full-page capture with lazy-image loading, CSS-selector element capture, dark mode, device presets, custom viewport and retina scale, PDF controls, custom CSS and JavaScript, click and wait actions, selector hiding, network and resource blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed image links, asynchronous webhooks, bulk capture for up to 100 URLs per call, a usage API and an OpenAPI specification. Familiar parameter names from other screenshot APIs are accepted to ease migration. The Free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 screenshots, and every feature is on every plan. Create a free ScreenshotNeo account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Google Flights and a custom tracker

Google Flights can track a route, specific dates or a specific flight and email users when prices change significantly; it can also warn that prices are likely to rise or a fare is expiring. Build your own system when you need provider choice, custom thresholds, push or webhook channels, complete price history, flexible-date scanning, team or family watches, or user-controlled storage. A custom tracker is not automatically more accurate; its value is control and an auditable history.

Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

Frequently Asked Questions

How often should a flight tracker search?

Choose an interval based on the route’s volatility, your provider quota and how quickly a user could act. Spread jobs with jitter, then perform a live refresh only when an alert is about to be delivered or opened.

Should I store airline prices in one currency?

Store the provider currency and amount exactly as returned. You may display a converted estimate, but label the conversion and retain the original value for comparison and checkout verification.

Can the tracker book the ticket automatically?

Only if your provider and commercial agreements explicitly support booking and you implement payment, passenger-data, fraud and cancellation requirements. The design here stops at an informed, refreshed handoff.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What should happen when no itinerary is returned?

Record a completed search with zero results, keep the request parameters, and avoid interpreting it as a price increase. Retry later according to provider guidance and tell the user that availability was not found for that query.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.