SEO cho ứng dụng trang đơn: vì sao SPA khó lên thứ hạng, cách SSR, tạo trang tĩnh và kết xuất trước khắc phục điều đó, và cách làm cho ứng dụng của bạn đọc được bởi các trình thu thập AI.

Trên trang này
Tóm lại
một ứng dụng trang đơn (SPA) tải một khung HTML duy nhất và dựng mọi màn hình bằng JavaScript trong trình duyệt. Google có thể kết xuất JavaScript, nhưng việc kết xuất bị trì hoãn và dễ hỏng, còn các trình thu thập đứng sau ChatGPT, Claude và Perplexity hoàn toàn không chạy JavaScript. Để lên thứ hạng và được trích dẫn, mỗi màn hình của SPA cần có URL riêng, một liên kết thật với href, tiêu đề và mô tả duy nhất, mã trạng thái đúng, và trên hết là nội dung chính có sẵn trong HTML mà máy chủ gửi về, thông qua kết xuất phía máy chủ, tạo trang tĩnh hoặc kết xuất trước.
Muốn tìm hiểu sâu hơn? Hãy hỏi
Bài trắc nghiệm nhanh
Ai nên sửa phần kỹ thuật của website?
Lời khuyên dành cho bạn
Cho mỗi màn hình một URL sạch, có thể thu thập là giải pháp phù hợp với bạn
Số 1 trong bảng xếp hạng này, phù hợp nhất với câu trả lời của bạn.
Lời khuyên dành cho bạn
Dùng liên kết thật là giải pháp phù hợp với bạn
Số 2 trong bảng xếp hạng này, phù hợp nhất với câu trả lời của bạn.
Lời khuyên dành cho bạn
Cập nhật tiêu đề, mô tả và canonical theo từng tuyến là giải pháp phù hợp với bạn
Số 3 trong bảng xếp hạng này, phù hợp nhất với câu trả lời của bạn.
Lời khuyên dành cho bạn
Trả về mã trạng thái trung thực là giải pháp phù hợp với bạn
Số 4 trong bảng xếp hạng này, phù hợp nhất với câu trả lời của bạn.
SEO cho ứng dụng trang đơn là tập hợp các kỹ thuật giúp một ứng dụng JavaScript được xây bằng React, Vue, Angular hay Svelte dễ được thu thập như một website cổ điển. Vấn đề này được ghi chép rõ: Google giải thích trong kiến thức nền tảng về SEO JavaScript rằng nó xử lý trang JavaScript qua ba giai đoạn (thu thập, kết xuất, lập chỉ mục), và mọi điểm yếu của SPA đều nằm ở đâu đó trong chuỗi đó. Bài này tập trung vào SPA; với các site JavaScript nói chung, hãy đọc hướng dẫn về SEO JavaScript của chúng tôi.
Một website truyền thống trả về một tài liệu HTML đầy đủ cho mỗi URL. Một SPA trả về gần như cùng một tài liệu cho mọi URL: một <div id="root"> trống, vài thẻ meta và một gói JavaScript lớn. Trình duyệt tải gói đó, gọi một API, rồi mới vẽ trang. Khi khách truy cập nhấp vào một liên kết, JavaScript thay nội dung mà không tải lại trang.
Với một người dùng trên điện thoại nhanh, kết quả có cảm giác tức thì. Với một trình thu thập, phản hồi đầu tiên là một vỏ rỗng: không có tiêu đề, không có văn bản, không có liên kết. Mọi thứ phụ thuộc vào việc bot có chạy JavaScript hay không, và khi nào. Một sự thật duy nhất này giải thích phần lớn các vấn đề SEO của SPA:
/#/pricing), và phần sau dấu # không bao giờ được gửi tới máy chủ, nên mọi màn hình gộp lại thành một URL.<title>, và nếu bộ định tuyến không cập nhật nó, mọi trang đều dùng chung.href: nút bấm và trình xử lý onClick giúp người dùng điều hướng nhưng không cho trình thu thập thứ gì để đi theo.Googlebot trước tiên tải HTML thô và đọc các liên kết cùng chỉ thị nó tìm thấy ở đó. Các trang trả về mã trạng thái 200 sau đó được xếp vào hàng đợi của Dịch vụ kết xuất web (Web Rendering Service), một Chromium không giao diện (headless). Google nêu rõ một trang “có thể nằm trong hàng đợi này vài giây, nhưng cũng có thể lâu hơn thế”. Khi đã kết xuất, HTML thu được được phân tích lại để lấy nội dung và liên kết, rồi mới được lập chỉ mục.
Bốn chi tiết trong tài liệu của Google có ý nghĩa với SPA:
<a> có href mới là liên kết đáng tin cậy. Các liên kết được JavaScript chèn vào vẫn ổn miễn là chúng theo đúng định dạng đó.pushState) thay vì định tuyến bằng #. Google đã ngừng hỗ trợ lược đồ thu thập AJAX cũ (các URL #!) vào tháng 10/2015.noindex trong HTML gốc có quyền quyết định. Google có thể bỏ qua việc kết xuất khi thấy noindex, nên việc gỡ nó bằng JavaScript sau đó không có tác dụng.Hệ quả thực tế: Google có thể lập chỉ mục một SPA được kết xuất ở phía trình duyệt, nhưng bạn thêm một bước thứ hai, một độ trễ và một điểm hỏng vào mọi trang. Một lần hết thời gian chờ, một lời gọi API bị chặn hoặc một lỗi JavaScript trong lúc kết xuất sẽ khiến phiên bản được lập chỉ mục bị trống. Hãy kiểm tra những gì Google nhìn thấy bằng công cụ Kiểm tra URL trong Search Console, và đọc hướng dẫn về cách hoạt động của lập chỉ mục trên Google của chúng tôi nếu các trang vẫn nằm ngoài chỉ mục.
Phần lớn là không. Trong một nghiên cứu công bố tháng 12/2024 dựa trên lưu lượng của mạng lưới của mình, Vercel và MERJ phát hiện rằng “hiện không có trình thu thập AI lớn nào kết xuất JavaScript”: GPTBot, OAI-SearchBot và ChatGPT-User (OpenAI), ClaudeBot (Anthropic), PerplexityBot, Meta-ExternalAgent và Bytespider đều chỉ đọc HTML thô. Chúng có tải các tệp JavaScript (khoảng 11,5% yêu cầu của ChatGPT và 23,8% của Claude) nhưng không chạy chúng. Ngoại lệ là Gemini, vốn dựa vào hạ tầng kết xuất của Google, và AppleBot, dùng một trình thu thập dựa trên trình duyệt.
Với một SPA được kết xuất ở phía trình duyệt, điều này có nghĩa là các trình thu thập AI nuôi ChatGPT, Claude và Perplexity chỉ thấy một trang trống. Sản phẩm của bạn có thể lên thứ hạng trên Google nhưng vẫn vô hình trong câu trả lời của AI, vì trợ lý chưa bao giờ đọc một chữ nào của nó. Điều tương tự áp dụng cho hầu hết các bot xem trước liên kết trên mạng xã hội và ứng dụng nhắn tin, vốn đọc các thẻ Open Graph trong HTML thô. Khi nội dung đã nằm trong HTML, hãy kiểm tra thêm rằng robots.txt của bạn cho phép các trình thu thập AI mà bạn muốn.
Cách khắc phục là gửi HTML thật ngay trong phản hồi đầu tiên. Google gọi kết xuất động (chỉ phục vụ phiên bản đã kết xuất trước cho bot) là “một giải pháp tạm thời chứ không phải giải pháp được khuyến nghị” trong tài liệu về kết xuất động, và hướng tới kết xuất phía máy chủ, kết xuất tĩnh hoặc hydration. Các định nghĩa dưới đây theo tài liệu Rendering on the Web trên web.dev.
| Chiến lược | Cách hoạt động | Nội dung trong HTML đầu tiên | Phù hợp nhất cho | Giới hạn |
|---|---|---|---|---|
| Kết xuất phía trình duyệt (CSR) | Trình duyệt dựng trang từ JavaScript và một API | Không | Bảng điều khiển và các trang sau đăng nhập | Lập chỉ mục bị trì hoãn trên Google, vô hình với hầu hết trình thu thập AI |
| Kết xuất phía máy chủ (SSR) | Máy chủ kết xuất HTML cho mỗi yêu cầu, sau đó JavaScript hydrate nó | Có | Danh mục, bảng niêm yết, nội dung thay đổi thường xuyên hoặc được cá nhân hóa | Chi phí máy chủ, thời gian phản hồi chậm hơn nếu không lưu đệm |
| Tạo trang tĩnh (SSG) | HTML được tạo lúc xây dựng cho mỗi URL và phục vụ từ CDN | Có | Trang marketing, blog, tài liệu, trang đích | Cần xây dựng lại khi nội dung thay đổi (có các tùy chọn tăng dần) |
| Kết xuất trước lúc xây dựng | Một trình duyệt không giao diện ghi lại trạng thái ban đầu của mỗi tuyến thành HTML tĩnh | Có | SPA hiện có với số tuyến công khai hạn chế | Dữ liệu bị đóng băng tại thời điểm xây dựng, các tuyến phải được liệt kê sẵn |
| Kết xuất động | Bot nhận một bản chụp đã kết xuất trước, người dùng nhận SPA | Có, chỉ cho các bot đã liệt kê | Giải pháp tạm thời cho một ứng dụng cũ | Chính thức là giải pháp tạm thời, chi phí bảo trì, rủi ro phục vụ bot nội dung khác |
Hầu hết các framework hiện đại cho phép bạn kết hợp chiến lược theo từng tuyến: tĩnh cho các trang marketing, kết xuất phía máy chủ cho danh mục, kết xuất phía trình duyệt cho ứng dụng sau đăng nhập. Cách kết hợp này cho trình thu thập HTML đầy đủ ở nơi lưu lượng tìm kiếm diễn ra, và giữ trải nghiệm SPA ở nơi nó mang lại giá trị.
| Thư viện | Framework hoặc tính năng cho HTML khi tải lần đầu |
|---|---|
| React | Next.js (server components, SSR và tạo trang tĩnh), React Router ở chế độ framework, Gatsby |
| Vue | Nuxt (kết xuất phổ quát theo mặc định, có thể tạo trang tĩnh) |
| Angular | Angular SSR (kết xuất phía máy chủ và kết xuất trước lúc xây dựng) |
| Svelte | SvelteKit (kết xuất phía máy chủ theo mặc định, kết xuất trước theo từng tuyến) |
| Bất kỳ loại nào trong số này | Astro (HTML tĩnh theo mặc định, các đảo tương tác chỉ tải khi cần) |
Các website do trình tạo website bằng AI xây dựng đáng được nhắc riêng: nhiều trình tạo xuất ra một ứng dụng React kết xuất ở phía trình duyệt. Nếu bạn đã xây site bằng một trình như vậy, hãy xem ghi chú của chúng tôi về SEO và GEO cho Lovable trước khi cho rằng Google và ChatGPT có thể đọc được nó.
Dùng History API (/pricing, không bao giờ /#/pricing), mỗi phần nội dung một URL, và cùng một URL dù khách vào trực tiếp hay qua điều hướng trong ứng dụng. Mỗi URL phải tải đúng nội dung khi mở trong một tab mới, đây chính là phép thử mà trình thu thập thực hiện.
Mọi phần tử điều hướng dẫn tới một trang có thể lập chỉ mục nên là một <a href="/path">. Các thành phần liên kết của framework (Link, NuxtLink, routerLink) xuất ra đúng đánh dấu này; các trình xử lý nhấp chuột tự viết trên phần tử div hay button thì không. Liên kết tốt cũng mang theo kiến trúc website của bạn: nếu một trang không được liên kết, trình thu thập hiếm khi tìm thấy nó.
Mỗi tuyến cần tiêu đề, mô tả meta, canonical và thẻ Open Graph riêng, được tạo trên máy chủ khi có thể. Trang thẻ meta của chúng tôi liệt kê những gì cần đặt. Giữ một thẻ canonical duy nhất: Google khuyến nghị đặt nó trong HTML, và nếu JavaScript thay đổi nó, kết quả không được mâu thuẫn với bản gốc.
Sản phẩm không còn tồn tại và bài viết đã xóa không được trả về 200 kèm thông báo lỗi. Với SSR, hãy trả về 404 hoặc 410 thật từ máy chủ. Trong một SPA thuần, Google chấp nhận hai phương án dự phòng: chuyển hướng bằng JavaScript tới một URL trả về 404, hoặc thêm thẻ meta robots noindex vào màn hình lỗi.
Tiêu đề, văn bản chính, giá, FAQ và dữ liệu có cấu trúc JSON-LD nên nằm trong phản hồi của máy chủ, chứ không được tải sau khi nhấp hay cuộn. Nội dung nằm sau các thẻ được kết xuất theo yêu cầu, hay sau nút “tải thêm”, thường bị bỏ sót.
Tách gói theo tuyến, trì hoãn những gì không cần cho lần xem đầu tiên và tránh kết xuất lại toàn bộ trang trong lúc hydrate. Lưu ý rằng dữ liệu thực địa của Chrome (CrUX) gán các chỉ số của điều hướng trong ứng dụng cho URL mà khách đã tải lần đầu, nên hãy kiểm tra từng mẫu trang quan trọng riêng lẻ.
So sánh ba phiên bản của mỗi mẫu trang quan trọng: HTML thô (xem mã nguồn trang hoặc tải trang bằng công cụ dòng lệnh), HTML đã kết xuất của Google (Kiểm tra URL, rồi “Xem trang đã thu thập”) và trang khi đã tắt JavaScript. Nếu văn bản chính chỉ xuất hiện trong phiên bản thứ hai, các trình thu thập AI không thấy nó. Kiểm tra khả năng thu thập cho AI miễn phí và công cụ kiểm tra khả năng lập chỉ mục của chúng tôi chạy các phép kiểm tra này trên bất kỳ URL nào.
| Triệu chứng | Nguyên nhân có thể | Cách khắc phục |
|---|---|---|
| Search Console cho thấy nhiều trang “Đã thu thập, hiện chưa được lập chỉ mục” | HTML trống hoặc gần như giống hệt nhau trước khi kết xuất | SSR, SSG hoặc kết xuất trước cho các tuyến công khai |
Mọi kết quả tìm kiếm site: đều hiện cùng một tiêu đề | Tiêu đề không được cập nhật theo từng tuyến | Quản lý phần đầu trang theo tuyến ở phía máy chủ |
| Chỉ trang chủ được lập chỉ mục | Định tuyến bằng phân đoạn hoặc liên kết không có href | History API và các liên kết <a> thật |
| Trang lỗi xuất hiện trong chỉ mục | Soft 404 (trạng thái 200 ở khắp nơi) | 404 từ máy chủ, hoặc chuyển hướng JavaScript tới URL 404, hoặc noindex |
| Lên thứ hạng trên Google nhưng không bao giờ được ChatGPT hay Perplexity trích dẫn | Nội dung chỉ hiển thị sau khi thực thi JavaScript | Nội dung có trong phản hồi HTML đầu tiên |
| Nội dung cũ hiện trong bản đã kết xuất của Google | Tệp JavaScript hoặc CSS được lưu đệm | Tên tệp có dấu vân tay |
Trong nhiều năm, kết xuất phía trình duyệt là một rủi ro có thể kiểm soát vì Google sớm muộn cũng kết xuất JavaScript. Khi một phần việc khám phá nội dung đã chuyển sang ChatGPT, Claude, Gemini và Perplexity, chi phí đã thay đổi: một trang chỉ tồn tại sau khi thực thi JavaScript sẽ vắng mặt trong các nguồn mà phần lớn trợ lý có thể đọc. Khả năng thu thập trong HTML thô đã trở thành điều kiện đầu tiên của tối ưu hóa công cụ tạo sinh (generative engine optimization).
Khi HTML đã đầy đủ, phần còn lại theo các quy tắc quen thuộc: các trang trả lời rõ ràng một câu hỏi, với dữ kiện có nguồn và dữ liệu có cấu trúc, là những trang mà trợ lý trích dẫn. Các tính năng tối ưu GEO của Sorank giúp bạn viết và xuất bản nội dung đó, và theo dõi lượt nhắc đến AI cho thấy ChatGPT, Claude và Gemini có trích dẫn thương hiệu của bạn sau khi sửa lỗi kết xuất hay không.
Quy tắc cốt lõi của SEO cho ứng dụng trang đơn gói gọn trong một câu: bất cứ thứ gì bạn muốn Google xếp hạng và AI trích dẫn đều phải nằm trong HTML mà máy chủ gửi về. Giữ SPA cho trải nghiệm sau đăng nhập, kết xuất các trang công khai trên máy chủ hoặc lúc xây dựng, rồi kiểm tra những gì bot nhận được trước và sau mỗi lần phát hành.
Google không phạt một ứng dụng trang đơn, nhưng cấu hình mặc định của nó, tức kết xuất phía trình duyệt với một khung HTML duy nhất, làm việc lập chỉ mục chậm hơn và kém tin cậy hơn. Hầu hết trình thu thập AI không chạy JavaScript, nên chúng thấy một trang trống. Với kết xuất phía máy chủ, tạo trang tĩnh hoặc kết xuất trước trên các tuyến công khai, một SPA có thể lên thứ hạng ngang bất kỳ website cổ điển nào.
Bản thân React trung lập: điều quan trọng là HTML được tạo ở đâu. Một ứng dụng React chỉ được kết xuất trong trình duyệt sẽ gặp các vấn đề SPA thông thường, còn cùng các thành phần đó được kết xuất trên máy chủ với Next.js hoặc React Router ở chế độ framework sẽ gửi HTML đầy đủ cho trình thu thập. Hãy chọn một framework hỗ trợ kết xuất phía máy chủ hoặc tạo trang tĩnh cho những trang bạn muốn lập chỉ mục.
Chỉ như một biện pháp tạm thời. Google mô tả kết xuất động là một giải pháp tạm thời chứ không phải giải pháp được khuyến nghị, vì việc duy trì một phiên bản riêng cho bot làm tăng chi phí và rủi ro. Kết xuất phía máy chủ, tạo trang tĩnh hoặc kết xuất trước lúc xây dựng cho mọi khách truy cập cùng một HTML và là giải pháp lâu dài.
HỌ ĐÃ THỬ SORANK TRƯỚC BẠN
