I built FlyLog (https://fly-log.netlify.app), a free app that logs every flight you take. It draws your routes on a world map, adds up your distance, and replays your trips on a globe.

The maps were the fun part. Getting flights into the app was the hard part.

FlyLog's world map showing flight routes from Sydney to Europe and Asia

The problem: your flights are stuck in your inbox

Most people don't remember their flight numbers or dates. The details sit in a confirmation email from the airline or a travel agent. To log a flight, you open the email, find the airport codes, the date, the airline and the flight number, and type each one into a form. A return trip with a connection means doing that four times.

Most people give up after a few flights, and then the map and the stats show nothing worth looking at.

The fix: let an AI read it

The Describe tab: a trip typed in plain words, turned into two flights ready to save

So I added a "Describe" tab. You paste the text from your booking email, or type the trip in your own words, like "Sydney to London via Singapore on Qantas, 3 March, back on the 20th". FlyLog fills in every flight, and you check them before saving.

Behind it, Gemini 2.5 Flash Lite reads the text through Firebase AI Logic. A JSON schema makes it return the same fields every time: airports, dates, times, airline, flight number and cabin. The prompt splits connections into separate flights, writes out the return leg, and never invents a flight number or a time that isn't in the text.

The new problem: anyone could use my quota

Every call to Gemini costs money, and the call comes from the browser. Anyone can open the network tab, copy the request and run it in a loop, or use my key in their own app. The same goes for the live flight status feature, which calls AeroDataBox through a Netlify function.

Proving the request comes from my site

Firebase App Check makes the browser prove it is running FlyLog before it can call either service. It gets that proof from reCAPTCHA Enterprise, which only works on the domains I allow. With App Check enforcement turned on for Firebase AI Logic, Firebase rejects any Gemini call without a valid token.

For the Netlify function I check the token myself. App Check tokens are signed JWTs, so the function only needs Firebase's public keys and the jose library rather than firebase-admin and a service-account secret:

const jwks = createRemoteJWKSet( new URL("https://firebaseappcheck.googleapis.com/v1/jwks"), ); await jwtVerify(token, jwks, { algorithms: ["RS256"], issuer: `https://firebaseappcheck.googleapis.com/${projectNumber}`, audience: [`projects/${projectNumber}`, `projects/${projectId}`], }); 

One catch: deploy previews

reCAPTCHA has no wildcards. Each Netlify deploy preview gets its own address, like deploy-preview-83--fly-log.netlify.app, so previews get no token and the AI tab fails there. Allowing all of netlify.app would let any Netlify site use my key. So when a pull request needs the real APIs, I add that one preview address, and the PR gets a checkbox reminding me to remove it when it closes.

Try it

FlyLog is free, works in English and Italian, and the code is on GitHub: https://github.com/FedericoTartarini/fly-log

Paste your next booking email into it, and tell me if it gets a flight wrong. FlyLog doesn't store the text you paste. It only saves the flights you confirm.