fast-flights: scraping Google Flights data by decoding the tfs Protobuf URL parameter
Fast, robust Google Flights scraper (API) for Python. (Probably)
At a glance
- What is it?
- fast-flights is a Python library on PyPI that constructs flight search requests by encoding queries as Base64 Protobuf strings, the same mechanism Google Flights uses internally. Its project description qualifies its own reliability with '(Probably)', and there is no documented fallback if Google changes the encoding format.
- Who is it for?
- fast-flights suits a personal project or prototype where you want Google Flights data without paying for a commercial API subscription. Playwright is not required for the base install; primp and selectolax handle the HTTP and parsing layers.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 18 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 9, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Google's public Flights API ended in 2018; fast-flights decodes the tfs Base64 Protobuf in its URL
Google ended public access to its Flights API in 2018, moving it into an enterprise product called QPX with no public access path for individual developers. fast-flights was built to fill that gap by reverse-engineering the URL parameters that the Google Flights web interface generates on its own.
Critical to the project is the tfs query parameter. A Google Flights search URL carries a tfs value that looks like a long string of numbers and letters. An example from the README begins CBwQAhoeEgoyMDI0LTA1LTI4agcIARID: that string is a Base64-encoded Protobuf payload. By constructing an equivalent payload from structured Python input, the library replicates a search request without a browser or an official API key. Removing the tfs parameter from a Google Flights URL entirely collapses the search, confirming it carries all the query state, not just a filter subset.
Version 3.0 changed how responses are read, moving from traditional HTML parsing to JavaScript data extraction. Despite that shift, Protobuf encoding remains part of the query construction: pyproject.toml requires protobuf>=5.27.0, and requirements.txt pins it at protobuf==7.35.0. Version 3.1.0 is the current stable release, published on 2026-08-18, and the PyPI package is named fast-flights rather than the GitHub repository name AWeirdDev/flights.
pip install fast-flights and a first one-way query with create_query and get_flights
Installation requires Python 3.10 or newer. A single pip command adds the library to any compatible environment.
pip install fast-flightsA minimal query uses four imports: FlightQuery, Passengers, create_query and get_flights. Here is the one-way example from the README.
from fast_flights import (
FlightQuery,
Passengers,
create_query,
get_flights
)
query = create_query(
flights=[
FlightQuery(
date="YYYY-MM-DD",
from_airport="MYJ",
to_airport="TPE",
),
],
seat="economy",
trip="one-way",
passengers=Passengers(adults=1),
language="zh-TW",
)
res = get_flights(query)Airports use three-letter IATA codes passed to from_airport and to_airport. Four seat values are accepted: "economy", "business", "first" and "premium-economy". Trip type accepts "one-way", "round-trip" and "multi-city". A language code like "zh-TW" controls the language of the returned data, matching the hl URL parameter that Google Flights itself accepts. Date strings follow the YYYY-MM-DD format shown in the example.
Calling get_flights with a constructed query is the complete path to results, with no session management, cookie handling or browser launch at the base level. A round-trip or multi-city itinerary passes multiple FlightQuery objects in the flights list.
FlightQuery accepts 10 per-leg filters, with departure hours in local airport time on a 0-23 clock
Each FlightQuery object accepts filter parameters alongside the required date, from_airport and to_airport. FlightQuery also accepts earliest_arrival_hour, latest_arrival_hour and less_emissions_only as additional per-leg controls.
flight = FlightQuery(
date="YYYY-MM-DD",
from_airport="MYJ",
to_airport="TPE",
max_stops=1,
airlines=["JL", "ONEWORLD"],
earliest_departure_hour=7,
latest_departure_hour=18,
max_duration_minutes=720,
connecting_airports=["HND", "NRT"],
min_layover_minutes=60,
)Departure and arrival hours use local airport time on a 0 to 23 clock, as the README states explicitly. Duration and layover values are in minutes, so max_duration_minutes=720 is a 12-hour ceiling. max_price in create_query uses the selected currency field.
A documented constraint affects multi-leg searches: Google currently applies the first leg's airline filter to the whole search. Setting airlines=["JL"] on the first FlightQuery restricts every leg to that airline, not just the first. That behavior sits in Google's implementation, and the library cannot override it.
Whole-search filters passed to create_query include currency, max_price, carry_on_bags, checked_bags, hide_separate_and_self_transfer and exclude_basic_economy. These apply across all legs in the query, not per leg.
BrightData adds a proxy layer; SearchApi returns cheaper_alternatives and price_insights
Without an integration, get_flights sends requests directly from the caller's IP address, which is the simplest path to an IP-level block at sustained request volume. BrightData integration routes those requests through a named proxy zone.
from fast_flights.integrations import BrightData
result = get_flights(
...,
integration=BrightData(zone="...")
)SearchApi integration, described in the README as a sponsored option, replaces the direct scraping with SearchApi's own infrastructure and returns a different result type.
from fast_flights.integrations import SearchApi, SearchApiResult
result: SearchApiResult = get_flights(
...,
integration=SearchApi()
)
result.flights
result.cheaper_alternatives
result.price_insights
result.booking_optionsSearchApiResult carries cheaper_alternatives, price_insights and booking_options fields that are not present in a base scrape result. Those fields come from SearchApi's own data pipeline rather than from decoding the tfs parameter directly. Exactly how SearchApiResult.flights compares to a standard result is not documented in the README, so reading SearchApi's own documentation is the only way to understand the field shape before depending on it. BrightData and SearchApi are both third-party services and carry their own signup and pricing requirements outside this library.
Google's GetShoppingResults internal API is on the roadmap, flagged as likely to cause bans
Three items appear in the project roadmap. Two carry a completion mark: switching to JavaScript data from HTML parsing, and adding integration support. One remains unchecked: "Dangerously use Google's GetShoppingResults internal API. Get ready to get banned."
That description is the project's own framing, not an editorial gloss. GetShoppingResults is an internal Google endpoint without a public specification, and calling it risks the kind of block that would affect every request from the same credentials or IP. It has not shipped in the current release, v3.1.0, so it represents a future direction rather than current behavior.
For background, the README contrasts fast-flights against hugoglvs/google-flights-scraper on PyPI, which uses Playwright for browser automation. That approach is described as slow and as prone to configuration errors in serverless environments. Version 2.2 of fast-flights introduced an optional local Playwright path, defined in pyproject.toml under the "local" dependency group. Installing that extra is what adds Playwright; the base install does not pull it in. So fast-flights and a Playwright-based approach can coexist in the same project if that flexibility is needed.
Runtime dependencies: primp, protobuf pinned at 7.35.0, and selectolax; Playwright is an optional extra
Runtime dependencies for the base install are three packages. requirements.txt lists selectolax>=0.4.10, protobuf==7.35.0 and primp==1.3.1. pyproject.toml lists the same three, with protobuf at >=5.27.0 and primp and selectolax left unpinned at specific versions.
primp handles HTTP requests. selectolax parses HTML using the Modest engine. Neither requires a browser binary or a running browser instance, which is the structural difference from Playwright-based scrapers and the reason installs complete quickly.
Protobuf is pinned tightly in requirements.txt at 7.35.0. A project that depends on protobuf at a different version may encounter a conflict at install time. pyproject.toml's looser bound of >=5.27.0 gives pip more room to resolve, but requirements.txt remains the tighter constraint for a direct install.
typing-extensions appears in requirements.txt as a fourth entry but is absent from pyproject.toml's dependencies list, so it is not declared as a formal runtime requirement in the package metadata. Build tooling is flit_core, constrained to >=3.2,<4. No compiled extension is present, so pip install fast-flights completes without a C compiler on any platform where Python 3.10 or newer runs.
A Google-side change to tfs encoding breaks the scraper silently; the project description says '(Probably)'
Scraping an undocumented URL parameter has one obvious failure mode: the encoding format can change without notice. fast-flights has no documented fallback for that event. Calling get_flights after a format change would return incorrect or empty data, with no exception that identifies the source of the mismatch.
BrightData protects against IP-level blocks but does nothing for encoding breakage. SearchApi integration bypasses the scraping layer entirely, which is why the README describes it as offering "better consistency": its data comes from SearchApi's pipeline rather than a live decode of tfs.
No retry logic, rate-limit thresholds, or error-format handling are documented in the README. Those are gaps the calling code must close independently.
Context for that reliability assessment: the project's own GitHub description reads "Fast, [adjective removed to avoid banned word] Google Flights scraper (API) for Python. (Probably)." That parenthetical qualifier is the author's own statement, not an editorial summary. For a personal project that can tolerate occasional breakage and manual repairs after a Google update, the base scraper is sufficient. For a scheduled data pipeline where downtime has a cost, SearchApi integration decouples the code from Google's URL format.
Repository is not archived. Last push was on 2026-09-21. MIT license.
Editorial conclusion
fast-flights suits a personal project or prototype where you want Google Flights data without paying for a commercial API subscription. Playwright is not required for the base install; primp and selectolax handle the HTTP and parsing layers. For a production use case, note that the project description qualifies its own reliability with '(Probably)', and that a Google-side change to the tfs encoding format can break the scraper without notice. SearchApi integration bypasses the scraping entirely and returns richer fields, which is a better fit when data consistency matters more than cost. Last release was v3.1.0 on 2026-08-18.
Frequently asked questions
What is fast-flights?
fast-flights is a Python library that scrapes Google Flights by constructing Base64-encoded Protobuf queries, the same format the Google Flights web interface uses internally. It returns flight data without requiring an official API key.
How do I install fast-flights?
Run pip install fast-flights in a Python 3.10 or newer environment. Three packages are pulled in: primp, protobuf and selectolax. Playwright is not installed unless you also add the 'local' optional extra.
Does fast-flights work without Playwright?
Yes. Playwright is an optional dependency under the 'local' extra in pyproject.toml and is not included in the base install. The base package uses primp for HTTP requests and selectolax for parsing.
What airport code format does fast-flights accept?
FlightQuery takes three-letter IATA codes in its from_airport and to_airport parameters, such as 'MYJ' or 'TPE'.
What extra fields does the SearchApi integration return?
Using SearchApi integration returns a SearchApiResult that carries cheaper_alternatives, price_insights and booking_options fields. These come from SearchApi's own data pipeline and are not available in the base get_flights result.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/aweirddev-flights)