Links
Custom domains
Serve your Appy links on your own domain, such as go.acme.com/spring, instead of appy.to. You add one DNS record, Appy checks it and issues the HTTPS certificate, and every link of your account works on the new domain.
Before you start
- Custom domains are part of the Business plan (one domain) and the Enterprise plan (up to 3 domains).
- You need access to the DNS settings of the domain, at your registrar or DNS host.
- Use a subdomain such as
go.acme.comorlink.acme.com. It needs one CNAME record and leaves your website onacme.comuntouched. - A root domain such as
acme.comworks only if your DNS provider supports CNAME flattening or an ALIAS/ANAME record on the root, as Cloudflare, DNSimple and Namecheap do. Route 53 and GoDaddy cannot point the root to another hostname, so use a subdomain there.
Set up a domain
- 1
Add the hostname
In the dashboard, open Custom domains from Settings or the Links page and click Add domain. Enter only the hostname, such as
go.acme.com, withouthttps://or a path. - 2
Add the CNAME record
Appy shows the record to add: type
CNAME, the name (forgo.acme.comthat isgo) and the valuecname.appy.to. Add it at your DNS provider exactly as shown. - 3
Wait for the check
Appy checks the record every minute for the first hour, then every 10 minutes. You can also click Check now. Most providers publish a new record within minutes; a long TTL on an old record can delay it.
- 4
Certificate and live
Once the record points to Appy, the HTTPS certificate is issued and renewed automatically. The status turns Active and
https://go.acme.com/<slug>opens the same link ashttps://appy.to/<slug>.
go.acme.com to Appy, which serves the certificate and the links of your account.Extra records
Sometimes the certificate authority or Cloudflare asks for one more record to prove ownership, usually a TXT record. When that happens the domain page lists it under the CNAME record with a copy button. Add it too; you can remove it once the domain is active.
Adding the record at common DNS providers
| Provider | Where | What to enter |
|---|---|---|
| Cloudflare | DNS > Records > Add record | Type CNAME, Name go, Target cname.appy.to, Proxy status DNS only (grey cloud). A proxied record hides the target and the check cannot finish. |
| GoDaddy | Domain > DNS > Add New Record | Type CNAME, Name go, Value cname.appy.to. |
| Namecheap | Domain List > Manage > Advanced DNS > Add New Record | CNAME Record, Host go, Value cname.appy.to. |
| Amazon Route 53 | Hosted zones > your domain > Create record | Record name go, Record type CNAME, Value cname.appy.to. |
| Google Cloud DNS | Cloud DNS > your zone > Add standard | DNS name go, Resource record type CNAME, Canonical name cname.appy.to. (with the trailing dot). |
Delete any existing A, AAAA or CNAME record for the same name first; a name can hold only one CNAME and nothing else.
Statuses
| Status | What it means | What to do |
|---|---|---|
| Pending | Appy has not found a CNAME record for the hostname that points to cname.appy.to yet. | Add or fix the record. Appy keeps checking for 72 hours. |
| Verifying | The record is correct and the certificate is being issued. | Nothing. This usually takes a few minutes. |
| Active | Links are served on the domain over HTTPS. Appy re-checks active domains once a day. | Optionally make it the default domain. |
| Error | The check stopped or found a problem. The domain page shows the exact message. | Fix what the message says, then click Check now. |
Common errors and fixes
| Message says | Fix |
|---|---|
No CNAME record for the hostname points to cname.appy.to | The record is missing, has a typo, or the provider added your domain to the name (for example go.acme.com.acme.com). Enter only go as the name. |
| A CAA record blocks the certificate | Your domain allows only some certificate authorities. Remove the CAA records or add ones that allow letsencrypt.org and pki.goog. |
| Could not reach the domain to issue the certificate | The record points somewhere else or another CDN proxies it. On Cloudflare, switch the record to DNS only. |
| Could not query the DNS servers | Your DNS provider does not answer for the name or DNSSEC is broken. Fix the DNSSEC (DS) records at your registrar. |
| Stopped checking after 72 hours | Add or fix the record, then click Check now to start checking again. |
| No longer points to Appy | The record was changed or removed after the domain went live. Until it points to cname.appy.to again, links on the domain redirect to the same path on appy.to. |
Default domain
Make one active domain the default. The dashboard then shows and copies short links on it, QR codes encode it, and the REST API returns it in the url field of links. Every link keeps working on every active domain of your account and on appy.to, so changing the default never breaks a URL you already shared or printed.
The root and unknown paths
Set a root redirect URL, usually your website, for visits to https://go.acme.com/ and to paths that are not one of your links. Without it, those visits see a plain not-found page without Appy branding. Links of other Appy accounts never open on your domain.
App links on your domain (Enterprise)
On the Enterprise plan you can assign an active domain to one of your SDK apps. Appy then serves the app’s apple-app-site-association and assetlinks.json on the domain, so Universal Links and Android App Links open the app from go.acme.com just as they do from your app subdomain.
- 1
Assign the domain
On the domain page, choose the app under Use for app links. You can also send
appIdwithPATCH /v1/domains/{id}. - 2
iOS
Add
applinks:go.acme.comto Associated Domains, next to your existing entry. - 3
Android
Add
<data android:host="go.acme.com" />to the intent filter withandroid:autoVerify="true". - 4
SDK
Add the domain to
linkDomains. Put it first if links built in the app should use it.
Appy.configure(AppyConfiguration(publishableKey: "appy_pk_live_...", linkDomains: ["go.acme.com", "acme.appy.to"]))Apple and Google cache these files. A new domain can take up to a day to open the app on devices that already have it installed; reinstalling the app refreshes the cache. See the iOS and Android guides for the full setup.
Removing a domain or changing plans
- Removing a domain stops it right away: links on that hostname no longer open, while the same links keep working on appy.to and on your other domains. If the domain is printed on QR codes, packaging or posters, keep it.
- After removing a domain you can delete its CNAME record. Removing frees the slot in your plan, and you can add the same hostname again later.
- If the account leaves the Business or Enterprise plan, its domains keep answering: every request is redirected with
301to the same path on appy.to for as long as the CNAME record points to Appy, so printed QR codes and shared links keep working.
Managing domains with the API
Every step of the dashboard is also available in the REST API with a secret key, on the Business and Enterprise plans. The MCP server has a read-only list_domains tool.
| Request | What it does |
|---|---|
GET /v1/domains | Your domains and limits (used, max). |
POST /v1/domains | Adds a domain from hostname and an optional rootRedirectUrl. Returns 201 with the DNS record to add. |
GET /v1/domains/{id} | One domain with its status, records and last error. |
POST /v1/domains/{id}/verify | Checks the domain now. At most once every 10 seconds per domain. |
PATCH /v1/domains/{id} | Sets isDefault, rootRedirectUrl or appId (Enterprise). null clears a value. |
DELETE /v1/domains/{id} | Removes the domain. Returns 204. |
curl https://api.appy.to/v1/domains \
-H "Authorization: Bearer $APPY_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"hostname": "go.acme.com", "rootRedirectUrl": "https://acme.com"}'{
"id": "5b1e9c2a-7d4f-4e8a-b3c6-0f2d8a6e4c19",
"hostname": "go.acme.com",
"status": "pending",
"isDefault": false,
"rootRedirectUrl": "https://acme.com",
"appId": null,
"dns": {
"type": "CNAME",
"name": "go",
"host": "go.acme.com",
"value": "cname.appy.to",
"apex": false,
"note": null
},
"verification": [],
"lastError": null,
"lastCheckedAt": null,
"verifiedAt": null,
"createdAt": "2026-10-01T09:00:00Z",
"updatedAt": "2026-10-01T09:00:00Z"
}Errors follow the usual format: validation_failed for a hostname or URL that cannot be used, conflict when the hostname is already in use, limit_reached when every domain slot of the plan is taken, and plan_required below Business.