How TeachRepo embeds StackBlitz and CodeSandbox environments that unlock on purchase — real, runnable code in the browser with zero student setup.
Technical courses live or die by their code examples. But most platforms force you into one of two bad options:
The right answer is a live, runnable code environment embedded directly in the lesson. Students click a button, a full dev environment boots in 3 seconds, they're writing and running code immediately.
TeachRepo integrates with two browser-based code environments:
Add a sandbox block to any lesson's YAML frontmatter:
--- title: "Async Python: Hands-On" access: paid sandbox: provider: stackblitz # stackblitz | codesandbox template: node # project template repo: "yourname/course-repo" # GitHub repo with starter code branch: "lesson-03-starter" # optional branch file: "src/index.py" # file to open on launch height: 600 # iframe height in px --- # Async Python: Hands-On In this lesson you'll implement a rate-limited HTTP client using asyncio + aiohttp. The sandbox below has the starter code ready. Hit **Run** to see the baseline, then follow the exercises below. [sandbox will appear here for paid students] ## Exercise 1: Add Exponential Backoff Modify the `fetch_with_retry` function to implement exponential backoff with jitter. Target: 3 retries, base delay of 1 second.
Sandboxes are gated behind the same access control as lesson content:
// SandboxEmbed.tsx (simplified)
export function SandboxEmbed({ config, hasAccess }: Props) {
if (!hasAccess) {
return (
<div className="sandbox-locked">
<LockIcon />
<p>Purchase the course to access this sandbox</p>
<CheckoutButton courseId={config.courseId} />
</div>
);
}
return (
<iframe
src={getSandboxUrl(config)} // StackBlitz or CodeSandbox embed URL
height={config.height ?? 500}
allow="cross-origin-isolated"
sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
/>
);
}The hasAccess check hits the database exactly once per page load (when the lesson page is rendered server-side). After that, it's baked into the HTML. No per-sandbox API calls.
StackBlitz supports several embed URL patterns. TeachRepo uses the GitHub-linked embed:
// For a GitHub repo:
const url = `https://stackblitz.com/github/${repo}` +
(branch ? `/tree/${branch}` : '') +
`?embed=1` +
`&view=editor` +
`&file=${encodeURIComponent(file)}` +
`&theme=dark` +
`&hideNavigation=1`;
// Example:
// https://stackblitz.com/github/yourname/course-repo/tree/lesson-03-starter
// ?embed=1&view=editor&file=src/index.py&theme=dark&hideNavigation=1The student gets a fully-functional VS Code-like editor with the exact starter code for that lesson, already cloned, already running.
Keep your starter code on a dedicated branch per lesson (lesson-01-starter, lesson-02-starter, etc.). This makes it trivial to update starter code without breaking other lessons.
Pair each lesson-N-starter with a lesson-N-solution. Students who get stuck can diff the two branches. You can embed the solution as a second, separately-gated sandbox (or just link to it as a spoiler).
Each sandbox should demonstrate one concept, not an entire feature. A 200-line starter file is too intimidating. A 40-line file with 3 clearly-marked TODO comments is exactly right.
StackBlitz WebContainers are fast, but they still download a Node runtime. On a 3G connection this can take 15–20 seconds. Provide a static fallback code block above the sandbox so students aren't staring at a loading spinner if they're on a slow connection.
---
title: "Async Python: Hands-On"
access: paid
sandbox:
provider: stackblitz
repo: "yourname/course-repo"
branch: "lesson-03-starter"
fallback_code: | # shown while sandbox loads
import asyncio
import aiohttp
async def fetch(session, url):
async with session.get(url) as response:
return await response.json()
# ... rest of starter code
---| Feature | StackBlitz | CodeSandbox |
|---|---|---|
| Startup time | ~2s (WebContainers) | ~5–15s (server-side) |
| Node.js support | Full (in-browser) | Full (cloud container) |
| Python/Ruby/etc. | Limited (WASM only) | Full (Docker) |
| File system | In-memory | Persistent |
| Network requests | Limited (CORS) | Full |
| Best for | JS/TS/Node lessons | Multi-language, complex apps |
TeachRepo fires a sandbox_opened event when a student interacts with a sandbox. This shows in your creator dashboard alongside lesson views and quiz completions — useful for understanding which exercises students actually engage with.
When a student can run, modify, and experiment with code inside the lesson — without cloning a repo, installing dependencies, or fighting their local environment — you get dramatically higher lesson completion rates.
The setup cost is minimal: one extra YAML block per lesson, a GitHub branch with starter code. The payoff is a significantly better learning experience.
Build a course with live sandbox exercises
Sandbox support is available on all TeachRepo plans — free and hosted. Add a sandbox: block to any lesson and ship.