CML
    Preparing search index...

    CMCD Validation Guide

    The @svta/cml-cmcd library provides a set of composable validation functions for verifying that CMCD payloads conform to the CTA-5004 (v1) and CTA-5004-A (v2) specifications. These are useful for validating payloads on the receiving end — for example, in an analytics server that collects CMCD event reports, or in a CDN log processor that inspects CMCD request data.

    There are three main validation functions, each targeting a different aspect of CMCD compliance:

    Function Purpose
    validateCmcd Orchestrator — runs key, value, and structure checks
    validateCmcdRequest Validates a Request or HttpRequest as request-mode data
    validateCmcdEvents Validates a multi-line text/cmcd body as event-mode data

    All validators return a CmcdValidationResult:

    type CmcdValidationResult = {
    valid: boolean; // true if zero errors (warnings are OK)
    issues: CmcdValidationIssue[];
    };

    type CmcdValidationIssue = {
    key?: string;
    message: string;
    severity: CmcdValidationSeverity; // 'error' | 'warning'
    };

    A common use case is validating CMCD v2 event reports received via POST. The payload is typically a text/cmcd body containing newline-separated CMCD-encoded strings, or application/json.

    The validateCmcdEvents function accepts a raw CMCD string and validates it as an event-mode payload. It supports multi-line text/cmcd bodies directly — each non-empty line is validated independently and the results are merged. An empty payload (no non-empty lines) is treated as an error.

    import { validateCmcdEvents } from "@svta/cml-cmcd";

    // Validate a complete text/cmcd POST body
    const body = `e=ps,sid="session-1",ts=1700000000000,sta=p,v=2
    e=t,sid="session-1",ts=1700000001000,bl=(5000),v=2`;

    const result = validateCmcdEvents(body);

    if (!result.valid) {
    console.error("Invalid CMCD event:", result.issues);
    }

    A single-line string works as well:

    import { validateCmcdEvents } from "@svta/cml-cmcd";

    const result = validateCmcdEvents(
    'e=ps,sid="session-1",ts=1700000000000,sta=p,v=2',
    );

    The validateCmcdEvents function is designed to validate multi-line text/cmcd bodies directly. However, if you need to validate a single-line string, you can decode the CMCD string and validate the data manually (this is what validateCmcdRequest does internally).

    import { decodeCmcd, validateCmcd } from "@svta/cml-cmcd";

    // Simulated POST body (text/cmcd)
    const body = `e=ps,sid="session-1",ts=1700000000000,sta=p,v=2
    e=t,sid="session-1",ts=1700000001000,bl=(5000),v=2`;

    // Parse each line and validate
    const lines = body.split("\n");

    for (const line of lines) {
    const data = decodeCmcd(line);
    const result = validateCmcd(data, { reportingMode: "event" });

    if (!result.valid) {
    console.error("Invalid CMCD event:", result.issues);
    }
    }

    In request mode, CMCD data is attached to segment requests via query parameters or HTTP headers. The validator ensures that event-only and response-only keys are not present.

    The validateCmcdRequest function accepts a Request object or an HttpRequest object from @svta/cml-utils. It checks for CMCD headers first — if any CMCD header shards are found, it delegates to validateCmcdHeaders for shard-placement verification. Otherwise, it extracts the CMCD query parameter from the URL.

    import { validateCmcdRequest } from "@svta/cml-cmcd";

    // From a Request with CMCD headers
    const request = new Request("https://cdn.example.com/seg.mp4", {
    headers: {
    "CMCD-Object": "br=5000,d=4000,ot=v",
    "CMCD-Request": "bl=25000",
    "CMCD-Session": 'sid="abc"',
    },
    });
    const headerResult = validateCmcdRequest(request);

    // From a Request with CMCD in the query parameter
    const queryRequest = new Request(
    "https://cdn.example.com/seg.mp4?CMCD=br%3D5000%2Cbl%3D25000",
    );
    const queryResult = validateCmcdRequest(queryRequest);

    // From an HttpRequest object
    const httpRequestResult = validateCmcdRequest({
    url: "https://cdn.example.com/seg.mp4?CMCD=br%3D5000%2Cbl%3D25000",
    });

    The validateCmcdRequest function is designed to validate the CMCD query parameter from the URL. However, if you need to validate the CMCD query parameter manually, you can extract it from the URL and validate the data using the validateCmcd function.

    import { fromCmcdQuery, validateCmcd } from "@svta/cml-cmcd";

    // Extract CMCD from a request URL's query string
    const url = new URL(
    "https://cdn.example.com/seg.mp4?CMCD=br%3D5000%2Cbl%3D25000%2Cd%3D4000%2Cot%3Dv%2Csid%3D%22abc%22",
    );

    const data = fromCmcdQuery(url.searchParams);
    const result = validateCmcd(data, { reportingMode: "request" });

    if (!result.valid) {
    console.error("Invalid CMCD request data:", result.issues);
    }

    When CMCD is transmitted via HTTP headers, you can validate the headers manually using the validateCmcdHeaders function.

    import { validateCmcdHeaders } from "@svta/cml-cmcd";

    // Pass raw header strings directly — decoding is handled internally.
    // Request mode validation is applied automatically since headers are
    // only used in request mode.
    const result = validateCmcdHeaders({
    "CMCD-Object": "br=5000,d=4000,ot=v",
    "CMCD-Request": "bl=25000",
    "CMCD-Session": 'sid="abc",sf=d,st=v',
    });

    if (!result.valid) {
    // Issues may include shard placement errors and/or payload validation errors
    console.error("Validation issues:", result.issues);
    }

    The validators automatically detect the CMCD version from the v key in the payload. If v is absent, version 1 is assumed per the spec. You can override this with the version option.

    import { validateCmcd } from "@svta/cml-cmcd";

    // Version inferred from payload (v=2)
    const v2Result = validateCmcd({ v: 2, br: [5000], sid: "abc" });

    // Version explicitly set via options
    const v1Result = validateCmcd({ br: 5000, sid: "abc" }, { version: 1 });
    • Key validation: v2-only keys (e.g., sta, ec, ab) are rejected when validating as v1
    • Type validation: Some keys have different types between versions. For example, bl is an integer in v1 but an inner list (array) in v2
    • Version key: v2 payloads must include the v key; v1 payloads should omit it

    A payload is considered valid if it contains zero errors. Warnings indicate spec recommendations that are not strict violations.

    import { validateCmcd, CMCD_VALIDATION_SEVERITY_ERROR } from "@svta/cml-cmcd";

    const result = validateCmcd({ v: 2, bl: [150], sid: "abc" });

    // Separate errors from warnings
    const errors = result.issues.filter(
    (i) => i.severity === CMCD_VALIDATION_SEVERITY_ERROR,
    );
    const warnings = result.issues.filter(
    (i) => i.severity !== CMCD_VALIDATION_SEVERITY_ERROR,
    );

    console.log(`Valid: ${result.valid}`);
    console.log(`Errors: ${errors.length}, Warnings: ${warnings.length}`);

    // bl=150 produces a warning (should be rounded to nearest 100)
    // but the payload is still valid
    import { validateCmcdEvents } from "@svta/cml-cmcd";

    function validateAndLog(body: string): boolean {
    const result = validateCmcdEvents(body);

    for (const issue of result.issues) {
    const level = issue.severity === "error" ? "ERROR" : "WARN";
    const key = issue.key ? `[${issue.key}] ` : "";
    console.log(`${level}: ${key}${issue.message}`);
    }

    return result.valid;
    }

    Custom keys (keys containing a hyphen, e.g., com.example-mykey) are recognized by all validators:

    • validateCmcdKeys — accepts custom keys without error
    • validateCmcdValues — checks that custom key values are strings with a max length of 64 characters, and that the key name contains a hyphen
    • validateCmcdHeaders — allows custom keys in any header shard
    import { validateCmcdValues } from "@svta/cml-cmcd";

    const result = validateCmcdValues({
    "com.example-debug": "enabled",
    "x-player-version": "2.1.0",
    });

    // result.valid === true