getOrgSiteUrl() is the single function every link-building path calls. It walks a fixed priority — the tenant's verified custom domain, then the platform canonical URL, then a legacy alias, then the deploy preview URL, then the request origin — and returns a value with a protocol and no trailing slash. Anything that looks like localhost or a loopback address is treated as unset.
Also called: link domain · portal link URL · links point to localhost · estimate link address
- 1The tenant's verified custom domain is looked up (cached 60 seconds) and wins if present.
- 2Otherwise the platform's canonical site URL environment values are used.
- 3Preview deployments fall back to their own URL; local development falls back to the request origin or referer.
- 4nonLocal() strips any candidate matching localhost, 127.x, 0.0.0.0 or [::1] before it can be returned.
- 5invalidateOrgSiteUrlCache() is called the moment a custom domain is attached, removed or changes status.
The guard is written as a hard rule with two dates attached: 'Customer links must NEVER point at localhost (hard rule, 07-12 + the 07-23 dev-send incident): a dev machine emailing a real customer would bake dead links.' A quote or invoice is often forwarded and opened days later, so a dead link is not a transient bug — it is a permanently broken document in a customer's inbox. Making it one resolver rather than a per-feature concatenation means a domain change lands everywhere at once.
- Links generated during development or preview builds could reach real customers with an unreachable host.
- A domain change had to be remembered at every link-building call site.
- Different features disagreed about which host a customer link should use.
See it on your own jobs
Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.
or keep browsing features →