Problemas con los datos abiertos del subte de Buenos Aires
Fecha: 5 de oct. de 2025
Resumen
La mayoría de los mapas digitales en Buenos Aires ofrecen indicaciones que pasan por estaciones de subte cerradas y no tienen cronogramas correctos. Estos datos erróneos son consistentes entre diferentes mapas, porque todos usan como fuente la "API Transporte" del gobierno de la ciudad, que tiene muchas deficiencias.
BA Data
El principal lugar para descargar datos públicos del GCBA es "BA Data". En la sección para transporte podemos encontrar tanto datos pensados para mapas como compilaciones de datos históricos sobre el uso del subte. Entiendo que estos últimos están bastante bien (no los miré mucho, pero he visto a otra gente usarlos); descontando "Subte: Cronograma de servicio", que dice que se actualizó el 20 de junio pero en realidad tiene datos de 2015.
Los datos que sirven para mapas digitales se publican siguiendo la especificación "GTFS", que es el estándar que usan gobiernos y empresas privadas para ofrecer datos sobre sus servicios de transporte. En nuestro caso se pueden obtener los datos en tiempo real desde la "API Transporte" (más sobre esto después). En BA Data lo que podemos descargar es una versión actualizada cada 6 meses en el item "Subte: GTFS". El tema es que, a pesar de que este último dice haberse actualizado el 30/6/2025, abrirlo revela que los archivos son de 2021.
Esto en principio no sería un problema si solo tuviera datos fijos y se comunicara que solo se actualizará en caso de que se modifique la estructura de la red, pero los datos están completos, por lo que incluyen frecuencias de los trenes y horarios de las líneas (que ya no son válidos). Tampoco se aclara en la página que se debería usar la API en vez de esta descarga, y hay recopilaciones de fuentes en GTFS que lo están usando. (ej: Transitland, que es usada por varias librerías y empresas como fuente de datos).
En esta página también se aclara "This feed contains an awkwardly nested zip file, so Transitland uses a custom script to fetch this feed", porque la descarga tiene esta estructura (debería tener solo un zip con los txt adentro):
📦 subte-gtfs-zip.zip
└ ? subte_gtfs (un zip sin extensión)
└ 📁 subte_gtfs_FILES
└ 📄 *.txt
Asumo que en parte se usa esta fuente en vez de la API porque esta requiere una "key" privada para usarse, que se consigue mandando una solicitud. Esto impide que lo usen aplicaciones de código abierto sin algún intermediario (porque la key es privada) y mapas globales hechos por grupos chicos (hay miles de fuentes GTFS globalmente, solo harían esta solicitud si tienen especial interés en CABA). Estimo que esto se hace para evitar abusos y no sobrecargar los servidores (la API incluye a los colectivos, que pesan ~209MB), pero no les costaría nada mantener BA Data actualizado o aclarar bien que no debe usarse; especialmente porque ya debe haber montones de servicios descargando regularmente los datos viejos de BA Data creyendo que son los actuales (Transitland lo hace a diario).
API Transporte
La API de transporte en su sección de subte tiene 3 feeds:
- /subtes/forecastGTFS
- /subtes/feed-gtfs
- /subtes/serviceAlerts
forecastGTFS
"forecastGTFS" es el que más me confunde. Es un archivo .json que contiene una lista de estaciones de líneas con llegadas y partidas estimadas de trenes. Según la descripción, debería ser una representación de los vehículos actualmente en tránsito. Sin embargo, no parece ser el caso, porque el 16 de febrero mostraba tiempos de llegada y partida para la estación Lima que eran iguales al del resto de las estaciones (lo cual veo difícil, considerando que estaba cerrada por obras).
{
"stop_id": "1072N",
"stop_name": "Sáenz Peña",
"arrival": { "time": 1739750203, "delay": 300 },
"departure": { "time": 1739750227, "delay": 324 }
},
{
"stop_id": "1073N",
"stop_name": "Lima",
"arrival": { "time": 1739750263, "delay": 360 },
"departure": { "time": 1739750287, "delay": 384 }
},
Lo más raro igual de este feed es que no parece corresponderse con nada de la especificación GTFS. La forma correcta de mostrar ubicación en tiempo real es con GTFS Realtime, cuyos formatos son distintos a lo que contiene esto. Además, se publica en formato .json, cuando las actualizaciones deberían ser un ProtocolBuffer. Aún si estuviera bien formateado, solo tendría sentido si mostrara las ubicaciones y tiempos reales de los trenes, ya que tiempos de llegada vagamente aproximados no son información muy útil para un servicio con una frecuencia de 5 minutos; especialmente porque Emova afirmó este año que "el subte no tiene horarios por formación, no es como en el tren". Lo único que se me ocurre es que esto extrapola tiempos a partir de la cantidad de trenes que se despacharon a la mañana, pero aún así no veo por qué lo publicarían de esta manera.
serviceAlerts
El serviceAlerts es un tipo del mencionado GTFS Realtime. En el subte se usa para reportar obras de renovación, exntensión de horarios, disrupciones por motivos externos, etc. Se puede encontrar un ejemplo bien formado en la página de la especificación. Comparándolo con el de la API, podemos notar que esta no provee información legible a máquina sobre las estaciones afectadas y los efectos y horarios de la disrupción, solo indicando la línea y un texto que a veces tiene errores de ortografía. Ejemplo de alerta del 29 de septiembre (omitiendo "description_text", que solo repite "header_text"):
"entity": [{
"id": "Alert_LineaB",
"is_deleted": false,
"trip_update": null,
"vehicle": null,
"alert": {
"active_period": [ ],
"informed_entity": [{
"agency_id": "",
"route_id": "LineaB",
"route_type": 0,
"trip": null,
"stop_id": ""
}],
"cause": 2,
"effect": 7,
"url": null,
"header_text": {
"translation": [
{ "text": "Estaciones Carlos Gardel y Uruguay cerradas por obras de renovación integral.",
"language": "es" }
]
}}}
Viendo la especificación para el formato, podemos leer que se está reportando que la línea tiene un problema con causa "other cause" y efecto "other effect" en la estación " " por el período [ ] (lo cual es igual para todos los problemas del año).
Esta deficiencia para mí es la más importante de la API*, ya que significa que las aplicaciones no pueden saber que una estación está cerrada, aún cuando alguien aparentemente se está tomando el trabajo de reportarlo. Esto causa que se recomienden viajes que no es posible hacer, y que tener todo esto en formato GTFS sea al cuete. Es decir, si la información solo tiene sentido al ser leída como texto por personas, entonces no hay mucha utilidad en ofrecerla en un formato que está pensado para ser leído por máquinas. Las veces que una aplicación sí sabe qué estaciones están en funcionamiento es porque puede mantener sus propias fuentes de información.
*En realidad las disrupciones largas programadas deberían estar en el GTFS estático y/o en una feed rt. del tipo "Trip Updates", pero por lo menos debería estar bien hecha en donde ya está.

Moovit el 29 de Sept. recomendando ir de Uruguay a Carlos Gardel, dos estaciones cerradas por obras.
La API también reporta extensiones temporales de horarios en el serviceAlerts, a pesar de que en principio debería ser usado solo para disrupciones. Esto igual es menor, ya que, al no tener un GTFS Realtime con actualizaciones de recorridos ni modificar el feed estático principal, este sería el único medio que le queda. Ejemplo el 11 de junio para la línea D:
"text": "Servicio extendido hasta la 1 am Más información en buenosaires.gob.ar/subte"
feed_gtfs
Lo primero que llama la atención del feed estático (el mismo de BA Data) es que la descarga tiene los archivos:
? feed-gtfs (un zip sin extensión)
└ 📁 google_transit
└ 📄 *.txt
Creo que a principio de año estaba bien formateado (era un "feed.zip" con los txt adentro), pero no puedo confirmarlo porque no me guardé uno sin descomprimir. Por qué lo habrán roto no sé, porque no cambió nada importante de la información en sí.
Están bastante bien las cosas más estáticas que describen a la red, como las rutas de las líneas, las ubicaciones de todas las entradas (aunque algunas están un poco desfasadas), cuáles son accesibles y cuáles tienen escaleras, etc. Sin embargo, la información sobre servicios tiene varios errores.
A principios de este año se extendió de forma semi-permanente el horario del subte B los viernes y sábados a la noche. Sin embargo, 10 meses después esto no figura en el feed estático, solo apareciendo como un texto en las alertas en el horario adecuado.


La app de Emova reportando F. Lacroze como cerrada y recomendando usar colectivos un sábado a las 00:27, aún cuando estaba en horario de funcionamiento.

La misma aplicación reportando en la sección de alertas que la línea está abierta.
Según las mejores prácticas, el schedule tendría que actualizarse para modificaciones que se hagan dentro de una semana o más. Esto es especialmente importante en el del subte, ya que no tiene actualizaciones en tiempo real decentes que le permitan hacer cambios a la base estática. Como este horario extendido se renueva mensualmente, no habría ningún motivo para que no esté (lo mismo se podría decir de las obras de renovación largas que se programan con meses de antelación, y tampoco están).
Otro problema es con las frecuencias. En frequencies.txt está marcado "exact_times", que indica que los trenes cumplen horarios exactos en vez de apegarse a frecuencias, lo cual es un problema por lo descrito en la sección de serviceAlerts.
Para mejorarlo también se podrían agregar varios datos para tener más información. Por ejemplo, en trips.txt se podría agregar el campo "bikes_allowed" para indicar que en la línea C y en ciertos horarios no se puede subir con bicis. También se podrían hacer más detallados los boletos, que ahora mismo solo tienen los precios base para SUBE registrada:
fare_id,price,currency_type,payment_method,transfers,agency_id,transfer_duration
4,1112,ARS,1,,3,
5,389.20,ARS,0,,3,
Conclusión
Intenté usar la API por primera vez hace unos 4 años, cuando un amigo y yo queríamos hacer un mapa que mostrara la ubicación de los trenes. Sin embargo, en su momento la página para obtener una key no funcionaba (el botón para subir el formulario tiraba un error). Estuvo en ese estado por meses, durante los cuales intenté contactarme con alguien que pudiera solucionar el problema, pero nunca recibía respuesta o la gente que me respondía no sabía a qué me refería. Eventualmente desistí, y me enteré que en algún momento lo habían arreglado cuando lo abrí por curiosidad a principios de este año. Después de obtener acceso a la API estuve un par de tardes intentando usarla, hasta que me dí cuenta que el estado en el que está no la hace muy útil.
Me puse a escribir esto un día que terminé bajo la lluvia mirando la entrada cerrada de Palermo. Al final lo dejé cuando ví que Emova publicó su aplicación de teléfono; por algún motivo creí que iba a causar que se arregle. Medio año después, la aplicación tiene varios de los errores del GTFS.
La realidad es que todo lo descrito es un problema bastante tonto que no figuró en ningún lado hasta ahora porque a no mucha gente le debe importar. Sin embargo, específicamente porque es algo sencillo es que no debería pasar. Muchos de los problemas "reales" que tiene el subte se solucionarían con inversiones de decenas de millones de dólares. Por contraste, arreglar esto sería trivial.
En mi caso, encontrarme con una estación cerrada es caminar un par de cuadras, pero para alguien con problemas de movilidad puede significar quedar completamente varado. Seguramente bastantes personas creyeron que el subte B estaba cerrado a las 00:30 al fijarse en Gmaps y terminaron tomándose un remís o colectivo. No debe ser menor el costo para mantener ascensores (aún si nunca andan) y extender el horario del subte, y aún así para estas personas fué totalmente en vano porque recibieron información equivocada. Obviamente la gente usó el subte por 100 años sin celular ni ningún drama, pero abrir la aplicación de Emova y que te recomiende entrar a una estación cerrada o tomarte un colectivo con el subte andando es el equivalente moderno de preguntarle si el tren anda a un guarda y que te diga cualquier cosa, o que haya carteles con horarios de hace 6 años en las estaciones.
Algo que llama la atención es que la misma aplicación parece tener otra fuente de datos, porque a veces tiene alguna cosa que no aparece en el feed público:

La app. de Emova reportando que una estación se cerraría al día siguiente, cuando el serviceAlerts de la línea A solo decía "Servicio finalizado".
Asumo que se le pagó una buena cantidad de plata a Ualabee para hacer la aplicación del subte y evidentemente tiene un mantenimiento, no veo por qué no se podría haberle pagado eso mismo para hacer una fuente de datos decente que reemplace a la actual.
Notas:
Mi experiencia es solo con el GTFS del subte, pero asumo que el resto del transporte público debe tener sus datos en un estado similar.
No se usaron modelos generativos en la escritura de este artículo.