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

Delayed 45 min
Departs, estimated Thursday, October 8, 14:05 London time (GMT+1), scheduled 13:20Delayed 45 min
Arrives, estimated Thursday, October 8, 16:40 Lisbon time (GMT+1), scheduled 15:55Delayed 45 min

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

  1. 12:21: Gate changed to B14
  2. 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 watch when you can actually notify the user. On watch, 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 +1 marks 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 progress while 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 watch is 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

app/api/chat/route.ts
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:

components/message.tsx
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

PropTypeNotes
flightNumberstringe.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
progressnumber?0–1 while in the air; derived from the times when absent. Data-bound
position{ altitudeFt?, groundSpeedKt? }?Shown while in the air. Data-bound
delayReasonstring?Read to screen readers, not shown. Data-bound
divertedTo{ code, city }?Data-bound
seat, classstring?, "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
asOfstringWhen the source last updated. Data-bound
source{ label, url? }url http(s) only. Data-bound
watchboolean?Adds "Notify me of changes"

Host props: status (streaming, ready, submitting, watching), now, onResult, result and className.

Source

On this page