Tuần trước tôi dựng lại toàn bộ hệ thống sitemap cho site này: một file index, hai file con cho hai ngôn ngữ, thẻ hreflang khai chéo, và lastmod phải phản ánh đúng lần sửa nội dung thật. Trong quá trình đó tôi gặp ba lỗi mà không tài liệu tiếng Việt nào tôi đọc được nhắc tới — vì phần lớn bài viết về sitemap dừng lại ở chỗ "cài plugin rồi bấm Submit".

Bài này là quy trình tôi đã chạy, gồm cả những chỗ làm sai và cách phát hiện ra. Nếu bạn dùng WordPress và plugin lo hết phần sinh file, bạn vẫn cần đọc phần lastmod, phần song ngữ và phần bảy lỗi thường gặp — plugin sinh file đúng cú pháp không có nghĩa là sitemap của bạn đúng.

Sitemap là gì

Sitemap XML là một file liệt kê các URL bạn muốn công cụ tìm kiếm biết tới, kèm một ít thông tin phụ về mỗi URL. Nó nằm ở một đường dẫn cố định trên tên miền của bạn, thường là /sitemap.xml.

Điểm quan trọng nhất, và cũng là điểm hay bị bỏ qua: sitemap là một lời gợi ý, không phải một mệnh lệnh. Bạn nói với Google "đây là những trang tôi cho là đáng thu thập". Google tự quyết định có thu thập không, thu thập khi nào, và sau khi thu thập thì có lập chỉ mục hay không. Ba việc đó tách rời nhau.

Sitemap giải quyết đúng một bài toán: phát hiện URL. Googlebot tìm ra các trang trên website chủ yếu bằng cách đi theo liên kết. Trang nào không có liên kết nào trỏ tới thì bot không có đường tới. Sitemap là kênh thứ hai để bot biết trang đó tồn tại.

Hiểu lầm lớn nhất: sitemap không làm trang được index

Rất nhiều người gửi sitemap rồi mở Search Console mỗi ngày để chờ trang lên. Khi trang không lên, họ gửi lại sitemap, đổi plugin, thêm priority 1.0 cho mọi URL.

Không cái nào trong số đó có tác dụng, vì vấn đề không nằm ở khâu phát hiện. Nếu Search Console báo trang ở trạng thái "Đã thu thập dữ liệu — hiện chưa lập chỉ mục" thì Google đã tìm thấy trang, đã đọc trang, và đã quyết định không đưa vào chỉ mục. Đó là phán quyết về chất lượng và mức độ trùng lặp của nội dung, không phải về sitemap.

Sitemap chỉ giúp khi nguyên nhân là Google chưa biết URL đó tồn tại. Với site nhỏ có cấu trúc liên kết tử tế, nguyên nhân đó gần như không bao giờ xảy ra.

Vậy sitemap có đáng làm không? Có — vì nó rẻ, vì nó cho bạn một bảng đối chiếu trong Search Console ("tôi khai 40 URL, Google nhận 40 URL"), và vì với site mới chưa có backlink thì kênh phát hiện thứ hai này thật sự có ích trong vài tuần đầu.

Bốn loại sitemap và loại bạn thật sự cần

Sitemap XML thường

File <urlset> chứa danh sách URL. Đây là loại bạn cần. Giới hạn kỹ thuật: tối đa 50.000 URL và 50MB chưa nén cho một file.

Sitemap index

File <sitemapindex> không chứa URL bài viết, chỉ chứa đường dẫn tới các sitemap con. Bạn cần nó trong hai trường hợp: website vượt 50.000 URL, hoặc bạn muốn tách sitemap theo nhóm để dễ đọc báo cáo.

Trường hợp thứ hai là lý do tôi dùng sitemap index dù site mới có vài chục URL. Tôi tách thành sitemap-vi.xmlsitemap-en.xml. Khi Search Console báo một sitemap có URL lỗi, tôi biết ngay lỗi nằm ở ngôn ngữ nào thay vì phải dò trong một file gộp.

Sitemap ảnh, video, tin tức

Các phần mở rộng cho trường hợp chuyên biệt. Sitemap tin tức chỉ dành cho site đã được duyệt vào Google News. Sitemap ảnh chỉ đáng làm nếu ảnh là sản phẩm chính của bạn — site ảnh stock, bất động sản, thương mại điện tử. Blog thông thường thì bỏ qua, ảnh trong bài đã được phát hiện qua chính trang chứa nó.

Sitemap HTML

Đây là thứ hoàn toàn khác, dù trùng tên. Nó là một trang web bình thường liệt kê liên kết tới các trang khác, dành cho người đọc chứ không dành cho bot. Với site có cấu trúc menu và breadcrumb rõ ràng, nó gần như không thêm giá trị gì. Nếu bạn đang cân nhắc làm sitemap HTML để "tăng liên kết nội bộ", hãy dành thời gian đó để đi link trong thân bài — hiệu quả hơn nhiều.

Cấu trúc một file sitemap XML

Bản tối thiểu, đủ dùng:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com/</loc>
    <lastmod>2026-08-06T15:36:27+07:00</lastmod>
  </url>
  <url>
    <loc>https://example.com/blog/seo/bai-viet</loc>
    <lastmod>2026-08-05T09:12:00+07:00</lastmod>
  </url>
</urlset>

Ba quy tắc về thẻ <loc> mà lỗi hay xảy ra nhất:

  • URL phải tuyệt đối, gồm cả giao thức và tên miền. Không dùng đường dẫn tương đối.
  • Phải khớp chính xác dạng chuẩn của site: nếu site chạy https không có www, mọi URL trong sitemap phải như vậy. Khai http:// hoặc thêm www là tự tạo một lượt chuyển hướng cho mỗi URL.
  • Ký tự đặc biệt phải được escape. Dấu & trong URL phải viết thành &amp;, nếu không file XML hỏng và Google bỏ qua toàn bộ file chứ không riêng URL đó.

Còn một quy tắc nữa quan trọng hơn cả ba cái trên, nhưng nó không nằm ở cú pháp: chỉ đưa vào sitemap những URL bạn muốn được lập chỉ mục. Chi tiết ở phần lỗi thường gặp bên dưới.

lastmod — thẻ duy nhất Google thật sự đọc

Google đã nói rõ họ dùng lastmod, với một điều kiện: chỉ khi giá trị đó đáng tin trên toàn site. Nếu bạn khai lastmod nhảy loạn, họ bỏ qua thẻ này cho cả tên miền của bạn.

Đây chính là lỗi đầu tiên tôi mắc. Trong lần dựng đầu, tôi để lastmod của trang chủ lấy giá trị now(). Kết quả: mỗi lần Googlebot tải sitemap, trang chủ lại báo "vừa sửa xong". Nhìn thì có vẻ tích cực, thực chất là tự khai một tín hiệu sai — và sai theo cách rất dễ bị phát hiện, vì nó thay đổi ở mọi lần tải.

Cách khai đúng:

  • Trang bài viết: lấy ngày sửa nội dung thật, không phải ngày bản ghi bị chạm vào. Nếu hệ thống của bạn cập nhật updated_at mỗi lần tăng lượt xem, cột đó không dùng được. Tôi tách riêng một cột content_updated_at, chỉ đổi khi tôi tự đánh dấu là "đã cập nhật nội dung", và trong Eloquent thì tăng lượt xem bằng withoutTimestamps() để không đụng vào timestamps.
  • Trang chủ và trang danh mục: lấy theo bài mới nhất trong đó. Trang chủ đổi thật khi có bài mới, nên khai như vậy là chính xác.
  • Trang chính sách, giới thiệu: lấy ngày sửa thật. Nếu bảng của bạn không có timestamps, bỏ hẳn thẻ <lastmod> cho nhóm trang này. Thẻ này không bắt buộc, và không khai còn tốt hơn khai bừa.

Sửa một lỗi nhỏ về chính tả không phải là "cập nhật nội dung". Đổi lastmod cho những thay đổi kiểu đó là cách nhanh nhất để Google ngừng tin thẻ này.

changefreq và priority: bỏ đi

Hai thẻ này nằm trong chuẩn sitemap từ 2005 và vẫn xuất hiện trong giao diện cấu hình của gần như mọi plugin. Google đã xác nhận họ không dùng chúng.

Lý do dễ hiểu: đó là hai con số do chính chủ site tự khai về site của mình, không có gì kiểm chứng. Ai cũng đặt priority 1.0 cho trang mình thích. Một tín hiệu mà mọi người đều khai mức cao nhất thì không phân biệt được gì.

Nếu plugin của bạn đang sinh ra hai thẻ này thì cũng không hại gì, chỉ là file nặng hơn một chút. Nhưng đừng dành thời gian tinh chỉnh chúng, và đừng tin bài viết nào bảo rằng đặt priority đúng sẽ giúp trang lên hạng.

Sitemap cho website song ngữ

Đây là phần các hướng dẫn phổ thông bỏ qua, và cũng là phần dễ làm hỏng nhất.

Khi một nội dung có hai phiên bản ngôn ngữ ở hai URL khác nhau, bạn phải nói cho Google biết chúng là bản dịch của nhau. Không nói thì Google có thể coi đó là hai trang cạnh tranh nhau, hoặc hiển thị sai phiên bản cho người tìm kiếm.

Có hai chỗ để khai: thẻ <link rel="alternate" hreflang="..."> trong phần <head> của trang, hoặc khai ngay trong sitemap. Khai trong sitemap gọn hơn khi bạn có nhiều ngôn ngữ, vì mọi thứ nằm ở một file.

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://example.com/blog/seo/bai-viet</loc>
    <lastmod>2026-08-06T15:36:27+07:00</lastmod>
    <xhtml:link rel="alternate" hreflang="vi"
                href="https://example.com/blog/seo/bai-viet"/>
    <xhtml:link rel="alternate" hreflang="en"
                href="https://example.com/en/blog/seo/the-article"/>
  </url>
</urlset>

Bốn quy tắc bắt buộc:

  1. Khai báo phải đối xứng. Nếu trang tiếng Việt trỏ tới bản tiếng Anh thì bản tiếng Anh phải trỏ ngược lại. Thiếu chiều ngược, Google bỏ qua cả cặp.
  2. Mỗi URL phải tự khai chính nó. Trong khối của URL tiếng Việt vẫn phải có dòng hreflang="vi" trỏ về chính URL đó.
  3. Khai bằng khai báo namespace xmlns:xhtml ở thẻ <urlset>. Thiếu dòng này thì file không hợp lệ.
  4. Chỉ khai cho những trang thật sự có bản dịch đã xuất bản. Trỏ hreflang tới một URL trả về 404 hoặc chưa xuất bản là lỗi phổ biến nhất trong nhóm này.

Điểm thứ tư đáng nói thêm. Trong hệ thống của tôi, một bài có thể đã xuất bản ở tiếng Việt nhưng bản dịch tiếng Anh vẫn ở trạng thái nháp. Nếu sitemap cứ khai máy móc theo cấu trúc dữ liệu, nó sẽ trỏ tới một URL người dùng chưa truy cập được. Sitemap phải kiểm tra trạng thái xuất bản của từng bản dịch trước khi khai, chứ không phải cứ có bản ghi là khai.

Khai báo sitemap: hai việc, không phải một

Khai trong robots.txt

Thêm một dòng vào cuối robots.txt:

Sitemap: https://example.com/sitemap.xml

Dòng này không phụ thuộc vào các dòng User-agent phía trên và có thể đặt ở bất cứ đâu trong file. Nó có tác dụng với mọi công cụ tìm kiếm, không riêng Google — Bing, Yandex và các công cụ khác đều đọc. Nếu bạn dùng sitemap index thì chỉ khai file index, không cần liệt kê từng file con.

Gửi qua Google Search Console

Vào phần Sitemaps trong menu bên trái, nhập đường dẫn tương đối (sitemap.xml) rồi gửi. Với sitemap index, chỉ gửi file index — Google tự đọc các file con bên trong và hiển thị chúng thành từng dòng riêng trong báo cáo.

Màn hình Sitemaps trong Google Search Console sau khi gửi file index thành công
Gửi file index, Google tự đọc các file con và tách thành từng dòng riêng trong báo cáo.

Bạn chỉ cần gửi một lần. Không cần gửi lại mỗi khi đăng bài mới; Google tự tải lại sitemap theo lịch của họ. Gửi lại nhiều lần không làm quá trình thu thập nhanh hơn.

Đọc báo cáo trong Search Console

Sau khi gửi, ba thông tin đáng theo dõi:

  • Trạng thái và ngày đọc gần nhất. Nếu ngày này đứng yên nhiều tuần trong khi bạn vẫn đăng bài, kiểm tra xem sitemap có trả về mã 200 không.
  • Số URL đã phát hiện. So với số bạn thật sự khai. Lệch nhiều nghĩa là có URL bị loại vì lỗi.
  • Báo cáo Lập chỉ mục trang, lọc theo sitemap. Đây là phần có giá trị nhất và ít người dùng. Nó cho bạn thấy trong số URL đã khai, bao nhiêu được lập chỉ mục và những URL còn lại bị loại vì lý do gì.
Báo cáo Lập chỉ mục trang trong Search Console lọc theo sitemap
Bộ lọc theo sitemap trong báo cáo Lập chỉ mục trang — phần có giá trị nhất và ít người dùng.

Chính bộ lọc đó là thứ biến sitemap từ một thủ tục hành chính thành công cụ chẩn đoán. Không có nó, bạn chỉ biết "Google đã nhận file".

Bảy lỗi tôi gặp và cách phát hiện

LỗiVì sao hại
URL trong sitemap bị chặn bởi noindexBạn vừa bảo Google "hãy lập chỉ mục trang này" vừa bảo "đừng lập chỉ mục". Search Console báo lỗi trực tiếp.
URL trong sitemap không phải URL chuẩnNếu trang khai canonical trỏ sang URL khác, URL trong sitemap là tín hiệu ngược chiều. Sitemap phải luôn chứa bản canonical.
URL trả về 404 hoặc chuyển hướngLãng phí lượt thu thập và làm giảm độ tin cậy của cả file. Hay xảy ra khi bạn đổi slug bài cũ.
Trộn lẫn http/https hoặc có/không wwwMỗi URL thành một lượt chuyển hướng thừa.
lastmod lấy theo thời điểm hiện tạiGoogle ngừng tin thẻ lastmod trên toàn site.
Sitemap trả về sai Content-TypePhải là application/xml hoặc text/xml. Trả về text/html thì có nơi vẫn đọc được, có nơi không.
Sitemap tồn tại nhưng không khai ở đâu cảFile nằm im, không công cụ nào biết để tìm.

Kiểm tra bằng dòng lệnh

Mở sitemap bằng trình duyệt rồi kết luận là cách kiểm tra tệ nhất, vì trình duyệt tự render XML theo cách của nó. Có lần tôi tưởng file hỏng chỉ vì trình duyệt hiển thị nội dung dưới dạng một khối chữ liền, trong khi file hoàn toàn đúng cú pháp.

Cách đáng tin hơn là xem đúng những gì máy chủ trả về:

# Xem 30 dòng đầu của file
curl -s https://example.com/sitemap.xml | head -30

# Kiểm tra mã trạng thái và Content-Type
curl -sI https://example.com/sitemap.xml

# Đếm số URL đã khai
curl -s https://example.com/sitemap-vi.xml | grep -c "<loc>"

# Kiểm tra một URL cụ thể có trong sitemap không
curl -s https://example.com/sitemap-vi.xml | grep -A2 "bai-viet"

Sau đó lấy vài URL bất kỳ trong sitemap, chạy curl -sI với từng URL và xác nhận tất cả đều trả về 200. Nếu có URL nào trả về 301 hoặc 404, sửa trước khi gửi Search Console.

Sitemap không thay thế được liên kết nội bộ

Đây là kết luận quan trọng nhất của bài, nên tôi để riêng một mục.

Sitemap giúp Google tìm thấy một URL. Nó không nói gì về việc URL đó quan trọng đến đâu trong website của bạn. Thông tin đó chỉ đến từ liên kết: bao nhiêu trang trỏ tới nó, chúng trỏ từ đâu, và dùng chữ gì để trỏ.

Một trang chỉ tồn tại trong sitemap mà không có trang nào trong site trỏ tới — orphan page — vẫn là orphan page. Google có thể vào xem, nhưng không nhận được tín hiệu nào cho thấy trang đó đáng chú ý. Nếu bạn định để sitemap gánh phần việc của cấu trúc liên kết, hãy đọc bài về liên kết nội bộ trước — sitemap không giải quyết được vấn đề đó.

Tóm lại

Sitemap là việc làm một lần, mất khoảng ba mươi phút, và sau đó gần như không cần đụng tới. Đừng biến nó thành nơi tối ưu. Bốn việc cần làm đúng:

  1. Chỉ khai những URL canonical, trả về 200, không bị noindex.
  2. Khai lastmod theo ngày sửa nội dung thật, hoặc không khai gì cả.
  3. Nếu có nhiều ngôn ngữ, khai hreflang đối xứng và chỉ trỏ tới bản dịch đã xuất bản.
  4. Khai trong robots.txt và gửi một lần qua Search Console.

Xong bốn việc đó thì chuyển sang phần thật sự quyết định thứ hạng. Sitemap chưa bao giờ là phần đó.