Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ Save as `quickstart.js` and run `node quickstart.js`. [Create a free account](ht
- [Upload an image](docs/upload-image.md)
- [Upload a large video](docs/upload-large-video.md)
- [Sign a browser upload](docs/sign-browser-upload.md)
- [Transform and deliver media](docs/transform-and-deliver-media.md)
- [Transform and deliver an image](docs/transform-and-deliver-image.md)
- [Transform and deliver a video](docs/transform-and-deliver-video.md)
- [Search and manage assets](docs/search-and-manage-assets.md)
- [Moderate an upload](docs/moderate-upload.md)
- [Use structured metadata](docs/use-structured-metadata.md)
Expand Down
3 changes: 2 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ failures. Runnable versions of most tasks are in `node_modules/cloudinary/exampl
- [Upload an image](upload-image.md)
- [Upload a large video](upload-large-video.md)
- [Sign a browser upload](sign-browser-upload.md)
- [Transform and deliver media](transform-and-deliver-media.md)
- [Transform and deliver an image](transform-and-deliver-image.md)
- [Transform and deliver a video](transform-and-deliver-video.md)
- [Search and manage assets](search-and-manage-assets.md)
- [Moderate an upload](moderate-upload.md)
- [Use structured metadata](use-structured-metadata.md)
Expand Down
5 changes: 3 additions & 2 deletions docs/platform-capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ Cloudinary publishes agent-readable indexes. Fetch these instead of guessing at

| To do this | Use | Where to go |
|---|---|---|
| Build a resize, crop, overlay, or format-optimized URL | `url`, `image`, `video` | [Transform and deliver media](transform-and-deliver-media.md) |
| Apply generative edits (gen fill, background removal, ...) | `effect` / `raw_transformation` — **generic strings only, no typed builders** | [Transform and deliver media](transform-and-deliver-media.md) |
| Build a resize, crop, overlay, or format-optimized image URL | `url`, `image` | [Transform and deliver an image](transform-and-deliver-image.md) |
| Build a video URL, player tag, poster frame, or HLS/DASH stream | `url` (with `resource_type: 'video'`), `video` | [Transform and deliver a video](transform-and-deliver-video.md) |
| Apply generative edits (gen fill, background removal, ...) | `effect` / `raw_transformation` — **generic strings only, no typed builders** | [Transform and deliver an image](transform-and-deliver-image.md) |

URL building is local: no network call, no `api_secret`.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# Transform and deliver media
# Transform and deliver an image

## When to use

Generate CDN-backed delivery URLs that resize, crop, overlay, or optimize images and video. URL
Generate CDN-backed delivery URLs that resize, crop, overlay, or optimize an image. URL
generation is local — no network call, no secret required — and the derived asset is
created by Cloudinary on first request, then served from CDN cache.

For video, see [Transform and deliver a video](transform-and-deliver-video.md).

## Optimized image URL

```js
Expand Down Expand Up @@ -52,18 +54,6 @@ console.log(bannerUrl);
Reordering components changes the output. When matching eagerly generated versions,
the serialized transformation string must match exactly.

## Video

```js
// 'examples/uploaded-large-video' is created by the "Upload a large video" task
const clip = cloudinary.video('examples/uploaded-large-video', {
width: 640,
crop: 'scale',
quality: 'auto',
controls: true
}); // returns an HTML <video> tag; cloudinary.url(..., {resource_type: 'video'}) returns just the URL
```

## Generative editing on delivery

Server-supported generative transformations (background removal, generative fill, and
Expand All @@ -81,6 +71,7 @@ https://cloudinary.com/documentation/generative_ai_transformations.md before rel
## Related

- Runnable example: `examples/transform-and-deliver-image.js`
- [Transform and deliver a video](transform-and-deliver-video.md)
- Every transformation parameter and its accepted values:
[Transformation reference](https://cloudinary.com/documentation/transformation_reference.md)
- [Image manipulation guide](https://cloudinary.com/documentation/node_image_manipulation.md)
109 changes: 109 additions & 0 deletions docs/transform-and-deliver-video.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Transform and deliver a video

## When to use

Generate CDN-backed delivery URLs and player markup for a video that is already in
Cloudinary. URL generation is local — no network call, no secret required — and the
derived asset is created by Cloudinary on first request, then served from CDN cache.

For images, see [Transform and deliver an image](transform-and-deliver-image.md).

## Player markup

`cloudinary.video()` returns a complete HTML `<video>` tag, not a URL:

```js
const cloudinary = require('cloudinary').v2; // only cloud_name is needed for URL generation

// 'examples/uploaded-large-video' is created by the "Upload a large video" task
const tag = cloudinary.video('examples/uploaded-large-video', {
width: 640,
crop: 'scale',
quality: 'auto',
controls: true,
secure: true
});
console.log(tag);
// <video controls poster='.../c_scale,q_auto,w_640/<id>.jpg' width='640'>
// <source src='.../<id>.webm' type='video/webm'>
// <source src='.../<id>.mp4' type='video/mp4'>
// <source src='.../<id>.ogv' type='video/ogg'>
// </video>
```

The tag carries three `<source>` variants so the browser picks a format it supports, plus
a generated JPG poster frame. Drop it into a template as-is.

## Video URL only

`cloudinary.video()` returns markup; for the URL alone use `cloudinary.url()` with
`resource_type: 'video'`.

```js
const videoUrl = cloudinary.url('examples/uploaded-large-video', {
resource_type: 'video',
width: 640,
crop: 'scale',
quality: 'auto',
secure: true
});
// https://res.cloudinary.com/<cloud>/video/upload/c_scale,q_auto,w_640/examples/uploaded-large-video
```

## Thumbnail from a video frame

Request an image format from a video asset to get a still. `start_offset` picks the
second to grab:

```js
const posterUrl = cloudinary.url('examples/uploaded-large-video', {
resource_type: 'video',
format: 'jpg',
start_offset: '2', // so_2 — two seconds in
width: 400,
crop: 'fill',
secure: true
});
// https://res.cloudinary.com/<cloud>/video/upload/c_fill,so_2,w_400/examples/uploaded-large-video.jpg
```

## Adaptive bitrate streaming

For anything longer than a short clip, deliver HLS or DASH rather than a single MP4 so
the player can switch renditions:

```js
const hlsUrl = cloudinary.url('examples/uploaded-large-video', {
resource_type: 'video',
streaming_profile: 'hd', // sp_hd
format: 'm3u8', // .mpd for DASH
secure: true
});
// https://res.cloudinary.com/<cloud>/video/upload/sp_hd/examples/uploaded-large-video.m3u8
```

Streaming profiles are per-environment; list the available ones with
`cloudinary.api.list_streaming_profiles()`.

## Cache behavior

- The same URL is served from CDN cache; a new transformation means a new URL.
- To bust stale caches after re-uploading, deliver with the asset `version` from the
upload response (`cloudinary.url(id, { resource_type: 'video', version: result.version })`).

## Troubleshooting

- The asset was uploaded with `upload_large` and will not transform or stream — it landed
as `raw`. Re-upload with `resource_type: 'video'`. See
[Upload a large video](upload-large-video.md).
- The first request for a new transformation is slow — the derived video is being
generated. For long jobs prefer `eager_async` with a `notification_url` over polling.

## Related

- Runnable example: `examples/transform-and-deliver-video.js`
- [Transform and deliver an image](transform-and-deliver-image.md)
- [Upload a large video](upload-large-video.md)
- Every transformation parameter and its accepted values:
[Transformation reference](https://cloudinary.com/documentation/transformation_reference.md)
- [Video manipulation guide](https://cloudinary.com/documentation/node_video_manipulation.md)
3 changes: 2 additions & 1 deletion docs/troubleshoot-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ chunked upload; chunks retry independently.
### Stale delivery after re-upload
CDN-cached URLs do not update instantly. Deliver with the new `version` from the upload
response, which changes the URL immediately. See
[Transform and deliver media](transform-and-deliver-media.md).
[Transform and deliver an image](transform-and-deliver-image.md) or
[a video](transform-and-deliver-video.md).

## Still stuck

Expand Down
2 changes: 1 addition & 1 deletion docs/upload-image.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,5 @@ it before uploading, or upgrade the plan.
## Related

- Runnable example: `examples/upload-image.js`
- [Transform and deliver media](transform-and-deliver-media.md)
- [Transform and deliver an image](transform-and-deliver-image.md)
- [Upload guide](https://cloudinary.com/documentation/node_image_and_video_upload.md)
2 changes: 2 additions & 0 deletions docs/upload-large-video.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,6 @@ webhook; the response then includes a pending status until Cloudinary calls your

- Runnable example: `examples/upload-large-video.js` — works with no arguments; it
downloads a sample video from the Cloudinary demo account if none is supplied.
- [Transform and deliver a video](transform-and-deliver-video.md) — what to do with it
once it is uploaded.
- [Video upload guide](https://cloudinary.com/documentation/node_image_and_video_upload.md#node_js_video_upload)
3 changes: 2 additions & 1 deletion examples/transform-and-deliver-image.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
* In your own project: const cloudinary = require('cloudinary').v2;
*
* Related:
* - Task doc: docs/transform-and-deliver-media.md
* - Task doc: docs/transform-and-deliver-image.md
* - For video: examples/transform-and-deliver-video.js
* - Every transformation parameter and its accepted values:
* https://cloudinary.com/documentation/transformation_reference.md
* - Building transformations from a plain-language description: the
Expand Down
74 changes: 74 additions & 0 deletions examples/transform-and-deliver-video.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Build transformation and delivery URLs for a video already in Cloudinary.
*
* URL generation is local - no network call and no credentials beyond the cloud name.
* The derived asset is created by Cloudinary on first request and then served from CDN cache.
*
* In your own project: const cloudinary = require('cloudinary').v2;
*
* Related:
* - Task doc: docs/transform-and-deliver-video.md
* - For images: examples/transform-and-deliver-image.js
* - Every transformation parameter and its accepted values:
* https://cloudinary.com/documentation/transformation_reference.md
* - Building transformations from a plain-language description: the
* cloudinary-transformations skill (npx skills add cloudinary-devs/skills)
*/
const cloudinary = require('../cloudinary').v2;

function main(publicId = 'dog') {
// A complete <video> tag: three <source> variants plus a generated poster frame.
const playerTag = cloudinary.video(publicId, {
width: 640,
crop: 'scale',
quality: 'auto',
controls: true,
secure: true
});

// The delivery URL on its own, for a player you control.
const videoUrl = cloudinary.url(publicId, {
resource_type: 'video',
width: 640,
crop: 'scale',
quality: 'auto',
secure: true
});

// A still frame as an image: ask a video asset for an image format.
const posterUrl = cloudinary.url(publicId, {
resource_type: 'video',
format: 'jpg',
start_offset: '2',
width: 400,
crop: 'fill',
secure: true
});

// Adaptive bitrate streaming - prefer this over a single MP4 for long videos.
const hlsUrl = cloudinary.url(publicId, {
resource_type: 'video',
streaming_profile: 'hd',
format: 'm3u8',
secure: true
});

console.log(`Video URL (640 wide): ${videoUrl}`);
console.log(`Poster frame at 2s: ${posterUrl}`);
console.log(`HLS adaptive streaming: ${hlsUrl}`);
console.log(`Player tag: ${playerTag}`);
return { playerTag, videoUrl, posterUrl, hlsUrl };
}

if (require.main === module) {
try {
main(process.argv[2]);
} catch (error) {
const { message } = error.error || error;
console.error(`URL generation failed: ${message}`);
console.error('Check that cloud_name is configured (CLOUDINARY_URL or cloudinary.config()).');
process.exitCode = 1;
}
}

module.exports = { main };
Loading