Multi-Domain Networks
One app on one host is easy. A family of apps across subdomains and
separate domains needs the relationships stated explicitly, because
nothing else states them.
What this page does
Explains and demonstrates register_network() — the API that turns a set of independently-hosted Dash apps into a directory that search engines and AI agents can traverse.
The problem it solves
Every SEO surface this package serves is scoped to a single origin, because that is what the specifications require:
sitemap.xmlmay only list URLs on its own host.robots.txtgoverns one host.- Prose links point within the app.
Run twenty hosts and you get twenty disconnected islands. Nothing on any of them mentions the other nineteen.
For search engines that is a slow problem — crawlers do follow cross-host links eventually. For AI agents it is a hard wall. An agent answering a question fetches a URL or two and reasons from what comes back. It does not crawl, does not accumulate a graph over time, and does not come back later. Whatever that one response says is the ecosystem, for that answer.
The three tiers
register_network() takes three separate lists, and the separation is the point.
peers— hosts you own that are genuinely one product family.
Emitted with <link rel="related"> and followed links. This is the tier that builds your real cross-host graph.
affiliated— your projects on unrelated domains. Listed under
"Related projects", followed. Separated so an agent can answer "what is this network?" without sweeping in every domain you happen to own.
external— third-party documentation you reference but do not own.
Emitted with rel="nofollow noopener", because a reference is not an endorsement and should not pass ranking signal.
Collapsing the tiers would either overclaim ownership of other people's sites or bury your own network in an undifferentiated link list.
What the user can do
- Read the worked configuration below and copy it.
- Fetch
/llms.txton this app to see the rendered directory. - Inspect this page's HTML source for the
<link rel="related">tags.
Configuration
from dash_improve_my_llms import register_network
register_network(
name="The 2plot network",
description="A family of open-source Dash component libraries.",
hub_url="https://2plot.dev",
peers=[
{"name": "2plot.ai", "url": "https://2plot.ai",
"description": "Network hub and account origin."},
{"name": "dash-leaflet2", "url": "https://leaflet.2plot.dev",
"description": "Leaflet maps as Dash components."},
],
affiliated=[
{"name": "Pirate's Bargain", "url": "https://piratesbargain.com",
"description": "Deal aggregator on the same stack."},
],
external=[
{"name": "Dash Mantine Components",
"url": "https://www.dash-mantine-components.com",
"description": "The UI layer these docs are built with."},
],
)
The hub
hub_url is the highest-value field. One canonical host listing every member gives an agent exactly one URL to land on and enumerate from, instead of depending on which member it happened to reach first. The hub is an ordinary app running this package with every other host in its peers; its /llms.txt becomes the network manifest.
Keeping twenty apps in sync
Define the directory once in a shared module and import it everywhere. Filter the current app's own URL out of peers — a site listing itself as its own peer is noise. See docs/NETWORKS.md for the pattern.
What it does NOT do
It does not verify that the hosts you list exist, respond, or serve an llms.txt. A directory full of dead links is worse than no directory, so check them in CI. It also does not federate content: each host still serves its own prose, and the directory only says how they relate.
Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs:
- /networks/llms.txt — LLM-friendly documentation
- /sitemap.xml
- /robots.txt