Package Exports
- react-lite-youtube-embed
- react-lite-youtube-embed/dist/LiteYouTubeEmbed.css
Readme
React Lite YouTube Embed
Private, performant YouTube embeds for React. Under 5KB gzipped.
🚀 Try the Live Demo →
Interactive demo with all features and code examples • Updated with each release
Why This Component?
YouTube's standard iframe embed can add over 500KB to your page and make dozens of network requests before the user even clicks play. This component fixes that:
- ✅ Tiny – Under 5KB gzipped total (JS + CSS)
- ✅ Fast – Loads only a thumbnail until the user clicks
- ✅ Private – No YouTube cookies or tracking by default
- ✅ SEO-Friendly – Structured data for search engines
- ✅ Accessible – Full keyboard navigation and screen reader support
- ✅ TypeScript – Complete type definitions included
The result? Faster page loads, better privacy, and a superior user experience.
Quick Start
Install
npm install react-lite-youtube-embedUse
import LiteYouTubeEmbed from 'react-lite-youtube-embed';
import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css';
export default function App() {
return (
<LiteYouTubeEmbed
id="dQw4w9WgXcQ"
title="Rick Astley - Never Gonna Give You Up"
/>
);
}That's it. You now have a performant, private YouTube embed.
Core Features
🔒 Privacy First
Privacy-Enhanced Mode is the default. Videos load from youtube-nocookie.com, blocking YouTube cookies and tracking until the user explicitly clicks play.
// Default: Privacy-Enhanced Mode (youtube-nocookie.com)
<LiteYouTubeEmbed id="VIDEO_ID" title="Video Title" />
// Opt into standard YouTube (with cookies)
<LiteYouTubeEmbed id="VIDEO_ID" title="Video Title" cookie={true} />⚡ Performance Optimization
Enable lazy loading for images to defer offscreen thumbnails and boost Lighthouse scores:
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
lazyLoad={true}
/>Impact: Defers loading offscreen images, reduces bandwidth, improves mobile performance.
🔍 SEO & Search Visibility
Help search engines discover your videos with structured data:
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
seo={{
name: "Full Video Title",
description: "Video description for search engines",
uploadDate: "2024-01-15T08:00:00Z",
duration: "PT3M33S"
}}
/>Includes:
- JSON-LD VideoObject structured data
- Noscript fallback for non-JS users
- Google Rich Results eligibility
Fetch metadata automatically:
./scripts/fetch-youtube-metadata.sh VIDEO_ID --format react🎬 Player Events (New in v3)
React to player state changes, playback controls, quality, and errors. All core events are fully tested and verified working!
import LiteYouTubeEmbed, { PlayerState, PlayerError } from 'react-lite-youtube-embed';
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
enableJsApi
// Simple handlers (✅ All verified)
onPlay={() => console.log('Started')}
onPause={() => console.log('Paused')}
onEnd={() => console.log('Finished')}
// Advanced handlers (✅ All verified)
onStateChange={(e) => console.log('State:', e.state)}
onPlaybackRateChange={(rate) => console.log('Speed:', rate)}
onPlaybackQualityChange={(quality) => console.log('Quality:', quality)}
onError={(code) => console.error('Error:', code)}
/>🎮 Programmatic Control
Control the player via YouTube's iframe API using refs:
function VideoPlayer() {
const playerRef = useRef(null);
const [isReady, setIsReady] = useState(false);
const handlePause = () => {
playerRef.current?.contentWindow?.postMessage(
'{"event":"command","func":"pauseVideo"}',
'*'
);
};
return (
<>
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
ref={playerRef}
enableJsApi
onIframeAdded={() => setIsReady(true)}
/>
{isReady && <button onClick={handlePause}>Pause</button>}
</>
);
}Installation Options
NPM (Recommended)
npm install react-lite-youtube-embedYarn
yarn add react-lite-youtube-embedGitHub Packages
npm install @ibrahimcesar/react-lite-youtube-embedSee GITHUB_PACKAGES.md for authentication details.
API Reference
Required Props
| Prop | Type | Description |
|---|---|---|
| id | string |
YouTube video or playlist ID |
| title | string |
Video title for iframe (accessibility requirement) |
Common Props
| Prop | Type | Default | Description |
|---|---|---|---|
| cookie | boolean |
false |
Use standard YouTube (true) or Privacy-Enhanced Mode (false) |
| lazyLoad | boolean |
false |
Enable native lazy loading for thumbnails |
| poster | string |
"hqdefault" |
Thumbnail quality: "default", "mqdefault", "hqdefault", "sddefault", "maxresdefault" |
| params | string |
"" |
Additional URL parameters (e.g., "start=90&end=120") |
| enableJsApi | boolean |
false |
Enable iframe API for programmatic control |
| playlist | boolean |
false |
Set to true if ID is a playlist |
Event Props (require enableJsApi={true})
| Prop | Type | Description |
|---|---|---|
| onReady | (event) => void |
Player is ready to receive commands |
| onPlay | () => void |
Video started playing |
| onPause | () => void |
Video was paused |
| onEnd | () => void |
Video finished playing |
| onBuffering | () => void |
Video is buffering |
| onStateChange | (event) => void |
Player state changed |
| onError | (code) => void |
Player encountered an error |
| onPlaybackRateChange | (rate) => void |
Playback speed changed |
| onPlaybackQualityChange | (quality) => void |
Video quality changed |
Advanced Props
| Prop | Type | Default | Description |
|---|---|---|---|
| adNetwork | boolean |
false |
Preconnect to Google's ad network |
| alwaysLoadIframe | boolean |
false |
Load iframe immediately (not recommended) |
| announce | string |
"Watch" |
Screen reader announcement text |
| aspectHeight | number |
9 |
Custom aspect ratio height |
| aspectWidth | number |
16 |
Custom aspect ratio width |
| autoplay | boolean |
false |
Autoplay video (requires muted={true}) |
| focusOnLoad | boolean |
false |
Focus iframe when loaded |
| muted | boolean |
false |
Mute video audio |
| noscriptFallback | boolean |
true |
Include noscript tag with YouTube link |
| onIframeAdded | () => void |
- | Callback when iframe loads (use for ref availability) |
| playlistCoverId | string |
- | Video ID for playlist cover image |
| referrerPolicy | string |
"strict-origin-when-cross-origin" |
Iframe referrer policy |
| seo | VideoSEO |
- | SEO metadata object |
| stopOnEnd | boolean |
false |
Stop video when it ends to prevent related videos |
| style | object |
{} |
Custom container styles |
| thumbnail | string |
- | Custom thumbnail image URL |
| webp | boolean |
false |
Use WebP format for thumbnails |
Styling Props
| Prop | Type | Default | Description |
|---|---|---|---|
| wrapperClass | string |
"yt-lite" |
Main wrapper class |
| playerClass | string |
"lty-playbtn" |
Play button class |
| iframeClass | string |
"" |
Iframe element class |
| activeClass | string |
"lyt-activated" |
Class when activated |
| containerElement | string |
"article" |
HTML element for container |
Deprecated Props
| Prop | Replacement | Note |
|---|---|---|
| noCookie | Use cookie prop |
Inverted logic for clarity |
| rel | Use resourceHint |
Conflicted with YouTube's rel parameter |
→ See all props with examples in the demo
Styling
Option 1: Import the CSS (Recommended)
import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css';Option 2: Copy to Global CSS
For Next.js, Remix, or other frameworks, copy the CSS to your global stylesheet. See CSS source
Option 3: Custom Styles
Use CSS-in-JS or pass custom class names:
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
wrapperClass="my-custom-wrapper"
playerClass="my-custom-button"
activeClass="video-playing"
/>Common Use Cases
Stop Video to Hide Related Videos
Automatically return to thumbnail when the video ends:
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
enableJsApi
stopOnEnd={true}
params="rel=0"
/>Video Gallery with Analytics
function VideoGallery() {
return videos.map(video => (
<LiteYouTubeEmbed
key={video.id}
id={video.id}
title={video.title}
lazyLoad
onPlay={() => analytics.track('video_play', { id: video.id })}
onEnd={() => analytics.track('video_complete', { id: video.id })}
/>
));
}Auto-Advancing Playlist
function Playlist() {
const videos = ['video1', 'video2', 'video3'];
const [currentIndex, setCurrentIndex] = useState(0);
return (
<LiteYouTubeEmbed
id={videos[currentIndex]}
title={`Video ${currentIndex + 1}`}
enableJsApi
onEnd={() => {
if (currentIndex < videos.length - 1) {
setCurrentIndex(currentIndex + 1);
}
}}
/>
);
}Custom Play/Pause Controls
function CustomPlayer() {
const playerRef = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);
const togglePlayPause = () => {
const command = isPlaying ? 'pauseVideo' : 'playVideo';
playerRef.current?.contentWindow?.postMessage(
`{"event":"command","func":"${command}"}`,
'*'
);
};
return (
<>
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
ref={playerRef}
enableJsApi
alwaysLoadIframe
onPlay={() => setIsPlaying(true)}
onPause={() => setIsPlaying(false)}
/>
<button onClick={togglePlayPause}>
{isPlaying ? 'Pause' : 'Play'}
</button>
</>
);
}Framework Guides
Next.js / SSR Setup
Using Next.js 13+ App Router or any server-side rendering framework? See the SSR Guide for:
- Setup instructions
- Troubleshooting common issues
- Best practices
- TypeScript configuration
TypeScript
Full TypeScript support is included. Import types as needed:
import LiteYouTubeEmbed, {
PlayerState,
PlayerError,
VideoSEO,
PlayerReadyEvent,
PlayerStateChangeEvent
} from 'react-lite-youtube-embed';🔍 SEO & Search Engine Optimization
Improve your video discoverability in search engines with structured data and fallback links.
Why SEO Matters
By default, search engine crawlers cannot discover videos embedded with lite embeds because:
- No followable links exist before user interaction
- No structured metadata for search engines to index
- The facade pattern is invisible to crawlers
This component now supports JSON-LD structured data and noscript fallbacks to solve these issues.
Basic SEO Setup
<LiteYouTubeEmbed
id="L2vS_050c-M"
title="What's new in Material Design"
seo={{
name: "What's new in Material Design for the web",
description: "Learn about the latest Material Design updates presented at Chrome Dev Summit 2019",
uploadDate: "2019-11-11T08:00:00Z",
duration: "PT15M33S"
}}
/>This generates:
- ✅ JSON-LD structured data following schema.org VideoObject
- ✅ Noscript fallback with direct YouTube link
- ✅ Google rich results eligibility (video carousels, thumbnails in search)
Fetching Video Metadata
There are several ways to get complete video metadata for SEO:
Method 1: Manual (Quick & Privacy-Friendly)
The fastest way is to visit the YouTube video page and get the info directly:
- Open the video: Visit
https://www.youtube.com/watch?v=VIDEO_ID - Get the duration: Look at the video player (e.g., "4:23")
- Convert duration to ISO 8601:
- 4:23 →
PT4M23S(4 minutes 23 seconds) - 1:30:45 →
PT1H30M45S(1 hour 30 minutes 45 seconds) - 15:00 →
PT15M(15 minutes)
- 4:23 →
- Get upload date: Shown below video title (e.g., "Dec 5, 2018")
- Convert date to ISO 8601 UTC format:
- Format:
YYYY-MM-DDTHH:MM:SSZ(theZindicates UTC timezone) - Dec 5, 2018 →
2018-12-05T08:00:00Z - Jun 5, 2025 →
2025-06-05T08:00:00Z - Note: The specific time (08:00:00) is not critical for SEO - the date is what matters. You can use
00:00:00Zor any time if you don't know the exact upload time.
- Format:
Method 2: Helper Script (Basic Metadata)
Use the included script to fetch title and thumbnail:
# Make the script executable (first time only)
chmod +x scripts/fetch-youtube-metadata.sh
# Fetch metadata in JSON format
./scripts/fetch-youtube-metadata.sh dQw4w9WgXcQ
# Get ready-to-use React component code
./scripts/fetch-youtube-metadata.sh dQw4w9WgXcQ --format reactNote: This script uses YouTube's oEmbed API which only provides basic info (title, author, thumbnail). You'll need to add uploadDate and duration manually.
Requirements: curl and jq must be installed.
Method 3: YouTube Data API v3 (Complete Metadata)
For complete automation, use YouTube's official API:
- Get a free API key: https://console.cloud.google.com/apis/credentials
- Make API request:
curl "https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails&id=VIDEO_ID&key=YOUR_API_KEY"
- Extract values from response:
snippet.publishedAt→ uploadDatecontentDetails.duration→ duration (already in ISO 8601 format!)snippet.description→ description
API Limits: Free tier provides 10,000 quota units/day (sufficient for most use cases)
SEO Prop Reference
interface VideoSEO {
name?: string; // Video title (falls back to title prop)
description?: string; // Video description (50-160 chars recommended)
uploadDate?: string; // ISO 8601 date (e.g., "2024-01-15T08:00:00Z")
duration?: string; // ISO 8601 duration (e.g., "PT3M33S")
thumbnailUrl?: string; // Custom thumbnail (auto-generated if omitted)
contentUrl?: string; // YouTube watch URL (auto-generated)
embedUrl?: string; // Embed URL (auto-generated)
}Duration Format Examples
ISO 8601 duration format: PT#H#M#S
"PT3M33S"- 3 minutes 33 seconds"PT15M"- 15 minutes"PT1H30M"- 1 hour 30 minutes"PT2H15M30S"- 2 hours 15 minutes 30 seconds
Verify Your SEO Setup
Test your structured data:
🎬 Player Events (New in v3.0)
Get real-time notifications when the YouTube player changes state, encounters errors, or when users interact with playback controls.
⚠️ Requirements
CRITICAL: Events require both of these:
enableJsApi={true}- Enables YouTube's JavaScript APIref={yourRef}- A React ref MUST be passed to the component (used to communicate with YouTube's iframe)
Without a ref, events will NOT work!
⚠️ Important Notice About YouTube's API
This event system relies on YouTube's internal postMessage API, which is not officially documented by Google and may change at any time without prior notice. While we strive to keep the implementation up-to-date, YouTube could modify their iframe communication protocol in future updates, potentially breaking event functionality.
Recommendations:
- Test events thoroughly in your production environment
- Have fallback behavior if events stop working
- Monitor for breaking changes when updating YouTube embed URLs
- Consider this when building critical features that depend on events
Event Compatibility Status
| Event | Status | Notes |
|---|---|---|
onIframeAdded |
✅ Verified Working | Fires when iframe is added to DOM |
onReady |
✅ Verified Working | Fires when YouTube player initializes |
onStateChange |
✅ Verified Working | Fires on all state changes |
onPlay |
✅ Verified Working | Convenience wrapper for PLAYING state |
onPause |
✅ Verified Working | Convenience wrapper for PAUSED state |
onEnd |
✅ Verified Working | Convenience wrapper for ENDED state |
onBuffering |
✅ Verified Working | Convenience wrapper for BUFFERING state |
onPlaybackRateChange |
✅ Verified Working | Fires when speed changes (use ⚙️ settings) |
onPlaybackQualityChange |
✅ Verified Working | Fires when quality changes (use ⚙️ settings) |
onError |
⚠️ Untested | Should work but not confirmed with invalid video |
Technical Note: YouTube sends state changes, playback rate, and quality changes via infoDelivery postMessage events. This library handles this automatically.
Quick Start
import { useRef } from 'react';
import LiteYouTubeEmbed, { PlayerState, PlayerError } from 'react-lite-youtube-embed';
function App() {
const ytRef = useRef(null); // ⚠️ REQUIRED for events to work!
return (
<LiteYouTubeEmbed
id="dQw4w9WgXcQ"
title="Rick Astley - Never Gonna Give You Up"
ref={ytRef} // ⚠️ CRITICAL: Must pass ref
enableJsApi // ⚠️ REQUIRED for events
// Simple convenience handlers
onPlay={() => console.log('Video started playing')}
onPause={() => console.log('Video paused')}
onEnd={() => console.log('Video ended')}
// Advanced state change handler
onStateChange={(event) => {
console.log('State:', event.state);
console.log('Current time:', event.currentTime);
}}
// Advanced playback handlers
onPlaybackRateChange={(rate) => console.log('Speed:', rate)}
onPlaybackQualityChange={(quality) => console.log('Quality:', quality)}
// Error handling
onError={(errorCode) => {
if (errorCode === PlayerError.VIDEO_NOT_FOUND) {
alert('Video not available');
}
}}
/>
);
}Core Events
onReady(event: PlayerReadyEvent)
Fires when the player is loaded and ready to receive commands.
onReady={(event) => {
console.log(`Player ready for: ${event.videoId}`);
}}onStateChange(event: PlayerStateChangeEvent)
Fires whenever the player's state changes.
onStateChange={(event) => {
switch (event.state) {
case PlayerState.PLAYING:
console.log('Playing at', event.currentTime, 'seconds');
break;
case PlayerState.PAUSED:
console.log('Paused');
break;
case PlayerState.ENDED:
console.log('Video finished');
break;
}
}}PlayerState values:
PlayerState.UNSTARTED(-1)PlayerState.ENDED(0)PlayerState.PLAYING(1)PlayerState.PAUSED(2)PlayerState.BUFFERING(3)PlayerState.CUED(5)
onError(errorCode: PlayerError)
Fires when the player encounters an error.
onError={(code) => {
switch (code) {
case PlayerError.INVALID_PARAM:
console.error('Invalid video parameter');
break;
case PlayerError.VIDEO_NOT_FOUND:
console.error('Video not found or removed');
break;
case PlayerError.NOT_EMBEDDABLE:
console.error('Video cannot be embedded');
break;
}
}}PlayerError codes:
PlayerError.INVALID_PARAM(2)PlayerError.HTML5_ERROR(5)PlayerError.VIDEO_NOT_FOUND(100)PlayerError.NOT_EMBEDDABLE(101)PlayerError.NOT_EMBEDDABLE_DISGUISED(150)
Convenience Events
Simple wrappers for common use cases:
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
enableJsApi
onPlay={() => analytics.track('video_play')}
onPause={() => analytics.track('video_pause')}
onEnd={() => loadNextVideo()}
onBuffering={() => showLoadingSpinner()}
/>Advanced Events
onPlaybackRateChange(playbackRate: number)
Fires when playback speed changes. To test this event, click the ⚙️ settings button in the YouTube player and change the playback speed.
Common values: 0.25, 0.5, 1, 1.5, 2.
onPlaybackRateChange={(rate) => {
console.log(`Playback speed: ${rate}x`);
// Example: Save user's preferred playback speed
localStorage.setItem('preferredSpeed', rate.toString());
}}onPlaybackQualityChange(quality: string)
Fires when video quality changes (either automatically or manually). To test this event manually, click the ⚙️ settings button in the YouTube player and change the video quality.
Common values: "small" (240p), "medium" (360p), "large" (480p), "hd720", "hd1080", "hd1440", "hd2160" (4K).
onPlaybackQualityChange={(quality) => {
console.log(`Quality changed to: ${quality}`);
// Example: Track quality changes for analytics
analytics.track('video_quality_change', {
quality,
timestamp: Date.now()
});
}}Event Status Tracker Demo
The live demo includes an Event Status Tracker that visually shows which events have fired during your interaction with the video. Each event displays:
- ⏸️ Gray background - Event has not fired yet
- ✅ Green background - Event has fired at least once
This interactive tracker helps you:
- Understand when different events fire
- Test your event handlers
- Learn about YouTube's event system
- Verify events are working correctly
Try it yourself:
- Visit the live demo
- Scroll to the Events section
- Play the video and watch events light up
- Change playback speed and quality via the ⚙️ settings button
Real-World Examples
Analytics Tracking
function VideoWithAnalytics() {
const [playStartTime, setPlayStartTime] = useState(null);
return (
<LiteYouTubeEmbed
id="dQw4w9WgXcQ"
title="My Video"
enableJsApi
onReady={() => analytics.track('video_ready')}
onPlay={() => {
setPlayStartTime(Date.now());
analytics.track('video_play');
}}
onEnd={() => {
const watchTime = Date.now() - playStartTime;
analytics.track('video_complete', { watchTime });
}}
onError={(code) => analytics.track('video_error', { errorCode: code })}
/>
);
}Video Playlist with Auto-Advance
function VideoPlaylist() {
const videos = ['dQw4w9WgXcQ', 'abc123def', 'xyz789uvw'];
const [currentIndex, setCurrentIndex] = useState(0);
return (
<LiteYouTubeEmbed
id={videos[currentIndex]}
title={`Video ${currentIndex + 1}`}
enableJsApi
onEnd={() => {
if (currentIndex < videos.length - 1) {
setCurrentIndex(currentIndex + 1);
}
}}
onError={() => {
// Skip to next video on error
if (currentIndex < videos.length - 1) {
setCurrentIndex(currentIndex + 1);
}
}}
/>
);
}Important Notes
⚠️ Events require enableJsApi={true}
⚠️ Lazy Loading Limitation - By default, the iframe only loads after the user clicks. Events won't fire until after user interaction. Use onIframeAdded callback to know when ready, or use alwaysLoadIframe={true} (not recommended for privacy/performance).
⚠️ Origin Validation - The component automatically validates events from YouTube domains for security.
⚠️ Cleanup - Event listeners are automatically cleaned up on unmount.
🤖 Controlling the player
You can programmatically control the YouTube player via YouTube's IFrame Player API using refs and postMessage.
⚠️ Important: This requires
enableJsApi={true}. The ref is only available after the user clicks the poster (useonIframeAddedcallback to know when ready).
function VideoPlayer() {
const ytRef = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);
return (
<div>
<button
onClick={() => {
setIsPlaying((oldState) => !oldState);
ytRef.current?.contentWindow?.postMessage(
`{"event": "command", "func": "${isPlaying ? "pauseVideo" : "playVideo"}"}`,
"*",
);
}}
>
{isPlaying ? 'Pause' : 'Play'}
</button>
<LiteYouTubeEmbed
title="My Video"
id="L2vS_050c-M"
ref={ytRef}
enableJsApi
alwaysLoadIframe
/>
</div>
);
}Using Refs with Lazy-Loaded Iframes
Important: The ref only becomes available after the user clicks the poster.
✅ Correct: Use onIframeAdded Callback
const videoRef = useRef(null);
const handleIframeAdded = () => {
console.log("Iframe loaded and ready!");
if (videoRef.current) {
videoRef.current.contentWindow?.postMessage(
'{"event":"command","func":"playVideo"}',
'*'
);
}
};
return (
<LiteYouTubeEmbed
id="VIDEO_ID"
title="My Video"
ref={videoRef}
onIframeAdded={handleIframeAdded}
enableJsApi
/>
);❌ Wrong: Accessing Ref on Mount
// This won't work - iframe doesn't exist yet!
useEffect(() => {
if (videoRef.current) {
console.log("This never runs");
}
}, []); // Empty deps - runs before iframe existsFAQ
Can I hide all related videos after my video ends?
Short answer: No, this is a YouTube platform limitation.
What changed: In September 2018, YouTube changed the rel=0 parameter to only limit related videos to the same channel, not hide them completely.
Best solution: Use the built-in stopOnEnd prop:
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
enableJsApi
stopOnEnd={true}
params="rel=0"
/>This automatically stops the video when it ends and returns to the thumbnail view, preventing related videos from showing.
→ See more solutions in the docs
How do I use this with Next.js?
See the SSR Guide for detailed Next.js setup instructions and troubleshooting.
Does this work with playlists?
Yes! Set playlist={true} and optionally provide a playlistCoverId:
<LiteYouTubeEmbed
id="PLAYLIST_ID"
title="My Playlist"
playlist={true}
playlistCoverId="VIDEO_ID"
/>Can I customize the thumbnail?
Yes! Use the thumbnail prop to provide a custom image URL:
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
thumbnail="https://example.com/custom-thumbnail.jpg"
/>Or choose a different YouTube thumbnail quality with poster:
<LiteYouTubeEmbed
id="VIDEO_ID"
title="Video Title"
poster="maxresdefault"
/>Contributing
We welcome contributions! See CONTRIBUTING.md for guidelines.
Development
# Install dependencies
npm install
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Build
npm run build
# Lint
npm run lint
# Format
npm run formatSecurity
This package includes:
- ✅ SLSA Build Level 3 Provenance - Cryptographically signed build provenance
- ✅ CodeQL Analysis - Automated security scanning
- ✅ Dependency Audits - Regular security updates
Verify package authenticity:
npm audit signaturesSee .github/SLSA.md for more details.
License
MIT © Ibrahim Cesar
See LICENSE for full details.
Credits
- Paul Irish (@paulirish) - Original Lite YouTube Embed
- Addy Osmani (@addyosmani) - Adaptive Loading concepts
- All contributors - View contributors
Resources
Made with 🧩 in Brazil 🇧🇷
