Automatic QC Tests
Automatic QC is configured as a list of tests in the qc object of a Job Description. Each test is one rule (for example, Max Characters Per Line) with its own parameters, a failure level, and a threshold. QC never changes your captions. It produces a report and an overall qc_status for the job.
{
"qc": {
"stage": "pre",
"tests": [
{ "id": "maxCharsPerLine", "max": 42, "level": "critical", "threshold": 0 },
{ "id": "maxLinesPerEvent", "max": 2, "level": "critical", "threshold": 0 },
{ "id": "frameGap", "min": 2, "minTolerance": 0, "maxTolerance": 6, "level": "info", "threshold": 0 },
{ "id": "sequentialTiming", "level": "critical", "threshold": 0 },
{ "id": "xmlEntities", "level": "critical", "threshold": 0 }
]
}
}
Test properties
| Property | Required | Description |
|---|---|---|
id | Yes* | The test to run (see the catalog). *You can use name instead: the display name (for example "Max Characters Per Line") is matched case-insensitively. |
level | No | critical, warn, or info. warning is also accepted. Defaults to the test's default level. |
threshold | No | Number of errors needed before the test changes the job status. 0 and 1 both mean the first error counts; 3 means three or more errors. Default 0. |
enabled | No | Set to false to keep a test in the config without running it. Default true. |
| parameters | No | Test-specific settings such as max, min, unit, or values. Missing parameters use the defaults listed below. |
You can list a test more than once with different settings. For example, add maxCps at 17 as warn and again at 20 as critical. The job is rejected when it is submitted if a test ID is unknown, a level is invalid, or a threshold is negative. The API returns HTTP 400 and the CLI exits with a non-zero code.
QC status
A test is triggered when its error count reaches max(threshold, 1). The job's qc_status is then:
qc_status | When |
|---|---|
fail | At least one triggered critical test |
warn | No triggered critical tests, and at least one triggered warn test |
pass | Anything else. info tests are reported but never change the status. |
qc_errors is the total number of errors from every test, including info tests. A QC failure never stops a Convert job from producing its output file. The CLI can optionally exit with code 2 on fail; see --qc_exit_code.
Stages
qc.stage controls when content tests run:
pre(the default) checks the captions as decoded from the source.postchecks them after all filters, right before encoding, at the target frame rate.
Technical tests (the XML checks) and source-order tests (sequentialTiming) always check the source file, whatever the stage.
QC report
The API response, the job record, and the webhook all include qc_status and qc_errors. The full report is returned as qcReport:
{
"version": 2,
"info": { "stage": "pre", "source_profile": "dfxp", "tc_start": "00:00:01:00" },
"summary": { "qc_status": "fail", "qc_errors": 3, "critical": 1, "warn": 1, "info": 0 },
"tests": [
{ "index": 0, "id": "maxCharsPerLine", "name": "Max Characters Per Line", "level": "critical", "threshold": 0, "scope": "content", "ran": true, "errorCount": 2, "triggered": true }
],
"results": {
"content": [
{ "testId": "maxCharsPerLine", "testName": "Max Characters Per Line", "name": "Character Length Error", "level": "critical", "details": "Event 4 has a line with a character length of 47.", "timecodeStart": "00:00:12:05", "timecodeEnd": "00:00:14:00", "start": 12.2, "end": 14, "eventId": 4, "text": "This line is longer than the..." }
],
"technical": [
{ "testId": "xmlEntities", "name": "XML Entity Error", "level": "critical", "details": "Line 12: unescaped \"&\" must be written as &.", "line": 12, "eventId": null }
]
}
}
- Summary counts:
summary.critical,summary.warn, andsummary.infocount triggered tests at each level, not errors. - Skipped tests: in
tests[],skippedexplains why a test did not apply, for example an XML test on an SRT source. - Test errors:
erroris set on a test that could not run. A test that errors counts as triggered. - Event groups: in post-processing jobs with more than one event group, each content error also has an
eventGroupindex.
Test catalog
Text
| ID | Name | Parameters (default) | Default level | Description |
|---|---|---|---|---|
minCharsPerLine | Min Characters Per Line | min (1) | critical | Flags events that contain a line shorter than the minimum number of characters. |
maxCharsPerLine | Max Characters Per Line | max (42) | critical | Flags events that contain a line longer than the maximum number of characters. |
minLinesPerEvent | Min Lines Per Event | min (1) | critical | Flags events with fewer text lines than the minimum. |
maxLinesPerEvent | Max Lines Per Event | max (2) | critical | Flags events with more text lines than the maximum. |
minWordsPerLine | Min Words Per Line | min (1) | warn | Flags events that contain a line with fewer words than the minimum. |
maxWordsPerLine | Max Words Per Line | max (12) | warn | Flags events that contain a line with more words than the maximum. |
illegalChars608 | Illegal 608 Characters | — | critical | Flags characters that cannot be encoded as CEA-608 closed captions. |
illegalCharsNetflix | Illegal Netflix Characters | — | critical | Flags characters outside the Netflix supported glyph list. |
whiteSpace | Leading, Trailing or Double Spaces | — | warn | Flags lines that start or end with a space, or contain two or more spaces in a row. |
emptyEvent | Empty Event | — | warn | Flags timed events that contain no text. Note: formats that use blank events as clears (e.g. SCC) will report those clears. |
Timing
| ID | Name | Parameters (default) | Default level | Description |
|---|---|---|---|---|
minDuration | Min Event Duration | min (0.833)unit ("seconds"; frames / seconds) | critical | Flags events shorter than the minimum duration. |
maxDuration | Max Event Duration | max (7)unit ("seconds"; frames / seconds) | critical | Flags events longer than the maximum duration. |
minCps | Min Characters Per Second | min (1)countSpaces (true) | info | Flags events whose reading speed is below the minimum characters per second. |
maxCps | Max Characters Per Second | max (20)countSpaces (true) | critical | Flags events whose reading speed is above the maximum characters per second. |
minWpm | Min Words Per Minute | min (1) | info | Flags events whose reading speed is below the minimum words per minute. |
maxWpm | Max Words Per Minute | max (200) | warn | Flags events whose reading speed is above the maximum words per minute. |
frameGap | Frame Gap | min (2 frames)minTolerance (0 frames)maxTolerance (11 frames) | warn | When the gap between two events falls between the min and max tolerance (in frames), it must be exactly the required gap. Gaps outside the tolerance window are ignored. |
minGap | Min Gap Between Events | min (2 frames) | critical | Flags consecutive events separated by fewer frames than the minimum. |
maxGap | Max Gap Between Events | max (100 frames) | info | Flags consecutive events separated by more frames than the maximum. |
overlap | Overlapping Events | — | critical | Flags events that start before the previous event ends. |
sequentialTiming | Sequential Timing | — | critical | Flags events that start earlier than the event before them in the source file (captions out of order). Always checks the source file order, whatever the QC stage. |
zeroOrNegativeDuration | Zero or Negative Duration | — | critical | Flags events whose end time is equal to or earlier than their start time. |
startTimeRange | Start Time Range | min ("00:00:00:00")max ("01:00:00:00") | warn | Flags events that start before the min timecode or after the max timecode. |
Formatting
| ID | Name | Parameters (default) | Default level | Description |
|---|---|---|---|---|
boldFormatting | Bold Formatting | — | info | Flags events that contain bolded text. |
italicsFormatting | Italics Formatting | — | info | Flags events that contain italics text. |
underlineFormatting | Underline Formatting | — | info | Flags events that contain underlined text. |
Technical (XML)
| ID | Name | Parameters (default) | Default level | Description |
|---|---|---|---|---|
xmlWellFormed | XML Well-Formed | — | critical | Validates that an XML-based source file (TTML, DFXP, IMSC, etc.) is well-formed. |
xmlEntities | XML Entity Escaping | — | critical | Flags unescaped ampersands and less-than signs, and entities that are not defined in XML (e.g. ). |
frameRate | Frame Rate | frameRate ("23.976"; 24 / 25 / 30 / 50 / 60 / 23.976 / 23.98 / 29.97 / 59.94) | critical | Checks ttp:frameRate and ttp:frameRateMultiplier against the expected media frame rate. |
timeBase | Time Base | values (["media"]) | critical | Checks ttp:timeBase against the allowed values. |
tcFormat | Timecode Format | values (["smpte"]) | critical | Checks that every begin/end value uses an allowed time expression format (smpte, tcMs, seconds, milliseconds, frames, ticks). |
fontSizeUnit | Font Size Unit | values (["%"]) | critical | Checks that every font size unit in the file is one of the allowed values. |
fontSizeRange | Font Size Range | min (80)max (100) | critical | Checks that every font size is within the min and max values. |
fontWeight | Font Weight | values (["normal"]) | critical | Checks that every font weight in the file is one of the allowed values. |
fontStyle | Font Style | values (["normal"]) | critical | Checks that every font style in the file is one of the allowed values. |
fontFamily | Font Family | values (["proportionalSansSerif"]) | critical | Checks that every font family in the file is one of the allowed values. |
textOutlineColor | Text Outline Color | values (["#101010"]) | critical | Checks that every text outline color in the file is one of the allowed values. |
textOutlineSize | Text Outline Size | values ([3]) | critical | Checks that every text outline size in the file is one of the allowed values. |
textOutlineSizeUnit | Text Outline Size Unit | values (["%"]) | critical | Checks that every text outline unit in the file is one of the allowed values. |
textColor | Text Color | values (["#ebebeb"]) | critical | Checks that every font color in the file is one of the allowed values. |
backgroundColor | Background Color | values (["transparent"]) | critical | Checks that every background color in the file is one of the allowed values. |
luminanceGain | Luminance Gain | values ([1.5]) | critical | Checks that every luminance gain in the file is one of the allowed values. |
Technical tests apply to XML-based sources such as TTML, DFXP, IMSC and SMPTE-TT, and are skipped for other formats. list parameters accept an array or a comma-separated string. minDuration and maxDuration use seconds by default; set unit to frames to use frames at the stage's frame rate.
Presets
Presets are ready-made test lists. You'll find them in the Automatic QC panel of the Job Form. Apply one as a starting point, then edit any of its tests. The Netflix presets use values from the Netflix English Timed Text Style Guide and Subtitle Timing Guidelines.
Netflix English (Adult) (netflixEnglishAdult)
Netflix English subtitle and timing guidelines for adult programs (20 CPS).
| Test | Settings | Level |
|---|---|---|
maxCharsPerLine | max: 42 | critical |
maxLinesPerEvent | max: 2 | critical |
minDuration | min: 0.833, unit: "seconds" | critical |
maxDuration | max: 7, unit: "seconds" | critical |
minGap | min: 2 | critical |
frameGap | min: 2, minTolerance: 3, maxTolerance: 11 | warn |
overlap | — | critical |
sequentialTiming | — | critical |
zeroOrNegativeDuration | — | critical |
illegalCharsNetflix | — | critical |
whiteSpace | — | warn |
emptyEvent | — | warn |
xmlWellFormed | — | critical |
xmlEntities | — | critical |
maxCps | max: 20, countSpaces: true | critical |
Netflix English (Children) (netflixEnglishChildren)
Netflix English subtitle and timing guidelines for children's programs (17 CPS).
| Test | Settings | Level |
|---|---|---|
maxCharsPerLine | max: 42 | critical |
maxLinesPerEvent | max: 2 | critical |
minDuration | min: 0.833, unit: "seconds" | critical |
maxDuration | max: 7, unit: "seconds" | critical |
minGap | min: 2 | critical |
frameGap | min: 2, minTolerance: 3, maxTolerance: 11 | warn |
overlap | — | critical |
sequentialTiming | — | critical |
zeroOrNegativeDuration | — | critical |
illegalCharsNetflix | — | critical |
whiteSpace | — | warn |
emptyEvent | — | warn |
xmlWellFormed | — | critical |
xmlEntities | — | critical |
maxCps | max: 17, countSpaces: true | critical |
Broadcast 608 Captions (broadcast608)
Common CEA-608 closed caption limits: 32 characters, 4 lines, legal 608 characters and sequential timing.
| Test | Settings | Level |
|---|---|---|
maxCharsPerLine | max: 32 | critical |
maxLinesPerEvent | max: 4 | critical |
illegalChars608 | — | critical |
overlap | — | critical |
sequentialTiming | — | critical |
zeroOrNegativeDuration | — | critical |
Legacy configuration
The original qc.content / qc.technical configuration is still accepted and is converted to tests automatically. Every converted test is critical with a threshold of 0, so any error sets qc_status to fail.
| Legacy setting | Test |
|---|---|
content.minChars / maxChars | minCharsPerLine / maxCharsPerLine |
content.minLines / maxLines | minLinesPerEvent / maxLinesPerEvent |
content.minWords / maxWords | minWordsPerLine / maxWordsPerLine |
content.overlap (unless false) | overlap |
content.illegalChars608 / illegalCharsNetflix | illegalChars608 / illegalCharsNetflix |
content.minEventDurationFrames / maxEventDurationFrames | minDuration / maxDuration with unit: "seconds" (the legacy values were always compared in seconds) |
content.minCps / maxCps, minWpm / maxWpm | minCps / maxCps, minWpm / maxWpm |
content.minEventGapFrames / maxEventGapFrames | minGap / maxGap |
content.whiteSpace | whiteSpace |
content.minStartSmpte / maxStartSmpte | startTimeRange |
content.formatBold / formatItalics / formatUnderline | boldFormatting / italicsFormatting / underlineFormatting |
technical.frameRate, timeBase, tcFormat, fontSizeUnit, fontWeight, fontStyle, fontFamily | The test with the same name |
technical.fontSizeMin / fontSizeMax | fontSizeRange |
technical.textOutlineColor / textOutlineSize / textOutlineSizeUnit | The test with the same name |
technical.color / bgColor / luminanceGain | textColor / backgroundColor / luminanceGain |
Content settings are converted only when content.enabled is true. Technical settings are converted only when technical.enabled is true and technical.profile is "xml".
The conversion also corrects some legacy behavior:
- Italics and underline checks now run.
- The
overlapflag is respected. - Frame gaps are rounded to the nearest frame.
- A
29.97frame-rate check expects a1000 1001multiplier.