Integration modes
Cobuntu has one rule that decides who sees what. Everything else in this page — three named modes, two override layers, a custom-routes bypass — is configuration on top of that rule.
If you only remember one thing from this page, remember this:
Effective visibility =
page.visibility ?? community.visibility. If the resolved value isPUBLIC, anyone sees the page. IfMEMBERS_ONLY, only an ACCEPTED member of the community does.
Everything below is a consequence of that line.
The rule that runs them all
Two columns drive every decision:
visibility(community default) — the org-wide default.PUBLICorMEMBERS_ONLY.- Per-page override — a specific page (feed, events, marketplace,
members, …) can be set to
PUBLICorMEMBERS_ONLYindependently, or left unset to fall through to the community default.
The resolver runs the same way on every request:
That's the whole gate. The three modes you'll see below are just names for the three useful shapes that resolver naturally produces when you set the two columns differently.
The three modes at a glance
| Portal | Storefront | Hybrid | |
|---|---|---|---|
community.visibility | MEMBERS_ONLY | PUBLIC | either |
| Page overrides? | none | none | one or more rows |
| What anon sees | gate page everywhere | every page | mixed, per-page |
| SEO / GEO | none (noindex) | maximum | partial — public pages indexed |
| SDK complexity | minimal | minimal | needs usePageAccess |
| Typical use case | paid mastermind, private club | content-led brand, public marketplace | curated community with a members-only inner ring |
The mode is derived from those two columns, not stored — flip either column in cobuntu-admin and the mode label changes on the next page-load.
Portal
A private members-only space. Like a Slack workspace or a Discord server — nobody outside sees anything.
Configuration. Community default visibility = MEMBERS_ONLY,
no page-level overrides. Every canonical page (/feed, /events,
/marketplace, /members, /atlas, /blog, /conversations,
plus the viewer-scoped /hub, /profile, /settings) inherits
MEMBERS_ONLY and gates accordingly.
What the visitor experiences.
Why pick it.
- Privacy guarantee — no member data leaks through any surface.
- Compliance-friendly: GDPR / DSA "private community" semantics are trivial to argue.
- Simple SDK story: landing nav is either "go to /login" or "logged in, render everything."
Cost.
- Zero SEO / GEO discoverability. Cobuntu pages emit
X-Robots-Tag: noindex(opens in a new tab). Search engines see only your landing. - Funnel is fully customer-owned: the landing has to convert anon → signup → application, because Cobuntu won't show anything before that.
SDK implication. The landing only needs to know "is this
visitor logged in?" The cobuntu_auth cookie
is enough — no usePageAccess call needed.
Storefront
Everything is public. The community functions as a public-facing showroom — anyone can browse feed, marketplace, events, members — and they choose whether to sign in later.
Configuration. Community default visibility = PUBLIC, no
page-level overrides. Every canonical page resolves to PUBLIC for an
anonymous visitor — with one intrinsic exception: /conversations
is always MEMBERS_ONLY, no matter the community shape, because
chat is private user data by invariant.
What the visitor experiences.
Why pick it.
- Maximum discoverability — feed posts, event pages, marketplace listings, member directory all crawled and indexed. Generative search engines can cite your event copy. Every member post is a fresh page in your site map.
- Frictionless funnel: anon → reads → sees value → signs up. No "members-only" wall hiding the goods.
- Inside Storefront you can still gate individual channels via the
chapter's own
visibilitycolumn — fine-grained without flipping the whole community.
Cost.
- Member content is public by default. Deletes work, but third-party caches can linger.
- The "members-only club" framing is gone. If exclusivity is the value prop, this isn't the right mode.
SDK implication. The landing doesn't need to gate any nav item — every Cobuntu route is clickable for anyone. The SDK is about layout, theming, and cross-domain auth, not page-access filtering.
Hybrid
Mixed-visibility. Some pages are open to the public, some require membership. The most flexible mode — and the most common for paid or curated communities.
Configuration. Any time at least one page has a visibility
override set in admin → Settings → Pages. Each page resolves
independently through the same rule from the top of this page
(effective = page.visibility ?? community.visibility).
Because either column can be the default and either can be the override, Hybrid expresses two opposite shapes:
These are the same two patterns you'll recognise from firewalls, OAuth scopes, and CSP headers — default-allow with exceptions vs default-deny with exceptions. Pick whichever frames your community more naturally.
Flavour A — Blocklist (default-allow)
Community default visibility = PUBLIC + selectively gate the inner
ring. The most common Hybrid shape today.
Sample shape:
Community default = PUBLIC
Per-page overrides:
FEED = MEMBERS_ONLY ← gated
MEMBERS = MEMBERS_ONLY ← gated
ATLAS = MEMBERS_ONLY ← gated
EVENTS = unset (inherits PUBLIC)
MARKETPLACE = unset (inherits PUBLIC)
BLOG = disabled (yields to your landing — see note below)
CHAT = always MEMBERS_ONLY (intrinsic)Use when your public surface is top-of-funnel and the gated pages are the value prop. Events and marketplace pull in traffic; joining unlocks the feed and member directory.
What happens when you disable a page (
enabled: false). The Cobuntu reverse proxy yields the route to your landing host. That is, if you disableBLOG, a request toyourdomain.com/blogfalls through to the landing host (Lovable, Webflow, Squarespace, your own Next.js, etc.) — same path Cobuntu uses for any Layer 3 custom route. This lets you author your own/blogon the landing without a route-collision with Cobuntu's. If your landing doesn't have that route either, the visitor gets whatever 404 / fallback the landing host serves. Cobuntu itself never renders a 404 for a disabled page.
Flavour B — Allowlist (default-deny)
Community default visibility = MEMBERS_ONLY + open up the specific
pages that should leak outward — typically for marketing or
recruiting.
Sample shape (closed network with a public face):
Community default = MEMBERS_ONLY
Per-page overrides:
EVENTS = PUBLIC ← published outward
BLOG = PUBLIC ← published outward
FEED = unset (inherits MEMBERS_ONLY)
MEMBERS = unset (inherits MEMBERS_ONLY)
ATLAS = unset (inherits MEMBERS_ONLY)
MARKETPLACE = unset (inherits MEMBERS_ONLY)
CHAT = always MEMBERS_ONLY (intrinsic)Use when the community itself is the value prop — a closed mastermind, an invite-only network — and only specific surfaces should be visible to the outside world.
What changes between flavours
Nothing in the resolver. The runtime gate treats them identically;
the only difference is which column you flip first. The
usePageAccess hook returns the
same shape either way, and SDK code that filters nav items by
"can the viewer see this page?" works without modification.
SDK implication. The landing can't know upfront which routes
to render in the nav — that depends on (a) what the leader
configured per page and (b) whether the current viewer is a
member. One usePageAccess(communityTag) call answers both, in
one round-trip. See auth & page access for
the wiring.
Layer 2 — Entity-level overrides
The three modes operate on pages. Layer 2 operates on individual entities within a page — events, feed posts, and (soon) more.
You'll see Layer 2 most often when:
- You're in Storefront and want a single event to require
member-only RSVP — without gating the whole
/eventslisting. - You're in Allowlist Hybrid and want a single event to
render publicly — without flipping the whole
/eventspage.
Events have two axes
Events split visibility into two independent columns:
The two columns are independent, giving four combinations — three useful, one borderline:
viewability | accessibility | Reading |
|---|---|---|
PUBLIC | PUBLIC | Anyone sees the event, anyone registers. Pure top-of-funnel. |
PUBLIC | MEMBERS_ONLY | Anyone sees the event card; only members can RSVP. The classic "members-only perks, shown publicly" framing. |
MEMBERS_ONLY | MEMBERS_ONLY | Card only renders for members; registration also gated. Default for internal events. |
MEMBERS_ONLY | PUBLIC | Allowed but usually a mistake — non-member viewer can't see the card, but if the URL is shared they can RSVP. |
Sample shape — a Storefront community using accessibility: MEMBERS_ONLY to gate registration on member events while keeping
the listings public:
Public Open Mixer viewability=PUBLIC accessibility=PUBLIC ← fully public event
Members Monthly Brunch viewability=PUBLIC accessibility=MEMBERS_ONLY ← public listing, member-only RSVP
Founders Workshop viewability=PUBLIC accessibility=MEMBERS_ONLY ← same pattern
Annual Retreat viewability=MEMBERS_ONLY accessibility=MEMBERS_ONLY ← fully internalHow Layer 2 interacts with Layer 1
The page gate (Layer 1) runs first on the listing URL. The detail URL bypasses the page gate and delegates to the entity:
This delegation is exactly what makes "fully-private community with a single fully-public event" work end-to-end: the event-detail URL respects its own columns, not the parent page's visibility.
Where Layer 2 exists today
| Entity | Per-row visibility? | Notes |
|---|---|---|
| Events | Yes — viewability + accessibility | Full 2-axis split, documented above. |
| Messages (feed posts) | Yes — visibility, stamped at create-time from the channel | Inherited from the channel, then frozen on the post. Flipping a channel private → public only affects new posts; old ones keep their original visibility. Posts in chat channels are always MEMBERS_ONLY by invariant. |
| Products (marketplace listings) | No — inherits from /marketplace page | No per-product override yet. |
| Articles (blog posts) | No — inherits from /blog page | No per-article override yet. |
When per-entity overrides ship on more entity types, this table grows. The Layer 1 + Layer 2 composition shape stays the same.
Layer 3 — Custom landing routes
Your landing has its own routes — /, /about, /pricing,
/custom-route, anything you build. These are outside the
visibility system entirely. Cobuntu's reverse proxy (Hosted apex
pattern) leaves them untouched: a request to a path Cobuntu doesn't
own falls through to your landing host, no gating, no rewriting,
no SEO overrides.
Cobuntu's reserved paths
Anything matching these prefixes is owned by Cobuntu — the reverse proxy serves the Cobuntu page, not your landing:
| Surface | Paths |
|---|---|
| Feed | /feed, /feed/<channel-slug>, /feed/post/<id> |
| Events | /events, /events/<slug>, /events/new |
| Marketplace | /marketplace, /marketplace/<slug> |
| Members | /members, /members/<usertag> |
| Atlas | /atlas |
| Blog | /blog, /blog/<slug> |
| Chat | /conversations, /conversations/<id> |
| Cart + checkout | /cart, /checkout |
| Personal hub | /hub, /notifications, /library, /downloads, /my-events, /my-orders, /selling-here |
| Profile | /profile, /profile/edit |
| Settings | /settings, /settings/account, /settings/edit-profile, /settings/notifications, /settings/privacy |
| Membership | /membership, /plans |
| Auth + onboarding | /login, /join, /apply, /onboarding, /sso/* |
| Legal | /privacy, /terms |
| API | /api/* |
Anything else routes to your landing. You keep full control over the routes you author.
Picking a mode
Quick-pick table:
| If your community... | Pick |
|---|---|
| Sells access to a private group, no public surface needed | Portal |
| Is content-led, wants every event and article indexed | Storefront |
| Has a public showroom and a members-only inner ring | Hybrid Blocklist |
| Is members-only at heart but wants a few outward-facing pages | Hybrid Allowlist |
| Doesn't know yet | Storefront — flip into Hybrid later by overriding one page |
The default for new communities is PUBLIC + no overrides — i.e.,
Storefront. Customers move toward Hybrid by overriding individual
pages in cobuntu-admin → Settings, or to Portal by flipping the
community-level visibility.
Cheat sheet — admin settings reference
What you set, where you set it, what value it takes:
| In cobuntu-admin → Settings | Field | Value |
|---|---|---|
| Community visibility toggle | visibility | PUBLIC | MEMBERS_ONLY |
| How members get in | accessibility | OPEN | APPLICATION | INVITE_ONLY |
| Per-page Enabled switch | page override | boolean |
| Per-page Visibility override | page override | PUBLIC | MEMBERS_ONLY | unset |
| Per-event Viewability (manage page) | event override | PUBLIC | MEMBERS_ONLY |
| Per-event Accessibility (manage page) | event override | PUBLIC | MEMBERS_ONLY |
Read these via the REST API:
GET /api/communities/<tag> ← visibility, accessibility, pageSettings
GET /api/communities/<tag>/page-access ← composed verdict for the current viewerThe page-access endpoint runs the resolver server-side and returns
one verdict per page key. SDK consumers wrap it with
usePageAccess (React) or
fetchPageAccess (vanilla).