Lenses and transforms

Use reusable named lenses or one-off transform selectors to resize and convert retained images through the CalmLens CDN. Transformations produce derived responses without creating new asset records. CDN URLs use https://cdn.calmlens.com/v1.

Choose a transform

NeedUse
A reusable thumbnail or image presetA named lens. Update its version when its definition changes.
A one-off size or formatA direct transform selector in the URL.

Named lenses

Lenses are named CDN transforms. They let you request a derived version of an asset without creating another asset record. Lens and transform selectors work on both /content and /preview. See Delivering assets for retention, visibility, authorization, and availability requirements.

Use a named lens by appending /@:lensIdentifier to the CDN URL. The @ prefix makes the selector unambiguously a named lens.

/assets/:projectId/:assetIdentifier/content/@thumbnail

Example:

const response = await client.cdn.serve({
  assetIdentifier: assetId,
  lens: "thumbnail",
});

When signing a private lens URL, include the same lens identifier in the signing request:

import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.createSignedUrl({
  "resource": "content",
  "lens": "thumbnail",
  "expiresInSeconds": 900,
  "assetId": "your-asset-id"
});

The CDN validates the signature against the lens, then applies it.

Direct transforms

For one-off derived assets, append a direct transform selector without @. The selector uses the existing transform syntax and can contain one or more comma-separated transforms.

/assets/:projectId/:assetIdentifier/content/imageTransform[format=png,width=1024]
const response = await client.cdn.serve({
  assetIdentifier: assetId,
  transform: "imageTransform[format=png,width=1024]",
});

Direct transforms are not saved as lenses. Use a versioned lens when a transform should have a stable project-owned name and cache invalidation on definition changes.

Image transform options

The supported transform type is imageTransform. Options are comma-separated key=value pairs inside brackets.

OptionAccepted values
formatjpg, png, webp, avif, or gif
width, heightNon-negative integers
fitscale-down, contain, pad, squeeze, cover, or crop
qualityInteger from 0 through 255
rotate0, 90, 180, or 270
fliph, v, or hv
Other adjustmentsbackground, blur, brightness, contrast, gamma, saturation, sharpen, gravity, border, segment, and trim

Unknown transform types and malformed selectors return 400 asset/invalid-transform. Unsupported options return 400 asset/invalid-transform-options.

Versioned custom lenses

Lenses are versioned, project-scoped definitions for reusable CDN transformations. Use them when a derived asset needs a stable URL and predictable cache invalidation.

Create or update a project lens with the SDK's idempotent client.ensureLens() method:

const normalLens = await client.ensureLens({
  identifier: "picmagic-normal",
  name: "PicMagic normal",
  type: "image",
  active: true,
  version: 1,
  transforms: [
    {
      type: "imageTransform",
      options: { fit: "scale-down", width: 1024, format: "png" },
    },
  ],
});

const response = await client.cdn.serve({
  assetIdentifier: assetId,
  resource: "content",
  lens: normalLens.identifier,
});

Versioning rules:

  • Create a new lens with any positive version.
  • Repeating the same version and complete definition is idempotent, so it is safe to run on every deploy.
  • Any other update must use a version greater than the current version; versions do not need to be consecutive.
  • Reusing or lowering the current version for a different definition returns 409 lens/version-conflict.
  • Lens identifiers contain lowercase letters, numbers, and hyphens and are at most 50 characters.

To change the width or output format, submit the complete new definition with version 2. Always submit the complete definition when updating a lens. CalmLens includes the resolved lens version in its CDN cache and ETag identities, so a new version never serves a cached result from the prior definition. SDK lens URLs use the required @ prefix automatically.

To ensure multiple lenses in one request, use client.ensureLenses():

const [normalLens, uhdLens] = await client.ensureLenses({
  lenses: [normalDefinition, uhdDefinition],
});

Use the single-lens endpoint for one definition or the bulk endpoint to ensure several definitions in one request. The endpoint details below document the complete REST request and response schemas.

Lens API reference

See the Lenses reference for objects, request schemas and endpoint details.

The lens object

View lens fields.

Endpoint details

Ensure a lens or ensure several lenses.

Signing in

Signing out

Cookies on CalmLens

We use essential cookies to keep you signed in and the site secure. With your permission, we'll also use functional cookies to remember preferences such as your layout and documentation language, and to offer Google One Tap sign-in. We don't use analytics or advertising cookies. Manage cookies