Skip to content
Gaurav TiwariDocs

Page Access for Buyers

Version 0.2.0 Updated November 15, 2026

How to sell access to pages, such as a members area, a course or a private changelog: access rules, the template gate, path protection, the access link and the editor’s Store panel. A buyer of the right product (or plan) sees the page; everyone else sees a notice with buy links.

Turn on the Page Access module (page_access toggle). It needs Licensing. A license that came with a bundle unlocks pages for its own product, the same as one bought on its own. In 0.2.0 the content editor’s Store panel can also limit an entry to buyers (see The Admin, the Sidebar and Product Pages).

EmDash has no content gating API, so Vendwick gates pages in two ways, and you’ll usually use one or both:

  • In templates: <AccessGate> and hasAccess() around content. See Components, Blocks and Styling.
  • By path: the companion middleware guards whole paths before the page renders.

Verified: the gate has run on a local workerd with D1 (for 0.1.0), as well as in the Node test suite. It hasn’t run on a deployed Worker yet.

Rules

You manage rules on the Page access admin page. A rule has:

  • A target: a content entry (a collection and an entry, picked from your content), or a path pattern. /members matches that path exactly; /members/* matches it and everything under it.
  • Grants: the products that unlock it, each for any plan or one plan, and optionally "requires a live subscription" instead of just an unexpired license.
  • A teaser: text shown to visitors without access.
  • noindex: on by default.
  • A mode: follow the store default, always show the notice (teaser), or always redirect (redirect).
  • Status: active or disabled.

Paths that can never be protected: /, /_emdash, /_vendwick, /_astro, /_image, /_server-islands, and the checkout, account and product paths.

Who gets in

  • A licensed product counts while its license is active, not past its expiry (no expiry means lifetime), and its order was paid and not refunded. If the license has a subscription, it must be live (active, trialing or past_due) or canceled with paid time left.
  • A product without a license (a service or event) counts while its order item is paid and not refunded.
  • A disabled license or a refunded order ends access at once. A partially refunded order still counts as paid.
  • With access_after_end set to "Keep access after the first payment", a license from a paid order keeps counting after it expires or its subscription ends.
  • Signed-in EmDash editors and admins always get in.

Visitors without access

SettingOptions (default first)
access_guest_action: visitors not signed insee the notice, or go to the access page
access_denied_action: signed-in customers without the productsee the notice, or go to the product
access_after_endaccess ends, or keep access after the first payment
access_locked_title, access_guest_text, access_denied_textnotice wording; {products} becomes the products that unlock the page
access_show_in_account, access_account_labelshow "My pages" in the customer account (on, "My pages")
access_cookie_daysaccess cookie lifetime, 1 to 365 days (30)

A rule’s mode overrides the first two settings for that rule.

Path protection

The middleware checks a request when its path falls under an active path rule, or under a pattern you declare in the site options:

vendwickSite({ accessPaths: ["/members/*", "/course"] })
  • A declared path with no admin rule stays closed to everyone except staff. Admin rules say who gets in.
  • Visitors with access get the page with Cache-Control: private, no-store. Others get a 303 to /_vendwick/access?return=<path> (or the first buy link, when the rule or store says so). Non-GET requests get 403.
  • Active path patterns are cached in each worker isolate for 30 seconds, so a new or changed rule can take up to 30 seconds to apply.
  • When storage or the plugin can’t be reached, declared paths and paths this isolate already knew were protected fail closed with 503. Every other path renders normally.
  • At most 100 active path rules are read.

On the gate or the access page, a buyer types their email under "Already bought?".

  • The answer is the same whether or not the email is known, so it can’t be used to find customers.
  • A known email (a customer, or licenses or orders for it) gets an emailed link, at most once every five minutes per email. Each IP may ask ten times a minute.
  • The email is the page_access_link template, so its wording is the page-access wording, not the account-link wording. It’s branded and editable when the emails module is on.
  • The link is good for 30 days and is signed with a page-only key: it never opens the customer account.
  • Opening it (/_vendwick/access?cf_page_access_token=…&return=<path>) creates a session and sets the cf_page_access cookie (HttpOnly, Secure, SameSite=Lax, path /) for access_cookie_days, then redirects to the page so the token doesn’t stay in the address bar. Return paths must be on the same site; anything else goes to /.
  • A customer who signs in to the account also gets the cf_page_access cookie, mirrored from their portal session.

On gated pages, Vendwick’s page:metadata contribution sets robots: noindex and a generic description, so the entry’s excerpt doesn’t reach the description tag. The same metadata goes to every visitor, buyers included. Gated responses also send X-Robots-Tag: noindex when the rule has noindex on.

What a plugin can’t do on EmDash:

  • Sitemaps: plugins can’t remove entries. Keep gated entries out with an excluded collection or the entry’s SEO "no index" setting, or protect a section the sitemap doesn’t list.
  • Site search: plugins can’t filter results. Mark the gated collection’s body fields as not searchable, or filter results in your search template with hasAccess().
  • Prerendered or edge-cached pages can’t be gated; their HTML is built once for everyone.
  • Media files aren’t protected. A page can be gated, but an image or file URL it links to from the public media library is still public. Sell files as releases or digital products instead.

"My pages"

<MyPages /> and the account’s "My pages" tab list the gated pages a customer has unlocked, with links where EmDash can resolve a public URL. Up to 500 active content rules are read for this list.

Share

Was this helpful?

Still stuck? Open a support ticket