AWS Security ChangesHomeSearch

AWS mediatailor: Document new MediaTailor lifecycle hooks and per-hook input fields

Service: mediatailor · 2026-09-27 · Documentation low

File: mediatailor/latest/ug/monetization-functions-hooks.md

Summary

Expands the monetization lifecycle hooks page from two to four hooks (adding POST_ADS_RESPONSE and PRE_MANIFEST_INSERTION), documents combined execution budget/skip behavior, and replaces the input-field table with a per-hook matrix covering new camelCase session fields, adsResponse/avails structures, and inference fields.

Security assessment

This is a functional/API-surface documentation update for ad personalization hooks (timing, input fields, execution budget). Although the field table lists session attributes such as client IP, user agent, and referer, the change merely documents their availability per hook rather than addressing a vulnerability, credential handling, or access control. No CVE, mitigation, or hardening guidance is introduced.

Evidence

+  * **`POST_ADS_RESPONSE`** fires after MediaTailor receives and parses the ADS response, including resolution of Video Ad Serving Template (VAST) wrapper redirects. Use it to filter, reorder, modify, or supplement the ads that the ADS returned, before MediaTailor selects ads to insert.

Diff

diff --git a/mediatailor/latest/ug/monetization-functions-hooks.md b/mediatailor/latest/ug/monetization-functions-hooks.md
index 5c04209e9..752c0ecf8 100644
--- a//mediatailor/latest/ug/monetization-functions-hooks.md
+++ b//mediatailor/latest/ug/monetization-functions-hooks.md
@@ -15 +15 @@ A lifecycle hook defines when MediaTailor runs your function during playback. Th
-MediaTailor supports two lifecycle hooks:
+MediaTailor supports four lifecycle hooks:
@@ -20,0 +21 @@ MediaTailor supports two lifecycle hooks:
+  * **`POST_ADS_RESPONSE`** fires after MediaTailor receives and parses the ADS response, including resolution of Video Ad Serving Template (VAST) wrapper redirects. Use it to filter, reorder, modify, or supplement the ads that the ADS returned, before MediaTailor selects ads to insert.
@@ -21,0 +23 @@ MediaTailor supports two lifecycle hooks:
+  * **`PRE_MANIFEST_INSERTION`** fires at the end of ad break personalization, after ad selection, transcode checks, and fill policy, immediately before MediaTailor writes ads into the manifest. Use it to inspect or modify the final ad set, including injecting additional ads into underfilled ad breaks.
@@ -24 +26,11 @@ MediaTailor supports two lifecycle hooks:
-The key difference is timing: `PRE_SESSION_INITIALIZATION` runs once and sets up data that persists for the entire session, while `PRE_ADS_REQUEST` runs repeatedly and can tailor each ADS request to the specific ad break.
+
+
+The hooks differ in timing and scope. `PRE_SESSION_INITIALIZATION` runs once and sets up data that persists for the entire session. `PRE_ADS_REQUEST` and `POST_ADS_RESPONSE` run around each ADS interaction. `PRE_ADS_REQUEST` shapes the outgoing request, and `POST_ADS_RESPONSE` acts on the parsed response before ad selection. `PRE_MANIFEST_INSERTION` runs after selection is complete and sees the final ad set for all newly personalized ad breaks in a single invocation.
+
+###### Important
+
+The `PRE_ADS_REQUEST`, `POST_ADS_RESPONSE`, and `PRE_MANIFEST_INSERTION` hooks share a combined execution budget of 2,000 ms for a single request. This budget is in addition to each hook's own 2,000 ms timeout. A hook's effective timeout is the smaller of its own timeout and the remaining budget. Time spent by an earlier hook reduces the time available to later hooks in the same request. If the remaining budget is exhausted before a hook starts, MediaTailor skips that hook and continues processing the request without it. `PRE_SESSION_INITIALIZATION` runs during session initialization and is not part of the combined budget. For more information, see [Limits](./monetization-functions-limits.html).
+
+###### Note
+
+In this documentation, an ad break is also called an _avail_. Input field names (such as `avail.availId` and `avails.avails`) and CloudWatch metrics use the `avail` form.
@@ -28,39 +40,102 @@ The key difference is timing: `PRE_SESSION_INITIALIZATION` runs once and sets up
-Field | Type | PRE_SESSION_INITIALIZATION | PRE_ADS_REQUEST  
----|---|---|---  
-`session.id` | Long | ✓ | ✓  
-`session.uuid` | String | ✓ | ✓  
-`session.client_ip` | String | ✓ | ✓  
-`session.user_agent` | String | ✓ | ✓  
-`session.referer`* | String | ✓ | ✓  
-`session.avail_duration_secs` | Long | ✗ | ✓  
-`session.avail_duration_ms` | Long | ✗ | ✓  
-`player_params.*` | String | ✓ | ✓  
-`event.id` | String | ✓ | ✓  
-`event.hook` | String | ✓ | ✓  
-`event.timestamp` | String | ✓ | ✓  
-`avail.index` | Int | ✗ | ✓  
-`avail.random` | Long | ✗ | ✓  
-`avail.source_content_time_epoch_ms` | Long | ✗ | ✓  
-`scte.event_id` | Int | ✗ | ✓  
-`scte.avail_num` | Int | ✗ | ✓  
-`scte.segmentation_event_id` | Int | ✗ | ✓  
-`scte.segmentation_type_id` | Int | ✗ | ✓  
-`scte.segmentation_upid` | String | ✗ | ✓  
-`scte.segmentation_upid.assetId` | String | ✗ | ✓  
-`scte.segmentation_upid.cueData.key` | String | ✗ | ✓  
-`scte.segmentation_upid.cueData.value` | String | ✗ | ✓  
-`scte.unique_program_id` | Int | ✗ | ✓  
-`scte.archive_allowed_flag` | Boolean | ✗ | ✓  
-`scte.delivery_not_restricted_flag` | Boolean | ✗ | ✓  
-`scte.device_restrictions` | Int | ✗ | ✓  
-`scte.no_regional_blackout_flag` | Boolean | ✗ | ✓  
-`scte.segment_num` | Int | ✗ | ✓  
-`scte.segments_expected` | Int | ✗ | ✓  
-`scte.sub_segment_num` | Int | ✗ | ✓  
-`scte.sub_segments_expected` | Int | ✗ | ✓  
-`scte.avails_expected` | Long | ✗ | ✓  
-`asset.*` | String | ✗ | ✓  
-`adsRequest.url` | String | ✗ | ✓  
-`adsRequest.method` | String | ✗ | ✓  
-`adsRequest.headers.<key>` | String | ✗ | ✓  
-`adsRequest.body` | String | ✗ | ✓  
+The following table lists the input fields available at each lifecycle hook. In the Field column, `parent[].child` notation indicates a field of each element in the `parent` array.
+
+###### Note
+
+The `POST_ADS_RESPONSE` and `PRE_MANIFEST_INSERTION` hooks expose session fields in camelCase (for example, `session.clientIp`), while the first two hooks use snake_case (for example, `session.client_ip`). Player parameters are available through the `player_params` namespace at the first two hooks and as the `session.playerParams` object at the other two.
+
+Field | Type | PRE_SESSION_INITIALIZATION | PRE_ADS_REQUEST | POST_ADS_RESPONSE | PRE_MANIFEST_INSERTION  
+---|---|---|---|---|---  
+`session.id`| Long| ✓| ✓| ✓| ✓  
+`session.uuid`| String| ✓| ✓| ✓| ✓  
+`session.client_ip`| String| ✓| ✓| ✗| ✗  
+`session.clientIp`| String| ✗| ✗| ✓| ✓  
+`session.user_agent`| String| ✓| ✓| ✗| ✗  
+`session.userAgent`| String| ✗| ✗| ✓| ✓  
+`session.referer*`| String| ✓| ✓| ✗| ✗  
+`session.avail_duration_secs`| Long| ✗| ✓| ✗| ✗  
+`session.avail_duration_ms`| Long| ✗| ✓| ✗| ✗  
+`session.streamingProtocol`| String| ✗| ✗| ✓| ✓  
+`session.playerParams`| Object| ✗| ✗| ✓| ✓  
+`player_params.*`| String| ✓| ✓| ✗| ✗  
+`event.id`| String| ✓| ✓| ✓| ✓  
+`event.hook`| String| ✓| ✓| ✓| ✓  
+`event.timestamp`| String| ✓| ✓| ✓| ✓  
+`avail.index`| Int| ✗| ✓| ✗| ✗  
+`avail.random`| Long| ✗| ✓| ✗| ✗  
+`avail.source_content_time_epoch_ms`| Long| ✗| ✓| ✗| ✗  
+`avail.availId†`| String| ✗| ✗| ✓| ✗  
+`avail.durationSeconds†`| Number| ✗| ✗| ✓| ✗  
+`avail.startTime†`| String| ✗| ✗| ✓| ✗  
+`scte.event_id`| Int| ✗| ✓| ✗| ✗  
+`scte.avail_num`| Int| ✗| ✓| ✗| ✗  
+`scte.segmentation_event_id`| Int| ✗| ✓| ✗| ✗  
+`scte.segmentation_type_id`| Int| ✗| ✓| ✗| ✗  
+`scte.segmentation_upid`| String| ✗| ✓| ✗| ✗  
+`scte.segmentation_upid.assetId`| String| ✗| ✓| ✗| ✗  
+`scte.segmentation_upid.cueData.key`| String| ✗| ✓| ✗| ✗  
+`scte.segmentation_upid.cueData.value`| String| ✗| ✓| ✗| ✗  
+`scte.unique_program_id`| Int| ✗| ✓| ✗| ✗  
+`scte.archive_allowed_flag`| Boolean| ✗| ✓| ✗| ✗  
+`scte.delivery_not_restricted_flag`| Boolean| ✗| ✓| ✗| ✗  
+`scte.device_restrictions`| Int| ✗| ✓| ✗| ✗  
+`scte.no_regional_blackout_flag`| Boolean| ✗| ✓| ✗| ✗  
+`scte.segment_num`| Int| ✗| ✓| ✗| ✗  
+`scte.segments_expected`| Int| ✗| ✓| ✗| ✗  
+`scte.sub_segment_num`| Int| ✗| ✓| ✗| ✗  
+`scte.sub_segments_expected`| Int| ✗| ✓| ✗| ✗  
+`scte.avails_expected`| Long| ✗| ✓| ✗| ✗  
+`asset.*`| String| ✗| ✓| ✗| ✗  
+`inference.enriched`| Boolean| ✗| ✓| ✗| ✗  
+`inference.feedId`| String| ✗| ✓| ✗| ✗  
+`inference.dataEndpoint`| String| ✗| ✓| ✗| ✗  
+`inference.pts`| Long| ✗| ✓| ✗| ✗  
+`inference.timescale`| Long| ✗| ✓| ✗| ✗  
+`inference.region`| String| ✗| ✓| ✗| ✗  
+`inference.previousBreakEndPts`| Long| ✗| ✓| ✗| ✗  
+`inference.parseError`| Boolean| ✗| ✓| ✗| ✗  
+`adsRequest.url`| String| ✗| ✓| ✓| ✗  
+`adsRequest.method`| String| ✗| ✓| ✓| ✗  
+`adsRequest.headers.<key>`| String| ✗| ✓| ✓| ✗  
+`adsRequest.body`| String| ✗| ✓| ✗| ✗  
+`adsResponse.responseType`| String| ✗| ✗| ✓| ✗  
+`adsResponse.ads`| Array| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].adId‡`| String| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].durationSeconds`| Number| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].adSystem`| String| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].adTitle`| String| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].creativeId`| String| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].sequence`| Int| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].mediaFiles`| Array| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].mediaFiles[].url`| String| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].mediaFiles[].mimeType`| String| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].mediaFiles[].width`| Int| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].mediaFiles[].height`| Int| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].mediaFiles[].bitrate`| Int| ✗| ✗| ✓| ✗  
+`adsResponse.ads[].trackingEvents.<eventType>`| Array of String| ✗| ✗| ✓| ✗  
+`avails.avails`| Array| ✗| ✗| ✗| ✓  
+`avails.avails[].availId`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].durationSeconds`| Number| ✗| ✗| ✗| ✓  
+`avails.avails[].startTime`| Number| ✗| ✗| ✗| ✓  
+`avails.avails[].mediaProtocol`| String (`HLS` | `DASH`)| ✗| ✗| ✗| ✓  
+`avails.avails[].streamingMode`| String (`LIVE` | `VOD`)| ✗| ✗| ✗| ✓  
+`avails.avails[].fillDurationSeconds`| Number| ✗| ✗| ✗| ✓  
+`avails.avails[].fillRate`| Number (0–1)| ✗| ✗| ✗| ✓  
+`avails.avails[].mutable`| Boolean| ✗| ✗| ✗| ✓  
+`avails.avails[].ads`| Array| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].adId§`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].vastAdId`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].creativeId`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].insertionUuid`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].sequenceInAvail`| Int| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].durationSeconds`| Number| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].adSystem¶`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].adTitle¶`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].mediaUrl`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].trackingEvents.<eventType>`| Array of String| ✗| ✗| ✗| ✓  
+`avails.avails[].ads[].mediaFiles`| Array| ✗| ✗| ✗| ✓  
+`avails.avails[].skippedAds`| Array| ✗| ✗| ✗| ✓  
+`avails.avails[].skippedAds[].adId`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].skippedAds[].vastAdId`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].skippedAds[].durationSeconds`| Number| ✗| ✗| ✗| ✓  
+`avails.avails[].skippedAds[].creativeUrl`| String| ✗| ✗| ✗| ✓  
+`avails.avails[].skippedAds[].reason`| String| ✗| ✗| ✗| ✓  
@@ -69,0 +145,8 @@ Field | Type | PRE_SESSION_INITIALIZATION | PRE_ADS_REQUEST
+† The `avail` namespace is present only when the ADS response applies to a single ad break. It is not present for multi-break (VMAP) responses or prefetched responses. Use `$exists(avail)` to check before accessing.
+
+‡ At `POST_ADS_RESPONSE`, `adId` is the `id` attribute of the VAST `<Ad>` element.
+
+§ At `PRE_MANIFEST_INSERTION`, `adId` is an internal placement identifier. It is stable for an ad within its ad break, but it is not the VAST ad ID and is not comparable across ad breaks or across hooks. For identity checks that span ad breaks or hooks, use `vastAdId` (the `id` attribute of the VAST `<Ad>` element) or `creativeId`.
+
+¶ On DASH VOD streams, `adTitle` and `adSystem` are `null` at this hook. Use `vastAdId` or `creativeId` in predicates there.
+