Lab
  • DRM packaging tutorialsCourse
  • 5 things you need to know about multi-DRMCourse
  • Getting started with DoveRunner Anti PiracyCourse
  • Getting started with DoveRunner Forensic WatermarkingCourse
  • Getting started with DoveRunner Mobile App SecurityCourse
  • Getting started with DoveRunner Multi-DRMCourse
  • Getting started with DoveRunner Transcoding & PackagingCourse
  • Packaging content with the DRM CLI PackagerLesson · DRM packaging tutorials
한국어

Watermark embedding

Deploy the CloudFront embedder and generate a per-viewer session URL with the Session Manager API, so the CDN mixes A/B segments at playback time to embed the watermark.

Lesson 27 min

DRM: —FWM: —Status: idle

How embedding works

Preprocessing produced two variants of your video, A (0/) and B (1/). Embedding happens at playback time. When a viewer requests the stream, the session information is converted to binary, and for each bit the matching segment variant is served. The result is a unique, invisibly watermarked stream for every viewer.

The segment list uses the same path and filename for every session, which protects against segment-naming attacks.

Flow

  1. The session manager generates a session key (payload) and stores the session data.
  2. The encrypted session data travels through the service site to the CDN.
  3. The CDN's watermark embedder module mixes DASH/HLS segments based on the session URL.

This lesson has two parts: deploy the CloudFront embedder (Part 1), then generate a per-viewer session URL with the Session Manager API (Part 2). The video above is packaged with DRM and watermarking, and it plays through the same flow: the Lab asks the Session URL API for a session on page load, so the session data under the player is the real data embedded in your playback.

Supported CDNs

  • Amazon CloudFront (this lesson)
  • Akamai
  • Cloudflare Workers

Before you start

  • Preprocessed content in your S3 output bucket (wm-contents/…/0 and …/1), from the previous lesson
  • DoveRunner site ID, site key, and access key, found in DoveRunner Console
  • An AWS account that can create IAM roles, Lambda functions, and CloudFront distributions

Part 1. Deploy the CloudFront embedder

A Lambda@Edge function runs on every viewer request at CloudFront. It reads the session token in the URL and mixes segments from the A and B variants. This lesson sets it up by hand in the AWS console; a CDK sample is also available if you prefer code.

1. Create the IAM role

Create an IAM role for the function. Grant it the Lambda and CloudFront permissions listed in the guide, plus CloudWatch Logs access. Then edit the trust relationship so both Lambda and Lambda@Edge can assume the role.

2. Create the Lambda@Edge function

  1. Open Lambda and make sure the region is N. Virginia (us-east-1). Lambda@Edge functions can only be created there. If you create the function elsewhere, you have to delete it and start over.
  2. Enter a function name, choose Node.js 22.x, and keep the x86_64 architecture.
  3. Under Additional settings, turn on Custom execution role, choose the role you just created, and click Create function.

Your S3 bucket can stay in another region (this tutorial keeps it in Oregon, us-west-2). Only the function must be in us-east-1.

3. Upload the embedder code

Choose Update, then Update from a .zip file, and select the CloudFront embedder sample from the DoveRunner sample download page.

4. Configure config.json

Key What to set
aesKey Your DoveRunner site key
type directory prefix when A and B are in separate 0/ and 1/ folders, as Transcoding & Packaging output is. If both variants share one folder and the B files have a b prefix, use the unlabeled A variant type instead.
availableInterval How many minutes a timestamp stays valid. 0 skips the check, which is fine for a demo.
prefixFolder The folder your packaged content lives under. For Transcoding & Packaging output, wm-contents.

5. Deploy and publish a version

Deploy the changes, then publish a new version. Lambda@Edge needs a published version, not the unpublished draft. Copy the version's ARN from the upper right corner.

6. Create the CloudFront distribution

  1. Open CloudFront and create a distribution. This demo chooses the Pay as you go plan.
  2. Name the distribution and, for the origin, choose the S3 bucket where your packaging job wrote its output.
  3. Your output bucket is private, so keep Allow private S3 bucket access to CloudFront checked. CloudFront creates an origin access control and updates the bucket policy for you. Without it, every request returns access denied.
  4. On the security step, this demo does not enable WAF protections, which are billed separately. Then create the distribution.

7. Attach the function on Viewer request

Open the distribution's Behaviors tab, select the default behavior, and click Edit. Under function associations, set Viewer request to Lambda@Edge, paste the function ARN you copied, and save.

Wait until Last modified shows a date instead of Deploying, then note the distribution's domain name. You need it in Part 2.

Part 2. Generate a session URL with the Session Manager API

Your service calls the Session Manager API with the viewer's information. It returns a mixed-content URL that carries the playback session, and that URL is what the player requests from CloudFront.

Authentication

You can authenticate with an encrypted pallycon-apidata parameter or a JWT bearer token. This lesson uses pallycon-apidata. Keep wmt_type at its default, AES, for CloudFront. JWT is for Akamai and Fastly.

Request parameters

Field Value
domain Your CloudFront domain
output_path The Output Directory Path you entered when you requested watermark packaging
cid The content ID you entered for the packaging job
streaming_format dash or hls
forensic_mark The session data to embed, such as a user ID or device information, up to 254 bytes
wmt_type AES
prefix_folder wm-contents for content packaged by Transcoding & Packaging

If the mark exceeds 254 bytes, the API returns error A1916. A wrong request hash returns A1007.

How the request is built

  1. Encrypt the JSON request data with your site key using AES-256 CBC.
  2. Hash the access key, site ID, encrypted data, and timestamp with SHA-256.
  3. Wrap data, timestamp, and hash in JSON and base64-encode it as pallycon-apidata.

You can write this in code (Python and Java samples are available). For this quickstart, let the Lab Playground do it.

Build the request in the Lab Playground

  1. Open FWM Session Tools in the Lab Playground and choose the Session URL API.
  2. Enter your site ID, site key, and access key.
  3. Fill in the request data: your CloudFront domain, the output path lab-contents, the content ID, and the prefix folder wm-contents.
  4. Enter a forensic mark, pick DASH or HLS, keep the token type AES, and click Build request.
  5. Open the request URL. The response contains the session URL for watermarked playback.

Anatomy of the session URL

The URL holds your CloudFront domain, the prefix folder, an encrypted payload with the forensic mark, then the same output path, content ID, and format you already know. When the player requests it, the embedder decodes the payload and mixes segments from the A and B variants.

Play it

Open the DRM Playback Tester in the Lab Playground and paste the session URL as the manifest, with your license URL and token. Issue the token for the DRM type shown in the tester's DRM badge.

Watermark embedding does not depend on DRM, and the session URL works the same way either way. This content is DRM-protected, so the player still needs a license. Each request with a different forensic mark produces a different session, and a uniquely watermarked stream.

Recap

  • The CloudFront embedder sits in front of your content and mixes A/B segments per session.
  • The Session Manager API creates a unique session URL for each viewer.
  • Next, learn how to detect the watermark from a leaked copy.

See the Watermark Embedding guide for other embedding methods and details.