Reference
Membership & Gated Content
Access control is enforced at the hosted runtime: non-members get a 401 (or login redirect) before the page is rendered. The engine surfaces
isMemberandmemberTierto your templates so logged-in members can see personalized content. Local preview does not enforce auth — gated pages render as if the viewer is a member, so you can author them.
Access control is enforced before the page is rendered — not just hidden in HTML. A non-member requesting a gated page gets a 401 response (or redirect to a login page), not a page with hidden content. This means gating is secure even if someone inspects the source.
How it works
- Set
access:in page frontmatter → Worker enforces it on every request - Use
{% if isMember %}blocks in templates → show/hide content based on membership memberTieris available for multi-tier gating
1. Gate an entire page
Add access: to the page frontmatter. The Worker checks the user's JWT before rendering:
---
title: Member Dashboard
description: Your exclusive member area
access: member
---
<h1>Welcome back, member!</h1>
<p>Here's your exclusive content...</p>
Access values:
| Value | Who can access |
|---|---|
member |
Any logged-in member (any tier) |
pro |
Members with tier pro or higher |
enterprise |
Members with tier enterprise only |
* |
Any authenticated user (any tier, even free) |
Non-members are redirected to the login page automatically.
2. Partial gating — show different content to members vs guests
Use {% if isMember %} blocks anywhere in a page or template. The Worker injects isMember (boolean) and memberTier (string) into every page render:
---
title: Advanced Guide to Investing
---
<h1>Advanced Guide to Investing</h1>
<!-- Free preview — everyone sees this -->
<div class="prose">
<p>Investing can seem complex, but with the right framework...</p>
<h2>The basics</h2>
<p>Start with an emergency fund before investing...</p>
</div>
{% if isMember %}
<!-- Full content — members only -->
<div class="prose mt-8">
<h2>Advanced strategies</h2>
<p>Once you have the basics covered, consider...</p>
</div>
{% else %}
<!-- Upgrade prompt — guests see this -->
<div class="bg-primary-50 border border-primary-200 rounded-xl p-8 mt-8 text-center">
<h2 class="text-xl font-bold mb-2">Continue reading with a membership</h2>
<p class="text-secondary-600 mb-6">Get access to the full guide plus all premium content.</p>
<a href="/join" class="bg-primary-600 text-white px-6 py-3 rounded-lg font-semibold hover:bg-primary-700">
Join now
</a>
</div>
{% endif %}
3. Tier-based gating
memberTier holds the member's tier string (e.g., "free", "pro", "enterprise"):
{% if memberTier == "pro" or memberTier == "enterprise" %}
<div>Pro-only feature...</div>
{% elsif isMember %}
<div class="p-6 bg-secondary-50 rounded-lg text-center">
<p class="font-semibold">Upgrade to Pro to unlock this feature</p>
<a href="/upgrade" class="text-primary-600 font-medium mt-2 inline-block">Upgrade →</a>
</div>
{% endif %}
4. Gated pages directory pattern
For a members area with multiple pages, gate the whole section with access: on each page:
pages/
members/
index.html ← access: member
dashboard.html ← access: member
courses.html ← access: member
billing.html ← access: member
Template variables
| Variable | Type | Value |
|---|---|---|
{{ isMember }} |
boolean | true if user is authenticated with any membership |
{{ memberTier }} |
string | Tier name ("free", "pro", "enterprise") or empty |
Both are available on every page — no configuration needed. On public pages where no one is logged in, isMember is false and memberTier is empty.
Rules
access:gating is server-side — don't try to replicate it with Alpine.jsx-showor CSShidden. The Worker enforces it before the page renders.{% if isMember %}blocks are for partial gating — showing a teaser to guests while showing full content to members. For full page gating, useaccess:frontmatter instead.- Always provide an upgrade/login prompt in the
{% else %}branch — don't just show nothing memberTiercomparison is case-sensitive — match the exact strings used when creating members- Membership setup (Stripe Subscriptions, login flow) is handled separately — this skill covers the template side only