Nhiệm vụ: Cấu hình Open Graph / meta tags để hiển thị bản xem trước trang chính xác trong các ứng dụng nhắn tin

Cấu hình Open Graph / meta tags để hiển thị bản xem trước trang chính xác trong các ứng dụng nhắn tin

Chỉ định rõ ràng siêu dữ liệu bản xem trước (tiêu đề, mô tả, hình ảnh) cho các trang web để các ứng dụng nhắn tin và mạng xã hội tạo thẻ liên kết chính xác.

Cần làm gì

Thêm siêu dữ liệu rõ ràng vào các trang web để tạo bản xem trước liên kết trong ứng dụng nhắn tin và mạng xã hội. Trước hết là Open Graph (og:title, og:description, og:image, og:url, og:type), và Twitter Cards nếu cần thiết.

Hiện tại, hình ảnh xem trước chưa được chỉ định rõ ràng. Do đó, Telegram, WhatsApp, VK, Facebook và các dịch vụ khác tự cố gắng tìm ra tiêu đề, mô tả và hình ảnh nào để sử dụng khi gửi liên kết. Chúng có thể lấy <title>, meta description, hình ảnh phù hợp đầu tiên từ trang, hình ảnh lớn từ nội dung hoặc thậm chí giữ lại tùy chọn đã tìm thấy trước đó. Kết quả là bản xem trước có thể hiển thị một cách khó đoán và khác với những gì chúng ta muốn hiển thị cho người dùng.

Tại sao điều này quan trọng

Bản xem trước liên kết thực chất là một đoạn trích nhỏ (snippet) của trang bên trong ứng dụng nhắn tin. Nó ảnh hưởng đến cách người dùng nhận thức liên kết trước khi nhấp vào: liệu họ có nhìn thấy tiêu đề dễ hiểu, mô tả phù hợp và hình ảnh sản phẩm/danh mục bình thường thay vì một hình ảnh ngẫu nhiên hay không.

Đây không phải là yếu tố xếp hạng SEO trực tiếp, nhưng nó liên quan đến việc đánh dấu trang chính xác và ảnh hưởng đến CTR, mức độ nhận diện thương hiệu và chất lượng chia sẻ liên kết. Đối với các công cụ tìm kiếm và dịch vụ bên ngoài, cũng tốt hơn khi siêu dữ liệu trang chính được xác định rõ ràng thay vì được xác định theo heuristic.

Nội dung cần có trong thẻ đánh dấu

Đối với mỗi trang được lập chỉ mục, tốt nhất nên tạo ít nhất:

<meta property="og:title" content="Tiêu đề trang">
<meta property="og:description" content="Mô tả ngắn gọn về trang">
<meta property="og:image" content="https://happybaby2000.ru/path/to/image.jpg">
<meta property="og:url" content="https://happybaby2000.ru/current-page/">
<meta property="og:type" content="website">

Đối với thẻ sản phẩm, bạn có thể sử dụng og:type=product nếu điều đó phù hợp với việc triển khai hiện tại và không gây ra sự cố hỗ trợ.

og:image phải chứa URL tuyệt đối có thể truy cập công khai của hình ảnh. Đối với sản phẩm, nên sử dụng ảnh sản phẩm chính; đối với danh mục và trang thông tin, hãy sử dụng hình ảnh có liên quan được xác định trước hoặc ảnh dự phòng chung (fallback).

Ngoài ra, hãy kiểm tra để đảm bảo hình ảnh có sẵn mà không cần ủy quyền, không bị chặn bởi robots/firewall/CDN và được phân phối chính xác cho các bot bên ngoài.

Logic lựa chọn hình ảnh

Cần xác định mức độ ưu tiên rõ ràng:

  1. Thẻ sản phẩm — hình ảnh sản phẩm chính.
  2. Danh mục — hình ảnh danh mục, nếu được chỉ định.
  3. Trang thông tin — hình ảnh riêng của trang, nếu được chỉ định.
  4. Nếu không có hình ảnh phù hợp — sử dụng ảnh dự phòng chung của trang web.

Điều quan trọng là phải xuất rõ ràng og:image thay vì dựa vào việc ứng dụng nhắn tin tự tìm hình ảnh "đúng" trong HTML.

Cách các ứng dụng nhắn tin tạo bản xem trước

Khi người dùng gửi liên kết lần đầu tiên, máy chủ của ứng dụng nhắn tin thường tự truy cập trang, đọc HTML và lưu siêu dữ liệu tìm được. Nghĩa là, bản xem trước thường không được tạo trên điện thoại của người dùng mà ở phía Telegram/WhatsApp/VK/dịch vụ khác.

Nếu có đánh dấu Open Graph, dịch vụ thường ưu tiên dựa vào đó. Nếu thiếu hoặc thiếu một số trường, dịch vụ sẽ sử dụng các quy tắc riêng của mình: có thể lấy <title> thông thường, description, hình ảnh lớn đầu tiên, hình ảnh từ nội dung, v.v. Các quy tắc này khác nhau ở các dịch vụ khác nhau, vì vậy nếu không có đánh dấu rõ ràng, kết quả không thể coi là ổn định.

Riêng về việc bộ nhớ đệm (cache) bản xem trước

Cần lưu ý rằng các ứng dụng nhắn tin lưu vào bộ nhớ đệm kết quả phân tích cú pháp URL. Ví dụ: nếu liên kết https://happybaby2000.ru/catalog/example/ đã được gửi ngày hôm nay và ứng dụng nhắn tin đã lưu hình ảnh cũ cho liên kết đó, thì sau khi thay thế hình ảnh trên trang web, cùng một URL này có thể tiếp tục hiển thị bản xem trước cũ trong một khoảng thời gian.

Lý do là ứng dụng nhắn tin không bắt buộc phải tải lại trang và hình ảnh mỗi khi gửi liên kết. Nó thấy một URL quen thuộc và sử dụng kết quả đã lưu từ bộ nhớ đệm của nó. Thời gian sống của bộ nhớ đệm này phụ thuộc vào từng dịch vụ cụ thể và thường không nằm trong quyền kiểm soát của chúng ta.

Do đó, sau khi thay đổi og:image, bạn không thể kiểm tra kết quả chỉ bằng cách gửi lại chính URL đó và kết luận rằng thẻ đánh dấu không hoạt động.

Cách kiểm tra bản xem trước mới, bỏ qua bộ nhớ đệm cũ

Để kiểm tra, bạn có thể thêm một tham số GET tùy ý vào URL, ví dụ:

https://happybaby2000.ru/catalog/example/?preview=2

hoặc:

https://happybaby2000.ru/catalog/example/?v=20260916

Đối với trình duyệt và trang web, đây vẫn là trang đó nếu các tham số này không được sử dụng trong logic của trang. Nhưng đối với ứng dụng nhắn tin, đây là một URL khác chưa có trong bộ nhớ đệm của nó. Do đó, khả năng cao là nó sẽ yêu cầu lại trang và tạo bản xem trước mới theo các thẻ Open Graph hiện tại.

Thao tác này không "xóa" bộ nhớ đệm cũ của ứng dụng nhắn tin. Chỉ là một URL mới với chuỗi truy vấn (query string) khác sẽ tạo ra một bản ghi bộ nhớ đệm riêng biệt và cho phép bạn kiểm tra thẻ đánh dấu hiện tại mà không phải đợi bộ nhớ đệm cũ hết hạn.

Trong quá trình thử nghiệm, bạn nên thay đổi tham số mỗi khi cần đảm bảo kiểm tra tùy chọn mới, ví dụ ?preview=1, sau đó là ?preview=2.

Tiêu chí hoàn thành

  • Các thẻ Open Graph được xuất rõ ràng trên các loại trang chính.
  • og:title, og:descriptionog:image tương ứng với nội dung của trang cụ thể.
  • og:image sử dụng URL tuyệt đối.
  • Có cung cấp ảnh dự phòng (fallback) cho các trang không có hình ảnh riêng.
  • Đã xác minh rằng các bot bên ngoài có thể truy xuất hình ảnh.
  • Việc tạo bản xem trước trong các ứng dụng nhắn tin phổ biến đã được kiểm tra thủ công trên một số loại trang.
  • Đã tính đến bộ nhớ đệm khi kiểm tra các thay đổi: tùy chọn mới được kiểm tra bổ sung thông qua URL có tham số GET duy nhất.

Ворклоги

Tăng cường kiểm tra og:image sau các lỗi từ Google

Google đã báo cáo lỗi "URL không hợp lệ trong trường image" cho một số thẻ sản phẩm. Nguyên nhân được cho là các đường dẫn hình ảnh gốc có chứa ký tự tiếng Cyrillic chưa được mã hóa và khoảng trắng, mà hệ thống kiểm tra trước đây chưa phát hiện ra.

Đã cập nhật tập lệnh agent/scripts/check-page-image/index.ts của dự án happybaby2000.ru:

  • kiểm tra giá trị og:image gốc trước khi thực hiện bất kỳ chuẩn hóa nào;
  • URL phải là địa chỉ HTTP(S) tuyệt đối có chứa host;
  • phát hiện các khoảng trắng chưa mã hóa, tiếng Cyrillic, ký tự điều khiển và các ký tự không hợp lệ khác;
  • kiểm tra tính hợp lệ của các chuỗi thoát %-escape;
  • phát hiện dấu ngoặc vuông chưa mã hóa trong path/query/fragment và dấu # lặp lại trong phần fragment, đồng thời cho phép IPv6 nằm trong dấu ngoặc vuông;
  • kiểm tra tất cả các thẻ og:image trên trang, không chỉ thẻ đầu tiên;
  • phần chẩn đoán chỉ rõ số thứ tự hình ảnh, URL gốc và nguyên nhân lỗi; đối với các ký tự không hợp lệ, hệ thống cũng hiển thị mã Unicode và vị trí;
  • khi xảy ra lỗi, tập lệnh trả về mã 1, khi thành công trả về 0.

Bên cạnh đó, một bài kiểm tra liên tục agent/scripts/check-page-image/index.test.ts sử dụng Vitest đã được thêm vào. Cấu hình Vitest được mở rộng cho scripts/**/*.test.ts. Bộ kiểm tra bao gồm 28 kịch bản, bao gồm URL hợp lệ và không hợp lệ, ký tự được mã hóa, IPv6, không có hình ảnh, nhiều thẻ og:image và độ chính xác của chẩn đoán.

Quá trình kiểm tra diễn ra thành công: đã vượt qua 28 bài kiểm tra, ESLint, Prettier và git diff --check — không có lỗi.

Lệnh chạy kiểm tra:

npm run test -- scripts/check-page-image/index.test.ts

Hạn chế kiểm tra: tập lệnh này xác thực cú pháp URL từ og:image, nhưng không kiểm tra tính khả dụng của chính hình ảnh đó và không đảm bảo URL sẽ được các dịch vụ của Google chấp nhận. Tập lệnh không tự động sửa lỗi URL.

Tiến trình: Đầu tiên là kiểm tra chạy được, sau đó mới đến triển khai

Trước khi thực hiện các thay đổi, một tập lệnh TypeScript chạy trên terminal riêng biệt đã được viết trước. Tập lệnh này thực hiện yêu cầu HTTP tới trang, phân tích cú pháp HTML thông qua cheerio và kiểm tra các thẻ Open Graph bắt buộc. Điều này cung cấp một đường cơ sở khách quan trước khi chỉnh sửa và một tiêu chí nghiệm thu sẵn có cho AI agent.

Tập lệnh kiểm tra

import * as cheerio from "cheerio";

const REQUIRED_TAGS = [
  "og:title",
  "og:description",
  "og:image",
  "og:url",
  "og:type",
] as const;

function isAbsoluteHttpUrl(value: string): boolean {
  try {
    const url = new URL(value);
    return url.protocol === "http:" || url.protocol === "https:";
  } catch {
    return false;
  }
}

async function main() {
  const targetUrl = process.argv[2];

  if (!targetUrl) {
    console.error("Usage: npx tsx check-open-graph.ts <url>");
    process.exit(2);
  }

  const response = await fetch(targetUrl, {
    redirect: "follow",
    headers: {
      "User-Agent": "OpenGraphChecker/1.0",
    },
  });

  if (!response.ok) {
    console.error(`HTTP ${response.status} ${response.statusText}`);
    process.exit(1);
  }

  const html = await response.text();
  const $ = cheerio.load(html);

  let hasErrors = false;

  console.log(`HTTP: ${response.status}\n`);

  const values = Object.fromEntries(
    REQUIRED_TAGS.map((property) => {
      const value =
        $(`meta[property="${property}"]`).first().attr("content")?.trim() ?? "";

      if (!value) {
        console.log(`${property}: missing`);
        hasErrors = true;
      } else {
        console.log(`${property}: ${value}`);
      }

      return [property, value];
    }),
  );

  const image = values["og:image"];
  const ogUrl = values["og:url"];

  if (image && !isAbsoluteHttpUrl(image)) {
    console.log(`✗ og:image is not absolute: ${image}`);
    hasErrors = true;
  }

  if (ogUrl && !isAbsoluteHttpUrl(ogUrl)) {
    console.log(`✗ og:url is not absolute: ${ogUrl}`);
    hasErrors = true;
  }

  console.log(
    hasErrors
      ? "\nRESULT: invalid or incomplete"
      : "\nRESULT: OK",
  );

  process.exit(hasErrors ? 1 : 0);
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});

Trạng thái trước khi triển khai

Lần chạy đầu tiên đã cho ra kết quả âm tính đúng như dự kiến:

HTTP: 200

✗ og:title: missing
✗ og:description: missing
✗ og:image: missing
✗ og:url: missing
✗ og:type: missing

RESULT: invalid or incomplete

Sau đó, tác vụ đã được chuyển cho AI agent không phải theo cách diễn đạt trừu tượng như "thêm Open Graph", mà đi kèm với một tập lệnh kiểm tra cụ thể và cách thức có thể tái tạo để kiểm tra kết quả.

Báo cáo của Agent

Agent đã thông báo về các thay đổi sau:

Đã xong. Các thay đổi:

index.tsx — đã thêm các prop image và ogType, hiển thị og:title, og:description, og:image, og:url, og:type
index.tsx — tính toán imageUrl và truyền vào SeoHeaders với ogType="product"
Bạn có thể kiểm tra bằng tập lệnh:

npx tsx scripts/check-page-image/index.ts "http://localhost:3000/catalog/product.html"

Kiểm tra lại

Sau khi thực hiện các thay đổi, phương pháp kiểm tra tương tự đã cho kết quả:

HTTP: 200

✓ og:title: Sân chơi kích thước nhỏ Korabl
✓ og:description: Kích thước 3.48 x 1.78 x 2.32 m.
✓ og:image: http://localhost:3000/images/resized/middle/images/img.jpg
✓ og:url: http://localhost:3000/catalog/product.html
✓ og:type: product

RESULT: OK

Kết luận thực tế

Phương pháp này tỏ ra rất hữu ích: đầu tiên, một bài kiểm tra có thể chạy được tạo ra để ghi nhận trạng thái hiện tại và tiêu chí hoàn thành, sau đó bài kiểm tra này được chuyển cho người thực hiện cùng với tác vụ. Điều này làm giảm sự mơ hồ trong việc giao nhiệm vụ và giúp kết quả có thể được kiểm chứng không dựa trên báo cáo của agent, mà dựa trên hành vi thực tế của hệ thống.

Bước tiếp theo là củng cố mẫu này: nếu agent được cung cấp một tập lệnh kiểm tra, phần giao việc sẽ ngay lập tức yêu cầu không chỉ thực hiện các thay đổi mà còn phải tự chạy tập lệnh đó sau khi triển khai và đính kèm kết quả thực tế. Khi đó, chu trình sẽ trở nên khép kín: reproduce → implement → verify (tái tạo → triển khai → xác minh), và con người chỉ còn phải thực hiện việc kiểm tra đối soát thay vì kiểm tra ban đầu.