A lightweight Java SDK for interacting with the Chicago Transit Authority (CTA) APIs — both Train Tracker and Bus Tracker.
Built for simplicity, reliability, and minimal external dependencies.
cta4j-java-sdk provides a clean, type-safe interface for accessing CTA's public transit data.
It wraps the official Train and Bus Tracker APIs with intuitive Java models and error handling.
Features:
- Simple, dependency-light HTTP client (uses Apache HttpClient 5)
- DTOs modeled as Java records
- Works with both Train Tracker and Bus Tracker APIs
You'll need a free API key from CTA to use the SDK.
- Train Tracker API → Apply here
- Bus Tracker API → Apply here
After applying, you'll receive an API key by email. Keep it safe — you'll use it when initializing the client.
<dependency>
<groupId>com.cta4j</groupId>
<artifactId>cta4j-java-sdk</artifactId>
<version>3.0.4</version>
</dependency>implementation("com.cta4j:cta4j-java-sdk:3.0.4")import com.cta4j.train.client.TrainClient;
public final class Application {
public static void main(String[] args) {
TrainClient trainClient = TrainClient.builder()
.apiKey("TRAIN_API_KEY")
.build();
trainClient.getStationArrivals("41320")
.stream()
.map(arrival -> String.format(
"%s-bound %s Line train is arriving at %s in %d minutes",
arrival.destinationName(),
arrival.route(),
arrival.stationName(),
arrival.etaMinutes()
))
.forEach(System.out::println);
// Example output:
// Howard-bound RED Line train is arriving at Belmont in 1 minutes
// 95th/Dan Ryan-bound RED Line train is arriving at Belmont in 2 minutes
// Kimball-bound BROWN Line train is arriving at Belmont in 4 minutes
// Loop-bound BROWN Line train is arriving at Belmont in 5 minutes
}
}import com.cta4j.bus.client.BusClient;
public final class Application {
public static void main(String[] args) {
BusClient busClient = BusClient.builder()
.apiKey("BUS_API_KEY")
.build();
busClient.getStopArrivals("22", "1828")
.stream()
.map(arrival -> String.format(
"%s-bound bus is arriving at %s in %d minutes",
arrival.destination(),
arrival.stopName(),
arrival.etaMinutes()
))
.forEach(System.out::println);
// Example output:
// Harrison-bound bus is arriving at Clark & Belmont in 1 minutes
// Harrison-bound bus is arriving at Clark & Belmont in 26 minutes
}
}- Dependency-light: no Spring, Feign, or Lombok
- Modern Java: uses records and Apache HttpClient 5
- Framework-agnostic: works in any Java 21+ project
- Add test coverage
- Improve error handling and logging
- Add support for more API endpoints, like service alerts
- Implement caching for frequently requested data
- Add asynchronous request support
Have ideas? Feel free to open an issue or submit a PR!
This project is licensed under the Apache License 2.0.
Copyright © 2025 Logan Bailey Kulinski.
Built with ❤️ by Logan Kulinski