Skip to content

Repository files navigation

goflights

Go Reference

An unofficial Go client for Google Flights. No API key, no browser, no HTML scraping.

go get github.com/maxmwang/goflights

Features

  • Round-trip selection. Pin a chosen outbound with SelectOption and the next search returns the inbounds that pair with it, the way the site itself works.
  • Fares to the cent. Results are decoded from each itinerary's booking token — itself a protobuf message — so a fare arrives as 41100, exact, where the page itself only shows a rounded 411.
  • Filters map nearly one-to-one onto Google Flights. Stops, airlines, connecting airports, layover and duration bounds, departure and arrival times, travel class, bags, price range, emissions, and more — see Filters.
  • Per-segment detail. Flight number, aircraft type and cabin for every segment, enough to identify a flight rather than only price it.
  • No key, cookie, or browser. A plain GET with an ordinary User-Agent — no abuse-exemption token to refresh, no captcha step, no WebDriver.
  • Bring your own client. ExecuteWith takes an *http.Client and header overrides, so timeouts, proxies, retries, instrumentation and a custom User-Agent stay yours to control.
  • Parties of up to four. One to four passengers return a full result list; see Limitations for what happens beyond that.

Usage

req := goflights.NewRequest().
    Adults(1).
    Currency("USD").
    Flights(
        goflights.NewFlightInfo().
            DepartureDateStr("2026-09-01").
            From("SFO").
            To("JFK"),
    )

options, err := req.Execute(ctx)
if err != nil && !errors.Is(err, goflights.ErrPartialResults) {
    return err
}

for _, o := range options {
    s := o.Segments[0]
    fmt.Printf("%s %d  %s%s  %s -> %s\n",
        o.Currency, o.Price, s.Airline, s.FlightNumber, s.FromAirport, s.ToAirport)
}

Price is in the currency's minor units and must be scaled by DecimalDigits — 2 for USD, but 0 for JPY:

amount := float64(o.Price) / math.Pow10(o.DecimalDigits)

Request.URL() renders the same search as a URL without running it, which is also the page you can open in a browser.

Round trips

A round trip is two legs, and a search returns options for the first one only. Pinning a chosen itinerary makes the next search return options for the leg after it:

outbound := goflights.NewFlightInfo().DepartureDateStr("2026-09-01").From("SFO").To("JFK")
inbound := goflights.NewFlightInfo().DepartureDateStr("2026-09-08").From("JFK").To("SFO")
req := goflights.NewRequest().Adults(1).Flights(outbound, inbound)

departures, err := req.Execute(ctx)
// ...
outbound.SelectOption(departures[0])
returns, err := req.Execute(ctx)

Custom client and headers

ExecuteWith runs the same search against a client and headers you supply. Both are optional — nil falls back to the default:

client := &http.Client{Timeout: 20 * time.Second}
header := http.Header{"X-Request-Id": {"abc123"}}

options, err := req.ExecuteWith(ctx, client, header)

Filters

Per leg, on FlightInfo:

Method Effect
MaxStops(n) Caps connections. 0 is nonstop only.
Airlines(codes...) Restricts the leg to those IATA airline codes.
ConnectingAirports(codes...) Restricts layovers to those airports. Nonstops are not excluded.
MinLayover(d) / MaxLayover(d) Bounds a connection's length. Nonstops are not excluded.
MaxDuration(d) Caps the whole leg gate to gate, not a single segment.
EarliestDepartureHour(h) / LatestDepartureHour(h) Local hour, 023, inclusive.
EarliestArrivalHour(h) / LatestArrivalHour(h) Same, on arrival. A low latest arrival selects red-eyes.
LessEmissions() Keeps only itineraries Google marks as lower emission.

Per search, on Request:

Method Effect
Adults(n) / Children(n) / InfantsInSeat(n) / InfantsOnLap(n) Builds the party. Nine passengers is the maximum.
Passengers(p...) Sets the party directly, instead of the counters above.
Class(c) Cabin to search. Results may still mix cabins across segments.
MaxPrice(n) Whole currency units, in the currency the search runs in.
CarryOnBag(n) / CheckedBag(n) Keeps only fares including that many bags. Filters rather than adds, so prices rise.
ExcludeBasicEconomy() Drops basic economy fares.
HideSeparateAndSelfTransfer() Unverified — no route probed produced such an itinerary.
Currency(code) / Language(code) / Region(code) Omitted when unset, leaving Google to infer them.
TripType(t) Checks the leg count against the trip. Multi city is not supported.

How it works

Both directions are protobuf. The search travels as a protobuf message in the tfs query parameter of a plain GET, and every itinerary on the resulting page carries a booking token that is itself protobuf. Results are decoded from those tokens rather than scraped from the rendered HTML.

That is what makes exact values available. The page's own JSON rounds a fare to 411 and reports times as [23, 28] with the date in a separate field; the token holds 41100 — $411.00 — alongside 2026-09-01T23:28:00-07:00, so an overnight flight and a timezone change are both self-evident. Flight numbers appear only in the token.

The request and response schemas were reverse engineered and are documented field by field in internal/pb, including how each was verified.

Limitations

  • Multi city is not supported. Searches whose legs do not form a one way or a round trip come back empty. The trip type is not the cause — Google leaves those itineraries out of the page entirely.
  • Large parties return partial results. Google renders the full list only for parties of four or fewer with no infants. Beyond that it renders one itinerary and defers the rest, which Execute reports as ErrPartialResults alongside whatever it did get. The itineraries returned are real; there are simply more.
  • No booking. This searches; it does not book, hold, or price a reservation.

Stability

Nothing here is a supported API. Google can change the format at any time and this will break. The schemas were verified against live responses, but that is a snapshot, not a contract. Pin a version.

License

MIT

About

Unofficial Google Flights API for Go

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages