Baidu Site Verification: The HTML File, Meta Tag and CNAME Methods

Someone has handed you a Baidu task and the first thing standing in the way is a verification screen. Baidu will not accept a sitemap, will not open its index reports and will not let you push a single URL until it is satisfied that the domain is yours. There are three ways to prove it, they behave differently, and the failure modes are not the ones you know from Google Search Console.
This is the implementation detail for each method, plus the reasons verification usually fails and how to check each one from a terminal.
Where verification sits
Baidu's webmaster product is the Baidu Search Resource Platform (百度搜索资源平台) at ziyuan.baidu.com, still widely called Baidu Zhanzhang. You add a site, pick a verification method, and Baidu fetches something from your domain to confirm control. Only then do link submission, sitemap upload and the crawl diagnostics unlock.
Two things about the property model catch people out before they even choose a method:
- The protocol and the host are part of the identity.
https://example.comandhttps://www.example.comare two different sites in Baidu's eyes, and so are thehttp://versions. Add the exact origin your canonical URLs use. If you verify the wrong one, everything you submit afterwards refers to a property that carries none of your traffic. - The fetch comes from mainland China. Whatever proves ownership has to be reachable from there, over the public internet, without a challenge page in front of it. That single fact explains most of the failures at the bottom of this article.
Before any of it, there is an account. A Baidu account is required to reach the verification screen at all, and registration is tied to SMS confirmation on a mainland Chinese mobile number. That is a real wall for a company in Europe or the UK, and it is worth knowing about before you spend an afternoon on DNS. More on that at the end.
Method 1: the HTML verification file
The most common method, and the one to prefer when you can deploy a static file.
Baidu generates a file for your site and offers it for download. The name looks like this:
baidu_verify_codeva-XXXXXXXXXX.html
Older properties were issued names in the form baidu_verify_XXXXXXXXXX.html, and some panels show a code- prefix instead of codeva-. Do not try to reconstruct the name or the token from a blog post: download the file Baidu gives you, or copy the string out of the panel character for character. The body of the file is short, usually the token itself and nothing else.
It has to be served from the root of the origin you registered:
https://example.com/baidu_verify_codeva-XXXXXXXXXX.html
Not in a subdirectory, not behind a language prefix, not on a different host.
Where the file goes, by stack
| Stack | Location |
| --- | --- |
| Vite, Create React App, SvelteKit (static), Nuxt | public/ or static/ at project root |
| Next.js (both routers) | public/ |
| Hugo, Astro | static/ and public/ respectively |
| Laravel | public/ |
| Django | a static/ dir collected by collectstatic, or served directly by nginx |
| ASP.NET Core | wwwroot/ |
| WordPress | the web root next to wp-config.php, over SFTP |
| Plain nginx or Apache | the document root |
Check it the way Baidu will
curl -sSI https://example.com/baidu_verify_codeva-XXXXXXXXXX.html
curl -sS https://example.com/baidu_verify_codeva-XXXXXXXXXX.html
You want HTTP/2 200, a content-type of text/html, no location header, and a body that is exactly the token. Three results mean you are not done:
- A 301 or 302. Something is normalising the path, most often a trailing-slash rule or a locale redirect that sends every unmatched path to
/en/.... Add an exception before the catch-all. - A 200 that returns your app shell. This is the single most common false pass. A single-page app with a catch-all route answers every path with
index.htmland status 200, so the file "exists" but the body is your React markup. Baidu reads the body, finds no token, and rejects it. Serve the static file ahead of the SPA fallback. - A 404 that persists after deploy. Usually a CDN that cached the negative response. Purge that exact path, then re-check with
curl -H 'Cache-Control: no-cache'.
Keep the file in the repository afterwards. Baidu re-checks ownership periodically, and a site that loses its verification file quietly drops out of the panel.
Method 2: the HTML meta tag
Use this when you can edit templates but not drop files into the web root, which is the normal situation on a managed CMS or a platform host.
Baidu gives you a tag of this shape, to go in the <head> of the homepage:
<meta name="baidu-site-verification" content="codeva-XXXXXXXXXX" />
The name attribute is always baidu-site-verification, spelled exactly like that, hyphens included. The content value is the token from the panel.
Three rules decide whether it works:
- It must be inside
<head>. A parser that finds it in<body>treats the head as already closed. Anything injected after the first non-head element is too late. - It must be in the HTML the server sends. Open
view-source:or, better,curl -sS https://example.com | grep baidu-site-verification. If the tag only appears in the DevTools element inspector, it was added by JavaScript after hydration, and it does not count. This is what breaks it on client-rendered React and Vue apps, and it is why the file method is easier on an SPA. - It must survive the framework. Head managers deduplicate and sanitise. Next.js wants it in the metadata export rather than a stray
<meta>in a component. React Helmet drops tags rendered outside its provider. Some CMS security plugins strip meta tags with unknown names. A tag manager cannot place it, because the tag manager runs client-side.
Framework-specific placement:
// Next.js App Router, app/layout.js
export const metadata = {
other: { 'baidu-site-verification': 'codeva-XXXXXXXXXX' },
}
// WordPress, functions.php of a child theme
add_action('wp_head', function () {
echo '<meta name="baidu-site-verification" content="codeva-XXXXXXXXXX" />' . "\n";
}, 1);
On a server-rendered site, put it in the base template next to the charset and viewport tags and forget about it. On Hugo, that is layouts/_default/baseof.html; on Django, the base template all pages extend.
Method 3: the CNAME record
The DNS method is the one to choose when you cannot deploy at all, when the site is behind an appliance you do not control, or when you want the check to survive every future redeploy. It also proves control of the whole domain rather than one document.
Baidu shows you a random host label to create under your domain, pointing at Baidu:
abcdef123456.example.com. 3600 IN CNAME ziyuan.baidu.com.
In most DNS panels you only enter the left-hand label, because the zone is implied:
| Field | Value |
| --- | --- |
| Type | CNAME |
| Name / Host | abcdef123456 |
| Value / Target | ziyuan.baidu.com |
| TTL | 3600, or the lowest the panel allows while testing |
Four things go wrong here, over and over:
- The domain gets appended twice. Typing
abcdef123456.example.cominto a panel that already implies the zone createsabcdef123456.example.com.example.com. If your panel shows the fully qualified name after saving, read it back. - The trailing dot on the target. In a raw zone file,
ziyuan.baidu.comwithout the final dot is interpreted relative to the zone and becomesziyuan.baidu.com.example.com. Panels handle this for you;namedand Terraform files do not. - A proxy in front of the record. On Cloudflare, a proxied (orange cloud) record no longer resolves as a CNAME from outside: the authoritative answer becomes Cloudflare's A records. Set the verification record to DNS only.
- Waiting less time than the TTL. If a resolver already has a negative answer cached for that name, the old TTL applies. Check what the world actually sees rather than what your panel says.
dig +short abcdef123456.example.com CNAME
# ziyuan.baidu.com.
dig +short @8.8.8.8 abcdef123456.example.com CNAME
Leave the record in place. Deleting it after a successful check invites a later re-verification failure.
Why verification fails when the setup looks correct
You have curled the file, it returns 200, and Baidu still says no. Work down this list:
- A bot challenge or WAF rule. Cloudflare Bot Fight Mode, AWS WAF managed rules and most "under attack" settings return a JavaScript interstitial with a 403 or 503 to any client that does not run scripts. Baidu's fetcher does not. Allowlist the verification path, or the crawler.
- Geo-blocking. Plenty of European sites block or rate-limit mainland Chinese traffic to cut scraping. The verification fetch comes from exactly that range. Confirm nothing on the edge is dropping it.
- The user agent is filtered. The crawler identifies as
Baiduspider. Some security stacks treat unfamiliar crawler strings as scrapers. If you want to confirm a request is genuine before allowlisting, reverse DNS on the source IP resolves to*.baidu.comor*.baidu.jp, and the forward lookup must match. robots.txtblocks it. ADisallow: /under a wildcard user-agent, or an explicitUser-agent: Baiduspiderblock left behind by someone else, stops the fetch before it starts.- A TLS problem that browsers hide. A missing intermediate certificate is repaired silently by desktop browsers and not by simple fetchers. Run your domain through an external TLS checker rather than trusting a green padlock.
- Verifying the wrong origin. The file lives on
www.example.com, the property in Baidu saysexample.com. Nothing about the error message will tell you that. - Slow first byte. Servers in Europe with no Chinese presence answer a request from Beijing slowly, and a cold serverless start on top of that can exceed the fetch timeout. Retrying at a different hour genuinely helps.
Which method to use
Deploy a static file if you have a build pipeline: it is the least likely to be mangled and the easiest to test. Take the meta tag if you live in a CMS and your pages are server-rendered. Take the CNAME if you cannot touch the site at all, or if you want ownership proved at the domain level once and never revisited.
Whichever you pick, keep it in place permanently and put it in your infrastructure notes, next to your other DNS records. The person who deletes a mysterious file in eighteen months will be you.
The part the methods do not solve
Every one of these three methods assumes you are already logged in to a Baidu account. Registration is confirmed by SMS to a mainland Chinese mobile number, and for many properties Baidu also asks for real-name verification (实名认证) against a Chinese national ID or a Chinese business licence. A company in Frankfurt or Manchester with a perfectly configured DNS zone still cannot reach the verification screen.
That is where our Baidu submission service comes in. You point us at the domain, complete one domain ownership check on your side, and we run the submission and report what Baidu actually indexed, at a fixed price per domain. No Chinese phone number, no Chinese entity, no Baidu account of your own.
If you want the wider picture first, the full Baidu submission guide covers sitemaps, the push API and what Baidu's ranking actually rewards. If you would rather talk it through, book a call.
Service
We can do all of this for you
The domain ownership check, sitemap and URL submission, and an indexing report two weeks later. One domain, one fixed fee, and you need no Chinese phone number, no Chinese entity and no Baidu account of your own.
See the Baidu submission service