Geonode logo
Geonode Team

Geonode Team

Actualizado: 7 de octubre de 2026

Publicado: 2 de septiembre de 2026

Curl para principiantes: una guía completa

curl recupera una URL y muestra el resultado. Todo lo demás son opciones, y hay más de doscientas. Necesitas unas ocho para ser productivo. Esta guía aborda esas ocho, el modelo mental que hace que el resto resulte comprensible y los pocos errores en los que todo el mundo cae al principio. Al final, serás capaz de enviar solicitudes, leer respuestas, depurar lo que realmente se ha transmitido por la red y saber qué página del manual consultar a continuación.

Una breve nota sobre quién escribe esto. Somos Geonode y vendemos proxies, por lo que «curl» es la herramienta que solemos recomendar a la gente para diagnosticar problemas. La verdad para un principiante: «curl» no es una herramienta de proxy y no necesitas un proxy para aprender a usarla. Todo lo que viene a continuación funciona con puntos finales públicos desde tu propia conexión, de forma gratuita. Los proxies cobran relevancia mucho más adelante, cuando realizas tantas solicitudes que el servidor de destino empieza a limitarte el ancho de banda, o cuando necesitas ver cómo se ve una página desde otro país. Ninguna de estas situaciones es un problema para un principiante. Primero, aprende a usar la herramienta.

Qué es curl y para qué sirve

curl es un programa de línea de comandos para transferir datos mediante URL. Su propio manual lo describe como compatible con «DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS y WSS», aunque en la práctica casi todo el mundo lo utiliza para HTTP y HTTPS.

Para qué sirve:

  • Llamar a una API desde un terminal o un script
  • Comprobar si una URL funciona y qué devuelve
  • Ver exactamente lo que devuelve un servidor, encabezados incluidos
  • Descargar archivos
  • Depuración: reproducir una solicitud fuera de tu aplicación para averiguar si el problema está en tu código o en el servidor

Lo que no es: un navegador. No ejecuta JavaScript, no muestra nada y no mantiene una sesión a menos que se le indique que lo haga. Una página que parece completa en un navegador puede devolver un esqueleto casi vacío a curl, y eso es lo esperado, no un error.

Tus primeras solicitudes

curl https://example.com

Esto realiza una solicitud GET y muestra el cuerpo de la respuesta en tu terminal. Si la salida es un texto extenso en formato HTML, significa que curl funciona correctamente.

Cuatro variantes que te resultarán útiles de inmediato:

Ver tanto los encabezados como el cuerpo con -i

, documentado en -i, --show-headers

: «Mostrar los encabezados de la respuesta en la salida».

curl -i https://example.com

Guarda en un archivo con -o

(el nombre que elijas) o -O

(el nombre remoto):

curl -o page.html https://example.com
curl -O https://example.com/file.zip

Sigue las redirecciones con -L

: «Sigue las redirecciones HTTP y repite las solicitudes con el método especificado originalmente». Sin este parámetro, curl se detiene en la primera redirección y te muestra la página de redirección en lugar del destino.

curl -L https://example.com

No mostrar mensajes, pero seguir informando de los errores con -sS

. -s

oculta el indicador de progreso, mientras que -S

mantiene los mensajes de error. Juntos son lo que necesitas en cualquier script.

curl -sS https://example.com

Si te quedas con una sola línea de este artículo, que sea esta:

curl -sSL https://example.com

Cómo interpretar la respuesta

Los principiantes suelen fijarse en el cuerpo de la respuesta cuando la respuesta está en los encabezados.

curl -i https://example.com
HTTP/2 200
content-type: text/html; charset=UTF-8
content-length: 1256

La primera línea indica el estado. 200

significa que la operación se ha realizado con éxito. 301

y 302

son redirecciones; hay que añadir -L

. 401

y 403

significan que no tienes permiso. 404

significa que no existe. 429

significa que vas demasiado rápido. 500

y valores superiores indican que el servidor tiene un problema.

content-type

te indica lo que has recibido realmente y aclara muchas dudas. Si has llamado a una API esperando JSON y ves text/html

, has recibido una página de error o una redirección de inicio de sesión, y el error de análisis que estás a punto de encontrar es un síntoma más que la causa.

Para obtener los encabezados sin el cuerpo:

curl -sS -o /dev/null -D - https://example.com

Esto realiza una solicitud GET normal, descarta el cuerpo y muestra los encabezados. Es más fiable que -I

, que envía una solicitud HEAD

y puede comportarse de forma diferente —una distinción que se trata en nuestra guía sobre solicitudes HEAD con curl.

Para obtener un resumen en lugar de los encabezados sin procesar, -w

muestra valores seleccionados:

curl -sS -o /dev/null -w 'status=%{response_code} time=%{time_total}s\n' https://example.com

Más información sobre cómo leer correctamente los encabezados en cómo mostrar los encabezados de respuesta con curl.

Envío de datos

La otra mitad del trabajo.

Una solicitud POST con datos de formulario:

curl -d "name=Ada&role=engineer" https://api.example.com/users

El uso de -d implica una solicitud POST y establece Content-Type: application/x-www-form-urlencoded.

Una solicitud POST con JSON —y este es el error más común entre los principiantes, ya que -d por sí solo no establece un tipo de contenido JSON:

curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Ada","role":"engineer"}'

Si te olvidas de ese encabezado, muchas API devuelven el error «415 Unsupported Media Type», lo cual resulta confuso hasta que sabes que se refiere a tu Content-Type en lugar de a tus datos. Hablamos de ese error concreto en ¿qué es un código de estado 415?.

Datos de un archivo, utilizando @ para indicar «lee este archivo»:

curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d @payload.json

Una solicitud GET con parámetros de consulta formados por pares clave-valor, utilizando -G:

curl -G https://api.example.com/search -d "q=proxy" -d "limit=10"

Otros métodos con -X. Úsalo solo para métodos que no tengan una opción específica: PUT, DELETE, PATCH. Ten en cuenta la advertencia del manual de que -X «solo cambia la palabra concreta utilizada en la solicitud HTTP, no altera el comportamiento de curl», razón por la cual -X HEAD no funciona y existe -I.

Encabezados, autenticación y cookies

Encabezados personalizados con -H

, repetibles:

curl -H "Authorization: Bearer eyJhbG..." \
     -H "Accept: application/json" \
     https://api.example.com/me

Autenticación básica con -u

:

curl -u username:password https://api.example.com/private

Omite la contraseña y curl te la pedirá, lo que evita que quede registrada en el historial de tu shell:

curl -u username https://api.example.com/private

Un agente de usuario con -A

, ya que curl se identifica como tal por defecto y algunos servidores responden de forma diferente:

curl -A "Mozilla/5.0 (compatible; MyBot/1.0; +https://example.com/bot)" https://example.com

Si estás desarrollando un cliente automatizado, utilizar un agente de usuario honesto con una URL de contacto es tanto una cuestión de buenos modales como una ventaja práctica: la automatización anónima se bloquea con mucha más facilidad que la identificada.

Cookies. curl no las conserva entre ejecuciones a menos que se le solicite:

curl -c cookies.txt -d "user=ada&pass=secret" https://example.com/login
curl -b cookies.txt https://example.com/dashboard

-c

escribe un archivo de cookies, -b

lee uno. Así es como se gestiona cualquier cosa que requiera una sesión.

Ver lo que realmente se ha transmitido

El hábito que distingue a quienes depuran rápidamente de quienes se limitan a adivinar.

curl -v https://example.com

El manual explica los prefijos: «>

: encabezado enviado por curl; <

: encabezado recibido por curl; }

: datos enviados por curl; {

: datos recibidos por curl; *

: información adicional proporcionada por curl».

Para ver solo lo que has enviado:

curl -v https://example.com 2>&1 | grep '^>'

Esto aclara toda una serie de confusiones, ya que el encabezado que estableces en el código no siempre es el que se ha transmitido. Las bibliotecas añaden valores por defecto, sobrescriben valores y reordenan elementos. Cuando un servidor «ignora» tu encabezado, comprueba primero si realmente lo has enviado.

La salida detallada se envía a stderr, por lo que es necesario utilizar «2>&1

» antes de la canalización —es algo deliberado, para que el cuerpo se mantenga limpio en stdout—.

Una advertencia que ofrece el manual y que vale la pena repetir: la salida detallada y de seguimiento «puede contener datos confidenciales, incluidos nombres de usuario, credenciales o contenido de datos secretos». Ocúlpalos antes de pegarlos en un ticket.

Las opciones que conviene recordar

Todo lo anterior se resume en un pequeño conjunto.

OpciónFunción
-iMostrar los encabezados de la respuesta junto con el cuerpo
-o file / -OGuardar en un archivo con nombre / en el nombre remoto
-LSeguir las redirecciones
-sSSilencioso, pero sigue informando de los errores
-HAñadir un encabezado
-dEnviar datos (implica POST)
-uAutenticación básica
-vMostrar el intercambio completo
--failTratar los errores HTTP como fallos
-m / --connect-timeoutLímites de tiempo

Las dos últimas son las que los principiantes se saltan y luego se arrepienten.

--fail es importante porque, por defecto, curl trata un 404 como una transferencia correcta: descarga la página de error y sale con un código de salida 0. En un script, eso significa que se guarda una página de error HTML con el nombre installer.dmg y se sigue adelante. --fail hace que los errores HTTP generen un código de salida distinto de cero y no produzcan ninguna salida.

Los tiempos de espera son importantes porque, por defecto, curl no tiene un límite de tiempo global. Una solicitud bloqueada deja el script colgado indefinidamente. --connect-timeout 5 -m 30 establece ese límite. Hay más información al respecto en cómo configurar un tiempo de espera con curl.

La línea que vale la pena incluir en todos los scripts:

curl --fail --silent --show-error --location --connect-timeout 5 --max-time 30 "$URL"

Un ejemplo práctico de principio a fin

Veamos cómo encajan todas las piezas en una tarea real: llamar a una API pública, comprobar que ha funcionado y gestionar el caso de error.

Paso uno: ver qué devuelve el punto final. Empieza por los encabezados, no por el cuerpo:

curl -sS -o /dev/null -D - https://api.github.com/repos/curl/curl

Obtendrás una línea de estado y los encabezados. Si el estado es 200

y content-type

indica JSON, te estás comunicando con lo correcto.

Paso dos: examina el cuerpo, formateado. El JSON sin procesar en una sola línea es ilegible, así que pásalo por jq

:

curl -sS https://api.github.com/repos/curl/curl | jq '{name, stargazers_count, language}'

Si jq

no está instalado, python3 -m json.tool

se encarga del formateo sin dependencias adicionales.

Paso tres: comprueba lo que has enviado. Si algo no funciona como debería, revisa la solicitud en lugar de hacer conjeturas:

curl -v https://api.github.com/repos/curl/curl 2>&1 | grep '^>'

Paso cuatro: haz que sea seguro para un script. Añade gestión de errores y límites de tiempo, y captura el estado por separado del cuerpo:

#!/usr/bin/env bash
set -euo pipefail

URL="https://api.github.com/repos/curl/curl"
BODY=$(mktemp)

STATUS=$(curl --silent --show-error --location \
              --connect-timeout 5 --max-time 30 \
              --write-out '%{response_code}' --output "$BODY" \
              "$URL")

case "$STATUS" in
  200) jq -r '.stargazers_count' < "$BODY" ;;
  404) echo "not found" >&2; exit 1 ;;
  429) echo "rate limited, retry after: $(date)" >&2; exit 1 ;;
  *)   echo "unexpected status $STATUS" >&2; head -c 200 "$BODY" >&2; exit 1 ;;
esac

rm -f "$BODY"

Hay tres aspectos que vale la pena aplicar en todo lo que escribas. --write-out '%{response_code}'

con --output

separa el estado del cuerpo para que puedas tomar decisiones en función de él. Mostrar los primeros 200 caracteres del cuerpo ante un estado inesperado convierte un misterio en un error legible. Y --connect-timeout

con --max-time

significa que el script finaliza incluso cuando la red no lo hace.

Paso cinco: respeta el límite de frecuencia. Las API públicas publican sus límites en los encabezados. Leerlos no cuesta nada y evita la forma más habitual de quedar bloqueado:

curl -sS -o /dev/null -D - https://api.github.com/repos/curl/curl | grep -i ratelimit

Errores comunes de principiantes

Olvidarse de -L. Se obtiene una respuesta corta que contiene un aviso de redirección y se concluye que la URL no funciona. No es así.

Olvidarse de --fail en los scripts. Un 404 se convierte en una página de error guardada y un código de salida de cero. Es un error silencioso, pero que sale caro más adelante.

Usar -d con JSON sin configurar Content-Type. Genera 415 o un error de análisis confuso en el servidor.

Comillas en el shell. Las comillas simples conservan todo al pie de la letra; las comillas dobles permiten que el shell expanda $ y las comillas invertidas. Para un cuerpo JSON que contenga comillas dobles, envuélvelo entre comillas simples. Si tus datos también contienen comillas simples, guárdalos en un archivo y utiliza -d @file.json.

Suponer que curl ve lo mismo que un navegador. curl no ejecuta JavaScript. Una respuesta casi vacía de una página que parece completa en un navegador significa que el contenido se representa en el lado del cliente, y que curl se está comportando correctamente.

Ignorar el código de estado. Un cuerpo que indique «error» con un estado 200 y otro que indique «error» con un estado 500 son problemas distintos. Lee ambos.

Introducir credenciales en la línea de comandos. Quedan registradas en el historial del shell y son visibles en la lista de procesos para otros usuarios de la máquina. Utiliza -u user y deja que curl te pida las credenciales, o que las lea de una variable de entorno.

Desactivar la verificación de certificados para que algo funcione. -k silencia una advertencia que te estaba indicando algo. Averigua primero de qué se trata.

Próximos pasos

Una vez que te sientas cómodo con los conceptos básicos, los siguientes pasos lógicos son:

Descargas correctas: reanudación de transferencias interrumpidas, descargas en paralelo y limitación de velocidad. Se trata en descargar un archivo con curl.

Tiempos de espera y reintentos, que es donde los scripts dejan de ser frágiles. Consulta cómo establecer un tiempo de espera con curl.

Lectura de encabezados como datos, con %{header_json}, que te ofrece una salida en JSON en lugar de texto que analizar.

curl frente a wget, ya que se solapan y son útiles para cosas diferentes; en curl vs wget se explica cuándo utilizar cada uno.

Proxies, para cuando los necesites: -x http://host:port redirige una solicitud a través de uno. Realmente útiles para comprobaciones geográficas y para distribuir el volumen; realmente innecesarios para aprender o para un uso moderado.

El manual. man curl es extenso y constituye la fuente de referencia. Leer la entrada correspondiente a una opción que ya utilizas es una forma fiable de descubrir la opción que realmente buscabas.

Preguntas frecuentes

¿Para qué se utiliza curl?

Para transferir datos a través de URL desde la línea de comandos o un script: llamar a API, comprobar qué devuelve un servidor, descargar archivos y reproducir una solicitud fuera de una aplicación para aislar un problema. Admite muchos protocolos, pero se utiliza principalmente para HTTP y HTTPS.

¿Cómo realizo una solicitud GET con curl?

curl https://example.com. GET es el valor por defecto, por lo que no se necesita ningún parámetro. Añade -L para seguir las redirecciones y -i para ver los encabezados de la respuesta junto con el cuerpo.

¿Cómo envío JSON con curl?

curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' URL. El encabezado es esencial: -d por sí solo envía un tipo de contenido codificado como formulario, y las API que esperan JSON suelen rechazarlo con un código de error 415.

¿Por qué curl no devuelve nada?

Hay varias posibilidades: el cuerpo de la respuesta está realmente vacío; has seguido una redirección que no habías previsto (añade -L); el contenido lo genera JavaScript, que curl no ejecuta; o la solicitud ha fallado y no has visto el error porque has utilizado -s sin -S. Ejecútalo con -i para ver el código de estado.

¿Cuál es la diferencia entre -o y -O en curl?

-o filename guarda el archivo con el nombre que elijas. -O guarda el archivo con el nombre que aparece en la URL, descartando la ruta. Utiliza -o cuando la URL no contenga un nombre de archivo útil o cuando necesites un nombre específico.

¿Cómo puedo ver la solicitud que envía curl?

curl -v URL y busca las líneas que empiezan por >. La salida detallada se envía a stderr, así que añade 2>&1 antes de la canalización. Esta es la forma más rápida de confirmar que un encabezado que has configurado se ha enviado realmente.

¿Sigue curl las redirecciones de forma predeterminada?

No. Añade -L. Esta es la razón más habitual por la que el comando curl de un principiante devuelve una respuesta breve e inesperada: estás viendo la redirección, no el destino.

¿Necesito un proxy para usar curl?

No. curl funciona perfectamente con puntos finales públicos desde tu propia conexión. Los proxies solo cobran relevancia cuando realizas tantas solicitudes que te limitan el ancho de banda, o cuando necesitas ver qué ofrece un sitio web en otro país. Ninguna de estas razones justifica comprar nada mientras estás aprendiendo.

Conclusión

curl tiene una cantidad abrumadora de opciones y un núcleo útil muy reducido. -i para ver los encabezados, -L para seguir redirecciones, -o para guardar, -H para añadir encabezados, -d para enviar datos, -u para la autenticación, -v para ver qué ha pasado y --fail, además de un tiempo de espera para cualquier proceso que se ejecute sin supervisión. Ese es todo el conjunto de funciones que la mayoría de la gente necesita.

Los dos hábitos que importan más que cualquier opción: lee el código de estado y el Content-Type antes de leer el cuerpo del mensaje, porque suelen indicar el problema de forma directa; y utiliza -v para comprobar lo que realmente has enviado en lugar de lo que pretendías enviar, porque la diferencia entre ambos es donde se esconden una cantidad sorprendente de errores.

Todo lo demás lo encontrarás en el manual, que es extenso, fidedigno y al que merece la pena echar un vistazo cada vez que te encuentres escribiendo una solución alternativa. La opción que buscas suele estar ahí.