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 / Keywords equals 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 Save cause 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_VALID for 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

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.