Đây là bài đồng hành với PDF properties nên hiển thị thương hiệu của bạn, không phải tên công cụ của người khác. Bài kia giải thích vì sao nên quan tâm metadata. Bài này là sổ tay vận hành: mỗi trường dùng để làm gì trong PDF specification, ai đọc nó, lỗi thường gặp và cách kiểm tra output của bạn đã phát hành đúng thứ bạn định đặt hay chưa.
gPdf cung cấp sáu trường chuẩn mà PDF spec định nghĩa cho document-level metadata. Chúng nằm trong settings.metadata của JSON DocumentRequest. Mỗi trường đều optional; nếu bạn không đặt, gPdf fallback về default_metadata của token (Enterprise policy feature) hoặc system default.
{
"settings": {
"metadata": {
"title": "...",
"language": "...",
"author": "...",
"subject": "...",
"creator": "...",
"producer": "..."
}
}
}
Phần còn lại của bài đi theo từng trường. Mỗi phần có cùng cấu trúc: trường này là gì, nó xuất hiện ở đâu, lỗi thường gặp, quy tắc thực dụng. Thứ tự là nên điền gì trước, rồi tới trường tiếp theo.
title — tài liệu là gì
PDF spec mô tả đây là “document title.”
Nó xuất hiện ở đâu:
- Title bar trong PDF viewer: Adobe Reader, Preview, Foxit, Chromium PDF viewer đều hiển thị.
- Tab trình duyệt khi PDF mở inline (
Content-Disposition: inline). - Search index: Spotlight, Outlook, SharePoint và full-text indexer của Google Drive đều đọc
titlevà đặt trọng số cao.
Lỗi thường gặp:
- ❌ Đặt title bằng filename.
invoice-20260318.pdflà filename. Title nên là thứ con người đọc, ví dụInvoice INV-2026-3401. Filename phục vụ filesystem; title phục vụ viewer và search. - ❌ Để title trống. Viewer fallback về filename. Kết quả nhìn như file được machine emit tự động.
- ❌ Nhét thương hiệu vào title.
Acme Logistics — Invoice INV-2026-3401làm title bar rối. Thương hiệu thuộc vềauthor, không phảititle.
Quy tắc thực dụng: title nên khớp với H1 của trang đã render. Nếu dòng đầu của invoice template là “Invoice INV-2026-3401”, đó là title.
language — cho accessibility, search và compliance
language là BCP-47 language tag: en, de, zh-Hans, pt-BR, ar-SA. Hãy đặt cho mọi tài liệu. Trong sáu trường, đây là trường có downstream consequence cụ thể nhất nhưng chi phí triển khai nhỏ nhất, nên nó đứng ở vị trí thứ hai thay vì bị chôn xuống dưới.
Nó xuất hiện ở đâu:
- Screen readers: JAWS, NVDA, VoiceOver dùng nó để chọn phoneme set đúng. Một screen reader tiếng Anh đọc PDF
language: "de"sẽ phát âm từ tiếng Đức đúng hơn; nếu thiếu tag, prosody sẽ sai. - Search engines và indexers: ảnh hưởng tới stemming và stopword list theo locale. Một invoice
language: "zh-Hans"được index bằng Chinese segmentation; thiếu tag thường khiến hệ thống default sang English và index kém hữu dụng. - PDF/A compliance: PDF/A-2a và PDF/A-3a (accessibility profiles) yêu cầu language tag. Thiếu nó, veraPDF validation fail.
Lỗi thường gặp:
- ❌ Không đặt. Default nên là “locale của người nhận”, không phải “default của platform”. Stack bị rò rỉ thường không viết field này, khiến screen reader phát âm sai và search index xử lý sai ngôn ngữ.
- ❌ Dùng string không phải BCP-47 như
"english"hoặc"EN-US". PDF spec kỳ vọng RFC 5646 tags:en,en-US,de,pt-BR. - ❌ Hard-code default của platform, ví dụ luôn
"en", bất kể ngôn ngữ thật của tài liệu. Một invoice tiếng Bồ Đào Nha gắn tag"en"còn tệ hơn không gắn tag, vì nó đánh lừa indexer.
Quy tắc thực dụng: tag phải khớp ngôn ngữ thật của nội dung. Với khách hàng Brazil nhận invoice tiếng Bồ Đào Nha, đặt "language": "pt-BR", không phải "en". Với tài liệu đa ngôn ngữ, chọn ngôn ngữ chính và dùng thuộc tính Lang trên từng content element cho phần còn lại; đó là tính năng accessibility của tagged PDF, nằm ngoài trường language cấp tài liệu.
author — ai sở hữu tài liệu
Trong PDF spec, author là “the name of the person or organisation that created the document.” Với business PDF gửi tới người nhận, câu trả lời gần như luôn là tổ chức, nhưng hình dạng đúng vẫn tùy ngữ cảnh.
Nó xuất hiện ở đâu:
- Properties dialog trong mọi PDF viewer, được ghi rõ là “Author.”
- DMS / archive indexers, thường dùng làm filter.
- PDF/A XMP metadata stream, nơi nó đi vào archive dài hạn.
Lỗi thường gặp:
- ❌
"author": "[email protected]": vô tình leak email operator vào mọi PDF, rồi đi vào search index và thành vấn đề PII dài hạn. - ❌
"author": "PDF Generator Service": tên internal tool, không có ý nghĩa với người nhận. - ❌ Trống: Preview và nhiều viewer hiển thị “(no author)”, đọc như không ai sở hữu tài liệu.
Dạng dùng tốt:
- ✅
"author": "Acme Logistics, Inc."— tổ chức rõ ràng. - ✅
"author": "Acme Logistics — Billing"— tổ chức + phòng ban, với tài liệu route tới desk cụ thể. - ✅
"author": "Bridge Capital Partners — Fund III"— hữu ích trong finance/legal khi attribution thuộc về entity cụ thể. - ✅
"author": "Maria López, RICS Surveyor"— với single-author publishing như report, valuation, legal opinion, nơi cá nhân chính là attribution biên tập.
Quy tắc thực dụng: author là entity mà người nhận nên gắn tài liệu với. Trong multi-tenant SaaS tạo PDF thay mặt khách hàng, author nên là tên tổ chức của khách hàng, không phải tên platform. Tên platform thuộc về creator, xem bên dưới. Với consultancy / publishing / legal nơi cá nhân là brand, dùng cá nhân là hợp lý.
subject — loại tài liệu là gì
subject là mô tả ngắn về loại tài liệu. Viewer không đặt nó ở vị trí nổi bật; phần lớn user không thấy nếu không mở Properties dialog. Nhưng document management systems, archive systems và rule-based email/file routing có dùng nó.
Nó xuất hiện ở đâu:
- Properties dialog, vị trí phụ.
- DMS routing rules và logic phân bucket archive.
- XMP metadata stream trong PDF/A.
Lỗi thường gặp:
- ❌
"subject": "Invoice for Acme on 2026-03-18 for $4,532.10": đây là mô tả instance tài liệu, không phải class. Nó thuộc vềtitle. - ❌ Trống: bạn mất một routing hook miễn phí cho downstream systems.
- ❌ Dùng class không nhất quán (
"Invoice"vs"Invoice/2026-03"vs"Monthly invoice"): DMS filter không thể bucket trên một target thay đổi.
Dạng dùng tốt:
- ✅
"subject": "Invoice" - ✅
"subject": "Monthly account statement" - ✅
"subject": "Shipping label — 4×6 thermal" - ✅
"subject": "Q3 2026 board pack"
Quy tắc thực dụng: độ chi tiết đúng là document class, không phải document instance. Một DMS nhận hàng nghìn PDF có thể route theo subject nếu bạn cho nó vocabulary nhất quán. Chọn một bộ class hữu hạn cho platform của bạn và đừng lệch khỏi nó: mọi invoice platform tạo ra nên có đúng "subject": "Invoice".
creator và producer — cặp dễ bị nhầm nhất
Đây là nơi nhiều đội ngừng đọc PDF spec và bắt đầu đoán. Spec nói rất rõ: hai trường này có nghĩa khác nhau.
creator: ứng dụng tạo source content, tức hệ thống upstream quyết định tài liệu nên nói gì.producer: ứng dụng tạo PDF bytes, tức rendering engine biến nội dung đó thành file PDF.
Với một SaaS billing platform tạo invoice qua JSON-to-PDF API như gPdf:
creator= SaaS billing platform kèm version. Đó là ứng dụng quyết định đây là invoice cho Acme với tổng tiền 4.532,10 USD.producer= renderer. Mặc định là “gPdf”. Nhưng vì rendering layer là hạ tầng do SaaS chọn, SaaS có thể chính đáng đặtproducerthành tên platform của mình. Platform đó, theo nghĩa thực tế, đã tạo PDF bytes bằng cách delegated tới gPdf như hạ tầng.
{
"creator": "Acme Billing Platform v7.2",
"producer": "Acme Billing Platform"
}
Nó xuất hiện ở đâu:
- Properties dialog, cả hai đều có label.
- Output
pdfinfo, nằm cạnh nhau. - PDF/A XMP stream; cả hai trường phải non-empty trong PDF/A.
Lỗi thường gặp:
- ❌
creatorbị đặt thành Chromium / Mozilla user-agent string. Thường xảy ra khi stack PDF dùng headless browser tự động truyền User-Agent vàocreator. Đó là version browser, không phải hệ thống source-of-truth. Hãy override. - ❌
producergiữ tên renderer mặc định. Nhiều đội không override, nên PDF nào cũng nói “Skia/PDF m120” hoặc “wkhtmltopdf”. Bài white-label giải thích vì sao điều này quan trọng với B2B. - ❌ Đặt cùng giá trị cho cả hai. Chấp nhận được nhưng lãng phí; hai trường tồn tại để viewer phân biệt “source app” với “render engine”. Hãy dùng đúng.
Quy tắc thực dụng: creator là tên application của bạn kèm version, ví dụ "Acme Billing Platform v7.2"; producer là brand hoặc tên platform không kèm version, ví dụ "Acme Billing Platform". Cả hai nên là giá trị người nhận nhận ra được.
Empty fields, per-token defaults và bất ngờ downstream
Ba chi tiết triển khai nên biết trước khi phát hành:
- Empty hoặc whitespace-only strings được xem như không cung cấp. Gửi
"title": ""giống như bỏ quatitle; API không viết empty string vào PDF mà đi theo fallback chain (token default -> system default). Đây là nguyên nhân phổ biến nhất của bug report “tôi đã set nhưng không thấy”. - Token policies có thể strip hoặc default metadata fields. Một multi-tenant SaaS dùng gPdf có thể đặt
default_metadatatrên từng API token để mọi PDF token đó tạo ra đều mangauthorvàproducercủa khách hàng, không cần tin từng developer đặt chúng trong mỗi request. Token-level default là lớp enforcement đúng cho yêu cầu “mọi PDF của Acme phải ghi Acme”. - Downstream pipelines có thể rewrite metadata của bạn. Công cụ post-process PDF sau khi gPdf trả về, như Ghostscript không bật metadata-preservation flags rõ ràng, một số enterprise DRM tools hoặc “PDF optimisers”, có thể overwrite Producer bằng tên của chúng và hoàn tác branding bạn vừa đặt. Hãy verify trên production pipeline thật, không chỉ raw gPdf response.
Kiểm tra metadata của bạn
Sau khi triển khai các thay đổi trên, có ba cách nhanh để kiểm tra PDF thật sự ship đúng thứ bạn định đặt:
Command line (macOS / Linux, cần poppler-utils):
$ pdfinfo your-output.pdf | head -10
Title: Invoice INV-2026-3401
Subject: Monthly invoice — 2026-03
Author: Acme Logistics, Inc.
Creator: Acme Billing Platform v7.2
Producer: Acme Billing Platform
Language: en
Acrobat / Adobe Reader: File -> Properties -> Description tab. Cả sáu trường xuất hiện, và Title hiển thị trên title bar của viewer ở phía trên.
macOS Preview: ⌘+I (Get Info). Pane inspector “PDF” hiển thị cùng các trường đó.
Nếu trường nào trống, blank hoặc hiện tên công cụ bạn không đặt, hãy lần ngược request body. Nguyên nhân phổ biến nhất là gửi "" (empty string), API xem như “not provided” và fallback về default. Nguyên nhân phổ biến thứ hai là downstream pipeline như Ghostscript, DRM hoặc optimiser overwrite field sau khi gPdf trả về; hãy test production, không chỉ raw render response.
Metadata trong PDF/A archival
Nếu bạn render cho lưu trữ dài hạn với settings.profile: "pdfa-2b" (hoặc -2a, -3a, -3b), metadata không còn optional mà trở thành phần chịu tải:
- Trường
producerkhông thể trống trong file conform PDF/A; tối thiểu system default sẽ được ghi. languagebắt buộc với accessibility profiles (PDF/A-2a, PDF/A-3a). Thiếu nó, veraPDF validation fail.- XMP metadata stream mà PDF/A yêu cầu được tạo tự động từ sáu trường ở trên; bạn không cần tự dựng.
title,author,subject,creator,producervàlanguageđều đi vào XMP stream, nên metadata indexer của archive downstream (Preservica, Archivematica) có thể build catalog từ chúng mà không cần parse lại document body.
Với tài liệu lưu trữ, branded metadata không chỉ là polish thương hiệu; nó là một phần độ bền của artifact. Cơ quan hải quan Đức, cơ quan thuế Brazil hoặc bất kỳ archive dài hạn nào mở PDF của bạn trong 10 năm sẽ thấy đúng những gì nằm trong các trường này vào ngày bạn render. Đặt chúng có chủ đích tại render time là cơ hội duy nhất của bạn.
gPdf chưa expose gì
Để trung thực về surface hiện tại: PDF spec cũng định nghĩa Keywords (search terms tự do) và XMP metadata stream có thể chứa arbitrary custom key-value pairs. gPdf chưa expose hai phần này trong API hiện tại.
Nếu bạn cần cất arbitrary business data trong PDF như order UUID, warehouse code hoặc template version, workaround hôm nay là:
- Đặt
subjectthành short string có cấu trúc để downstream systems parse. - Giữ business data trong database của bạn, key theo filename hoặc content hash.
- Chờ: XMP custom fields nằm trong roadmap, và khi phát hành sẽ là câu trả lời đúng cho hidden machine-readable workflow context.
Trộn lẫn “branded metadata” (sáu trường chuẩn, có hôm nay) với “custom business metadata” (XMP custom fields, tương lai) là cách dễ nhất để over-promise khả năng hiện tại. Nên giữ chúng tách biệt trong planning của bạn.
Ví dụ hoàn chỉnh
Một SaaS billing platform (Acme Billing Platform) tạo invoice cho khách hàng Đức (Müller Versand GmbH), sẵn sàng lưu trữ như PDF/A:
{
"settings": {
"profile": "pdfa-3b",
"metadata": {
"title": "Rechnung RE-2026-0412",
"language": "de",
"author": "Müller Versand GmbH",
"subject": "Monatsrechnung — März 2026",
"creator": "Acme Billing Platform v7.2",
"producer": "Acme Billing Platform"
}
}
}
pdfinfo trên PDF kết quả:
$ pdfinfo invoice-2026-0412.pdf | head -10
Title: Rechnung RE-2026-0412
Subject: Monatsrechnung — März 2026
Author: Müller Versand GmbH
Creator: Acme Billing Platform v7.2
Producer: Acme Billing Platform
Language: de
Title bằng tiếng Đức, author là Müller Versand (entity GmbH của khách hàng, bên nhận tài liệu), creator là Acme Billing Platform (hệ thống biên tập quyết định nội dung trang), producer là brand Acme Billing Platform, language tag đúng cho German screen reader và German full-text indexer sau này trong DMS của Müller. Profile PDF/A-3b nghĩa là bộ metadata này cũng được serialize vào XMP stream cho lưu trữ dài hạn.
Không có gì trong file properties nêu tên gPdf, Chromium hoặc bất kỳ công cụ nào khách hàng không chọn. Đó chính là mục tiêu.
Nâng cấp nhỏ nhất
Nếu bạn đã POST tới /api/v1/pdf/render và request hiện tại không có settings.metadata, cải tiến nhỏ nhất là thêm ba dòng vào JSON bạn đã gửi:
{
"pages": [...],
"settings": {
+ "metadata": {
+ "author": "Your customer's organisation",
+ "producer": "Your platform"
+ }
}
}
Hai trường, một key mới. Kiểm tra bằng pdfinfo trong vài giây. Khi chúng đã ổn, hãy điền title, language, subject và creator khi có thời gian.
Nằm ở đâu
- §4.14.2 Metadata — API reference cho các trường này.
- PDF white-labelling (companion post) — lý do và case B2B SaaS.
- PDF/A and Factur-X explained for engineers — liên quan nếu metadata story của bạn bao gồm lưu trữ dài hạn.