YouTube URL Validation
Comprehensive guide to YouTube URL validation utilities
Overview
The YouTube URL validation module (/src/lib/youtube-validator.ts) provides robust utilities for validating and parsing various YouTube URL formats. It helps ensure that user-provided URLs are valid before making API calls.
Type Definitions
YoutubeValidationResult
export interface YoutubeValidationResult {
isValid: boolean;
type: 'video' | 'playlist' | 'invalid';
videoId?: string;
playlistId?: string;
error?: string;
}Properties:
isValid: Whether the URL is a valid YouTube URLtype: The type of content ('video', 'playlist', or 'invalid')videoId: Extracted video ID (if type is 'video')playlistId: Extracted playlist ID (if applicable)error: Error message explaining why validation failed
Core Validation Functions
validateYoutubeUrl
Main validation function that handles all YouTube URL formats.
export function validateYoutubeUrl(url: string): YoutubeValidationResultSupported Video URL Formats:
https://www.youtube.com/watch?v=VIDEO_IDhttps://www.youtube.com/watch?v=VIDEO_ID&list=PLAYLIST_IDhttps://youtu.be/VIDEO_IDhttps://www.youtube.com/embed/VIDEO_IDhttps://www.youtube.com/v/VIDEO_IDhttps://m.youtube.com/watch?v=VIDEO_ID
Supported Playlist URL Formats:
https://www.youtube.com/playlist?list=PLAYLIST_IDhttps://www.youtube.com/watch?v=VIDEO_ID&list=PLAYLIST_ID(prioritizes video)
Example Usage:
import { validateYoutubeUrl } from '@/lib/youtube-validator';
// Valid video URL
const result1 = validateYoutubeUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
console.log(result1);
// {
// isValid: true,
// type: 'video',
// videoId: 'dQw4w9WgXcQ'
// }
// Valid playlist URL
const result2 = validateYoutubeUrl(
'https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf'
);
console.log(result2);
// {
// isValid: true,
// type: 'playlist',
// playlistId: 'PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf'
// }
// Video with playlist (video takes precedence)
const result3 = validateYoutubeUrl(
'https://www.youtube.com/watch?v=abc123&list=PLxyz'
);
console.log(result3);
// {
// isValid: true,
// type: 'video',
// videoId: 'abc123',
// playlistId: 'PLxyz'
// }
// Invalid URL
const result4 = validateYoutubeUrl('https://vimeo.com/12345');
console.log(result4);
// {
// isValid: false,
// type: 'invalid',
// error: 'URL must be from YouTube (youtube.com or youtu.be)'
// }
// Malformed URL
const result5 = validateYoutubeUrl('not a url');
console.log(result5);
// {
// isValid: false,
// type: 'invalid',
// error: 'Invalid URL format'
// }Validation Process:
- Input Validation: Checks if input is a non-empty string
- URL Parsing: Attempts to parse as URL using
URLconstructor - Domain Validation: Verifies the domain is a YouTube domain
- ID Extraction: Extracts video and/or playlist IDs based on URL structure
- Type Determination: Returns appropriate type based on extracted IDs
validateYoutubeVideoUrl
Validates that a URL is specifically a video URL (not a playlist).
export function validateYoutubeVideoUrl(url: string): YoutubeValidationResultUse Case: Use this when you specifically need a single video URL and want to reject playlist URLs.
Example:
import { validateYoutubeVideoUrl } from '@/lib/youtube-validator';
// Valid video - OK
const result1 = validateYoutubeVideoUrl(
'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
);
console.log(result1);
// {
// isValid: true,
// type: 'video',
// videoId: 'dQw4w9WgXcQ'
// }
// Playlist URL - Rejected
const result2 = validateYoutubeVideoUrl(
'https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf'
);
console.log(result2);
// {
// isValid: false,
// type: 'invalid',
// error: 'Please provide a YouTube video URL, not a playlist URL'
// }
// Short URL - OK
const result3 = validateYoutubeVideoUrl('https://youtu.be/abc123');
console.log(result3);
// {
// isValid: true,
// type: 'video',
// videoId: 'abc123'
// }Common Use Cases:
- Transcript extraction (requires single video)
- Video analysis features
- Single video upload forms
- AI chat features with specific videos
validateYoutubePlaylistUrl
Validates that a URL is specifically a playlist URL (not a single video).
export function validateYoutubePlaylistUrl(
url: string
): YoutubeValidationResultUse Case: Use this when you specifically need a playlist URL and want to reject single video URLs.
Example:
import { validateYoutubePlaylistUrl } from '@/lib/youtube-validator';
// Valid playlist - OK
const result1 = validateYoutubePlaylistUrl(
'https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf'
);
console.log(result1);
// {
// isValid: true,
// type: 'playlist',
// playlistId: 'PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf'
// }
// Video URL - Rejected
const result2 = validateYoutubePlaylistUrl(
'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
);
console.log(result2);
// {
// isValid: false,
// type: 'invalid',
// error: 'Please provide a YouTube playlist URL, not a single video URL'
// }
// Video with playlist parameter - OK (has playlist)
const result3 = validateYoutubePlaylistUrl(
'https://www.youtube.com/watch?v=abc123&list=PLxyz'
);
console.log(result3);
// {
// isValid: true,
// type: 'video',
// videoId: 'abc123',
// playlistId: 'PLxyz'
// }Common Use Cases:
- Playlist analysis features
- Batch video processing
- Course content management
- Video series organization
Validation Error Messages
The validator provides clear, user-friendly error messages:
| Error Message | Cause |
|---|---|
"Please enter a valid URL" | Empty, null, or non-string input |
"Invalid URL format" | String is not a valid URL structure |
"URL must be from YouTube (youtube.com or youtu.be)" | URL is from a different domain |
"Could not extract video or playlist ID from URL" | YouTube URL but no valid IDs found |
"Please provide a YouTube video URL, not a playlist URL" | Playlist given when video expected |
"Please provide a YouTube playlist URL, not a single video URL" | Video given when playlist expected |
Integration Examples
Form Validation
'use client';
import { useState } from 'react';
import { validateYoutubeVideoUrl } from '@/lib/youtube-validator';
export function VideoUrlForm() {
const [url, setUrl] = useState('');
const [error, setError] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Validate URL
const validation = validateYoutubeVideoUrl(url);
if (!validation.isValid) {
setError(validation.error || 'Invalid URL');
return;
}
// URL is valid, proceed with video ID
console.log('Processing video:', validation.videoId);
// ... API call
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="Enter YouTube video URL"
/>
{error && <p className="error">{error}</p>}
<button type="submit">Submit</button>
</form>
);
}API Route Validation
import { NextResponse } from 'next/server';
import { validateYoutubeVideoUrl } from '@/lib/youtube-validator';
import { fetchVideoData } from '@/lib/ythelper';
export async function POST(request: Request) {
try {
const { videoUrl } = await request.json();
// Validate URL
const validation = validateYoutubeVideoUrl(videoUrl);
if (!validation.isValid) {
return NextResponse.json(
{ error: validation.error },
{ status: 400 }
);
}
// Extract video ID and fetch data
const videoData = await fetchVideoData(validation.videoId!);
return NextResponse.json({ video: videoData });
} catch (error) {
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}Server Action with Validation
'use server';
import { validateYoutubePlaylistUrl } from '@/lib/youtube-validator';
import {
fetchPlaylistDetails,
fetchPlaylistVideoIds,
fetchVideoDetails
} from '@/lib/ythelper';
export async function analyzePlaylist(playlistUrl: string) {
// Validate playlist URL
const validation = validateYoutubePlaylistUrl(playlistUrl);
if (!validation.isValid) {
return {
success: false,
error: validation.error
};
}
try {
// Fetch playlist data
const playlistDetails = await fetchPlaylistDetails(validation.playlistId!);
const videoIds = await fetchPlaylistVideoIds(validation.playlistId!);
const { videos, totalDuration } = await fetchVideoDetails(videoIds);
return {
success: true,
data: {
playlist: playlistDetails,
videos,
totalDuration,
videoCount: videos.length
}
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to analyze playlist'
};
}
}React Hook for Validation
import { useState, useCallback } from 'react';
import { validateYoutubeUrl, YoutubeValidationResult } from '@/lib/youtube-validator';
export function useYoutubeUrlValidation() {
const [validation, setValidation] = useState<YoutubeValidationResult | null>(null);
const validate = useCallback((url: string) => {
const result = validateYoutubeUrl(url);
setValidation(result);
return result;
}, []);
const reset = useCallback(() => {
setValidation(null);
}, []);
return {
validation,
validate,
reset,
isValid: validation?.isValid ?? false,
error: validation?.error,
videoId: validation?.videoId,
playlistId: validation?.playlistId,
type: validation?.type
};
}
// Usage in component
function VideoForm() {
const [url, setUrl] = useState('');
const { validate, isValid, error, videoId } = useYoutubeUrlValidation();
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newUrl = e.target.value;
setUrl(newUrl);
// Validate on change
if (newUrl) {
validate(newUrl);
}
};
return (
<div>
<input
type="text"
value={url}
onChange={handleChange}
className={error ? 'error' : ''}
/>
{error && <span className="error-message">{error}</span>}
{isValid && <span className="success">✓ Valid video ID: {videoId}</span>}
</div>
);
}URL Format Reference
Standard Watch URL
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID&t=30s
https://www.youtube.com/watch?v=VIDEO_ID&list=PLAYLIST_IDShort URL
https://youtu.be/VIDEO_ID
https://youtu.be/VIDEO_ID?t=30Embed URL
https://www.youtube.com/embed/VIDEO_ID
https://www.youtube.com/embed/VIDEO_ID?start=30Video URL
https://www.youtube.com/v/VIDEO_IDMobile URL
https://m.youtube.com/watch?v=VIDEO_IDPlaylist URL
https://www.youtube.com/playlist?list=PLAYLIST_IDTesting Examples
import {
validateYoutubeUrl,
validateYoutubeVideoUrl,
validateYoutubePlaylistUrl
} from '@/lib/youtube-validator';
// Test cases
const testCases = [
// Valid videos
{ url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', expected: 'video' },
{ url: 'https://youtu.be/dQw4w9WgXcQ', expected: 'video' },
{ url: 'https://www.youtube.com/embed/dQw4w9WgXcQ', expected: 'video' },
// Valid playlists
{ url: 'https://www.youtube.com/playlist?list=PLrAXtmErZgOe', expected: 'playlist' },
// Invalid URLs
{ url: 'https://vimeo.com/12345', expected: 'invalid' },
{ url: 'not a url', expected: 'invalid' },
{ url: '', expected: 'invalid' },
{ url: 'https://www.youtube.com/channel/UCabc123', expected: 'invalid' },
];
testCases.forEach(({ url, expected }) => {
const result = validateYoutubeUrl(url);
console.log(`URL: ${url}`);
console.log(`Expected: ${expected}, Got: ${result.type}`);
console.log(`Valid: ${result.isValid}`);
console.log('---');
});