How to Download Skool.com Videos (and the Entire Course)
Comprehensive tutorial for mirroring entire Skool classrooms using cookies, custom scripts, and wget automation.

How to download skool.com videos (and the entire course)
Want the easy way? Try the Skool Downloader.
Version 1 - Comprehensive, More Difficult
You can download the entire classroom with this, but its not beginner friendly. If you want the beginner version to just download 1 video at a time, scroll down to the bottom!
This is not a beginner friendly video, but if you follow along Iβll show you how to get around the download protections.
If youβre looking for a simpler solution or have any questions about this process, just leave a comment and Iβll create a follow-up video.
Watch the video
Prereqs
- homebrew (free)
- wget (free)
- Get cookies.txt LOCALLY
- visual studio code (free)
- live server extension for visual studio code (free)
- pants (in order for this process to work you have to be wearing pants unfortunately)
Steps overview
- Put on pants π
- Login to skool & navigate to the classroom
- Save the cookies with Get cookies.txt extension (netscape format)
- Open browser console & paste in the
.jscode, press enter - Create a folder on your desktop called
project - Put your
cookies.txtandurls.txtfile in the project folder - Open terminal application and type
cd ~/Desktop/project - Run the
wgetcommand to start the process - Remove pants π©² and wait for it to finish
Detailed step by step guide
1. Put on pants π
2. Login to skool & navigate to the classroom
3. Save the cookies with Get cookies.txt extension (netscape format)
4. Open browser console & paste in the .js code, press enter
// Extract all lesson URLs from Skool classroom - paste in browser console
function extractAllLessonUrls() {
console.log("π Searching for lesson URLs on this page...");
const urls = new Set();
// Dynamically get base URL from current page
const currentUrl = new URL(window.location.href);
const baseUrl = `${currentUrl.protocol}//${currentUrl.host}${currentUrl.pathname}`;
console.log(`π Auto-detected base URL: ${baseUrl}`);
console.log(`π Current full URL: ${window.location.href}`);
// Method 1: Look for direct links with md= parameters
document.querySelectorAll('a[href*="classroom"]').forEach(link => {
if (link.href.includes('md=')) {
urls.add(link.href);
console.log("Found link:", link.href);
}
});
// Method 2: Look for any links containing md= in any attribute
document.querySelectorAll('*').forEach(el => {
// Check onclick handlers
const onclick = el.getAttribute('onclick');
if (onclick && onclick.includes('md=')) {
const mdMatch = onclick.match(/md=([a-f0-9]+)/);
if (mdMatch) {
const url = `${baseUrl}?md=${mdMatch[1]}`;
urls.add(url);
console.log("Found in onclick:", url);
}
}
// Check data attributes
['data-href', 'data-url', 'data-link', 'data-md'].forEach(attr => {
const value = el.getAttribute(attr);
if (value && value.includes('md=')) {
if (value.startsWith('http')) {
urls.add(value);
} else {
const mdMatch = value.match(/md=([a-f0-9]+)/);
if (mdMatch) {
const url = `${baseUrl}?md=${mdMatch[1]}`;
urls.add(url);
console.log(`Found in ${attr}:`, url);
}
}
}
});
// Check for md= in any attribute value
for (let attr of el.attributes) {
if (attr.value.includes('md=') && !attr.name.startsWith('data-react')) {
const mdMatch = attr.value.match(/md=([a-f0-9]+)/g);
if (mdMatch) {
mdMatch.forEach(match => {
const mdValue = match.replace('md=', '');
const url = `${baseUrl}?md=${mdValue}`;
urls.add(url);
console.log(`Found in ${attr.name}:`, url);
});
}
}
}
});
// Method 3: Look in page source/innerHTML for md= patterns
const pageSource = document.documentElement.innerHTML;
const mdMatches = pageSource.match(/md=([a-f0-9]{32})/g);
if (mdMatches) {
mdMatches.forEach(match => {
const mdValue = match.replace('md=', '');
const url = `${baseUrl}?md=${mdValue}`;
urls.add(url);
});
console.log(`Found ${mdMatches.length} md= patterns in page source`);
}
// Add current page URL if it has md=
if (window.location.href.includes('md=')) {
urls.add(window.location.href);
console.log("Added current page:", window.location.href);
}
const urlArray = Array.from(urls).sort();
console.log(`\nβ
Found ${urlArray.length} unique lesson URLs:`);
urlArray.forEach((url, index) => {
console.log(`${index + 1}. ${url}`);
});
if (urlArray.length === 0) {
console.log("\nβ No lesson URLs found!");
console.log("π‘ Try running this from the main classroom navigation page");
console.log("π‘ Or manually add URLs to the list below");
// Add current URL as fallback
urlArray.push(window.location.href);
}
// Create urls.txt file and download it
const urlText = urlArray.join('\n');
const blob = new Blob([urlText], {type: 'text/plain'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'urls.txt';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
console.log("\nπ Downloaded urls.txt with all found URLs");
console.log("π Next steps:");
console.log("1. Check the downloaded urls.txt file");
console.log("2. Add any missing URLs manually if needed");
console.log("3. Use: wget --input-file=urls.txt [other options]");
return urlArray;
}
// Run the extraction
extractAllLessonUrls();
5. Create a folder on your desktop called project
6. Put your cookies.txt and urls.txt file in the project folder
7. Open terminal application and navigate to your project folder
cd ~/Desktop/project
8. Run the wget command to start the process
#!/bin/bash
# Complete website scraping with wget
wget \
--input-file=urls.txt \
--page-requisites \
--html-extension \
--convert-links \
--restrict-file-names=windows \
--force-directories \
--no-clobber \
--directory-prefix=./skool_complete \
--load-cookies=cookies.txt \
--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" \
--wait=2 \
--span-hosts \
--recursive \
--level=5 \
--no-parent
9. Remove pants π©² and wait for it to finish
10. How to use it
At this point you basically have a copy of what school has on their servers but you have it on your computer so you can access it anytime anywhere and without internet. Simply open the folder in Visual Studio Code and click on one of the HTML files and open with live server.
How to download a single video from skool.com (easy method)
Here's the easier version, as request by all ye youtubers!
Step 1: Visit the page on skool.com where the video is
Step 2: Copy and paste this command in your dev tools console (right click > inspect > go to console tab)
/**
* Skool Loom Video Extractor - Final Version
* Extracts video from current lesson using the md query parameter
*
* Usage: Paste this entire script in browser console while on a Skool classroom page
* Then, go subscribe to @devinschumacher on YouTube
*/
(function() {
console.log('π₯ Skool Loom Video Extractor - Final Version');
// Get the md parameter from URL
const urlParams = new URLSearchParams(window.location.search);
const courseId = urlParams.get('md');
if (!courseId) {
console.log('β No "md" parameter found in URL');
alert('This page does not have a lesson ID (md parameter). Make sure you are on a lesson page.');
return;
}
console.log(`π Looking for course with ID: ${courseId}`);
// Function to recursively search for course by ID
function findCourseById(obj, targetId) {
if (!obj || typeof obj !== 'object') return null;
// Direct match
if (obj.id === targetId && obj.metadata && obj.metadata.videoLink) {
return obj;
}
// Check if this object has a course property with matching ID
if (obj.course && obj.course.id === targetId && obj.course.metadata && obj.course.metadata.videoLink) {
return obj.course;
}
// Recursively search all properties
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
const result = findCourseById(obj[key], targetId);
if (result) return result;
}
}
return null;
}
// Get the Next.js data
const nextDataScript = document.getElementById('__NEXT_DATA__');
if (!nextDataScript) {
console.log('β Could not find __NEXT_DATA__ script');
alert('Could not find page data. This script works on Skool classroom pages.');
return;
}
try {
const nextData = JSON.parse(nextDataScript.textContent);
console.log('π Found page data, searching for course...');
// Search for the course
const course = findCourseById(nextData, courseId);
if (!course) {
console.log('β Could not find course with ID:', courseId);
alert(`Could not find lesson with ID: ${courseId}`);
return;
}
// Extract video information
const metadata = course.metadata;
const videoUrl = metadata.videoLink.split('?')[0]; // Clean URL without parameters
const title = metadata.title || 'Untitled Lesson';
const duration = metadata.videoLenMs ? Math.round(metadata.videoLenMs / 1000) : null;
console.log('β
Found video!');
console.log(`πΉ Title: ${title}`);
console.log(`π URL: ${videoUrl}`);
if (duration) {
const minutes = Math.floor(duration / 60);
const seconds = duration % 60;
console.log(`β±οΈ Duration: ${minutes}:${seconds.toString().padStart(2, '0')}`);
}
// Create download content
const urlContent = videoUrl;
const summaryContent = `# Skool Loom Video
# Course ID: ${courseId}
# Title: ${title}
# Duration: ${duration ? `${Math.floor(duration/60)}:${(duration%60).toString().padStart(2, '0')}` : 'Unknown'}
# Extracted: ${new Date().toLocaleString()}
${videoUrl}
# To download:
# yt-dlp "${videoUrl}"`;
// Download function
function download(content, filename) {
const blob = new Blob([content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// Create filename based on title (sanitized)
const safeTitle = title.replace(/[^a-z0-9]/gi, '_').toLowerCase();
const shortTitle = safeTitle.substring(0, 30);
// Download files
download(urlContent, `loom_${shortTitle}.txt`);
setTimeout(() => {
download(summaryContent, `loom_${shortTitle}_info.txt`);
}, 500);
// Success message
setTimeout(() => {
alert(`β
Found video: "${title}"\n\nDownloaded:\nβ’ loom_${shortTitle}.txt\nβ’ loom_${shortTitle}_info.txt\n\nTo download:\nyt-dlp --batch-file loom_${shortTitle}.txt`);
}, 1000);
} catch (e) {
console.error('β Error parsing page data:', e);
alert('Error parsing page data. See console for details.');
}
})();
This will download something to your desktop on Mac.
Step 3: Get the command from the file and run it in your terminal
It will look something like this:
# Skool Loom Video
# Course ID: c22bf3e55b6f41f98e12eedfbb14391e
# Title: How We Notify You If You Won
# Duration: 1:23
# Extracted: 5/28/2025, 2:13:17 PM
https://www.loom.com/share/b19b38d0ce2b44f5a049b871d9a38925
# To download:
# yt-dlp "https://www.loom.com/share/b19b38d0ce2b44f5a049b871d9a38925"
Focus on the yt-dlp "https://www.loom.com/share/b19b38d0ce2b44f5a049b871d9a38925" part.
Paste that in your terminal and it will download to where you are!
So if that helped, and you're feelin generous - feel free to sponsor me so I can make more tutorials like this.
....and take baths like this
How to download skool.com videos (and the entire course)
Version 1 - Comprehensive, More Difficult
You can download the entire classroom with this, but its not beginner friendly. If you want the beginner version to just download 1 video at a time, scroll down to the bottom!
This is not a beginner friendly video, but if you follow along Iβll show you how to get around the download protections.
If youβre looking for a simpler solution or have any questions about this process, just leave a comment and Iβll create a follow-up video.
Watch the video
Prereqs
- homebrew (free)
- wget (free)
- Get cookies.txt LOCALLY
- visual studio code (free)
- live server extension for visual studio code (free)
- pants (in order for this process to work you have to be wearing pants unfortunately)
Steps overview
- Put on pants π
- Login to skool & navigate to the classroom
- Save the cookies with Get cookies.txt extension (netscape format)
- Open browser console & paste in the
.jscode, press enter - Create a folder on your desktop called
project - Put your
cookies.txtandurls.txtfile in the project folder - Open terminal application and type
cd ~/Desktop/project - Run the
wgetcommand to start the process - Remove pants π©² and wait for it to finish
Detailed step by step guide
1. Put on pants π
2. Login to skool & navigate to the classroom
3. Save the cookies with Get cookies.txt extension (netscape format)
4. Open browser console & paste in the .js code, press enter
// Extract all lesson URLs from Skool classroom - paste in browser console
function extractAllLessonUrls() {
console.log("π Searching for lesson URLs on this page...");
const urls = new Set();
// Dynamically get base URL from current page
const currentUrl = new URL(window.location.href);
const baseUrl = `${currentUrl.protocol}//${currentUrl.host}${currentUrl.pathname}`;
console.log(`π Auto-detected base URL: ${baseUrl}`);
console.log(`π Current full URL: ${window.location.href}`);
// Method 1: Look for direct links with md= parameters
document.querySelectorAll('a[href*="classroom"]').forEach(link => {
if (link.href.includes('md=')) {
urls.add(link.href);
console.log("Found link:", link.href);
}
});
// Method 2: Look for any links containing md= in any attribute
document.querySelectorAll('*').forEach(el => {
// Check onclick handlers
const onclick = el.getAttribute('onclick');
if (onclick && onclick.includes('md=')) {
const mdMatch = onclick.match(/md=([a-f0-9]+)/);
if (mdMatch) {
const url = `${baseUrl}?md=${mdMatch[1]}`;
urls.add(url);
console.log("Found in onclick:", url);
}
}
// Check data attributes
['data-href', 'data-url', 'data-link', 'data-md'].forEach(attr => {
const value = el.getAttribute(attr);
if (value && value.includes('md=')) {
if (value.startsWith('http')) {
urls.add(value);
} else {
const mdMatch = value.match(/md=([a-f0-9]+)/);
if (mdMatch) {
const url = `${baseUrl}?md=${mdMatch[1]}`;
urls.add(url);
console.log(`Found in ${attr}:`, url);
}
}
}
});
// Check for md= in any attribute value
for (let attr of el.attributes) {
if (attr.value.includes('md=') && !attr.name.startsWith('data-react')) {
const mdMatch = attr.value.match(/md=([a-f0-9]+)/g);
if (mdMatch) {
mdMatch.forEach(match => {
const mdValue = match.replace('md=', '');
const url = `${baseUrl}?md=${mdValue}`;
urls.add(url);
console.log(`Found in ${attr.name}:`, url);
});
}
}
}
});
// Method 3: Look in page source/innerHTML for md= patterns
const pageSource = document.documentElement.innerHTML;
const mdMatches = pageSource.match(/md=([a-f0-9]{32})/g);
if (mdMatches) {
mdMatches.forEach(match => {
const mdValue = match.replace('md=', '');
const url = `${baseUrl}?md=${mdValue}`;
urls.add(url);
});
console.log(`Found ${mdMatches.length} md= patterns in page source`);
}
// Add current page URL if it has md=
if (window.location.href.includes('md=')) {
urls.add(window.location.href);
console.log("Added current page:", window.location.href);
}
const urlArray = Array.from(urls).sort();
console.log(`\nβ
Found ${urlArray.length} unique lesson URLs:`);
urlArray.forEach((url, index) => {
console.log(`${index + 1}. ${url}`);
});
if (urlArray.length === 0) {
console.log("\nβ No lesson URLs found!");
console.log("π‘ Try running this from the main classroom navigation page");
console.log("π‘ Or manually add URLs to the list below");
// Add current URL as fallback
urlArray.push(window.location.href);
}
// Create urls.txt file and download it
const urlText = urlArray.join('\n');
const blob = new Blob([urlText], {type: 'text/plain'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'urls.txt';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
console.log("\nπ Downloaded urls.txt with all found URLs");
console.log("π Next steps:");
console.log("1. Check the downloaded urls.txt file");
console.log("2. Add any missing URLs manually if needed");
console.log("3. Use: wget --input-file=urls.txt [other options]");
return urlArray;
}
// Run the extraction
extractAllLessonUrls();
5. Create a folder on your desktop called project
6. Put your cookies.txt and urls.txt file in the project folder
7. Open terminal application and navigate to your project folder
cd ~/Desktop/project
8. Run the wget command to start the process
#!/bin/bash
# Complete website scraping with wget
wget \
--input-file=urls.txt \
--page-requisites \
--html-extension \
--convert-links \
--restrict-file-names=windows \
--force-directories \
--no-clobber \
--directory-prefix=./skool_complete \
--load-cookies=cookies.txt \
--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" \
--wait=2 \
--span-hosts \
--recursive \
--level=5 \
--no-parent
9. Remove pants π©² and wait for it to finish
10. How to use it
At this point you basically have a copy of what school has on their servers but you have it on your computer so you can access it anytime anywhere and without internet. Simply open the folder in Visual Studio Code and click on one of the HTML files and open with live server.
How to download a single video from skool.com (easy method)
Here's the easier version, as request by all ye youtubers!
Step 1: Visit the page on skool.com where the video is
Step 2: Copy and paste this command in your dev tools console (right click > inspect > go to console tab)
/**
* Skool Loom Video Extractor - Final Version
* Extracts video from current lesson using the md query parameter
*
* Usage: Paste this entire script in browser console while on a Skool classroom page
* Then, go subscribe to @devinschumacher on YouTube
*/
(function() {
console.log('π₯ Skool Loom Video Extractor - Final Version');
// Get the md parameter from URL
const urlParams = new URLSearchParams(window.location.search);
const courseId = urlParams.get('md');
if (!courseId) {
console.log('β No "md" parameter found in URL');
alert('This page does not have a lesson ID (md parameter). Make sure you are on a lesson page.');
return;
}
console.log(`π Looking for course with ID: ${courseId}`);
// Function to recursively search for course by ID
function findCourseById(obj, targetId) {
if (!obj || typeof obj !== 'object') return null;
// Direct match
if (obj.id === targetId && obj.metadata && obj.metadata.videoLink) {
return obj;
}
// Check if this object has a course property with matching ID
if (obj.course && obj.course.id === targetId && obj.course.metadata && obj.course.metadata.videoLink) {
return obj.course;
}
// Recursively search all properties
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
const result = findCourseById(obj[key], targetId);
if (result) return result;
}
}
return null;
}
// Get the Next.js data
const nextDataScript = document.getElementById('__NEXT_DATA__');
if (!nextDataScript) {
console.log('β Could not find __NEXT_DATA__ script');
alert('Could not find page data. This script works on Skool classroom pages.');
return;
}
try {
const nextData = JSON.parse(nextDataScript.textContent);
console.log('π Found page data, searching for course...');
// Search for the course
const course = findCourseById(nextData, courseId);
if (!course) {
console.log('β Could not find course with ID:', courseId);
alert(`Could not find lesson with ID: ${courseId}`);
return;
}
// Extract video information
const metadata = course.metadata;
const videoUrl = metadata.videoLink.split('?')[0]; // Clean URL without parameters
const title = metadata.title || 'Untitled Lesson';
const duration = metadata.videoLenMs ? Math.round(metadata.videoLenMs / 1000) : null;
console.log('β
Found video!');
console.log(`πΉ Title: ${title}`);
console.log(`π URL: ${videoUrl}`);
if (duration) {
const minutes = Math.floor(duration / 60);
const seconds = duration % 60;
console.log(`β±οΈ Duration: ${minutes}:${seconds.toString().padStart(2, '0')}`);
}
// Create download content
const urlContent = videoUrl;
const summaryContent = `# Skool Loom Video
# Course ID: ${courseId}
# Title: ${title}
# Duration: ${duration ? `${Math.floor(duration/60)}:${(duration%60).toString().padStart(2, '0')}` : 'Unknown'}
# Extracted: ${new Date().toLocaleString()}
${videoUrl}
# To download:
# yt-dlp "${videoUrl}"`;
// Download function
function download(content, filename) {
const blob = new Blob([content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// Create filename based on title (sanitized)
const safeTitle = title.replace(/[^a-z0-9]/gi, '_').toLowerCase();
const shortTitle = safeTitle.substring(0, 30);
// Download files
download(urlContent, `loom_${shortTitle}.txt`);
setTimeout(() => {
download(summaryContent, `loom_${shortTitle}_info.txt`);
}, 500);
// Success message
setTimeout(() => {
alert(`β
Found video: "${title}"\n\nDownloaded:\nβ’ loom_${shortTitle}.txt\nβ’ loom_${shortTitle}_info.txt\n\nTo download:\nyt-dlp --batch-file loom_${shortTitle}.txt`);
}, 1000);
} catch (e) {
console.error('β Error parsing page data:', e);
alert('Error parsing page data. See console for details.');
}
})();
This will download something to your desktop on Mac.
Step 3: Get the command from the file and run it in your terminal
It will look something like this:
# Skool Loom Video
# Course ID: c22bf3e55b6f41f98e12eedfbb14391e
# Title: How We Notify You If You Won
# Duration: 1:23
# Extracted: 5/28/2025, 2:13:17 PM
https://www.loom.com/share/b19b38d0ce2b44f5a049b871d9a38925
# To download:
# yt-dlp "https://www.loom.com/share/b19b38d0ce2b44f5a049b871d9a38925"
Focus on the yt-dlp "https://www.loom.com/share/b19b38d0ce2b44f5a049b871d9a38925" part.
Paste that in your terminal and it will download to where you are!
So if that helped, and you're feelin generous - feel free to sponsor me so I can make more tutorials like this.
....and take baths like this
Related Posts
How to Download Onlyfans Profile's Videos & Images for FREE (yt-dlp tutorial)
Download OnlyFans profile videos and images using yt-dlp by capturing the MP4 media URL from DevTools; simple step-by-step workflow and examples.
How to Download Circle.so Videos for Free (HLS m3u8 Streams) - using yt-dlp
Step-by-step guide to download Circle.so HLS m3u8 videos with yt-dlp, auto-naming, ffmpeg optimization, and troubleshooting tips.
How to Download Coursera Videos for FREE (yt-dlp tutorial)
Download Coursera lectures with yt-dlp by capturing MP4 or HLS/DASH URLs from DevTools. Step-by-step workflow and examples.