Trong ba bài trước tôi đã đi qua hai câu hỏi đầu tiên của technical SEO: Google có tìm thấy URL không, và có được phép vào không. Bài này là câu hỏi thứ ba, và là câu khó nhất trong ba câu: khi nhiều URL cùng dẫn tới một nội dung, bản nào là bản chính?

Câu trả lời phổ biến là "khai thẻ canonical". Đúng, nhưng thiếu một vế quan trọng: canonical là lời đề nghị, không phải mệnh lệnh. Google bỏ qua nó thường xuyên hơn bạn nghĩ, và Search Console có hẳn một trạng thái riêng cho tình huống đó.

Bài này nói về việc canonical làm được gì, hai chỗ người ta hay khai sai đến mức tự hại mình, và khi nào nên dùng chuyển hướng 301 thay vì canonical.

Trùng lặp URL sinh ra từ đâu

Trước khi nói về giải pháp, cần thấy vấn đề. Một bài viết duy nhất có thể truy cập được qua rất nhiều URL mà bạn không cố ý tạo ra:

  • https://example.com/bai-viethttps://www.example.com/bai-viet
  • http://https://
  • Có dấu gạch chéo cuối và không có
  • /bai-viet?utm_source=facebook — mọi tham số theo dõi chiến dịch
  • /bai-viet?ref=newsletter, /bai-viet?fbclid=... — tham số do nền tảng khác tự thêm vào
  • Cùng một bài nằm dưới hai danh mục, sinh ra hai đường dẫn

Với người đọc, tất cả đều là một trang. Với công cụ tìm kiếm, mỗi chuỗi ký tự khác nhau là một URL khác nhau, và chúng phải quyết định xem đây là nhiều trang riêng biệt hay nhiều phiên bản của một trang.

Hậu quả khi để mặc: tín hiệu bị chia nhỏ. Liên kết từ bên ngoài trỏ vào ba biến thể khác nhau thì không bản nào tích luỹ đủ. Google cũng phải tốn lượt thu thập cho những bản gần như y hệt nhau. Và trên kết quả tìm kiếm, bản được hiển thị có thể không phải bản bạn muốn.

Canonical là gợi ý, không phải lệnh

Đây là điểm nhiều bài hướng dẫn bỏ qua, và bỏ qua nó thì mọi thứ phía sau dễ hiểu sai.

Khi bạn khai rel="canonical", bạn đang nói với Google: trong nhóm URL giống nhau này, tôi cho rằng đây là bản chính. Google cân nhắc lời đề nghị đó cùng nhiều tín hiệu khác — sitemap khai gì, các liên kết nội bộ trỏ vào đâu, chuyển hướng dẫn tới đâu, URL nào sạch hơn — rồi tự quyết định.

Nếu các tín hiệu mâu thuẫn nhau, Google tin phần còn lại hơn là tin thẻ canonical. Thẻ ấy chỉ có sức nặng khi mọi thứ khác đồng thuận với nó.

Search Console có hẳn một trạng thái cho việc này: trong báo cáo Lập chỉ mục trang, mục "Trang trùng lặp, Google đã chọn trang chuẩn khác với người dùng". Khi thấy dòng đó, đừng vội cho là lỗi của Google. Trong phần lớn trường hợp, đó là dấu hiệu các tín hiệu trên site đang chỏi nhau — chẳng hạn canonical trỏ một đằng còn sitemap và liên kết nội bộ trỏ một nẻo.

Cú pháp và ba quy tắc

Thẻ đặt trong phần <head>:

<link rel="canonical" href="https://example.com/bai-viet">

Ba quy tắc quyết định thẻ này có tác dụng hay không:

  1. Dùng URL tuyệt đối. Đường dẫn tương đối tuy hợp lệ về mặt kỹ thuật nhưng dễ sai khi trang được phục vụ ở nhiều host. Khai đủ giao thức và tên miền.
  2. Mỗi trang chỉ một thẻ. Hai thẻ canonical trên cùng một trang thì Google bỏ qua cả hai. Lỗi này hay xảy ra khi vừa có plugin SEO tự sinh vừa có thẻ khai tay trong template.
  3. URL trong canonical phải trả về mã 200. Trỏ tới một URL bị chuyển hướng hoặc đã 404 là tự vô hiệu hoá thẻ.

Thêm một quy tắc về tính nhất quán: URL trong canonical phải khớp chính xác với URL trong sitemap và với đích của các liên kết nội bộ. Ba nơi này lệch nhau là nguyên nhân phổ biến nhất khiến Google chọn bản khác.

Canonical tự trỏ về chính nó

Một trang không có bản trùng nào vẫn nên khai canonical trỏ về chính URL của nó. Nghe thừa, nhưng nó xử lý một lớp vấn đề bạn không kiểm soát được.

Khi ai đó chia sẻ bài của bạn lên mạng xã hội, nền tảng thường tự gắn thêm tham số theo dõi vào URL. Người đọc bấm vào, máy chủ của bạn phục vụ đúng nội dung đó ở một URL mới có đuôi tham số. Nếu trang khai canonical tự trỏ, bản có tham số vẫn tự khai rằng bản chính là URL sạch — và Google gộp tín hiệu về đúng chỗ.

Không khai gì thì bạn phó mặc cho Google tự đoán. Thường nó đoán đúng, nhưng đây là dòng code khai một lần trong layout và áp dụng cho toàn site, nên không có lý do gì để bỏ.

Trên site này, canonical mặc định lấy theo URL hiện tại, và mỗi bản dịch có thêm một trường tuỳ chọn để ghi đè khi cần. Trường ghi đè ấy gần như không dùng tới — đó là dấu hiệu tốt, vì canonical thủ công chỉ nên xuất hiện ở trường hợp đặc biệt.

Phân trang: chỗ sai phổ biến nhất

Danh mục blog của bạn có /blog, /blog?page=2, /blog?page=3. Một lời khuyên vẫn lan truyền rộng rãi: cho tất cả các trang sau trỏ canonical về /blog, để "gom sức mạnh về trang đầu".

Đừng làm. Nó gây ra đúng vấn đề mà bạn đang cố tránh.

Trang 2 và trang 1 không phải là hai phiên bản của cùng một nội dung. Chúng liệt kê những bài hoàn toàn khác nhau. Khi bạn khai trang 2 có bản chính là trang 1, bạn đang nói với Google rằng nội dung trang 2 là bản sao — và Google có thể ngừng thu thập trang 2. Các bài chỉ xuất hiện từ trang 2 trở đi mất một đường liên kết quan trọng dẫn tới chúng.

Cách đúng: mỗi trang phân trang khai canonical trỏ về chính nó. Trang 2 khai canonical là trang 2. Chúng để index, follow bình thường — tôi đã nói kỹ chuyện này trong bài về robots.txt và meta robots.

Nếu bạn lo các trang phân trang cạnh tranh với nhau trên kết quả tìm kiếm thì thực tế là chúng gần như không bao giờ xếp hạng cho truy vấn nào cả. Vai trò của chúng là đường đi cho bot, không phải trang đích cho người tìm kiếm.

Canonical và hreflang làm hai việc khác nhau

Đây là chỗ site song ngữ hay hỏng, và hỏng theo cách khó phát hiện.

Có một suy nghĩ nghe rất hợp lý: bản tiếng Anh là bản dịch của bản tiếng Việt, vậy nên khai canonical của trang tiếng Anh trỏ về trang tiếng Việt. Làm vậy là xoá trang tiếng Anh khỏi kết quả tìm kiếm. Bạn vừa tuyên bố nó là bản sao không cần lập chỉ mục.

Hai công cụ, hai nhiệm vụ:

  • Canonical xử lý các URL cùng một nội dung. Bản dịch không phải cùng nội dung — chúng là nội dung khác nhau phục vụ đối tượng khác nhau.
  • hreflang xử lý các URL là bản dịch của nhau. Nó nói với Google: hai trang này tương đương về mặt nội dung, hãy hiển thị bản phù hợp với ngôn ngữ của người tìm kiếm.

Khai đúng là mỗi bản dịch có canonical trỏ về chính nó, và hai bản khai hreflang chéo cho nhau:

<!-- Trên trang tiếng Việt -->
<link rel="canonical" href="https://example.com/bai-viet">
<link rel="alternate" hreflang="vi" href="https://example.com/bai-viet">
<link rel="alternate" hreflang="en" href="https://example.com/en/the-article">

<!-- Trên trang tiếng Anh -->
<link rel="canonical" href="https://example.com/en/the-article">
<link rel="alternate" hreflang="vi" href="https://example.com/bai-viet">
<link rel="alternate" hreflang="en" href="https://example.com/en/the-article">

Một chi tiết đáng nói về cách site này xử lý: thẻ hreflang chỉ được in ra khi có ít nhất hai ngôn ngữ đã xuất bản. Bài nào chỉ mới có bản tiếng Việt, còn bản dịch đang ở trạng thái nháp, thì không in thẻ hreflang nào cả. Lý do là hreflang khai một chiều không có giá trị, và tệ hơn là nếu nó trỏ tới URL chưa xuất bản thì đó là một liên kết hỏng trong mắt Google.

Khi nào dùng 301 thay vì canonical

Canonical để lại cả hai URL hoạt động và để Google chọn. Chuyển hướng 301 thì đóng hẳn một URL và đẩy mọi thứ sang URL kia. Chọn cái nào tuỳ vào việc bạn có cần cả hai URL cùng tồn tại hay không.

Tình huốngNên dùng
Gộp www về non-www, hoặc http về https301. Không có lý do gì để cả hai cùng phục vụ được.
Đổi slug của một bài cũ301. URL cũ nên biến mất hoàn toàn.
URL có tham số theo dõi chiến dịchCanonical. Tham số phải giữ được cho công cụ đo lường hoạt động.
Cùng bài xuất hiện dưới hai danh mụcCanonical về đường dẫn chính, nếu bạn cần cả hai đường dẫn.
Trang in hoặc bản rút gọn của một bàiCanonical về bản đầy đủ.
Nội dung đăng lại trên site khác có thoả thuậnCanonical trỏ về bản gốc, khai trên site đăng lại.

Quy tắc chung: nếu URL kia không có lý do gì để tồn tại, dùng 301. Nếu nó cần tiếp tục hoạt động vì một lý do khác ngoài SEO, dùng canonical.

Về trường hợp www và non-www của site này: www trả về 301 sang bản non-www, và đó là cách xử lý đúng. Nhưng làm 301 xong chưa đủ — dòng khai sitemap trong robots.txt, giá trị APP_URL trong cấu hình, và các URL bên trong sitemap đều phải dùng bản non-www. Tôi đã tìm ra và sửa lỗi này ở chính site mình khi viết bài trước.

Đọc báo cáo khi Google chọn khác

Mở báo cáo Lập chỉ mục trang trong Search Console và tìm hai trạng thái:

"Trang trùng lặp, Google đã chọn trang chuẩn khác với người dùng" — Google thấy thẻ canonical của bạn và không đồng ý. Bấm vào để xem nó chọn URL nào. Từ đó kiểm tra ba thứ: sitemap đang khai URL nào, liên kết nội bộ đang trỏ tới URL nào, và có chuyển hướng nào dẫn ngược lại không. Gần như luôn có một trong ba đang mâu thuẫn với thẻ canonical.

"Trang trùng lặp, không có thẻ canonical do người dùng chọn" — Google phát hiện trùng lặp và tự chọn bản chính vì bạn không khai gì. Nếu bản nó chọn đúng ý bạn thì không cần làm gì. Nếu không, khai canonical và đồng bộ các tín hiệu còn lại.

Báo cáo Lập chỉ mục trang trong Search Console hiển thị trạng thái Google chọn trang chuẩn khác
Trạng thái này không phải lỗi của Google — nó thường có nghĩa là các tín hiệu trên site đang chỏi nhau.

Công cụ Kiểm tra URL cho câu trả lời trực tiếp hơn với một URL cụ thể: nó hiển thị cả canonical do bạn khai lẫn canonical Google đã chọn, đặt cạnh nhau.

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

# Xem thẻ canonical của một trang
curl -s https://example.com/bai-viet | grep -i 'rel="canonical"'

# Kiểm tra URL trong canonical có trả về 200 không
curl -sI https://example.com/bai-viet | head -1

# Xem cả canonical và hreflang cùng lúc
curl -s https://example.com/bai-viet | grep -iE 'canonical|hreflang'

Sáu lỗi thường gặp

LỗiHậu quả
Trang phân trang trỏ canonical về trang đầuGoogle ngừng thu thập các trang sau, bài cũ mất đường vào.
Bản dịch trỏ canonical về bản gốcBản dịch bị loại khỏi chỉ mục. Đây là chỗ dùng hreflang, không phải canonical.
Canonical trỏ tới URL bị chuyển hướng hoặc 404Thẻ mất tác dụng hoàn toàn.
Hai thẻ canonical trên một trangGoogle bỏ qua cả hai. Thường do plugin và template cùng sinh thẻ.
Canonical mâu thuẫn với sitemap và liên kết nội bộGoogle tin phần còn lại và chọn URL khác.
Vừa chặn URL trong robots.txt vừa khai canonicalBot không vào được nên không đọc được thẻ. Hai lệnh triệt tiêu nhau.

Tóm lại

Bốn điều đáng nhớ:

  1. Canonical là gợi ý. Nó chỉ có sức nặng khi sitemap, liên kết nội bộ và chuyển hướng cùng nói một điều.
  2. Mọi trang nên có canonical trỏ về chính nó, kể cả trang phân trang.
  3. Bản dịch dùng hreflang, không dùng canonical. Nhầm chỗ này là xoá bản dịch khỏi Google.
  4. URL không có lý do tồn tại thì dùng 301, không dùng canonical.

Đến đây là hết ba câu hỏi nền của technical SEO: tìm thấy, vào được, chọn đúng bản. Phần còn lại của technical SEO — tốc độ tải, dữ liệu có cấu trúc, trải nghiệm trên di động — đều dựa trên ba thứ này đã đúng. Sai ở tầng nền thì tối ưu tầng trên không cứu được gì.