Flight Status
Live status of one flight, with delays, local times, progress, gates and baggage belt.
Experience · Shares patterns with Timeline, Map
≈ 1,953 tokens per use (tool 1,468 · guidance 258 · typical payload 227)How token costs are estimated
Example: Flight Status
Is my flight to Lisbon on time?
NW 217 · Northwind Air
London to Lisbon · Thu, Oct 8
Departs in 1 h 29 min
Flight time 2 h 35 min
Reason: Late inbound aircraft
- Departure terminal, London
- 2
- Departure gate, London
- B14
- Arrival terminal, Lisbon
- 1
- Seat
- 17F
- Class
- Economy
Updates, London time
- 12:21: Gate changed to B14
- 11:58: Departure delayed to 14:05
When to use
- The user asks about a flight's live status: is it on time, has it landed, where is it now, which gate or baggage belt.
- The agent has the status from a flight-data tool result.
When not to use
- The agent doesn't have live data from a tool result. Never guess states, gates or times.
- The user wants their booking details, seat or boarding pass. Use Flight Ticket.
- The user is comparing flights to book.
How the agent should use it
- Pass times with the airport's UTC offset and IANA timezone, exactly as the source gives them. Don't convert them.
- Pass scheduled, estimated and actual times as reported. The component works out the delay, the remaining time and the "On time" marks.
- List updates newest first, in the source's words.
- Only set
watchwhen you can actually notify the user. Onwatch, subscribe them and confirm in text. - For live tracking, re-render the same component with new props instead of calling the tool again.
What it shows
- Header: flight number and airline, one quiet line with the cities and date, and a state badge with its own icon and label: "Delayed", "Cancelled" (destructive), "Diverted to OPO". Nothing relies on color alone.
- Departure and arrival: the airport code, then the time in large type in each airport's zone. A changed time shows the schedule struck through next to the new one. Under each end, "On time", "Delayed 45 min" or "11 min early". Within 5 minutes counts as on time. A
+1marks an arrival on a later calendar day. - Progress bar: a dot at the origin, a ring at the destination, and a plane at the fill edge. Progress comes from
progresswhile in the air, or from elapsed time over the expected flight time; it's 0 before departure and 1 once landed. Under it, one relative line: "Departs in 1 h 29 min", "Arrives in 2 h 52 min", "Landed 12 min ago". - Details: terminals and gates at both ends, baggage belt, and altitude and ground speed while in the air.
- Footer: the update time and source, and the "Notify me of changes" action when
watchis set. - Screen readers only: the flight time,
delayReason, the user's seat and class, and the list of updates. The update times use the departure airport's zone before take-off and the arrival airport's after, as does the footer time.
Times and timezones
Every time shows in its airport's own timezone on a 24-hour clock. Screen readers hear the date, city and offset: "Departs, estimated Thursday, October 8, 14:05 London time (GMT+1), scheduled 13:20". Formatting uses Intl only; the helpers are in flight-status-utils.ts (effectiveTime, stateDelay, deriveProgress, relativeText, …).
Relative text is computed after mount and refreshed every 30 seconds, so server and client render the same markup. Pass now to measure from a fixed moment instead.
Live updates
Re-render with new props as the source changes. The plane glides to its new position (a transform, so it's skipped under reduced motion), and changes of state or a new latest update are announced in a polite live region, such as "NW 482: Landed". Nothing is announced on the first render.
Installation
npx shadcn@latest add https://your-site.com/r/flight-status.json
Usage
import { tool } from "ai"
import { flightStatusTool } from "@/components/genui/flight-status.schema"
const tools = {
[flightStatusTool.name]: tool({
description: flightStatusTool.description,
inputSchema: flightStatusTool.inputSchema,
// Without `watch` it's display-only, so the tool can return immediately.
execute: async () => ({ shown: true }),
}),
}Render it, refreshing the props from your flight-data feed:
import { FlightStatus } from "@/components/genui/flight-status"
function ToolPart({ part }) {
if (part.type !== "tool-track_flight") return null
const live = useLiveFlight(part.input) // your polling or push feed
return (
<FlightStatus
{...live}
status={part.state === "input-streaming" ? "streaming" : undefined}
result={savedWatch(part.toolCallId)}
onResult={(result) => {
// { action: "watch" }: subscribe the user, then tell the agent.
subscribeToFlight(part.input.flightNumber)
sendMessage({ text: `Flight status action: ${JSON.stringify(result)}` })
}}
/>
)
}With watch, the agent receives:
{ action: "watch" }With LangGraph
Push it from a graph node with ui.push({ name: "track_flight", props: { toolCallId, ...args } }, { message }), and push it again with fresh props as the status changes. Render the thread's UI messages with the Renderer.
Restoring from history
Pass the stored watch result back as result. The button is replaced by "We'll tell you about changes" and onResult is never called again.
<FlightStatus {...props} result={{ action: "watch" }} />Schema
| Prop | Type | Notes |
|---|---|---|
flightNumber | string | e.g. "NW 482". Data-bound |
airline | { name, code } | Data-bound |
from | { code, city, timeZone, terminal?, gate? } | IATA code, IANA timezone. Data-bound |
to | { code, city, timeZone, terminal?, gate?, baggageBelt? } | Data-bound |
state | "scheduled" | "boarding" | "departed" | "en-route" | "landed" | "arrived" | "delayed" | "cancelled" | "diverted" | As the source reports it. Data-bound |
times | { depart, arrive }, each { scheduled, estimated?, actual? } | ISO 8601, with the airport's offset or as local time. Data-bound |
progress | number? | 0–1 while in the air; derived from the times when absent. Data-bound |
position | { altitudeFt?, groundSpeedKt? }? | Shown while in the air. Data-bound |
delayReason | string? | Read to screen readers, not shown. Data-bound |
divertedTo | { code, city }? | Data-bound |
seat, class | string?, "economy" | "premium" | "business" | "first"? | The user's own booking, when known. Read to screen readers, not shown. Data-bound |
updates | { at, text }[]? | Up to 20, newest first. Read to screen readers; the newest is announced on change. Data-bound |
asOf | string | When the source last updated. Data-bound |
source | { label, url? } | url http(s) only. Data-bound |
watch | boolean? | Adds "Notify me of changes" |
Host props: status (streaming, ready, submitting, watching), now, onResult, result and className.