Overview

HTTP Live Streaming (HLS) validation ensures your streams meet Apple’s technical specifications and work reliably across all Apple devices. Probe.dev provides Apple’s official MediaStreamValidator tool as a service, eliminating the need for local tool installation while providing comprehensive validation reports.
MediaStreamValidator is essential for App Store submissions, streaming service quality assurance, and debugging playback issues across iOS, macOS, and tvOS devices.

Why HLS Validation Matters

App Store Requirements

Mandatory for iOS Apps
Apple requires HLS compliance for video streaming apps
Rejection Prevention
Avoid App Store rejections due to streaming issues

Playback Quality

Universal Compatibility
Ensure streams work across all Apple devices
Error Prevention
Catch issues before they reach end users

Specification Compliance

RFC 8216 Standards
Validate against official HLS specifications
Future-Proofing
Ensure compatibility with upcoming iOS versions

Debugging Support

Detailed Error Reports
Identify specific compliance violations
Root Cause Analysis
Pinpoint encoding or packaging issues

Getting Started

Basic HLS Validation

Validate an HLS playlist for Apple compliance:
curl -G https://api.probe.dev/v1/probe/mediastreamvalidator \
  --data-urlencode "token=${PROBE_API_TOKEN}" \
  --data-urlencode "url=https://example.com/master.m3u8"

Quick Playlist-Only Check

For faster validation during development:
curl -G https://api.probe.dev/v1/probe/mediastreamvalidator \
  --data-urlencode "token=${PROBE_API_TOKEN}" \
  --data-urlencode "url=https://example.com/master.m3u8" \
  --data-urlencode "parse_playlist_only=true"
Use parse_playlist_only=true for rapid iteration during development. Switch to full validation before production deployment.

Comprehensive Validation

Full Stream Analysis

For production-ready validation including segment analysis:
curl -X POST https://api.probe.dev/v1/probe/mediastreamvalidator \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/master.m3u8",
    "parse_playlist_only": false,
    "enable_cli_output": true,
    "timeout": 650000,
    "inject_json": true
  }'

Parameter Configuration

ParameterPurposeRecommended Values
parse_playlist_onlySkip segment download/analysistrue for development, false for production
enable_cli_outputInclude raw MediaStreamValidator outputtrue for debugging
timeoutMaximum analysis time (milliseconds)650000 (10+ minutes for large streams)
inject_jsonEnhanced JSON formattingtrue for easier parsing

Apple HLS Compliance Requirements

Essential Compliance Checks

MediaStreamValidator verifies these critical requirements:
Minimum Requirements:
  • At least 3 video quality levels for iOS apps
  • 64 kbps audio-only variant required
  • Maximum 10 Mbps bitrate for cellular delivery
Recommended Structure:
Audio-only: 64 kbps
Low: 400-800 kbps
Medium: 1.2-2.5 Mbps
High: 3-6 Mbps
Premium: 8-10 Mbps (WiFi only)
Target Duration:
  • 6-second segments recommended
  • 10-second maximum for new content
  • Consistent duration across quality levels
Validation Points:
  • #EXT-X-TARGETDURATION accuracy
  • Segment length consistency
  • Discontinuity handling
Video Codecs:
  • H.264 Baseline, Main, or High profile
  • HEVC (H.265) for 4K content
  • Proper level constraints
Audio Codecs:
  • AAC-LC required for all streams
  • HE-AAC v1/v2 for low-bitrate variants
  • Dolby Digital/Digital Plus for premium content
Requirements:
  • WebVTT format for new implementations
  • CEA-608/708 support for broadcast content
  • Proper language tagging
  • Accessibility compliance

Common Validation Errors

Critical Issues

1

Bitrate Declaration Mismatch

Error: BANDWIDTH attribute doesn't match measured bitrateCause: Playlist declares different bitrate than actual streamSolution:
# Re-encode with correct bitrate or update playlist
ffmpeg -i input.mp4 -b:v 2500k -maxrate 2750k -bufsize 5000k output.m3u8
2

Segment Duration Violations

Error: Segment duration exceeds target durationCause: Individual segments longer than #EXT-X-TARGETDURATIONSolution:
# Adjust segment duration during encoding
ffmpeg -i input.mp4 -hls_time 6 -hls_list_size 0 output.m3u8
3

Missing Audio-Only Variant

Error: No audio-only variant foundCause: Required 64 kbps audio stream missing from master playlistSolution:
# Create audio-only variant
ffmpeg -i input.mp4 -vn -acodec aac -b:a 64k audio_only.m3u8

Warning-Level Issues

Warnings:
  • Inefficient bitrate ladder gaps
  • Missing I-frame playlists
  • Suboptimal segment counts
Impact: Playback experience degradation

Integration Workflows

CI/CD Pipeline Integration

GitHub Actions Example

name: HLS Validation
on:
  push:
    paths: ['streams/**/*.m3u8']

jobs:
  validate-hls:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Validate HLS Streams
        run: |
          for playlist in streams/**/*.m3u8; do
            echo "Validating $playlist"
            response=$(curl -s -G https://api.probe.dev/v1/probe/mediastreamvalidator \
              --data-urlencode "token=${{ secrets.PROBE_API_TOKEN }}" \
              --data-urlencode "url=https://cdn.example.com/$playlist" \
              --data-urlencode "parse_playlist_only=true")
            
            if echo "$response" | jq -r '.success' | grep -q false; then
              echo "❌ Validation failed for $playlist"
              echo "$response" | jq -r '.error'
              exit 1
            else
              echo "✅ Validation passed for $playlist"
            fi
          done

Jenkins Pipeline

pipeline {
    agent any
    environment {
        PROBE_API_TOKEN = credentials('probe-api-token')
    }
    
    stages {
        stage('HLS Validation') {
            steps:
                script {
                    def playlists = sh(
                        script: "find streams/ -name '*.m3u8'",
                        returnStdout: true
                    ).trim().split('\n')
                    
                    playlists.each { playlist ->
                        def response = sh(
                            script: """
                                curl -s -G https://api.probe.dev/v1/probe/mediastreamvalidator \\
                                --data-urlencode "token=${PROBE_API_TOKEN}" \\
                                --data-urlencode "url=https://cdn.example.com/${playlist}"
                            """,
                            returnStdout: true
                        )
                        
                        def result = readJSON text: response
                        if (!result.success) {
                            error("HLS validation failed for ${playlist}: ${result.error}")
                        }
                    }
                }
            }
        }
    }
}

Pre-Publish Validation Script

#!/usr/bin/env python3
import requests
import sys
import time
from urllib.parse import urljoin

def validate_hls_stream(base_url, playlist_path, api_token):
    """Validate HLS stream before publishing"""
    
    full_url = urljoin(base_url, playlist_path)
    
    # Start validation
    response = requests.get(
        'https://api.probe.dev/v1/probe/mediastreamvalidator',
        params={
            'token': api_token,
            'url': full_url,
            'parse_playlist_only': False,
            'enable_cli_output': True
        }
    )
    
    if response.status_code != 200:
        print(f"❌ API Error: {response.status_code}")
        return False
    
    data = response.json()
    
    if not data.get('success', False):
        print(f"❌ Validation Failed: {data.get('error', 'Unknown error')}")
        if 'cli_output' in data:
            print("\nDetailed Output:")
            print(data['cli_output'])
        return False
    
    print(f"✅ Validation Passed: {playlist_path}")
    return True

if __name__ == "__main__":
    # Validate all streams before deployment
    streams = [
        "master.m3u8",
        "audio_only/playlist.m3u8",
        "video/720p/playlist.m3u8"
    ]
    
    base_url = "https://cdn.example.com/streams/"
    api_token = os.getenv('PROBE_API_TOKEN')
    
    all_passed = True
    for stream in streams:
        if not validate_hls_stream(base_url, stream, api_token):
            all_passed = False
    
    sys.exit(0 if all_passed else 1)

App Store Submission Workflow

Pre-Submission Checklist

  • All HLS streams pass MediaStreamValidator
  • Audio-only variant present (64 kbps)
  • Minimum 3 video quality levels
  • Closed captions properly implemented
  • Segment durations within specifications
  • Bitrate declarations accurate
  • Test on iPhone (latest iOS)
  • Test on iPad (latest iPadOS)
  • Test on Apple TV (latest tvOS)
  • Test on Mac (latest macOS Safari)
  • Verify cellular vs WiFi behavior
  • Closed captions available
  • Audio descriptions where applicable
  • Language tags properly set
  • VoiceOver compatibility verified

Documentation for App Review

Include MediaStreamValidator reports in your App Store submission:
# Generate comprehensive validation report
curl -X POST https://api.probe.dev/v1/probe/mediastreamvalidator \
  -H "Authorization: Bearer $PROBE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-cdn.com/master.m3u8",
    "parse_playlist_only": false,
    "enable_cli_output": true
  }' > hls_validation_report.json

Performance Optimization

Validation Speed Tips

  1. Development Phase: Use parse_playlist_only=true
  2. Staging Phase: Full validation with reasonable timeout
  3. Production Phase: Validate representative samples
  4. CI/CD: Parallel validation of multiple streams
Stream TypeRecommended TimeoutReasoning
Short clips (< 5 min)2-3 minutesQuick analysis
Standard content (5-60 min)5-8 minutesThorough checking
Long-form content (> 1 hour)10-15 minutesComplete validation
Live streams3-5 minutesSample-based analysis

Troubleshooting

Common Issues and Solutions

Symptoms: Analysis times out before completionSolutions:
  • Increase timeout parameter (max 650,000ms)
  • Use parse_playlist_only=true for faster validation
  • Validate shorter content samples first
  • Check network connectivity to stream source
Symptoms: Cannot access stream URLSolutions:
  • Verify stream URL is publicly accessible
  • Check CDN/server allows HEAD requests
  • Ensure proper CORS headers if needed
  • Test URL accessibility from external networks
Symptoms: Partial results or missing analysisSolutions:
  • Set parse_playlist_only=false for complete analysis
  • Increase timeout for large streams
  • Check stream availability during validation
  • Verify all referenced segments are accessible

Debugging with CLI Output

Enable detailed output for troubleshooting:
curl -X POST https://api.probe.dev/v1/probe/mediastreamvalidator \
  -H "Authorization: Bearer $PROBE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://problematic-stream.com/playlist.m3u8",
    "enable_cli_output": true,
    "parse_playlist_only": false
  }' | jq -r '.cli_output'

Best Practices

Development Workflow

  • Validate frequently during encoding
  • Use playlist-only validation for quick checks
  • Automate validation in build pipelines
  • Keep validation reports for debugging

Production Deployment

  • Full validation before CDN upload
  • Validate after CDN propagation
  • Monitor validation results over time
  • Document compliance for App Store

Performance

  • Cache validation results for unchanged content
  • Validate samples of long-form content
  • Use appropriate timeouts for content length
  • Parallel validation for multiple streams

Quality Assurance

  • Validate across all bitrate variants
  • Test accessibility features
  • Verify closed caption compliance
  • Check audio-only variant functionality

Next Steps

Need help with HLS validation or App Store submission? Contact our support team at support@probe.dev for personalized assistance with your streaming workflows.