DEV Community

Fernando Paladini
Fernando Paladini

Posted on

Download Authorized Circle Course Videos with Python and Playwright

If you have permission to watch a Circle course but your connection is unreliable, saving it for later is harder than it sounds. The useful data is behind a browser session, course pages can contain many lessons, and a downloader should not turn authentication into a pile of copied cookies.

This tutorial shows a local workflow with Circle Course Downloader. It opens a dedicated Chromium profile for you to sign in normally, discovers video URLs from pages you can already access, and delegates the media transfer to yt-dlp.

The important boundary is authorization: use this only for content you are allowed to view and download. The project is unofficial and does not bypass DRM, paywalls, two-factor authentication, captchas, or access controls.

TL;DR

Install version 0.1.4 from PyPI, install the Chromium runtime, and run a dry run against a course URL:

py -m pip install circle-course-downloader
py -m playwright install chromium
circle-course-downloader download "https://your-community.example.com/c/course-slug" --dry-run
Enter fullscreen mode Exit fullscreen mode

On the first run, a visible Chromium window lets you authenticate. The tool stores the session in its own local profile, discovers lessons, and prints the yt-dlp commands without downloading media. Remove --dry-run only after checking the result and confirming your rights to save the content.

Prerequisites

You need Python 3.11 or newer, an account authorized for the Circle community and specific content, Chromium installed through Playwright, and enough local disk space for the media.

The package is MIT licensed and currently early-stage software. Version 0.1.4 is available on PyPI and the source is maintained in the public GitHub repository.

Create a virtual environment when you want the CLI isolated from other Python tools:

py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install circle-course-downloader
python -m playwright install chromium
Enter fullscreen mode Exit fullscreen mode

Start with a dry run

Use download for a full course page. Replace the example hostname and slug with a URL from your own community:

circle-course-downloader download "https://your-community.example.com/c/course-slug" --dry-run
Enter fullscreen mode Exit fullscreen mode

The first run opens a dedicated Chromium profile. Sign in in that window, return to the terminal, and press Enter. This is deliberately browser-first. You do not paste a password into the terminal, export cookies from your default browser, or place a token in a command argument.

After authentication, the downloader visits the course page, finds lesson links, inspects each lesson for supported video providers, and prints the commands it would use. The supported list includes Circle HLS, direct video URLs, YouTube, Vimeo, Wistia, Loom, Mux, and Cloudflare Stream.

The dry run is a decision point. Review the discovered lesson names and URLs. If the page includes material you are not authorized to download, stop there or narrow the operation according to the project capabilities and service rules.

For a single community post or event page with one embedded video, use the separate command:

circle-course-downloader download-standalone "https://your-community.example.com/c/space-slug/post-slug" --dry-run
Enter fullscreen mode Exit fullscreen mode

The commands are not interchangeable. download expects a course structure with sections and lessons. download-standalone targets one page with one embedded video.

Download after checking the plan

When the dry-run output matches your intended scope, run the same command without --dry-run:

circle-course-downloader download "https://your-community.example.com/c/course-slug"
Enter fullscreen mode Exit fullscreen mode

By default, media and manifests go under downloads/. Use --output-dir for a dedicated destination:

circle-course-downloader download "https://your-community.example.com/c/course-slug" --output-dir "./authorized-course-export"
Enter fullscreen mode Exit fullscreen mode

The downloader uses yt-dlp with resume support and MP4 merge output. This helps with long courses and interrupted connections, but it does not guarantee that every provider or stream will work forever. Provider changes, expired signed URLs, unavailable lessons, and codec issues can still affect individual downloads.

The yt-dlp documentation describes its output and continuation behavior. That downstream tool receives URLs discovered from the authorized browser session, so protect those URLs like credentials.

Understand the local files

The default layout is easy to inspect:

.auth/session-browser-profile/
.auth/session.json
downloads/manifest.json
downloads/manifest.csv
downloads/01 - Lesson title.mp4
Enter fullscreen mode Exit fullscreen mode

The manifest records what discovery found. Treat it as an audit artifact, not disposable noise. It can contain signed media URLs, so do not publish or commit it.

The session files are even more sensitive. Playwright's authentication documentation explains that saved browser state can contain cookies, local storage, and other credentials that may impersonate an account. Keep .auth/ local and add it to .gitignore in any workspace where you use the tool.

This design follows Playwright's storage-state pattern: authenticate once in a controlled browser context and reuse that state later. It is safer than copying cookies from a personal browser, but it is not a security boundary. Anyone who obtains the stored state may be able to act as you until it expires or is revoked.

Useful options

Both commands accept the same operational options:

circle-course-downloader download "https://your-community.example.com/c/course-slug" --output-dir "./downloads" --session "./.auth/session.json" --headless
Enter fullscreen mode Exit fullscreen mode

Use --session to choose a different exported session location. The browser profile is stored next to it. Use --force-login when the existing session is stale and you want a fresh visible login. Use --headless only after a saved browser profile exists. A first login requires a visible browser window.

The CLI exposes the exact options installed on your machine:

circle-course-downloader download --help
circle-course-downloader download-standalone --help
Enter fullscreen mode Exit fullscreen mode

Verify the installation locally

You can verify the installed CLI without logging into a community:

circle-course-downloader --help
circle-course-downloader download --help
circle-course-downloader download-standalone --help
Enter fullscreen mode Exit fullscreen mode

For a source checkout, the repository's development checks include tests, Python compilation, wheel building, and package metadata validation. At the current v0.1.4 release commit, those checks completed successfully in a clean checkout: 17 tests passed, compileall passed, the package build produced both sdist and wheel, and twine check passed for both artifacts.

Those results validate the package and parser logic. They do not prove that a particular Circle community, lesson, provider, or account session will work today. The meaningful end-to-end check for your account is a small authorized dry run followed by one or two downloads that you can inspect.

Failure modes and limits

If Chromium does not start, install the browser runtime with python -m playwright install chromium and check that the active Python environment is the one running the CLI.

If the browser opens but discovery returns no lessons, confirm that the URL is a full course page and that the signed-in account can see the lessons in the browser. For one standalone post, use download-standalone instead.

If a session stops working, use --force-login. Do not work around the problem by copying cookies or tokens from another browser. If a provider URL has expired, rerun discovery instead of sharing the old signed URL.

The tool does not defeat access controls. It cannot make unavailable content available, and a successful browser login is not proof that downloading is contractually or legally permitted. Check the course license, community terms, and content owner's instructions.

FAQ

Does this upload my course to an API?

The project runs the browser and downloader locally and does not require a hosted AI service. It still connects to the community and media providers required to authenticate, discover pages, and transfer authorized files.

Can I reuse my normal Chrome profile?

The documented workflow uses a dedicated Chromium profile. Keep it separate. This avoids exposing unrelated browser cookies and makes the session files easier to identify and protect.

Can I use it for any video URL?

No. It is designed around Circle course and community pages and the providers its extractors recognize. It is not a general-purpose access-control bypass.

Why run --dry-run first?

It makes the scope visible before media is written. You can inspect discovery results, catch a wrong URL, and review the generated commands before accepting the external content transfer.

Takeaway

The useful pattern is a controlled workflow: authenticate in a dedicated browser, discover only what the account can already access, inspect the plan, download locally, and protect the session and manifest files.

Circle Course Downloader packages that workflow behind two small commands. Start with --dry-run, test a narrow authorized scope, and treat the current 0.1.4 release as early-stage software whose provider support can change.

Have you found a reliable way to audit and expire local browser sessions for authorized offline course backups?

AI assistance disclosure

AI assistance was used to organize and edit this tutorial. The commands, package metadata, repository behavior, test results, security boundaries, and limitations were checked against the public project sources and local validation runs described above.

Top comments (0)