Custom Domains
Serve your shiply site at your own domain instead of a *.shiply.now URL
Custom domains let you serve a shiply site at a domain you already own —
www.yourdomain.com, docs.yourapp.io, or any subdomain — instead of the
default <slug>.shiply.now address. Certificates are issued automatically;
the original *.shiply.now URL continues to work.
Custom domains require a paid plan.
How it works in three steps
- Add your domain — tell shiply which root domain you own (e.g.
example.com). - Connect it — either with one click (if your registrar supports it) or by adding one DNS record yourself.
- Point a subdomain at a site — map
www.example.comto the slug of the site you want to serve there.
shiply polls for the DNS change and issues an SSL certificate automatically. Most setups go live within a few minutes.
Step 1 — Add a domain
Dashboard
Open Domains in your dashboard and click Add domain. Enter your root
domain (e.g. example.com).
CLI
shiply domain add example.comMCP / agents
add_custom_domain({ domain: "example.com" })The response includes the provider that was detected (e.g. cloudflare,
godaddy, ionos, or manual) and what to do next.
Step 2 — Connect (add DNS)
One-click connect (Cloudflare, GoDaddy, IONOS, and more)
If shiply detects that your domain is on Cloudflare, GoDaddy, IONOS, or another Domain Connect-compatible provider, it offers to add the required DNS record for you automatically — no copying and pasting.
Dashboard: click Connect automatically on the domain row.
CLI:
shiply domain connect example.comThe CLI prints an authorization URL. Open it in your browser, approve the request, and DNS is updated for you.
MCP / agents:
connect_provider({ domain: "example.com" })The tool returns a url. Show this URL to the user so they can open it in
a browser and authorize the connection. Do not skip this step — the OAuth grant
is required before DNS can be written.
Manual fallback (any other provider)
If your registrar is not supported for one-click connect, add a single CNAME record at your registrar's DNS control panel:
| Type | Name | Value |
|---|---|---|
| CNAME | www | cname.shiply.now |
For providers that accept it, a TXT verification record is shown alongside
the CNAME — add that too so shiply can confirm ownership.
Step 3 — Point a subdomain at a site
Once the domain is connected, map a specific subdomain to one of your sites:
Dashboard
On the domain row, click Add subdomain, choose the subdomain (e.g. www)
and pick a site from the dropdown.
CLI
shiply domain sub add www.example.com --site my-siteMCP / agents
add_subdomain({ subdomain: "www.example.com", slug: "my-site" })You can point multiple subdomains at different sites under the same root domain.
Primary domain and redirects (SEO)
If you point both example.com and www.example.com at the same site, Google
treats those as two URLs serving identical content — the duplicate-content
problem. Search engines penalise it, and link equity gets split.
shiply lets you mark one hostname as the primary (canonical) URL for a site. Every other hostname pointing at that site starts returning 301 Moved Permanently to the primary, preserving path and query string. Search engines consolidate ranking signals on the primary URL.
The first subdomain you map to a site is set as primary automatically. Subsequent mappings default to non-primary, so the behaviour is sensible out of the box. Use the commands below to switch which hostname is primary.
Pick the primary
shiply domain primary example.com example.com # apex is primary
shiply domain primary example.com www.example.com # www is primaryMCP / agents
set_primary_subdomain({ domain: "example.com", hostname: "example.com" })REST
POST /api/v1/custom-domains/{domain}/subdomains/{id}/primary
PATCH /api/v1/custom-domains/{domain}/subdomains/{id} { "isPrimary": true }After switching, verify with curl:
$ curl -sI https://www.example.com/pricing?utm=abc
HTTP/1.1 301 Moved Permanently
Location: https://example.com/pricing?utm=abcRoot / apex domains
Pointing the bare apex (example.com, with no www) requires an ALIAS or
ANAME record — not a CNAME. Many registrars support this (Cloudflare calls
it a "proxied A record"; some call it ALIAS/ANAME). Where supported, shiply
configures it automatically via the one-click flow.
For registrars that don't support ALIAS/ANAME, use the www subdomain
instead and set up a redirect from the apex to www in your registrar's
control panel.
Checking status
DNS propagation usually takes 1–5 minutes; certificate issuance adds another minute or two.
Dashboard
The Check status button on each subdomain row shows whether the CNAME is resolving and the certificate is valid.
CLI
shiply domain ls # list all domains + subdomains + status
shiply status www.example.com --wait # poll until SSL_READY + SITE_READYMCP / agents
check_custom_domain({ subdomain: "www.example.com" })
# → { cname: true, ssl: { valid: true, daysLeft: 89 }, ready: true }Poll check_custom_domain until ready is true before telling the user
their domain is live.
Managing domains
List all domains and their subdomains
CLI: shiply domain ls
MCP: list_custom_domains()
REST: GET /api/v1/custom-domains
Sync DNS (refresh provider connection)
If DNS records were changed externally, re-sync them:
CLI: shiply domain sync example.com
MCP: sync_dns({ domain: "example.com" })
REST: POST /api/v1/custom-domains/example.com/sync-dns
Remove a domain
Dashboard: click Remove on the domain row.
CLI: (delete the subdomain mapping first, then the domain)
MCP: remove_custom_domain({ domain: "example.com" })
REST: DELETE /api/v1/custom-domains/example.com
Quick reference
CLI commands
shiply domain add example.com # add a root domain
shiply domain connect example.com # one-click OAuth DNS setup
shiply domain sub add www.example.com --site my-site # map subdomain → site
shiply domain primary example.com www.example.com # pick canonical URL (SEO)
shiply domain ls # list all domains + subdomains
shiply domain sync example.com # re-sync DNS with providerMCP tools
| Tool | What it does |
|---|---|
add_custom_domain | Add a root domain and detect the provider |
connect_provider | Start OAuth flow; returns URL for user to authorize |
add_subdomain | Map a subdomain to a site slug |
set_primary_subdomain | Pick the canonical URL; siblings 301-redirect (SEO) |
check_custom_domain | Live CNAME + SSL + readiness check |
sync_dns | Re-push DNS records to a connected provider |
list_custom_domains | List all domains and their subdomain mappings |
remove_custom_domain | Remove a domain and all its subdomain mappings |
REST endpoints
GET /api/v1/custom-domains list all domains
POST /api/v1/custom-domains add a domain { domain }
DELETE /api/v1/custom-domains/{domain} remove a domain
POST /api/v1/custom-domains/{domain}/subdomains add subdomain { subdomain, slug }
POST /api/v1/custom-domains/{domain}/subdomains/{id}/primary mark hostname as canonical (siblings 301-redirect)
PATCH /api/v1/custom-domains/{domain}/subdomains/{id} same, body: { "isPrimary": true }
POST /api/v1/custom-domains/{domain}/connect start OAuth connect → { url }
POST /api/v1/custom-domains/{domain}/sync-dns re-sync DNS records
POST /api/v1/custom-domains/{domain}/check live status checkAll endpoints require Authorization: Bearer shp_….