Get started
Build TfL interfaces using installable React components and normalised tfl-ts data.
Try a display
localhost:3000
1. Get a free TfL key from the TfL API portal
# .env.local or .env.development.local
TFL_APP_KEY=your-primary-or-secondary-keyOptional. Paste a key here if you want Explorer or live examples in these docs. Your browser calls TfL with it. It stays in this browser and is never sent to our server.
2. Set up a typeface (optional)
Components inherit your app's font. Johnston needs a licence from TfL (see Licensing and brand use). This site uses P22 Underground. Hammersmith One is the free alternative. See Typography.
3. Install and render
Start from a React app with shadcn already initialised. The command copies the board source into your repo and installs tfl-ts. Use the React tab in Vite. Use a Next.js tab if you want the key to stay on the server.
pnpm dlx shadcn@latest add https://tfl.manglekuo.com/r/rail-arrivals-board.json(Quick and easy) Calls TfL from the browser, AKA client side. Anyone can right click dev tools and see your TfL key.
import { useEffect, useState } from "react"
import TflClient, { type RealtimePrediction } from "tfl-ts"
import { RailArrivalsBoard } from "@/components/tfl/arrivals/rail-arrivals-board"
const tfl = new TflClient({ appKey: import.meta.env.VITE_TFL_APP_KEY })
export default function Page() {
const [data, setData] = useState<RealtimePrediction[]>([])
useEffect(() => {
let cancelled = false
const load = async () => {
const arrivals = await tfl.stopPoint.getArrivals({
stopPointIds: ["940GZZLUOXC"],
sortBy: "timeToStation",
})
if (!cancelled) setData(arrivals)
}
void load()
const id = setInterval(load, 20_000)
return () => {
cancelled = true
clearInterval(id)
}
}, [])
return <RailArrivalsBoard data={data} stopName="Oxford Circus" />
}Still having trouble? See Troubleshoot.