Podscope is a self-hosted podcast membership platform built on Laravel. Private RSS feeds, Stripe-powered subscriptions, Cloudflare Stream video, and full ownership of your content and subscriber data.
No platform lock-in. No revenue share. No monthly SaaS bill. Just your podcast, your way.
Every paying member gets a unique feed URL that works with every podcast app. Cancel a subscription and the feed stops -- automatically, no manual action required.
Create show-specific plans or an all-shows tier. Monthly recurring billing, automatic renewal, and a grace period on cancellation. All handled by Stripe.
Upload episode videos directly from the admin panel. Signed playback tokens keep videos locked to paid members -- no public URL, no workarounds.
Full namespace support: chapters, transcripts, persons, funding, soundbites, GUID, locked, medium, and more. Your feed works with every modern podcast app.
Store audio files and artwork on local disk or Backblaze B2 cloud storage. Switch between backends from settings -- no code changes, no file migrations.
Let paid episodes breathe. Set a preview period so new episodes are publicly available for a configurable number of days before the paywall kicks in.
OP3 prefix on public feeds for directory-level analytics. Internal play tracking on private feeds. A dedicated stats dashboard shows plays by episode, show, and type.
Manage shows, episodes, members, plans, pages, media, and settings from a clean, modern admin built on Filament 5. No clunky legacy CMS interface.
Podscope is a standard Laravel application. If you can run a PHP site, you can run Podscope.
Clone the repo, run composer install, configure your .env file, and run migrations. Works on any server with PHP 8.4 and a queue worker.
Add your Stripe keys, connect Backblaze B2 or use local storage, set up Mailgun for notifications, and configure Cloudflare Stream if you want video.
Create your show, upload episodes, set up membership plans, and submit your RSS feed to Apple Podcasts and Spotify. Your members subscribe and get immediate access.
Podscope runs on the same stack as any modern Laravel application. No exotic dependencies.
A complete install from a fresh server. Full documentation covers CloudPanel, Nginx, and Supervisor configuration.
Podscope is free to self-host. No monthly platform fee, no revenue share, no third-party holding your subscriber list hostage.
Podscope is under active development. New features ship regularly.
maps to show_id=NULL via MembershipPlan::ALL_SHOWS sentinel + scopeToShowId()/showIdToScope() helpers wired through the field formatStateUsing/dehydrateStateUsing. No schema change; subscriptionName()/checkout/RSS/access untouched; no pseudo-show record created. Tests: MembershipPlanScopeTest (6: he
membership_plans.show_id FK was ON DELETE SET NULL, and a NULL show_id is the app all_shows sentinel, so deleting a show turned its show-specific plans into platform-wide everything-plans (reported: deleted Don Talk plans showed as all-access on Book of Donovan). Fix (hybrid): Show deleting hook now
Report-Only header present with full policy, nginx narrow enforced CSP still present, header nonce == script nonce within a response, admin/RSS excluded, episode/home render, no inline handlers remain, no log errors. ROLLOUT: nginx keeps its enforced CSP during the soak; to enforce later set CSP_ENF
StreamUploadController::storeAndCopy forces a safe video extension (new safeVideoExtension() allow-list mp4/mov/webm/mkv/m4v/avi, else mp4) instead of trusting the client extension, so a polyglot cannot be written as an executable .php under the public stream-tmp dir. N-7: favicon upload drops image
:clean() (Symfony HtmlSanitizer, curated safe allow-list) and applied it at all four raw {!! body !!} render sinks: episodes/show.blade.php (HTML branch), pages/show.blade.php, rss/feed.blade.php, rss/private-feed.blade.php. Sanitizing at the render sink closes existing stored content plus future au
EpisodePlayController::web (404 unless published; 403 unless admin/canAccessEpisode), CommentController::store and ReactionController::toggle (404 unless target published), ChaptersController::show public endpoint (404 unless published), ShowNotificationController::toggle (404 unless show published)
TrackingController::privateAudio now 404s unpublished/scheduled episodes even for valid token holders (canAccessEpisode was publish-agnostic, leaking unreleased free-episode audio). N-3: composer update guzzlehttp/guzzle 7.11.1->7.13.1 and psr7 2.11.0->2.12.3, clearing CVE-2026-55767/-55568/-55766;
restricted trusted proxies from at:* to loopback only (127.0.0.1, ::1) in bootstrap/app.php. trustProxies(at:*) made $request->ip() spoofable: CloudPanel edge nginx appends the real IP to $proxy_add_x_forwarded_for, and Symfony returned the leftmost (client-injected) XFF entry, defeating the M-4 aut