Extended manifest format
The extended manifest format reference. Defense designers and tool authors should read this first.
Overview
An extended manifest is a JSON file that wraps a standard DASH MPD with a per-stream defense plan. It is the way defenses are expressed in Dodge: a single extended manifest embeds one video's MPD and describes which representations from that MPD are defended, and the specific defense plan for each representation.
Defense plans consist of arrays of cycles, which are Dodge's generalization of segments. A cycle can be a full or partial segment download. Its contents may be discarded immediately (padding); otherwise, they are stored in an intermediate buffer until a cycle is encountered where a buffer directive is explicitly set.
An MPD on its own plays as standard DASH. An MPD plus its extended manifest plays as Dodge-defended DASH. MPDs can be embedded as is, without modification, in extended manifests; the extended manifest simply adds a layer the player consults at fetch time.
Basic example
{
"start": {
"mpd": "<MPD xmlns='urn:mpeg:dash:schema:mpd:2011' ...>",
"base_uri": "https://example.com/segments/"
},
"streams": [
{
"label": "video_1000k",
"period": 0,
"init": [
{ "range": "0-449" },
{ "range": "450-704", "buffer": true }
],
"data": [
{ "index": 0, "range": "0-391827" },
{ "index": 0, "range": "366413-758240" },
{ "index": 0, "range": "366413-758240", "buffer": true },
{ "index": 1, "range": "0-391827" },
{ "index": 5, "range": "0-43999", "padding": true }
]
}
]
} Top-level fields
start
mpd(string, required) — the original MPD XML, embedded as a string. Dynamic (live) MPDs are rejected.base_uri(string, required) — the segment server's base URI, used to resolve relative URLs in the MPD.
streams[]
An array of one or more stream entries. Each entry describes a defense plan for one representation, optionally scoped to a period.
label(string, required) — the representation ID this stream defends. Whether it actually corresponds to a representation in the MPD is checked at request time, not at manifest load.period(non-negative integer, optional) — scopes the entry to a specific period in multi-period MPDs. When absent, the entry matches any period. Multiple stream entries may share the samelabelwith differentperiodvalues.init[](array of init cycles, optional)data[](array of data cycles, optional)
At least one of init and data must be non-empty. Either can be omitted entirely (e.g., a stream with only init cycles, such as non-fragmented text tracks; or only data cycles, in the case of self-initializing streams).
Cycles
A cycle is one entry in an init or data array. Each cycle is a single download the player will perform; the cycle array as a whole determines the wire shape.
Common fields
range(string, optional) — the byte range to fetch, of the form"start-end". Either bound may be omitted:"-855"means "from the start through byte 855", and"44-"means "from byte 44 to end of resource". When the field is absent entirely, the cycle uses the segment's full extent.padding(boolean, optional) — see below. Allowed on both init and data cycles.buffer(boolean or array, optional) — see below. The array form is allowed only on data cycles.quality(string or non-negative integer, optional) — see below.
Data cycle-only field
index(non-negative integer, required) — which segment in the representation this cycle downloads.
Cycle directives
buffer
Marks a flush point. The player accumulates cycles in an intermediate buffer and assembles them into playable media at each buffer cycle.
Two forms:
buffer: true— flush every pending segment downloaded since the last flush.buffer: [idx1, idx2, …]— selective flush; only assemble the listed segment indices, leaving any others pending for a later flush. Every index in the array must have already appeared in an earlier cycle, or the manifest is rejected.
The array form lets a defense interleave segments from different playback positions and flush them in groups, instead of in strict download order. It should be used sparingly.
padding
Marks the cycle as padding traffic. The bytes are fetched to shape the wire pattern but discarded immediately and never assembled into playable media.
quality
Fetches the cycle from a different representation in the same adaptation set, useful for concealing the size of a large segment by fetching it at a lower quality. Accepted values:
- A string matching the target representation's
id(e.g.,"quality": "video_500k"). - A non-negative integer, interpreted as an index into the adaptation set's representation list.
Numeric strings (e.g., "3") are kept as strings and treated as representation IDs; a warning is logged at manifest load time to flag the ambiguity. Use a JSON number if an index is intended.
On init cycles, quality pre-fetches the alternate representation's init segment so that it can be cached for later use in quality override data cycles. The defense designer must include init cycles with quality for every alternate representation used in data cycles.
What's validated at manifest load
The defense registry checks structural correctness only:
start.mpdandstart.base_uriare present and string-typed; the MPD is not dynamic.streamsis present; each stream has a stringlabel, a validperiodif present, and at least one non-empty cycle array (initordata).- Each cycle's
range(if present) parses as a well-formed byte range. - Each data cycle's
indexis a non-negative integer. buffer,padding, andqualityhave valid types.- Selective
bufferarrays only reference segment indices that have appeared earlier in the cycle stream.
What the registry does not check: that label resolves to a real representation in the MPD, that index resolves to a real segment, or that a quality override resolves to an existing representation. Those resolutions happen later, at request time. If a referenced representation or segment is missing, the player stalls rather than skipping or falling back — preserving the defense traffic shape.
Strict mode
The dash.js module's dodge.strictMode setting controls how aggressively undefended traffic is blocked when a defense is active. The four levels:
'representation'(default) — block undefended representations when an extended manifest is active. Plain DASH still works when an MPD is loaded instead of an extended manifest.'manifest'— also refuse to play when the source URL is not an extended manifest. A defense must be used to play.'max'— also reject extended manifests with thumbnail tracks, non-fragmented text, or XLink references; warn about retries, background UTC sync, and content steering settings that could leak signal outside the defense.false— disable enforcement (fall back to vanilla DASH on a per-representation basis; not recommended).
In any mode other than false, embedded MPDs containing DRM, CMCD telemetry, content steering, or DVB reporting trigger informational warnings — these features may not interact safely with traffic analysis defenses and the defense designer should verify their behavior in context. However, we assume that they are unlikely enough to pose a traffic analysis threat that they are not disabled by default; they are important in the streaming ecosystem and must be available to certain content providers.