Rendimiento multimedia

# Cómo servir imágenes responsivas desde una sola URL

Genera cada tamaño de imagen desde una URL canónica, almacena los resultados en caché perimetral y mantén estable el costo de codificación al crecer el tráfico.

Publicado el 13 de agosto de 2026

## Conclusiones clave

* Una URL de Smart CDN se compone de un Workspace, el nombre de un Template y una ruta de archivo, con parámetros de consulta que proporcionan valores al Template.
* El Template lee esos parámetros como Assembly Variables, por lo que ${fields.w} puede convertirse en el ancho del cambio de tamaño.
* Solo se codifica la primera solicitud de una combinación determinada de parámetros; las demás se responden desde la caché.

Servir imágenes responsivas consiste principalmente en decidir dónde reside la lista de variantes. Generar todos los tamaños con antelación vincula la factura de almacenamiento con la cantidad de puntos de quiebre, mientras que derivar tamaños bajo demanda traslada el costo a la primera solicitud de cada variante y coloca una caché delante de todas las solicitudes posteriores.

## En esta guía

1. [Coloca el Template detrás de la URL](#serve-responsive-images-from-one-url-section-1)
2. [Decide qué parámetros puede establecer una URL](#serve-responsive-images-from-one-url-section-2)
3. [Firma la URL y trata su vencimiento como un ajuste de caché](#serve-responsive-images-from-one-url-section-3)
4. [Deja que el encabezado Accept elija el formato](#serve-responsive-images-from-one-url-section-4)
5. [La tasa de aciertos de caché es todo el argumento económico](#serve-responsive-images-from-one-url-section-5)
6. [Conserva los originales en un lugar bajo tu control](#serve-responsive-images-from-one-url-section-6)

## Lo más importante

* AVIF y WebP pueden seleccionarse a partir del encabezado Accept del navegador mediante la variable ${browser.wanted\_image\_format}.
* Restringe los anchos que una URL puede solicitar, porque cada combinación diferente requiere una codificación independiente.
* Una URL firmada vence, y el tiempo restante de esa firma también limita durante cuánto tiempo el resultado puede permanecer en caché.

## Coloca el Template detrás de la URL

Una URL de Smart CDN se compone de tres partes y una cadena de consulta: el Workspace como subdominio de `tlcdn.com`, el nombre de un Template y la ruta del archivo que se procesará. Al solicitarla, se ejecuta ese Template y los parámetros de consulta llegan a él como Assembly Variables. Así, un Template que cambia el tamaño a `${fields.w}` convierte `?w=640` en un resultado de 640 píxeles de ancho. La lista de variantes no está compilada en el front end.

Esa separación determina qué corresponde a cada lugar. El Template contiene el pipeline: importar el original, transformarlo y entregarlo. La URL solo lleva los pocos valores que pueden variar legítimamente en cada solicitud. Mantener el pipeline del lado del servidor permite publicar un cambio en la calidad de codificación o un nuevo Step de procesamiento sin modificar una sola página de marcado.

Crear un Template cuyo ancho provenga de la URL

```
{
  "steps": {
    "imported": {
      "robot": "/s3/import",
      "credentials": "my_s3_credentials",
      "path": "/images/${fields.input}"
    },
    "resized": {
      "use": "imported",
      "robot": "/image/resize",
      "resize_strategy": "fit",
      "width": "${fields.w}"
    },
    "served": {
      "use": "resized",
      "robot": "/file/serve",
      "cache_duration": 604800
    }
  }
}
```

### Workspace y Template

El subdominio identifica el Workspace y el primer segmento de la ruta indica el Template que debe ejecutarse.

### Ruta del archivo

El resto de la ruta identifica el original que debe procesar el Template.

### Parámetros de consulta

Estos llegan al Template como Assembly Variables, lo que permite que una sola URL entregue muchos tamaños.

## Decide qué parámetros puede establecer una URL

Cada combinación distinta de parámetros produce un resultado distinto, lo que implica una entrada de caché distinta y, la primera vez que se solicita, una codificación distinta. Un diseño que solicite cualquier ancho que tenga el contenedor generará un conjunto ilimitado de imágenes casi idénticas, cada una pagada una sola vez y luego reutilizada en contadas ocasiones. Una lista breve de anchos elegidos a partir de puntos de quiebre reales requiere unas pocas codificaciones y, después, todo se obtiene de la caché.

Esta también es el área expuesta a abusos. Una URL que acepta dimensiones arbitrarias permite que cualquiera que la encuentre enumere anchos y convierta tu endpoint de entrega en una factura de codificación. Firmar la URL elimina por completo esa posibilidad. Cuando firmarla no sea práctico, valida los valores dentro del Template, ya sea limitando el ancho solicitado o recurriendo a un valor predeterminado, para contener el daño.

### Un conjunto fijo de anchos

Elígelos a partir de los puntos de quiebre que realmente utiliza el diseño, no de las medidas del contenedor.

### Fragmentación de la caché

Las variantes casi idénticas dividen el tráfico que, de otro modo, compartiría un solo resultado en caché.

### Limitar en el Template

Limita los valores que puede solicitar una petición para evitar que un parámetro inesperado se convierta en uno costoso.

## Firma la URL y trata su vencimiento como un ajuste de caché

La firma se realiza en el back end porque requiere el Auth Secret. La cadena que se firmará se compone del Workspace, el nombre del Template y la ruta del archivo, seguidos de los parámetros de consulta ordenados de forma ascendente según sus claves; el HMAC usa SHA256 y el resultado se incluye en un parámetro `sig` con el prefijo `sha256:`. Ten en cuenta que las firmas de Smart CDN usan SHA256, mientras que las firmas de solicitudes habituales a la API usan SHA384, y que la Auth Key debe estar habilitada para usarse con Smart CDN.

El parámetro `exp`, una marca de tiempo UNIX en milisegundos, determina la principal disyuntiva. Evidentemente, funciona como control de acceso: después de ese momento, la URL deja de funcionar. También controla la caché, porque la duración efectiva en caché de una respuesta firmada está limitada por el tiempo restante de su firma. Un vencimiento próximo refuerza la seguridad, pero descarta la reutilización de la caché; uno lejano mantiene los resultados disponibles en caché y permite usar la URL durante más tiempo.

Firmar una URL de Smart CDN en el back end con el SDK de Node

```
import { Transloadit } from 'transloadit'

const transloadit = new Transloadit({
  authKey: process.env.TL_KEY,
  authSecret: process.env.TL_SECRET,
})

const url = transloadit.getSignedSmartCDNUrl({
  workspace: 'my-workspace',
  template: 'responsive-image',
  input: 'canoe.jpg',
  urlParams: { w: 640 },
})
```

### Orden ascendente de las claves

Los parámetros se ordenan de forma ascendente según sus unidades de código UTF-16 antes de firmar la cadena.

### sig y exp

Las URL modernas usan estos dos parámetros; los parámetros heredados s y expires están obsoletos.

### El vencimiento limita la caché

Elige el intervalo según la sensibilidad del contenido y el grado de reutilización de la caché que desees.

## Deja que el encabezado Accept elija el formato

Los formatos modernos permiten ahorrar una cantidad considerable de bytes, y el navegador ya anuncia cuáles acepta. La Assembly Variable `${browser.wanted_image_format}` convierte ese anuncio en `avif`, `webp` o `jpg`, respetando las ponderaciones de calidad del encabezado. De este modo, un Template que lee el valor en el parámetro `format` de `/image/resize` entrega a cada navegador el mejor formato que declara explícitamente admitir. Nada de esa lógica de selección termina en tu marcado y no se necesita una segunda URL para expresarla.

El detalle sutil es lo que significa realmente `jpg`. Por diseño, un rango de medios con comodín no indica que el cliente acepte un formato específico, por lo que curl, la mayoría de los SDK y los clientes de servidor a servidor reciben ese valor. Este describe lo que aceptará el cliente, no el formato del archivo. Pasarlo directamente a `format` convierte un PNG transparente o un GIF animado a JPEG en cada una de esas solicitudes. En cambio, asignar `null` como respaldo hace que `/image/resize` conserve el formato de entrada, por lo que los navegadores reciben un formato moderno y los demás clientes reciben el original sin modificaciones.

Entregar AVIF o WebP a los navegadores y el original a los demás clientes

```
{
  "steps": {
    "resized": {
      "use": ":original",
      "robot": "/image/resize",
      "width": 800,
      "format": "${browser.wanted_image_format === 'jpg' ? null : browser.wanted_image_format}"
    },
    "served": {
      "use": "resized",
      "robot": "/file/serve"
    }
  }
}
```

### avif y webp

Se seleccionan cuando el navegador los acepta explícitamente, teniendo en cuenta las ponderaciones de calidad.

### El respaldo jpg

Se devuelve cuando faltan los encabezados o estos solo contienen comodines, lo que abarca a la mayoría de los clientes que no son navegadores.

### Asignar null como respaldo

Mantiene el cambio de tamaño en el formato de entrada para conservar la transparencia y la animación durante todo el recorrido.

## La tasa de aciertos de caché es todo el argumento económico

Dos Robots se reparten los costos, y entender la función de cada uno explica la mayoría de las sorpresas. `/file/serve` solo cobra cuando la CDN no tiene una copia en caché y solicita que el contenido se vuelva a producir, por lo que el costo de codificación depende de la tasa de fallos de caché y no del tráfico. `/tlcdn/deliver` se encarga de la distribución global, está implícito al usar el dominio `tlcdn.com` en lugar de incluirse en las Assembly Instructions, y factura el ancho de banda con un cargo mínimo de 102.400 bytes por entrega.

Los valores predeterminados indican a los navegadores que almacenen el contenido en la caché durante 72 horas y a las CDN durante 24 horas, mientras que `cache_duration` en `/file/serve` sustituye ambos valores a la vez. Configúralo según el tiempo durante el cual el original subyacente siga siendo válido: el contenido que nunca cambia puede permanecer mucho tiempo en la caché, mientras que los archivos eliminados después de un día no deberían conservarse más allá de ese plazo en la caché perimetral. Una configuración que debes evitar es hacer que el marcado apunte directamente a un endpoint de entrega sin una CDN delante, ya que una página popular convertiría cada visualización en una nueva codificación.

### Cobro al volver a generar

Una variante almacenada en caché solo genera costos de entrega; la codificación se cobra cuando se produce un fallo de caché.

### cache\_duration

Establece conjuntamente los intervalos de caché del navegador y de la CDN, y reemplaza los valores predeterminados de 72 y 24 horas.

### Usar siempre una CDN delante

La entrega directa desde un endpoint de origen convierte cada visualización de la página en otra codificación.

### Vary: Accept

Los formatos negociados se almacenan en caché por separado, por lo que cada formato multiplica las entradas que produce un ancho.

## Conserva los originales en un lugar bajo tu control

El Template comienza importando el original, normalmente con `/s3/import` desde tu propio bucket, mediante una ruta creada a partir de la URL, como `/images/${fields.input}`. Los derivados son una caché, no un registro. Conservar los originales en un almacenamiento bajo tu control mantiene la relación en una sola dirección: todo lo entregado puede reconstruirse a partir de algo que conservas y nada importante existe únicamente como variante en caché.

Esa configuración es lo que permite rediseñar a bajo costo. Los nuevos puntos de quiebre implican nuevos valores de parámetros y un periodo de calentamiento mientras se llena la caché, no una tarea de migración de los archivos almacenados. Esa es también la razón por la que un cambio de formato no supone nada especial: el Template solicita algo diferente, las variantes antiguas caducan y los originales nunca se mueven.

### Importar en cada solicitud

El Template obtiene el original de tu almacenamiento mediante una ruta tomada de la URL.

### Los derivados son descartables

Todo lo que conserva la CDN puede volver a producirse, por lo que perder una variante en caché requiere una sola codificación.

### Los puntos de quiebre pueden cambiar

Un tamaño nuevo es un valor de parámetro nuevo, no una tarea por lotes aplicada a los archivos almacenados.

## Detalles técnicos que conviene conocer

* Una URL de Smart CDN se compone de un subdominio de Workspace en tlcdn.com seguido del nombre del Template y la ruta del archivo; sus parámetros de consulta llegan al Template como Assembly Variables, por ejemplo, ${fields.w}.
* La respuesta servida indica a los navegadores que almacenen en caché durante 72 horas y a las CDN durante 24 horas de forma predeterminada, y el parámetro cache\_duration de /file/serve sobrescribe ambos valores de una sola vez.
* /file/serve solo genera un cargo cuando la CDN no tiene una copia en caché y solicita que se vuelva a producir el contenido, lo que vincula el costo de codificación con la tasa de aciertos de caché y no con el tráfico.
* La entrega global está a cargo de /tlcdn/deliver, que está implícito en el dominio tlcdn.com en lugar de estar escrito en las Assembly Instructions, y factura el ancho de banda con un cargo mínimo de 102.400 bytes.
* La firma es un HMAC SHA256 calculado sobre el Workspace, el nombre del Template, la ruta del archivo y los parámetros de consulta ordenados de forma ascendente según sus claves; se envía como un parámetro sig con el prefijo sha256 seguido de dos puntos.
* El parámetro exp es una marca de tiempo UNIX en milisegundos y, dado que la duración efectiva en caché de una respuesta firmada está limitada por el tiempo restante de la firma, su vencimiento es tanto una decisión de caché como de seguridad.
* La Assembly Variable ${browser.wanted\_image\_format} se resuelve como avif cuando AVIF se acepta explícitamente, como webp cuando WebP es el mejor formato moderno aceptado explícitamente y como jpg cuando el encabezado Accept está ausente o solo contiene comodines, respetando las ponderaciones de calidad.
* Un rango de medios comodín deliberadamente no hace que un cliente use un formato moderno, lo que mantiene las solicitudes de curl, SDK y servidor a servidor en el valor jpg; en cambio, asignar ese valor a null hace que /image/resize conserve el formato de entrada.
* Las respuestas de Smart CDN incluyen el encabezado Vary: Accept, por lo que las cachés mantienen una entrada separada por cada formato negociado y la cantidad de formatos en uso multiplica la cantidad de variantes almacenadas en caché.

## Un enfoque práctico

1. 1\
   Conserva los originales en un almacenamiento que controles e impórtalos al Template con /s3/import.
2. 2\
   Expón en la URL una lista breve y fija de anchos, en lugar de un parámetro sin límites.
3. 3\
   Firma las URL en el back end con una Auth Key habilitada para usarse con Smart CDN.
4. 4\
   Lee ${browser.wanted\_image\_format} en el Template y asigna el respaldo jpg a null.

Un flujo de trabajo multimedia de cuatro etapas

## Cuándo resulta útil Transloadit

Usa un Template que importe el original desde tu propio almacenamiento, lo transforme con /image/resize y termine en /file/serve. Solicítalo mediante una URL de tlcdn.com cuyos parámetros de consulta proporcionen las Assembly Variables que lee el Template.

## Límite de la arquitectura

La negociación de formatos se ofrece al Template en lugar de aplicarse automáticamente, por lo que un Template que nunca lea ${browser.wanted\_image\_format} seguirá sirviendo exactamente lo mismo que antes. La variable también se resuelve como jpg cuando faltan los encabezados Accept o estos solo contienen comodines. Esto describe al cliente, no al archivo, por lo que pasar ese respaldo directamente a un parámetro de formato elimina la transparencia y la animación en todas las solicitudes que no provienen de navegadores.

## Preguntas frecuentes

### ¿Smart CDN entrega WebP o AVIF automáticamente?

Sí, pero solo una vez que el Template lo solicite. Pasa `${browser.wanted_image_format}` al parámetro `format` y cada navegador recibirá el mejor formato que acepte explícitamente. Un Template que nunca lea la variable seguirá entregando lo mismo que antes.

### ¿Por qué mi PNG transparente se devolvió como JPEG?

Porque quien hizo la solicitud no envió el encabezado `Accept`, o solo envió uno con comodín, y el Template usó el respaldo `jpg` como formato literal. El respaldo describe la compatibilidad del cliente, no el archivo, así que asígnalo a `null` y permite que el cambio de tamaño conserve el formato de entrada.

### ¿Cuántos anchos debo exponer?

Tan pocos como realmente necesite el diseño, normalmente unos cuantos seleccionados de puntos de quiebre reales. Cada combinación adicional supone otra entrada de caché y otra codificación en la primera solicitud, y las variantes de tamaño similar rara vez justifican el tráfico que se quitan entre sí.

### ¿Por qué mi costo de codificación es mayor de lo que sugiere la cantidad de imágenes?

Casi siempre se debe a fallos de caché. Los parámetros de ancho sin límites, los vencimientos breves de las firmas y un valor bajo de `cache_duration` acortan la vida útil de un resultado en caché, y cada vencimiento implica que la siguiente solicitud vuelve a pagar la codificación.

### ¿Tengo que firmar cada URL?

No es obligatorio, pero cualquiera que encuentre una URL sin firma que acepte parámetros arbitrarios puede enumerar sus valores, y cada combinación nueva es una codificación que debes pagar. Firma las URL o limita los valores aceptados dentro del Template.

### ¿Dónde se alojan los archivos originales?

En tu propio almacenamiento. El Template importa el original en cada solicitud, normalmente con /s3/import y una ruta construida a partir de la URL. Así, la CDN conserva variantes derivadas que siempre pueden volver a producirse a partir de algo que controlas.

## Crea el flujo de trabajo

Pasa del concepto a una Assembly probada con documentación de Robots y demos funcionales.

### Robots relevantes

* [/image/resize](/es/docs/robots/image-resize.md)
* [/file/serve](/es/docs/robots/file-serve.md)
* [Lee la documentación de la API](/es/docs.md)
* [Explora demos funcionales EN (English)](/demos.md)
* [Crea un Workspace gratuito](/c/signup/)

Rendimiento multimedia

## Continúa con guías relacionadas

* [Ocho prácticas para optimizar el SEO de imágenes](/es/guides/image-seo-optimization.md)\
  Ocho prácticas de SEO para imágenes sobre semántica, dimensiones, formatos, rendimiento, descubrimiento y medición.
* [Añadir imágenes e insignias a un README de GitHub: cuatro formas](/es/guides/images-in-github-readmes.md)\
  Agrega imágenes a un README de GitHub mediante archivos del repositorio, adjuntos de incidencias, URL sin procesar, HTML o recursos generados.
* [Cinco mejores prácticas para imágenes de fondo en HTML y CSS](/es/guides/html-background-image-best-practices.md)\
  Cinco prácticas para imágenes de fondo CSS que equilibran la composición, la accesibilidad y el rendimiento de la página.
* [Cinco formas de usar imágenes en React, desde la importación estática hasta las subidas del usuario](/es/guides/import-images-in-react.md)\
  Compara importaciones estáticas, rutas públicas, URL remotas, importaciones de CSS y resultados de subidas en tiempo de ejecución en React.
* [Seis formas confiables de guardar imágenes en Python](/es/guides/save-images-in-python.md)\
  Guarda imágenes desde bytes, URL, Pillow, OpenCV, subidas y resultados de procesamiento gestionado sin perder el manejo de errores.
