Full working example available on GitHub: strip-pdf-metadata-dotnet
Introduction
PDF metadata sanitization is a GroupDocs.Metadata workflow for .NET that clears PDF Info dictionary and XMP identity fields from C# services. When a contract PDF leaves an internal drive, Author, Creator, Producer, Keywords, and XMP packets often leave with it. Browser cleaners and a quick Acrobat pass can look successful while XMP still names the original author. I hit that gap when a “cleaned” draft still showed Alice Example under Author after a partner opened the file in another viewer.
GroupDocs.Metadata for .NET gives C# services two clear intensities of cleanup on the same Metadata object: Sanitize() for a full wipe of detected packages, and RemoveProperties when Title and Subject must stay but person identity must not. This article compares both approaches with the inspect and verify steps that make the result auditable.
You will leave with working .NET 8 samples, a decision rule for outbound versus archive-friendly cleanup, and a verify predicate that checks Author / Person.Creator instead of panicking over PDF-engine Creator/Producer fingerprints after Save.
Why PDF metadata cleanup matters
Outbound file shares, multi-tenant downloads, and regulated archives all need a repeatable metadata removal API rather than a desktop click. This approach is particularly valuable for:
- Partner portals: Full wipe before a PDF crosses a trust boundary
- Records search: Keep Title/Subject while dropping Author-style fields
- Incident response: Prove Author is gone after a mistaken share
- CI gates: Fail a build when verify returns false
A one-line policy (“remove metadata”) hides the Sanitize versus selective choice. Naming the intensity in code review prevents silent over-deletion of Keywords your archive still needs.
Prerequisites
Before starting, ensure you have:
- .NET 8 SDK
- GroupDocs.Metadata 26.8.0 (temporary license)
- A PDF that still carries Info and/or XMP identity fields
- Visual Studio 2022 or VS Code (optional)
Installation
Install GroupDocs.Metadata via NuGet:
dotnet add package GroupDocs.Metadata --version 26.8.0
Or restore from the sample project’s .csproj. For unrestricted Save, set environment variable LIC_METADATA_VALID to the folder that contains GroupDocs.Metadata.Product.Family.lic.
Method 1 - Inspect before you clean
Start with a read-only listing so you know which fields the PDF actually carries. Browser tools often miss XMP; this listing is the baseline for a before/after check.
using var metadata = new Metadata(inputPath);
var properties = metadata.FindProperties(p =>
p.Tags.Contains(Tags.Person.Creator) ||
p.Tags.Contains(Tags.Tool.Software) ||
p.Tags.Contains(Tags.Content.Title) ||
p.Tags.Contains(Tags.Content.Subject) ||
string.Equals(p.Name, "Author", StringComparison.OrdinalIgnoreCase) ||
string.Equals(p.Name, "Creator", StringComparison.OrdinalIgnoreCase) ||
string.Equals(p.Name, "Producer", StringComparison.OrdinalIgnoreCase) ||
string.Equals(p.Name, "Keywords", StringComparison.OrdinalIgnoreCase));
foreach (var property in properties)
{
Console.WriteLine($"{property.Name} = {property.Value}");
}
Key points:
- Tags plus names: Mix tag checks with
Author/Keywordsequals for producers that tag fields differently - No mutation: Safe for dry-run modes and support tickets
- Shared filters: Reuse the same ideas in removal predicates later
Method 2 - Sanitize all detected metadata
Use Sanitize() when the PDF must leave with no authorship trail. The call clears recognized packages, including Info dictionary fields and XMP when the API detects them, then you save a new file.
using var metadata = new Metadata(inputPath);
int removed = metadata.Sanitize();
Console.WriteLine(removed);
metadata.Save(outputPath);
Key points:
- One call: Small surface for outbound routes
- Log the count: Operators can spot already-clean inputs versus large wipes
- Expect tool stamps: After
Save, Creator/Producer may show PDF-engine Tool.Software values
Best when: partner downloads, public links, cross-tenant exchange.
Method 3 - Remove author-style properties only
When Title, Subject, and Keywords still feed search, strip person identity with RemoveProperties instead of wiping every package.
using var metadata = new Metadata(inputPath);
int removed = metadata.RemoveProperties(p =>
p.Tags.Contains(Tags.Person.Creator) ||
p.Tags.Contains(Tags.Person.Editor) ||
string.Equals(p.Name, "Author", StringComparison.OrdinalIgnoreCase) ||
string.Equals(p.Name, "Creator", StringComparison.OrdinalIgnoreCase) ||
string.Equals(p.Name, "Producer", StringComparison.OrdinalIgnoreCase));
Console.WriteLine(removed);
metadata.Save(outputPath);
Key points:
- Predicate is reviewable: Code review can see exactly which identity fields drop
- Descriptive fields stay: Title/Subject/Keywords remain with this sample filter
- Same SDK: No second library for the selective path
Best when: internal archives, circulating drafts, policies that ban Author but allow keywords.
How do I prove Author removal after Save?
Re-open the cleaned PDF and search only for Author / Person.Creator / Person.Editor. Print True when none remain. Do not treat residual Creator/Producer Tool.Software fingerprints as a failed wipe - Save may rewrite those with the PDF engine name. That distinction is what keeps compliance checks honest in CI and stops false alarms when the engine stamps its own tool fields.
using var metadata = new Metadata(inputPath);
var leftovers = metadata.FindProperties(p =>
p.Tags.Contains(Tags.Person.Creator) ||
p.Tags.Contains(Tags.Person.Editor) ||
string.Equals(p.Name, "Author", StringComparison.OrdinalIgnoreCase));
Console.WriteLine(!leftovers.Any());
Key points:
- Ask the right question: “Is Author gone?” not “Is Creator blank?”
- Second open: Verify after
Save, not only in-memory - CI friendly: One boolean for tests and logs
Choosing between Sanitize and RemoveProperties
| Question | Prefer Sanitize | Prefer RemoveProperties |
|---|---|---|
| File exits the company? | Yes | Only if descriptive fields must survive |
| Archive search needs Title? | No | Yes |
| Policy says “no people in metadata”? | Either, then verify | Yes, with person-focused predicate |
| Operator wants one button? | Yes | Wrap behind a named route |
strip-pdf-metadata-dotnet is a runnable .NET demo that wires all four steps against Resources/contract-with-metadata.pdf so you can see inspect, sanitize, selective removal, and verify in one console run.
Common mistakes
- Trusting a browser cleaner alone: XMP often survives.
- Verifying Creator/Producer names: Engine fingerprints after
Savecause false failures. - One predicate forever: Revisit identity field names when new producers appear.
- Skipping license setup for Save: Evaluation mode can block unrestricted writes; set
LIC_METADATA_VALIDfor full pipeline tests. - Skipping inspect: Without a before listing you cannot tell whether Sanitize removed 7 fields or 0 because the file was already clean.
On the seeded sample contract-with-metadata.pdf, a licensed run typically prints Author and Keywords on inspect, a Sanitize removal count around 7, and True from the Author-focused verify. Selective author removal prints a smaller count (around 3) while Title and Subject remain visible on a second inspect.
Additional Resources
- Use case: Sanitize vs author removal for PDF metadata (.NET)
- Docs: remove all detected metadata packages
- Docs: remove specific metadata properties
- GitHub: strip-pdf-metadata-dotnet
- API reference
Conclusion
PDF metadata cleanup on .NET is not one API call with a vague name. Choose Sanitize() for outbound wipes, RemoveProperties when Title and Subject must remain, and always inspect then verify Author-style fields after Save. Clone the sample repository, run it on the seeded contract PDF, then copy the same methods into your upload service with logging around the removal counts.