Real fixes from seven live sites. No pitch.Log in / My reports
Idea to Traffic Pressure Test

Why does my Pages domain show a certificate warning?

Cloudflare Pages reports two statuses for a custom domain, verification_data.status and validation_data.status, and both must read active. A certificate warning usually means verification passed while the certificate is still pending, and the usual cause is a DNS record that is missing or not proxied.

A hostname that resolved and still failed TLS

We attached a custom hostname to a Pages project, the name began resolving, and the browser then refused to load the site with a certificate warning. The Pages domains endpoint showed a status that was not an error, so the first read of the situation was that everything was fine and the browser was wrong.

It was not fine, and it was not finished. The endpoint reports two separate status fields, and we had read one of them. The other was still pending. The instinct at that moment was to start editing DNS records, which is precisely the wrong move while a certificate is mid-issuance, and it is the move that turns a wait into a genuine outage.

The visible symptom is also worse than the underlying state. A resolving hostname with a browser certificate warning looks far more alarming than a hostname that does not resolve at all, so it invites exactly the kind of urgent intervention that prolongs it. We sat in that window for .

Verification and validation are two checks

The two status fields answer two different questions. verification_data.status is about whether Cloudflare can confirm you control the hostname. validation_data.status is about whether the TLS certificate for that hostname has actually been issued. They can and do sit in different states, and both must read active before the hostname is really live.

This is why checking one field misleads so reliably. You look, you see something that is not an error, and you conclude the process has finished. In the window after DNS resolves but before validation reaches active, the hostname resolves and the browser shows a certificate warning, which is a normal transitional state rather than a fault.

The usual root cause of a certificate that never leaves pending is a DNS record that is missing or is not proxied. Certificate issuance has to resolve the hostname, so a name that returns NXDOMAIN can sit at pending indefinitely with no error explaining why. Nothing in the response will say "your DNS record does not exist".

Attaching a custom domain to a Pages project does not create the DNS record. That is a separate API call, and missing it is common enough to have its own write-up: see the guide on www not working on Cloudflare Pages for the full sequence. The domain attach response carries a zone_tag field, which is the zone id you need for the DNS call, so there is no reason to look the zone up separately.

An unproxied CNAME is the worse variant, because it half works. Sometimes you get the right site, sometimes a certificate mismatch, sometimes a 404, depending on the path the request takes. Proxied is required in practice on Pages, and a half-working record passes a naive check for whether the name resolves.

Read both status fields

Poll the API rather than watching the dashboard, and read both fields every time.

curl -s -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT/pages/projects/$PROJECT/domains"

Verification active with validation pending is the state this guide is about. Both pending points at hostname control or at a record that has never resolved. Both active with a browser still complaining means the problem is on the client side rather than at Cloudflare.

Then check DNS, and know what the answer shapes mean before you interpret them.

curl -s -H "accept: application/dns-json" \
  "https://cloudflare-dns.com/dns-query?name=www.ideatotraffic.com&type=CNAME"

curl -s -H "accept: application/dns-json" \
  "https://cloudflare-dns.com/dns-query?name=www.ideatotraffic.com&type=A"

A resolver returning "Status":3 means NXDOMAIN, so the name does not exist and the record is your problem. A proxied CNAME is flattened, so a CNAME query on a working proxied hostname returns "Status":0 with no Answer array, while the A query returns Cloudflare edge addresses. That empty CNAME answer looks like a failure and is not one. Only NXDOMAIN means what people think it means.

Fix the record, then leave it alone

  1. Read both status fields from the domains endpoint before doing anything else. If verification_data.status is active and validation_data.status is pending, resist the urge to edit records until you have checked whether DNS resolves.
  2. Query both CNAME and A for the hostname and interpret the shapes above. A "Status":3 is a missing record. A "Status":0 with no Answer on CNAME plus edge addresses on A is a healthy proxied record.
  3. If the record is missing, create it, proxied, using the zone_tag from the domain attach response as the zone id. The companion guide linked above covers this call in full.
    curl -s -X POST "https://api.cloudflare.com/client/v4/zones/<zone_id>/dns_records" \
      -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"type":"CNAME","name":"www","content":"$PROJECT.pages.dev","proxied":true,"ttl":1}'
  4. If the record exists but is not proxied, find its id and set proxied to true rather than deleting and recreating it.
    curl -s -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
      "https://api.cloudflare.com/client/v4/zones/<zone_id>/dns_records?name=www.ideatotraffic.com"
    
    curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/<zone_id>/dns_records/<record_id>" \
      -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"proxied":true}'
  5. Poll the domains endpoint until both fields read active. Do not remove and re-add the custom domain while waiting, because that restarts the process without fixing whatever was blocking it.
  6. Only once both fields are active, load the hostname in a clean browser session. A reload of the tab that showed the warning is not a test.

Attach and create the record in one step

Make the attach call and the DNS record one atomic provisioning step. A script that does one without the other is the single most common way a hostname ends up permanently pending, and the fact that the attach succeeds makes the gap invisible.

Capture zone_tag from the attach response at the moment you get it and pass it straight into the DNS call. Looking the zone up again later is an extra call and an extra chance to use the wrong zone.

Always create the record proxied, and assert that proxied is true in your post-deploy check. A naive check that only asks whether the name resolves will pass an unproxied record that serves the wrong thing on some request paths.

Poll both status fields with a fixed ceiling rather than eyeballing the dashboard. Treat verification active plus validation pending plus a resolving proxied record as normal waiting, and budget before anyone is allowed to call it broken.

Take the browser out of the diagnosis during issuance. The certificate warning is a lagging indicator of a state the API already reports precisely, and acting on the browser instead of the two status fields is what causes the DNS edits that extend the outage.

Hostnames that were never attached

None of this helps a hostname that was never attached to the Pages project. With no attachment there is no certificate request, so there is nothing pending and nothing to poll.

The apex and www are separate hostnames. Each needs its own attach, its own DNS record and its own pair of active statuses, and getting one working tells you nothing about the other.

It does not address a certificate warning coming from the visitor's side, such as a badly set system clock, a corporate inspection proxy, or a stale HSTS entry in one browser. Both status fields active plus a clean session is the test that distinguishes those.

It has no bearing on canonicalisation. Both hostnames can reach active and serve the same site, which is a duplicate content problem rather than a TLS problem, and it needs a redirect rather than a certificate.

Finally, a record can be present and proxied and still point at the wrong Pages project, in which case both statuses will reach active and the site served will simply be the wrong one.

Questions about pending custom domains

Why does my Cloudflare Pages custom domain stay at pending?

Usually because validation_data.status is still pending while the DNS record is missing or not proxied. Certificate issuance has to resolve the hostname, so a name returning NXDOMAIN can sit at pending indefinitely with no explanatory error.

What is the difference between verification_data and validation_data?

verification_data is about whether Cloudflare can confirm you control the hostname. validation_data is about whether the TLS certificate has been issued. Both must read active, and they can sit in different states.

Should I delete and re-add the domain while it is pending?

No. That restarts the process without fixing whatever is blocking it. Check both status fields and confirm the DNS record exists and is proxied first.

Does attaching a custom domain to Pages create the DNS record?

No, that is a separate API call, which is the subject of the companion guide on www not working. The attach response does carry a zone_tag field, which is the zone id you need for the DNS call.

Why does a CNAME query return no answer for a hostname that works?

A proxied CNAME is flattened, so the CNAME query returns "Status":0 with no Answer array while an A query returns Cloudflare edge addresses. That is healthy. Only "Status":3, meaning NXDOMAIN, indicates a missing record.

Can I leave the CNAME unproxied on Cloudflare Pages?

In practice no. An unproxied record half works, returning sometimes the right site, sometimes a certificate mismatch and sometimes a 404 depending on the path the request takes, which is harder to diagnose than an outright failure.