Limit a space to some networks
Some spaces are meant for one building or one VPN: an internal handbook, an IT help desk FAQ, a roadmap for staff. Making every reader sign in is one way to keep them in. A network allow-list is the other: the space stays public in the sense that nobody has to sign in, but only readers connecting from addresses you list can open it. Anyone else gets a page that says the space is not available from their network.
There is one allow-list per space, settings.networkAccess.ipAllowList. Status pages are the exception and keep a list of their own (see Status pages below).
Which spaces it applies to
Space type | List | Where you set it |
|---|---|---|
Documentation, Community spaces, blog, changelog, roadmap, FAQ, events, courses, legal, careers, contact, custom |
|
|
Status page |
|
|
Content library | none — it has no reader to gate | — |
The list only matters for a public space. A private space is already closed to everyone without a share link, and a share-link preview of a private space is not asked about the network: you handed that link out yourself.
Defaults
Unset or empty means everyone. A space you never touched is readable from anywhere, exactly as before. There is no organization-wide default; each space decides for itself.
The list applies to everyone who reads, including you. It is checked on the reader, not on your account, so an owner reading the published space from a café is refused like anyone else. Make sure your own network is on the list before you save. Your console and the authenticated API (
/orgs/{orgId}/…) are not affected, so you can always fix the list.The network is checked first. A reader from elsewhere is refused before a space password or reader sign-in is asked for, so the sign-in screen never appears to someone who could not read the space anyway.
Setting the list
Each entry is an IPv4 or IPv6 address, or a CIDR block: 203.0.113.7, 203.0.113.0/24, 2001:db8::/32. Up to 200 entries. An entry nothing can parse is refused with a 422 naming it, rather than saved to silently never match. Duplicates are dropped. PUT replaces the whole list; send [] to open the space to everyone again.
curl -X PUT "https://forumulate.com/api/orgs/$ORG/spaces/$SPACE/network-access" \
-H "Authorization: Bearer $FORUMULATE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "ipAllowList": ["203.0.113.0/24", "198.51.100.14", "2001:db8:42::/48"] }'{ "ipAllowList": ["203.0.113.0/24", "198.51.100.14", "2001:db8:42::/48"] }GET on the same address answers the stored list (space.read); PUT needs space.update. Sending the list to a status page's network-access is a 422 that points at …/status/access. See Space network access.
Which address to list: the public address your office or VPN reaches the internet from (its egress or NAT address), not the private 10.x / 192.168.x address a laptop has on the office network. Saving the list empties every cached copy of the space's pages, so the change applies at once.
In the studio
Open the space's studio, then Settings → Network access. Each network is its own row, so when the API refuses one entry you can see which; Add a network adds a row, and the panel reminds you to include your own network. The section is on every space type except status pages (which have their own panel) and content libraries.
What a refused reader sees
A reader page draws a short notice instead of the space: "Not available from this network", with a line suggesting they connect to their organisation's network or VPN and reload. It is translated into English, German, Spanish, French and Portuguese. It never shows the list, and it never says which addresses would be allowed.
What else the list covers
The gate runs in the API's public read path, so it covers every way of reading the space, not just its pages:
Surface | From an allowed network | From anywhere else |
|---|---|---|
Reader pages (every page, hub, tag page, print view) | served | the "not available" notice |
Public JSON ( | served |
|
A page's markdown twin ( | served |
|
Feeds ( | served |
|
Widgets and embeds (search box, Ask AI launcher, FAQ widget) | served | refused the same way |
Sitemap, | the space is left out | the space is left out |
Two behaviours follow from it on purpose:
A limited space is never advertised. Sitemaps,
robots.txtandllms.txtare fetched by crawlers, which are not on your network, so a space with a list is left out of them for everyone. Search engines will not index it.A limited space is never kept in a shared cache. Every answer depends on who asked, so gated responses are marked
private, no-storeand the edge never serves one reader's copy to another. A space whose list was just added is treated as limited for up to a minute while the edge learns about it; the cost is a few uncached renders, never a leaked page.
A feed reader or a markdown fetch made from a server elsewhere (a hosted feed reader, an AI tool's crawler) is refused like a browser from elsewhere.
Checking from where you are
Two public addresses, both without a token:
# Is this space limited at all? Facts only: the list is never published.
curl "https://forumulate.com/api/public/orgs/$ORG/spaces/$SPACE/network-check/facts"
# { "network": true }
# May I read it from here?
curl "https://forumulate.com/api/public/orgs/$ORG/spaces/$SPACE/network-check"
# 200 { "ok": true }, or 403 space.network_refusednetwork-check runs the space's whole public gate for the caller: a space behind a password or reader sign-in answers 401 as any read of it does, and a space the caller may not read at all answers 404. It is never cached. See Public network.
Status pages keep their own list
A status page has the same kind of list with the same rules and the same parser, stored as settings.statusAccess.ipAllowList and set at GET/PUT /orgs/{orgId}/spaces/{spaceId}/status/access (Status access). It covers the page, its JSON, feeds, badge and widget. The space allow-list above is never applied to a status page, so a status page is not checked twice. See Status pages.
Related
Who may read, sign up and sign in to a space — reader sign-in, legal gates and approvals, which combine with a network list.
Published but invisible — when a page does not show up where you expect it.
In the API
Every operation below is also reachable from the other surfaces without a dedicated command. forumulate api <Operation> calls it from the CLI, the JavaScript SDK has a typed method for each one (the last column names it; the Python and Go clients are generated from the same spec), and an agent reaches the organization-scoped ones through the MCP call_api tool. Where a CLI command or MCP tool exists too, the last column names it. Operation names link to the API reference.
Status Access
Operation | Request | What it does | Shortcuts |
|---|---|---|---|
| A status page's network allow-list |
| |
| Set a status page's network allow-list |
|