gflights
Unofficial async Rust client for the Google Flights web API.
Search flights, compare prices across a date range, retrieve booking offers, and resolve booking URLs — all without an official API key.
Disclaimer: This library talks to the same endpoints used by the Google Flights website. It is not affiliated with or endorsed by Google. Usage is subject to Google's Terms of Service.
Features
- Flight search — one-way, return, multi-stop itineraries
- Price graph — cheapest fares across a configurable date range
- Date grid — full departure × return price matrix for round trips
- Booking offers — airline/OTA offers with prices and booking URLs
- City / airport lookup — resolve city names and IATA codes
- Multi-airport search — up to 4 departure or destination airports
- Airline / alliance filters — include or exclude specific airlines or alliances (oneworld, SkyTeam, Star Alliance)
- Connection filters — require layover through specific airports; set min/max layover duration
- Lower-emissions filter — restrict to flights with below-average CO₂
- Locale support —
language+countryfor non-English results - Sort order — Best · Price · Duration · Departure time · Arrival time
- CO2 / emissions — included in parsed itinerary data
- Layover details — connection time, airport codes, overnight warnings
- Rate limiting — built-in governor-based token-bucket limiter
- Retry logic — exponential back-off for transient 5xx / timeout errors
- CLI — interactive REPL and one-shot subcommands (
search,graph,dgrid,offer)
Installation
[]
= "0.1.0"
= { = "1", = ["full"] }
CLI
The crate ships a gflights binary. Install it with:
One-shot mode
# Search flights
# Round trip with filters
# Price graph (cheapest fare per day over 3 months)
# Departure × return price grid
# Booking offers with clickable URLs (OSC 8, supported in most modern terminals)
Interactive REPL
Run gflights with no arguments to enter an interactive session with history:
gflights> search --from LHR --to JFK --date 2026-08-01
gflights> graph --from MXP --to SYD --date 2026-09-01 --months 2
gflights> dgrid --from LHR --to JFK --dep-start 2026-08-01 --dep-end 2026-08-07 --ret-start 2026-08-15 --ret-end 2026-08-22
gflights> quit
search flag reference
| Flag | Default | Description |
|---|---|---|
--from <CODE> |
required | Departure airport IATA code or city name |
--to <CODE> |
required | Destination airport IATA code or city name |
--date <YYYY-MM-DD> |
required | Outbound departure date |
--return <YYYY-MM-DD> |
one-way | Return date |
--adults <N> |
1 |
Number of adult passengers |
--class <CLASS> |
economy |
economy · premium-economy · business · first |
--stops <STOPS> |
all |
all · non-stop · one-stop |
--sort <SORT> |
best |
best · price · duration · departure-time · arrival-time ¹ |
--airline <CODE> |
— | Include airline IATA code or alliance (ONEWORLD, SKYTEAM, STAR_ALLIANCE). Repeatable. |
--exclude-airline <CODE> |
— | Exclude airline or alliance. Repeatable. |
--via <IATA> |
— | Require connection through this airport. Repeatable. |
--min-layover <MINS> |
none | Minimum layover in minutes (rounded up to 30 min intervals) |
--max-layover <MINS> |
none | Maximum layover in minutes |
--lower-emissions |
off | Restrict to below-average CO₂ flights |
--currency <CURRENCY> |
euro |
Result currency (e.g. us-dollar, british-pound) |
--lang <CODE> |
en |
BCP-47 language subtag |
--country <CODE> |
GB |
ISO 3166-1 alpha-2 country code |
--format <FORMAT> |
table |
table · json |
¹ departure-time and arrival-time are sorted client-side after Google returns results.
dgrid flag reference
| Flag | Default | Description |
|---|---|---|
--from <CODE> |
required | Departure airport IATA code or city name |
--to <CODE> |
required | Destination airport IATA code or city name |
--dep-start <DATE> |
required | First outbound departure date |
--dep-end <DATE> |
required | Last outbound departure date |
--ret-start <DATE> |
required | First return date |
--ret-end <DATE> |
required | Last return date |
--adults <N> |
1 |
Number of adult passengers |
--class <CLASS> |
economy |
Travel class |
--stops <STOPS> |
all |
Stop filter |
--currency <CURRENCY> |
euro |
Result currency |
--format <FORMAT> |
table |
table · json |
Quick start
Search for flights
use ;
use ;
async
Run the full worked example:
Price graph across a date range
use ;
use ;
async
Run with:
Configuration reference
| Builder method | Type | Default | Description |
|---|---|---|---|
.departure(iata, &client) |
async &str |
required | Departure airport / city |
.destination(iata, &client) |
async &str |
required | Destination airport / city |
.departure_location(loc) |
Location |
— | Set departure from existing Location (no network) |
.destination_location(loc) |
Location |
— | Set destination from existing Location |
.add_departure(iata, &client) |
async &str |
— | Add extra departure (max 4) |
.add_destination(iata, &client) |
async &str |
— | Add extra destination (max 4) |
.departing_date(date) |
NaiveDate |
required | Outbound departure date |
.return_date(date) |
NaiveDate |
one-way | Return date (omit for one-way) |
.travelers(t) |
Travelers |
1 adult | Passenger counts |
.travel_class(c) |
TravelClass |
Economy | Economy / Business / First |
.stop_options(s) |
StopOptions |
Any | Non-stop · Max1 · Any |
.sort_order(s) |
SortOrder |
Best | Best · Price · Duration · DepartureTime · ArrivalTime |
.currency(c) |
Currency |
EUR | Result currency |
.language(s) |
&str |
"en" |
BCP-47 language subtag |
.country(s) |
&str |
"GB" |
ISO 3166-1 alpha-2 country code |
.stopover_min(d) |
StopoverDuration |
Unlimited | Minimum layover duration |
.stopover_max(d) |
StopoverDuration |
Unlimited | Maximum layover duration |
.duration_max(d) |
TotalDuration |
Unlimited | Maximum total trip duration |
.departing_times(t) |
FlightTimes |
Any | Outbound departure time window |
.return_times(t) |
FlightTimes |
Any | Return departure time window |
.airlines_include(v) |
Vec<AirlineFilter> |
none | Restrict to these airlines / alliances |
.add_airline_include(f) |
AirlineFilter |
— | Add one airline / alliance to include filter |
.airlines_exclude(v) |
Vec<AirlineFilter> |
none | Exclude these airlines / alliances |
.add_airline_exclude(f) |
AirlineFilter |
— | Add one airline / alliance to exclude filter |
.connecting_airports(v) |
Vec<String> |
none | Require connection through these IATA airport codes |
.add_connecting_airport(s) |
&str |
— | Add one connecting airport |
.lower_emissions(b) |
bool |
false |
Restrict to below-average CO₂ flights |
Travelers
use Travelers;
// [adults, children, infants_in_seat, infants_on_lap]
let travelers = new?; // 2 adults + 1 child
Rules: at least 1 adult, total ≤ 9 passengers.
Airline & connection filters
use ;
let config = builder
.departure.await?
.destination.await?
.departing_date
// Only show British Airways and oneworld alliance members
.add_airline_include
.add_airline_include
// Must connect through Dublin
.add_connecting_airport
// At least 45 min layover, at most 3 hours
.stopover_min
.stopover_max
// Lower CO₂ only
.lower_emissions
.build?;
Rate limiting
ApiClient uses a governor token-bucket rate limiter (default: 10 req/s).
use ApiClient;
use Quota;
use NonZeroU32;
// Custom: 2 requests per second
let quota = per_second;
let client = new_with_ratelimit.await;
If Google returns HTTP 429, the client sets an internal flag and all subsequent requests immediately return RateLimitedError without touching the network. Reset it after a cooling-off period:
if client.is_rate_limited
Retry logic
Transient server errors (HTTP 500/502/503/504) and connection timeouts are automatically retried with exponential back-off. Defaults: 3 attempts, 500 ms base delay, 30 s cap.
use ;
let client = new.await
.with_retry_config;
Set max_attempts: 1 to disable retries entirely.
Error handling
All public async methods return anyhow::Result<T>. Downcast RateLimitedError to check for 429:
use RateLimitedError;
match client.request_flights.await
Known limitations
x-goog-batchexecute-bgr header — computed deep in Google's obfuscated JS from the current time and request payload length — is omitted. Responses are still valid but may occasionally be less accurate (e.g. missing low-fare calendar data). Contributions to reverse-engineer the algorithm are welcome.
Development
# Build
# Unit tests (no network)
# Binary (CLI) tests
# Doc tests
# Live integration tests (requires internet, skipped in CI)
RUN_LIVE_TESTS=1
# Docs
# Lint
# Format
# Security audit